From 6c77c2fafbeb323dae454ec3df64550a98bf317d Mon Sep 17 00:00:00 2001 From: Dan Caddigan Date: Mon, 24 Aug 2020 00:06:26 -0400 Subject: [PATCH] feat(decorators): add DateOnly and DateTime (#393) --- .../02-complex-example/generated/binding.ts | 27 +++ .../02-complex-example/generated/classes.ts | 104 ++++++++--- .../generated/schema.graphql | 27 +++ .../src/modules/user/user.model.ts | 12 +- examples/02-complex-example/tools/seed.ts | 4 + package.json | 1 + src/core/server.ts | 6 + src/core/types.ts | 3 +- src/decorators/DateField.ts | 1 + src/decorators/DateOnlyField.ts | 28 +++ src/decorators/DateTimeField.ts | 28 +++ src/decorators/index.ts | 2 + src/metadata/metadata-storage.ts | 2 + src/schema/SchemaGenerator.ts | 6 +- src/schema/TypeORMConverter.ts | 25 +-- src/schema/type-conversion.ts | 16 +- .../__snapshots__/schema.test.ts.snap | 27 +++ src/test/generated/binding.ts | 27 +++ src/test/generated/classes.ts | 164 ++++++++++++------ src/test/generated/schema.graphql | 27 +++ .../kitchen-sink/kitchen-sink.model.ts | 10 ++ yarn.lock | 5 + 22 files changed, 454 insertions(+), 98 deletions(-) create mode 100644 src/decorators/DateOnlyField.ts create mode 100644 src/decorators/DateTimeField.ts diff --git a/examples/02-complex-example/generated/binding.ts b/examples/02-complex-example/generated/binding.ts index 9dad4a55..512c26bc 100644 --- a/examples/02-complex-example/generated/binding.ts +++ b/examples/02-complex-example/generated/binding.ts @@ -55,6 +55,10 @@ export type UserOrderByInput = 'createdAt_ASC' | 'booleanField_DESC' | 'dateField_ASC' | 'dateField_DESC' | + 'dateOnlyField_ASC' | + 'dateOnlyField_DESC' | + 'dateTimeField_ASC' | + 'dateTimeField_DESC' | 'emailField_ASC' | 'emailField_DESC' | 'enumField_ASC' | @@ -137,6 +141,8 @@ export interface BaseWhereInput { export interface UserCreateInput { booleanField?: Boolean | null dateField?: DateTime | null + dateOnlyField?: Date | null + dateTimeField?: DateTime | null emailField?: String | null enumField?: StringEnum | null floatField?: Float | null @@ -175,6 +181,8 @@ export interface UserCreateInput { export interface UserUpdateInput { booleanField?: Boolean | null dateField?: DateTime | null + dateOnlyField?: Date | null + dateTimeField?: DateTime | null emailField?: String | null enumField?: StringEnum | null floatField?: Float | null @@ -242,6 +250,16 @@ export interface UserWhereInput { dateField_lte?: DateTime | null dateField_gt?: DateTime | null dateField_gte?: DateTime | null + dateOnlyField_eq?: Date | null + dateOnlyField_lt?: Date | null + dateOnlyField_lte?: Date | null + dateOnlyField_gt?: Date | null + dateOnlyField_gte?: Date | null + dateTimeField_eq?: DateTime | null + dateTimeField_lt?: DateTime | null + dateTimeField_lte?: DateTime | null + dateTimeField_gt?: DateTime | null + dateTimeField_gte?: DateTime | null emailField_eq?: String | null emailField_contains?: String | null emailField_startsWith?: String | null @@ -456,6 +474,8 @@ export interface User extends BaseGraphQLObject { version: Int booleanField?: Boolean | null dateField?: DateTime | null + dateOnlyField?: Date | null + dateTimeField?: DateTime | null emailField?: String | null enumField?: StringEnum | null floatField?: Float | null @@ -495,6 +515,13 @@ The `Boolean` scalar type represents `true` or `false`. */ export type Boolean = boolean +/* +A date string, such as 2007-12-03, compliant with the `full-date` format +outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for +representation of dates and times using the Gregorian calendar. +*/ +export type Date = string + /* The javascript `Date` as string. Type represents date and time as the ISO Date string. */ diff --git a/examples/02-complex-example/generated/classes.ts b/examples/02-complex-example/generated/classes.ts index 8f3cc055..e0048401 100644 --- a/examples/02-complex-example/generated/classes.ts +++ b/examples/02-complex-example/generated/classes.ts @@ -2,7 +2,7 @@ // will be re-written. If you need to change this file, update models or add // new TypeGraphQL objects // @ts-ignore -import { GraphQLDateTime as DateTime } from "graphql-iso-date"; +import { DateResolver as Date } from "graphql-scalars"; // @ts-ignore import { GraphQLID as ID } from "graphql"; // @ts-ignore @@ -14,13 +14,19 @@ import { Int } from "type-graphql"; // @ts-ignore -import { registerEnumType } from "type-graphql"; +import { registerEnumType, GraphQLISODateTime as DateTime } from "type-graphql"; // @ts-ignore eslint-disable-next-line @typescript-eslint/no-var-requires const { GraphQLJSONObject } = require("graphql-type-json"); // @ts-ignore -import { BaseWhereInput, JsonObject, PaginationArgs } from "../../../src"; +import { + BaseWhereInput, + JsonObject, + PaginationArgs, + DateOnlyString, + DateTimeString +} from "../../../src"; import { StringEnum } from "../src/modules/user/user.model"; // @ts-ignore import { User } from "../src/modules/user/user.model"; @@ -41,6 +47,12 @@ export enum UserOrderByEnum { dateField_ASC = "dateField_ASC", dateField_DESC = "dateField_DESC", + dateOnlyField_ASC = "dateOnlyField_ASC", + dateOnlyField_DESC = "dateOnlyField_DESC", + + dateTimeField_ASC = "dateTimeField_ASC", + dateTimeField_DESC = "dateTimeField_DESC", + emailField_ASC = "emailField_ASC", emailField_DESC = "emailField_DESC", @@ -135,19 +147,19 @@ export class UserWhereInput { @TypeGraphQLField(() => [ID], { nullable: true }) id_in?: string[]; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) createdAt_eq?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) createdAt_lt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) createdAt_lte?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) createdAt_gt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) createdAt_gte?: Date; @TypeGraphQLField(() => ID, { nullable: true }) @@ -156,19 +168,19 @@ export class UserWhereInput { @TypeGraphQLField(() => [ID], { nullable: true }) createdById_in?: string[]; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) updatedAt_eq?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) updatedAt_lt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) updatedAt_lte?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) updatedAt_gt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) updatedAt_gte?: Date; @TypeGraphQLField(() => ID, { nullable: true }) @@ -180,19 +192,19 @@ export class UserWhereInput { @TypeGraphQLField({ nullable: true }) deletedAt_all?: Boolean; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) deletedAt_eq?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) deletedAt_lt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) deletedAt_lte?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) deletedAt_gt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) deletedAt_gte?: Date; @TypeGraphQLField(() => ID, { nullable: true }) @@ -207,21 +219,51 @@ export class UserWhereInput { @TypeGraphQLField(() => [Boolean], { nullable: true }) booleanField_in?: Boolean[]; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) dateField_eq?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) dateField_lt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) dateField_lte?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) dateField_gt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) dateField_gte?: Date; + @TypeGraphQLField(() => Date, { nullable: true }) + dateOnlyField_eq?: DateOnlyString; + + @TypeGraphQLField(() => Date, { nullable: true }) + dateOnlyField_lt?: DateOnlyString; + + @TypeGraphQLField(() => Date, { nullable: true }) + dateOnlyField_lte?: DateOnlyString; + + @TypeGraphQLField(() => Date, { nullable: true }) + dateOnlyField_gt?: DateOnlyString; + + @TypeGraphQLField(() => Date, { nullable: true }) + dateOnlyField_gte?: DateOnlyString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + dateTimeField_eq?: DateTimeString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + dateTimeField_lt?: DateTimeString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + dateTimeField_lte?: DateTimeString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + dateTimeField_gt?: DateTimeString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + dateTimeField_gte?: DateTimeString; + @TypeGraphQLField({ nullable: true }) emailField_eq?: string; @@ -678,9 +720,15 @@ export class UserCreateInput { @TypeGraphQLField({ nullable: true }) booleanField?: boolean; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) dateField?: Date; + @TypeGraphQLField(() => Date, { nullable: true }) + dateOnlyField?: DateOnlyString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + dateTimeField?: DateTimeString; + @TypeGraphQLField({ nullable: true }) emailField?: string; @@ -786,9 +834,15 @@ export class UserUpdateInput { @TypeGraphQLField({ nullable: true }) booleanField?: boolean; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) dateField?: Date; + @TypeGraphQLField(() => Date, { nullable: true }) + dateOnlyField?: DateOnlyString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + dateTimeField?: DateTimeString; + @TypeGraphQLField({ nullable: true }) emailField?: string; diff --git a/examples/02-complex-example/generated/schema.graphql b/examples/02-complex-example/generated/schema.graphql index 8846f76b..9f5d7655 100644 --- a/examples/02-complex-example/generated/schema.graphql +++ b/examples/02-complex-example/generated/schema.graphql @@ -55,6 +55,13 @@ input BaseWhereInput { deletedById_eq: String } +""" +A date string, such as 2007-12-03, compliant with the `full-date` format +outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for +representation of dates and times using the Gregorian calendar. +""" +scalar Date + """ The javascript `Date` as string. Type represents date and time as the ISO Date string. """ @@ -108,6 +115,8 @@ type User implements BaseGraphQLObject { version: Int! booleanField: Boolean dateField: DateTime + dateOnlyField: Date + dateTimeField: DateTime emailField: String enumField: StringEnum floatField: Float @@ -147,6 +156,8 @@ type User implements BaseGraphQLObject { input UserCreateInput { booleanField: Boolean dateField: DateTime + dateOnlyField: Date + dateTimeField: DateTime emailField: String enumField: StringEnum floatField: Float @@ -193,6 +204,10 @@ enum UserOrderByInput { booleanField_DESC dateField_ASC dateField_DESC + dateOnlyField_ASC + dateOnlyField_DESC + dateTimeField_ASC + dateTimeField_DESC emailField_ASC emailField_DESC enumField_ASC @@ -252,6 +267,8 @@ enum UserOrderByInput { input UserUpdateInput { booleanField: Boolean dateField: DateTime + dateOnlyField: Date + dateTimeField: DateTime emailField: String enumField: StringEnum floatField: Float @@ -319,6 +336,16 @@ input UserWhereInput { dateField_lte: DateTime dateField_gt: DateTime dateField_gte: DateTime + dateOnlyField_eq: Date + dateOnlyField_lt: Date + dateOnlyField_lte: Date + dateOnlyField_gt: Date + dateOnlyField_gte: Date + dateTimeField_eq: DateTime + dateTimeField_lt: DateTime + dateTimeField_lte: DateTime + dateTimeField_gt: DateTime + dateTimeField_gte: DateTime emailField_eq: String emailField_contains: String emailField_startsWith: String diff --git a/examples/02-complex-example/src/modules/user/user.model.ts b/examples/02-complex-example/src/modules/user/user.model.ts index d4c65edc..6a4d2f75 100644 --- a/examples/02-complex-example/src/modules/user/user.model.ts +++ b/examples/02-complex-example/src/modules/user/user.model.ts @@ -4,6 +4,10 @@ import { BooleanField, CustomField, DateField, + DateOnlyField, + DateOnlyString, + DateTimeField, + DateTimeString, EmailField, EnumField, IdField, @@ -32,8 +36,14 @@ export class User extends BaseModel { @DateField({ nullable: true }) dateField: Date; + @DateOnlyField({ nullable: true }) + dateOnlyField?: DateOnlyString; + + @DateTimeField({ nullable: true }) + dateTimeField?: DateTimeString; + @EmailField({ nullable: true }) - emailField: string; + emailField?: string; @EnumField('StringEnum', StringEnum, { nullable: true }) enumField: StringEnum; diff --git a/examples/02-complex-example/tools/seed.ts b/examples/02-complex-example/tools/seed.ts index 31b3db65..dd1e88a0 100644 --- a/examples/02-complex-example/tools/seed.ts +++ b/examples/02-complex-example/tools/seed.ts @@ -44,6 +44,8 @@ async function seedDatabase() { emptyArray: [] }; const dateField = new Date().toISOString(); + const dateOnlyField = new Date().toISOString().substring(0, 10); + const dateTimeField = new Date().toISOString(); try { const user = await binding.mutation.createUser( @@ -53,6 +55,8 @@ async function seedDatabase() { stringField, jsonField, dateField, + dateOnlyField, + dateTimeField, enumField: 'FOO', geometryField: { type: 'Point', diff --git a/package.json b/package.json index 17e6702f..5537e93a 100644 --- a/package.json +++ b/package.json @@ -93,6 +93,7 @@ "graphql-fields": "^2.0.3", "graphql-import-node": "^0.0.4", "graphql-iso-date": "^3.6.1", + "graphql-scalars": "^1.2.6", "graphql-tools": "^4.0.6", "graphql-type-json": "^0.3.0", "lodash": "^4.17.15", diff --git a/src/core/server.ts b/src/core/server.ts index 06e3cc9e..1ed2e61c 100644 --- a/src/core/server.ts +++ b/src/core/server.ts @@ -6,6 +6,7 @@ import { Request } from 'express'; import express = require('express'); import { GraphQLID, GraphQLSchema } from 'graphql'; import { Binding } from 'graphql-binding'; +import { DateResolver } from 'graphql-scalars'; import { Server as HttpServer } from 'http'; import { Server as HttpsServer } from 'https'; const open = require('open'); // eslint-disable-line @typescript-eslint/no-var-requires @@ -166,6 +167,11 @@ export class Server { { type: 'ID' as any, scalar: GraphQLID + }, + // Note: DateTime already included in type-graphql + { + type: 'DateOnlyString' as any, + scalar: DateResolver } ], container: this.container as any, diff --git a/src/core/types.ts b/src/core/types.ts index e47d2c80..61617e59 100644 --- a/src/core/types.ts +++ b/src/core/types.ts @@ -7,7 +7,8 @@ export interface StringMapOptional { [key: string]: string | undefined; } -export type DateTime = string; +export type DateOnlyString = string; +export type DateTimeString = string; export type IDType = string; export interface BaseEntity { diff --git a/src/decorators/DateField.ts b/src/decorators/DateField.ts index 9d9e8311..a1bf493a 100644 --- a/src/decorators/DateField.ts +++ b/src/decorators/DateField.ts @@ -11,6 +11,7 @@ interface DateFieldOptions extends DecoratorCommonOptions { default?: Date; } +// V3: Deprecate this usage in favor of DateTimeField export function DateField(options: DateFieldOptions = {}): any { const nullableOption = options.nullable === true ? { nullable: true } : {}; const defaultOption = options.default ? { default: options.default } : {}; diff --git a/src/decorators/DateOnlyField.ts b/src/decorators/DateOnlyField.ts new file mode 100644 index 00000000..cc0c3e00 --- /dev/null +++ b/src/decorators/DateOnlyField.ts @@ -0,0 +1,28 @@ +// https://www.postgresql.org/docs/10/datatype-datetime.html +import { DateResolver } from 'graphql-scalars'; + +import { DecoratorCommonOptions } from '../metadata'; +import { DateOnlyString } from '../core'; +import { composeMethodDecorators } from '../utils'; + +import { getCombinedDecorator } from './getCombinedDecorator'; + +interface DateOnlyFieldOptions extends DecoratorCommonOptions { + default?: DateOnlyString; +} + +// V3: Update this to DateField +export function DateOnlyField(options: DateOnlyFieldOptions = {}): any { + const nullableOption = options.nullable === true ? { nullable: true } : {}; + const defaultOption = options.default ? { default: options.default } : {}; + + const factories = getCombinedDecorator({ + fieldType: 'dateonly', + warthogColumnMeta: options, + gqlFieldType: DateResolver, + dbType: 'date', + dbColumnOptions: { ...nullableOption, ...defaultOption } + }); + + return composeMethodDecorators(...factories); +} diff --git a/src/decorators/DateTimeField.ts b/src/decorators/DateTimeField.ts new file mode 100644 index 00000000..0c1a193a --- /dev/null +++ b/src/decorators/DateTimeField.ts @@ -0,0 +1,28 @@ +// https://www.postgresql.org/docs/10/datatype-datetime.html +import { GraphQLISODateTime } from 'type-graphql'; + +import { DecoratorCommonOptions } from '../metadata'; +import { DateTimeString } from '../core'; +import { composeMethodDecorators } from '../utils'; + +import { getCombinedDecorator } from './getCombinedDecorator'; + +interface DateTimeFieldOptions extends DecoratorCommonOptions { + default?: DateTimeString; +} + +// V3: Deprecate this usage in favor of DateTimeField +export function DateTimeField(options: DateTimeFieldOptions = {}): any { + const nullableOption = options.nullable === true ? { nullable: true } : {}; + const defaultOption = options.default ? { default: options.default } : {}; + + const factories = getCombinedDecorator({ + fieldType: 'datetime', + warthogColumnMeta: options, + gqlFieldType: GraphQLISODateTime, + dbType: 'timestamp', + dbColumnOptions: { ...nullableOption, ...defaultOption } + }); + + return composeMethodDecorators(...factories); +} diff --git a/src/decorators/index.ts b/src/decorators/index.ts index dba72c21..67f7ca16 100644 --- a/src/decorators/index.ts +++ b/src/decorators/index.ts @@ -1,6 +1,8 @@ export * from './BooleanField'; export * from './CustomField'; export * from './DateField'; +export * from './DateOnlyField'; +export * from './DateTimeField'; export * from './EmailField'; export * from './EnumField'; export * from './Fields'; diff --git a/src/metadata/metadata-storage.ts b/src/metadata/metadata-storage.ts index 0e0f3f52..53e81d8f 100644 --- a/src/metadata/metadata-storage.ts +++ b/src/metadata/metadata-storage.ts @@ -7,6 +7,8 @@ import { Config } from '../core'; export type FieldType = | 'boolean' | 'date' + | 'dateonly' + | 'datetime' | 'email' | 'enum' | 'float' diff --git a/src/schema/SchemaGenerator.ts b/src/schema/SchemaGenerator.ts index a8d4b0d9..9739b49a 100644 --- a/src/schema/SchemaGenerator.ts +++ b/src/schema/SchemaGenerator.ts @@ -30,19 +30,19 @@ export class SchemaGenerator { // will be re-written. If you need to change this file, update models or add // new TypeGraphQL objects // @ts-ignore - import { GraphQLDateTime as DateTime } from 'graphql-iso-date'; + import { DateResolver as Date } from 'graphql-scalars'; // @ts-ignore import { GraphQLID as ID } from 'graphql'; // @ts-ignore import { ArgsType, Field as TypeGraphQLField, Float, InputType as TypeGraphQLInputType, Int } from 'type-graphql'; // @ts-ignore - import { registerEnumType } from 'type-graphql'; + import { registerEnumType, GraphQLISODateTime as DateTime } from "type-graphql"; // @ts-ignore eslint-disable-next-line @typescript-eslint/no-var-requires const { GraphQLJSONObject } = require('graphql-type-json'); // @ts-ignore - import { BaseWhereInput, JsonObject, PaginationArgs } from '${warthogImportPath}'; + import { BaseWhereInput, JsonObject, PaginationArgs, DateOnlyString, DateTimeString } from '${warthogImportPath}'; ${generateEnumMapImports().join('')} `; diff --git a/src/schema/TypeORMConverter.ts b/src/schema/TypeORMConverter.ts index 83f04653..d307e848 100644 --- a/src/schema/TypeORMConverter.ts +++ b/src/schema/TypeORMConverter.ts @@ -314,32 +314,30 @@ export function entityToWhereInput(model: ModelMetadata): string { @TypeGraphQLField(() => [${graphQLDataType}], { nullable: true }) ${column.propertyName}_in?: ${tsType}[]; `; - } else if (column.type === 'date') { + } else if (column.type === 'date' || column.type === 'datetime' || column.type === 'dateonly') { // I really don't like putting this magic here, but it has to go somewhere // This deletedAt_all turns off the default filtering of soft-deleted items if (column.propertyName === 'deletedAt') { fieldTemplates += ` - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField({ nullable: true }) deletedAt_all?: Boolean; `; } - const tsType = 'Date'; - fieldTemplates += ` - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => ${graphQLDataType}, { nullable: true }) ${column.propertyName}_eq?: ${tsType}; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => ${graphQLDataType}, { nullable: true }) ${column.propertyName}_lt?: ${tsType}; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => ${graphQLDataType}, { nullable: true }) ${column.propertyName}_lte?: ${tsType}; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => ${graphQLDataType}, { nullable: true }) ${column.propertyName}_gt?: ${tsType}; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => ${graphQLDataType}, { nullable: true }) ${column.propertyName}_gte?: ${tsType}; `; } else if (column.type === 'enum') { @@ -429,5 +427,12 @@ export function entityToOrderByEnum(model: ModelMetadata): string { } function columnRequiresExplicitGQLType(column: ColumnMetadata) { - return column.enum || column.type === 'json' || column.type === 'id'; + return ( + column.enum || + column.type === 'json' || + column.type === 'id' || + column.type === 'date' || + column.type === 'datetime' || + column.type === 'dateonly' + ); } diff --git a/src/schema/type-conversion.ts b/src/schema/type-conversion.ts index 5b652e40..6c6b712e 100644 --- a/src/schema/type-conversion.ts +++ b/src/schema/type-conversion.ts @@ -1,3 +1,4 @@ +import { DateResolver } from 'graphql-scalars'; import { GraphQLBoolean, GraphQLFloat, @@ -36,7 +37,10 @@ export function columnToGraphQLType( return GraphQLInt; case 'date': return GraphQLISODateTime; - // return GraphQLString; // V2: This should be GraphQLISODateTime + case 'datetime': + return GraphQLISODateTime; + case 'dateonly': + return DateResolver; case 'json': return GraphQLJSONObject; case 'enum': @@ -61,7 +65,10 @@ export function columnTypeToGraphQLType(type: FieldType): GraphQLScalarType { return GraphQLInt; case 'date': return GraphQLISODateTime; - // return GraphQLString; // V2: This should be GraphQLISODateTime + case 'datetime': + return GraphQLISODateTime; + case 'dateonly': + return DateResolver; case 'json': return GraphQLJSONObject; case 'enum': @@ -85,10 +92,13 @@ export function columnTypeToGraphQLDataType(type: FieldType, enumName?: string): } } -// const ID_TYPE = 'ID'; export function columnInfoToTypeScriptType(type: FieldType, enumName?: string): string { if (type === 'id') { return 'string'; // TODO: should this be ID_TYPE? + } else if (type === 'dateonly') { + return 'DateOnlyString'; + } else if (type === 'datetime') { + return 'DateTimeString'; } else if (enumName) { return String(enumName); } else { diff --git a/src/test/functional/__snapshots__/schema.test.ts.snap b/src/test/functional/__snapshots__/schema.test.ts.snap index 83bce01e..0f5c177d 100644 --- a/src/test/functional/__snapshots__/schema.test.ts.snap +++ b/src/test/functional/__snapshots__/schema.test.ts.snap @@ -114,6 +114,13 @@ input BaseWhereInput { deletedById_eq: String } +\\"\\"\\" +A date string, such as 2007-12-03, compliant with the \`full-date\` format +outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for +representation of dates and times using the Gregorian calendar. +\\"\\"\\" +scalar Date + \\"\\"\\" The javascript \`Date\` as string. Type represents date and time as the ISO Date string. \\"\\"\\" @@ -222,6 +229,8 @@ type KitchenSink implements BaseGraphQLObject { stringField: String! nullableStringField: String dateField: DateTime + dateOnlyField: Date + dateTimeField: DateTime emailField: String! integerField: Int! booleanField: Boolean! @@ -245,6 +254,8 @@ input KitchenSinkCreateInput { stringField: String! nullableStringField: String dateField: DateTime + dateOnlyField: Date + dateTimeField: DateTime emailField: String! integerField: Float! booleanField: Boolean! @@ -276,6 +287,10 @@ enum KitchenSinkOrderByInput { nullableStringField_DESC dateField_ASC dateField_DESC + dateOnlyField_ASC + dateOnlyField_DESC + dateTimeField_ASC + dateTimeField_DESC emailField_ASC emailField_DESC integerField_ASC @@ -306,6 +321,8 @@ input KitchenSinkUpdateInput { stringField: String nullableStringField: String dateField: DateTime + dateOnlyField: Date + dateTimeField: DateTime emailField: String integerField: Float booleanField: Boolean @@ -364,6 +381,16 @@ input KitchenSinkWhereInput { dateField_lte: DateTime dateField_gt: DateTime dateField_gte: DateTime + dateOnlyField_eq: Date + dateOnlyField_lt: Date + dateOnlyField_lte: Date + dateOnlyField_gt: Date + dateOnlyField_gte: Date + dateTimeField_eq: DateTime + dateTimeField_lt: DateTime + dateTimeField_lte: DateTime + dateTimeField_gt: DateTime + dateTimeField_gte: DateTime emailField_eq: String emailField_contains: String emailField_startsWith: String diff --git a/src/test/generated/binding.ts b/src/test/generated/binding.ts index ddb057fe..daf9b6fb 100644 --- a/src/test/generated/binding.ts +++ b/src/test/generated/binding.ts @@ -75,6 +75,10 @@ export type KitchenSinkOrderByInput = 'createdAt_ASC' | 'nullableStringField_DESC' | 'dateField_ASC' | 'dateField_DESC' | + 'dateOnlyField_ASC' | + 'dateOnlyField_DESC' | + 'dateTimeField_ASC' | + 'dateTimeField_DESC' | 'emailField_ASC' | 'emailField_DESC' | 'integerField_ASC' | @@ -223,6 +227,8 @@ export interface KitchenSinkCreateInput { stringField: String nullableStringField?: String | null dateField?: DateTime | null + dateOnlyField?: Date | null + dateTimeField?: DateTime | null emailField: String integerField: Float booleanField: Boolean @@ -245,6 +251,8 @@ export interface KitchenSinkUpdateInput { stringField?: String | null nullableStringField?: String | null dateField?: DateTime | null + dateOnlyField?: Date | null + dateTimeField?: DateTime | null emailField?: String | null integerField?: Float | null booleanField?: Boolean | null @@ -303,6 +311,16 @@ export interface KitchenSinkWhereInput { dateField_lte?: DateTime | null dateField_gt?: DateTime | null dateField_gte?: DateTime | null + dateOnlyField_eq?: Date | null + dateOnlyField_lt?: Date | null + dateOnlyField_lte?: Date | null + dateOnlyField_gt?: Date | null + dateOnlyField_gte?: Date | null + dateTimeField_eq?: DateTime | null + dateTimeField_lt?: DateTime | null + dateTimeField_lte?: DateTime | null + dateTimeField_gt?: DateTime | null + dateTimeField_gte?: DateTime | null emailField_eq?: String | null emailField_contains?: String | null emailField_startsWith?: String | null @@ -446,6 +464,8 @@ export interface KitchenSink extends BaseGraphQLObject { stringField: String nullableStringField?: String | null dateField?: DateTime | null + dateOnlyField?: Date | null + dateTimeField?: DateTime | null emailField: String integerField: Int booleanField: Boolean @@ -482,6 +502,13 @@ The `Boolean` scalar type represents `true` or `false`. */ export type Boolean = boolean +/* +A date string, such as 2007-12-03, compliant with the `full-date` format +outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for +representation of dates and times using the Gregorian calendar. +*/ +export type Date = string + /* The javascript `Date` as string. Type represents date and time as the ISO Date string. */ diff --git a/src/test/generated/classes.ts b/src/test/generated/classes.ts index 127a4abc..0d37991b 100644 --- a/src/test/generated/classes.ts +++ b/src/test/generated/classes.ts @@ -2,7 +2,7 @@ // will be re-written. If you need to change this file, update models or add // new TypeGraphQL objects // @ts-ignore -import { GraphQLDateTime as DateTime } from "graphql-iso-date"; +import { DateResolver as Date } from "graphql-scalars"; // @ts-ignore import { GraphQLID as ID } from "graphql"; // @ts-ignore @@ -14,13 +14,19 @@ import { Int } from "type-graphql"; // @ts-ignore -import { registerEnumType } from "type-graphql"; +import { registerEnumType, GraphQLISODateTime as DateTime } from "type-graphql"; // @ts-ignore eslint-disable-next-line @typescript-eslint/no-var-requires const { GraphQLJSONObject } = require("graphql-type-json"); // @ts-ignore -import { BaseWhereInput, JsonObject, PaginationArgs } from "../../"; +import { + BaseWhereInput, + JsonObject, + PaginationArgs, + DateOnlyString, + DateTimeString +} from "../../"; import { StringEnum } from "../modules/kitchen-sink/kitchen-sink.model"; // @ts-ignore import { ApiOnly } from "../modules/api-only/api-only.model"; @@ -55,19 +61,19 @@ export class ApiOnlyWhereInput { @TypeGraphQLField(() => [ID], { nullable: true }) id_in?: string[]; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) createdAt_eq?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) createdAt_lt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) createdAt_lte?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) createdAt_gt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) createdAt_gte?: Date; @TypeGraphQLField(() => ID, { nullable: true }) @@ -76,19 +82,19 @@ export class ApiOnlyWhereInput { @TypeGraphQLField(() => [ID], { nullable: true }) createdById_in?: string[]; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) updatedAt_eq?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) updatedAt_lt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) updatedAt_lte?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) updatedAt_gt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) updatedAt_gte?: Date; @TypeGraphQLField(() => ID, { nullable: true }) @@ -100,19 +106,19 @@ export class ApiOnlyWhereInput { @TypeGraphQLField({ nullable: true }) deletedAt_all?: Boolean; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) deletedAt_eq?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) deletedAt_lt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) deletedAt_lte?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) deletedAt_gt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) deletedAt_gte?: Date; @TypeGraphQLField(() => ID, { nullable: true }) @@ -195,6 +201,12 @@ export enum KitchenSinkOrderByEnum { dateField_ASC = "dateField_ASC", dateField_DESC = "dateField_DESC", + dateOnlyField_ASC = "dateOnlyField_ASC", + dateOnlyField_DESC = "dateOnlyField_DESC", + + dateTimeField_ASC = "dateTimeField_ASC", + dateTimeField_DESC = "dateTimeField_DESC", + emailField_ASC = "emailField_ASC", emailField_DESC = "emailField_DESC", @@ -244,19 +256,19 @@ export class KitchenSinkWhereInput { @TypeGraphQLField(() => [ID], { nullable: true }) id_in?: string[]; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) createdAt_eq?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) createdAt_lt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) createdAt_lte?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) createdAt_gt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) createdAt_gte?: Date; @TypeGraphQLField(() => ID, { nullable: true }) @@ -265,19 +277,19 @@ export class KitchenSinkWhereInput { @TypeGraphQLField(() => [ID], { nullable: true }) createdById_in?: string[]; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) updatedAt_eq?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) updatedAt_lt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) updatedAt_lte?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) updatedAt_gt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) updatedAt_gte?: Date; @TypeGraphQLField(() => ID, { nullable: true }) @@ -289,19 +301,19 @@ export class KitchenSinkWhereInput { @TypeGraphQLField({ nullable: true }) deletedAt_all?: Boolean; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) deletedAt_eq?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) deletedAt_lt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) deletedAt_lte?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) deletedAt_gt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) deletedAt_gte?: Date; @TypeGraphQLField(() => ID, { nullable: true }) @@ -340,21 +352,51 @@ export class KitchenSinkWhereInput { @TypeGraphQLField(() => [String], { nullable: true }) nullableStringField_in?: string[]; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) dateField_eq?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) dateField_lt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) dateField_lte?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) dateField_gt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) dateField_gte?: Date; + @TypeGraphQLField(() => Date, { nullable: true }) + dateOnlyField_eq?: DateOnlyString; + + @TypeGraphQLField(() => Date, { nullable: true }) + dateOnlyField_lt?: DateOnlyString; + + @TypeGraphQLField(() => Date, { nullable: true }) + dateOnlyField_lte?: DateOnlyString; + + @TypeGraphQLField(() => Date, { nullable: true }) + dateOnlyField_gt?: DateOnlyString; + + @TypeGraphQLField(() => Date, { nullable: true }) + dateOnlyField_gte?: DateOnlyString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + dateTimeField_eq?: DateTimeString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + dateTimeField_lt?: DateTimeString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + dateTimeField_lte?: DateTimeString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + dateTimeField_gt?: DateTimeString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + dateTimeField_gte?: DateTimeString; + @TypeGraphQLField({ nullable: true }) emailField_eq?: string; @@ -541,9 +583,15 @@ export class KitchenSinkCreateInput { @TypeGraphQLField({ nullable: true }) nullableStringField?: string; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) dateField?: Date; + @TypeGraphQLField(() => Date, { nullable: true }) + dateOnlyField?: DateOnlyString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + dateTimeField?: DateTimeString; + @TypeGraphQLField() emailField!: string; @@ -601,9 +649,15 @@ export class KitchenSinkUpdateInput { @TypeGraphQLField({ nullable: true }) nullableStringField?: string; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) dateField?: Date; + @TypeGraphQLField(() => Date, { nullable: true }) + dateOnlyField?: DateOnlyString; + + @TypeGraphQLField(() => DateTime, { nullable: true }) + dateTimeField?: DateTimeString; + @TypeGraphQLField({ nullable: true }) emailField?: string; @@ -703,19 +757,19 @@ export class DishWhereInput { @TypeGraphQLField(() => [ID], { nullable: true }) id_in?: string[]; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) createdAt_eq?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) createdAt_lt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) createdAt_lte?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) createdAt_gt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) createdAt_gte?: Date; @TypeGraphQLField(() => ID, { nullable: true }) @@ -724,19 +778,19 @@ export class DishWhereInput { @TypeGraphQLField(() => [ID], { nullable: true }) createdById_in?: string[]; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) updatedAt_eq?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) updatedAt_lt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) updatedAt_lte?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) updatedAt_gt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) updatedAt_gte?: Date; @TypeGraphQLField(() => ID, { nullable: true }) @@ -748,19 +802,19 @@ export class DishWhereInput { @TypeGraphQLField({ nullable: true }) deletedAt_all?: Boolean; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) deletedAt_eq?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) deletedAt_lt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) deletedAt_lte?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) deletedAt_gt?: Date; - @TypeGraphQLField({ nullable: true }) + @TypeGraphQLField(() => DateTime, { nullable: true }) deletedAt_gte?: Date; @TypeGraphQLField(() => ID, { nullable: true }) diff --git a/src/test/generated/schema.graphql b/src/test/generated/schema.graphql index a84cde71..3bdc7fa9 100644 --- a/src/test/generated/schema.graphql +++ b/src/test/generated/schema.graphql @@ -111,6 +111,13 @@ input BaseWhereInput { deletedById_eq: String } +""" +A date string, such as 2007-12-03, compliant with the `full-date` format +outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for +representation of dates and times using the Gregorian calendar. +""" +scalar Date + """ The javascript `Date` as string. Type represents date and time as the ISO Date string. """ @@ -219,6 +226,8 @@ type KitchenSink implements BaseGraphQLObject { stringField: String! nullableStringField: String dateField: DateTime + dateOnlyField: Date + dateTimeField: DateTime emailField: String! integerField: Int! booleanField: Boolean! @@ -242,6 +251,8 @@ input KitchenSinkCreateInput { stringField: String! nullableStringField: String dateField: DateTime + dateOnlyField: Date + dateTimeField: DateTime emailField: String! integerField: Float! booleanField: Boolean! @@ -273,6 +284,10 @@ enum KitchenSinkOrderByInput { nullableStringField_DESC dateField_ASC dateField_DESC + dateOnlyField_ASC + dateOnlyField_DESC + dateTimeField_ASC + dateTimeField_DESC emailField_ASC emailField_DESC integerField_ASC @@ -303,6 +318,8 @@ input KitchenSinkUpdateInput { stringField: String nullableStringField: String dateField: DateTime + dateOnlyField: Date + dateTimeField: DateTime emailField: String integerField: Float booleanField: Boolean @@ -361,6 +378,16 @@ input KitchenSinkWhereInput { dateField_lte: DateTime dateField_gt: DateTime dateField_gte: DateTime + dateOnlyField_eq: Date + dateOnlyField_lt: Date + dateOnlyField_lte: Date + dateOnlyField_gt: Date + dateOnlyField_gte: Date + dateTimeField_eq: DateTime + dateTimeField_lt: DateTime + dateTimeField_lte: DateTime + dateTimeField_gt: DateTime + dateTimeField_gte: DateTime emailField_eq: String emailField_contains: String emailField_startsWith: String diff --git a/src/test/modules/kitchen-sink/kitchen-sink.model.ts b/src/test/modules/kitchen-sink/kitchen-sink.model.ts index 31984cf8..396d271f 100644 --- a/src/test/modules/kitchen-sink/kitchen-sink.model.ts +++ b/src/test/modules/kitchen-sink/kitchen-sink.model.ts @@ -5,6 +5,10 @@ import { BooleanField, CustomField, DateField, + DateOnlyField, + DateOnlyString, + DateTimeField, + DateTimeString, EmailField, EnumField, FloatField, @@ -38,6 +42,12 @@ export class KitchenSink extends BaseModel { @DateField({ nullable: true }) dateField?: Date; + @DateOnlyField({ nullable: true }) + dateOnlyField?: DateOnlyString; + + @DateTimeField({ nullable: true }) + dateTimeField?: DateTimeString; + @EmailField() emailField!: string; diff --git a/yarn.lock b/yarn.lock index ee1de04d..1504a470 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4218,6 +4218,11 @@ graphql-query-complexity@^0.3.0: dependencies: lodash.get "^4.4.2" +graphql-scalars@^1.2.6: + version "1.2.6" + resolved "https://registry.npmjs.org/graphql-scalars/-/graphql-scalars-1.2.6.tgz#a934ed63c91054db00cde41b9beeddb09b606729" + integrity sha512-k/88kZVXIuUKQuVLokokkKU2lnFEZ9aTn7O0fDweJpISd0pP5fQU1wzPN0jarH4Lnadr4092PfyIUtCcKzkeAw== + graphql-subscriptions@^1.0.0, graphql-subscriptions@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/graphql-subscriptions/-/graphql-subscriptions-1.1.0.tgz#5f2fa4233eda44cf7570526adfcf3c16937aef11"