From bfa3e545c12221f2f27e06b487f816379265ec95 Mon Sep 17 00:00:00 2001 From: Dan Caddigan Date: Tue, 25 Aug 2020 00:23:09 -0400 Subject: [PATCH] feat(filter): allow specific filters by field (#395) --- .../02-complex-example/generated/binding.ts | 10 ++ .../02-complex-example/generated/classes.ts | 24 +++ .../generated/schema.graphql | 10 ++ .../src/modules/user/user.model.ts | 6 + src/decorators/BooleanField.ts | 2 + src/decorators/DateField.ts | 3 +- src/decorators/DateOnlyField.ts | 2 + src/decorators/DateTimeField.ts | 2 + src/decorators/EmailField.ts | 2 + src/decorators/EnumField.ts | 2 + src/decorators/FloatField.ts | 3 +- src/decorators/IdField.ts | 2 + src/decorators/IntField.ts | 3 +- src/decorators/NumericField.ts | 3 +- src/decorators/StringField.ts | 3 +- src/metadata/metadata-storage.ts | 4 +- src/schema/TypeORMConverter.ts | 162 +++++++++++++----- .../__snapshots__/schema.test.ts.snap | 10 ++ src/test/generated/binding.ts | 10 ++ src/test/generated/classes.ts | 24 +++ src/test/generated/schema.graphql | 10 ++ .../kitchen-sink/kitchen-sink.model.ts | 6 + src/torm/operators.ts | 30 ++++ 23 files changed, 285 insertions(+), 48 deletions(-) diff --git a/examples/02-complex-example/generated/binding.ts b/examples/02-complex-example/generated/binding.ts index 512c26bc..3b9f2e68 100644 --- a/examples/02-complex-example/generated/binding.ts +++ b/examples/02-complex-example/generated/binding.ts @@ -157,6 +157,8 @@ export interface UserCreateInput { noFilterField?: String | null noSortField?: String | null noFilterOrSortField?: String | null + stringFieldFilterEqContains?: String | null + intFieldFilterLteGte?: Float | null numericField?: Float | null numericFieldCustomPrecisionScale?: Float | null charField?: String | null @@ -197,6 +199,8 @@ export interface UserUpdateInput { noFilterField?: String | null noSortField?: String | null noFilterOrSortField?: String | null + stringFieldFilterEqContains?: String | null + intFieldFilterLteGte?: Float | null numericField?: Float | null numericFieldCustomPrecisionScale?: Float | null charField?: String | null @@ -310,6 +314,10 @@ export interface UserWhereInput { noSortField_startsWith?: String | null noSortField_endsWith?: String | null noSortField_in?: String[] | String | null + stringFieldFilterEqContains_eq?: String | null + stringFieldFilterEqContains_contains?: String | null + intFieldFilterLteGte_gte?: Int | null + intFieldFilterLteGte_lte?: Int | null numericField_eq?: Float | null numericField_gt?: Float | null numericField_gte?: Float | null @@ -490,6 +498,8 @@ export interface User extends BaseGraphQLObject { noFilterField?: String | null noSortField?: String | null noFilterOrSortField?: String | null + stringFieldFilterEqContains?: String | null + intFieldFilterLteGte?: Int | null numericField?: Float | null numericFieldCustomPrecisionScale?: Float | null charField?: String | null diff --git a/examples/02-complex-example/generated/classes.ts b/examples/02-complex-example/generated/classes.ts index e0048401..44b94235 100644 --- a/examples/02-complex-example/generated/classes.ts +++ b/examples/02-complex-example/generated/classes.ts @@ -414,6 +414,18 @@ export class UserWhereInput { @TypeGraphQLField(() => [String], { nullable: true }) noSortField_in?: string[]; + @TypeGraphQLField({ nullable: true }) + stringFieldFilterEqContains_eq?: string; + + @TypeGraphQLField({ nullable: true }) + stringFieldFilterEqContains_contains?: string; + + @TypeGraphQLField(() => Int, { nullable: true }) + intFieldFilterLteGte_gte?: number; + + @TypeGraphQLField(() => Int, { nullable: true }) + intFieldFilterLteGte_lte?: number; + @TypeGraphQLField(() => Float, { nullable: true }) numericField_eq?: number; @@ -771,6 +783,12 @@ export class UserCreateInput { @TypeGraphQLField({ nullable: true }) noFilterOrSortField?: string; + @TypeGraphQLField({ nullable: true }) + stringFieldFilterEqContains?: string; + + @TypeGraphQLField({ nullable: true }) + intFieldFilterLteGte?: number; + @TypeGraphQLField({ nullable: true }) numericField?: number; @@ -885,6 +903,12 @@ export class UserUpdateInput { @TypeGraphQLField({ nullable: true }) noFilterOrSortField?: string; + @TypeGraphQLField({ nullable: true }) + stringFieldFilterEqContains?: string; + + @TypeGraphQLField({ nullable: true }) + intFieldFilterLteGte?: number; + @TypeGraphQLField({ nullable: true }) numericField?: number; diff --git a/examples/02-complex-example/generated/schema.graphql b/examples/02-complex-example/generated/schema.graphql index 9f5d7655..627eed08 100644 --- a/examples/02-complex-example/generated/schema.graphql +++ b/examples/02-complex-example/generated/schema.graphql @@ -133,6 +133,8 @@ type User implements BaseGraphQLObject { noFilterField: String noSortField: String noFilterOrSortField: String + stringFieldFilterEqContains: String + intFieldFilterLteGte: Int numericField: Float numericFieldCustomPrecisionScale: Float charField: String @@ -172,6 +174,8 @@ input UserCreateInput { noFilterField: String noSortField: String noFilterOrSortField: String + stringFieldFilterEqContains: String + intFieldFilterLteGte: Float numericField: Float numericFieldCustomPrecisionScale: Float charField: String @@ -283,6 +287,8 @@ input UserUpdateInput { noFilterField: String noSortField: String noFilterOrSortField: String + stringFieldFilterEqContains: String + intFieldFilterLteGte: Float numericField: Float numericFieldCustomPrecisionScale: Float charField: String @@ -396,6 +402,10 @@ input UserWhereInput { noSortField_startsWith: String noSortField_endsWith: String noSortField_in: [String!] + stringFieldFilterEqContains_eq: String + stringFieldFilterEqContains_contains: String + intFieldFilterLteGte_gte: Int + intFieldFilterLteGte_lte: Int numericField_eq: Float numericField_gt: Float numericField_gte: Float 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 6a4d2f75..f4f93861 100644 --- a/examples/02-complex-example/src/modules/user/user.model.ts +++ b/examples/02-complex-example/src/modules/user/user.model.ts @@ -101,6 +101,12 @@ export class User extends BaseModel { @StringField({ filter: false, sort: false, nullable: true }) noFilterOrSortField?: string; + @StringField({ filter: ['eq', 'contains'], sort: false, nullable: true }) + stringFieldFilterEqContains?: string; + + @IntField({ filter: ['lte', 'gte'], sort: false, nullable: true }) + intFieldFilterLteGte?: number; + // See https://github.com/typeorm/typeorm/blob/a4dec02cc59d3219a29c7be0322af2253e1452dc/test/functional/database-schema/column-types/postgres/entity/PostWithOptions.ts // Numeric fields (exact precision) @NumericField({ nullable: true }) diff --git a/src/decorators/BooleanField.ts b/src/decorators/BooleanField.ts index fc91f79d..77ee33e0 100644 --- a/src/decorators/BooleanField.ts +++ b/src/decorators/BooleanField.ts @@ -1,12 +1,14 @@ import { GraphQLBoolean } from 'graphql'; import { DecoratorCommonOptions } from '../metadata'; +import { BooleanWhereOperator } from '../torm'; import { composeMethodDecorators } from '../utils'; import { getCombinedDecorator } from './getCombinedDecorator'; interface BooleanFieldOptions extends DecoratorCommonOptions { default?: boolean; + filter?: boolean | BooleanWhereOperator[]; } export function BooleanField(options: BooleanFieldOptions = {}): any { diff --git a/src/decorators/DateField.ts b/src/decorators/DateField.ts index a1bf493a..198357fb 100644 --- a/src/decorators/DateField.ts +++ b/src/decorators/DateField.ts @@ -1,7 +1,7 @@ import { GraphQLISODateTime } from 'type-graphql'; import { DecoratorCommonOptions } from '../metadata'; -import { ColumnType } from '../torm'; +import { ColumnType, DateWhereOperator } from '../torm'; import { composeMethodDecorators } from '../utils'; import { getCombinedDecorator } from './getCombinedDecorator'; @@ -9,6 +9,7 @@ import { getCombinedDecorator } from './getCombinedDecorator'; interface DateFieldOptions extends DecoratorCommonOptions { dataType?: ColumnType; // int16, jsonb, etc... default?: Date; + filter?: boolean | DateWhereOperator[]; } // V3: Deprecate this usage in favor of DateTimeField diff --git a/src/decorators/DateOnlyField.ts b/src/decorators/DateOnlyField.ts index cc0c3e00..49cd59c1 100644 --- a/src/decorators/DateOnlyField.ts +++ b/src/decorators/DateOnlyField.ts @@ -3,12 +3,14 @@ import { DateResolver } from 'graphql-scalars'; import { DecoratorCommonOptions } from '../metadata'; import { DateOnlyString } from '../core'; +import { DateOnlyWhereOperator } from '../torm'; import { composeMethodDecorators } from '../utils'; import { getCombinedDecorator } from './getCombinedDecorator'; interface DateOnlyFieldOptions extends DecoratorCommonOptions { default?: DateOnlyString; + filter?: boolean | DateOnlyWhereOperator[]; } // V3: Update this to DateField diff --git a/src/decorators/DateTimeField.ts b/src/decorators/DateTimeField.ts index 0c1a193a..b093654b 100644 --- a/src/decorators/DateTimeField.ts +++ b/src/decorators/DateTimeField.ts @@ -3,12 +3,14 @@ import { GraphQLISODateTime } from 'type-graphql'; import { DecoratorCommonOptions } from '../metadata'; import { DateTimeString } from '../core'; +import { DateTimeWhereOperator } from '../torm'; import { composeMethodDecorators } from '../utils'; import { getCombinedDecorator } from './getCombinedDecorator'; interface DateTimeFieldOptions extends DecoratorCommonOptions { default?: DateTimeString; + filter?: boolean | DateTimeWhereOperator[]; } // V3: Deprecate this usage in favor of DateTimeField diff --git a/src/decorators/EmailField.ts b/src/decorators/EmailField.ts index f13076d7..4dbcbcb7 100644 --- a/src/decorators/EmailField.ts +++ b/src/decorators/EmailField.ts @@ -1,12 +1,14 @@ import { IsEmail } from 'class-validator'; import { DecoratorCommonOptions } from '../metadata'; +import { EmailWhereOperator } from '../torm'; import { composeMethodDecorators } from '../utils'; import { getCombinedDecorator } from './getCombinedDecorator'; interface EmailFieldOptions extends DecoratorCommonOptions { unique?: boolean; + filter?: boolean | EmailWhereOperator[]; } export function EmailField(options: EmailFieldOptions = {}): any { diff --git a/src/decorators/EnumField.ts b/src/decorators/EnumField.ts index a5e9ce1c..a58578d5 100644 --- a/src/decorators/EnumField.ts +++ b/src/decorators/EnumField.ts @@ -5,9 +5,11 @@ import { Column } from 'typeorm'; import { getMetadataStorage, DecoratorCommonOptions } from '../metadata'; import { composeMethodDecorators, generatedFolderPath, MethodDecoratorFactory } from '../utils'; +import { EnumWhereOperator } from '../torm'; interface EnumFieldOptions extends DecoratorCommonOptions { default?: any; + filter?: boolean | EnumWhereOperator[]; } export function EnumField(name: string, enumeration: object, options: EnumFieldOptions = {}): any { diff --git a/src/decorators/FloatField.ts b/src/decorators/FloatField.ts index 0ebb55e9..452184a8 100644 --- a/src/decorators/FloatField.ts +++ b/src/decorators/FloatField.ts @@ -2,13 +2,14 @@ import { Float } from 'type-graphql'; import { DecoratorCommonOptions } from '../metadata'; import { composeMethodDecorators } from '../utils'; -import { FloatColumnType } from '../torm'; +import { FloatColumnType, FloatWhereOperator } from '../torm'; import { getCombinedDecorator } from './getCombinedDecorator'; interface FloatFieldOptions extends DecoratorCommonOptions { dataType?: FloatColumnType; // int16, jsonb, etc... default?: number; + filter?: boolean | FloatWhereOperator[]; } export function FloatField(options: FloatFieldOptions = {}): any { diff --git a/src/decorators/IdField.ts b/src/decorators/IdField.ts index 32fc4e92..1562d801 100644 --- a/src/decorators/IdField.ts +++ b/src/decorators/IdField.ts @@ -1,10 +1,12 @@ import { DecoratorCommonOptions } from '../metadata'; +import { IdWhereOperator } from '../torm'; import { composeMethodDecorators } from '../utils'; import { getCombinedDecorator } from './getCombinedDecorator'; interface IdFieldOptions extends DecoratorCommonOptions { unique?: boolean; + filter?: boolean | IdWhereOperator[]; } export function IdField(options: IdFieldOptions = {}): any { diff --git a/src/decorators/IntField.ts b/src/decorators/IntField.ts index ec180e10..818985c4 100644 --- a/src/decorators/IntField.ts +++ b/src/decorators/IntField.ts @@ -1,14 +1,15 @@ import { Int } from 'type-graphql'; import { DecoratorCommonOptions } from '../metadata'; +import { IntColumnType, IntWhereOperator } from '../torm'; import { composeMethodDecorators } from '../utils'; -import { IntColumnType } from '../torm'; import { getCombinedDecorator } from './getCombinedDecorator'; interface IntFieldOptions extends DecoratorCommonOptions { dataType?: IntColumnType; default?: number; + filter?: boolean | IntWhereOperator[]; } export function IntField(options: IntFieldOptions = {}): any { diff --git a/src/decorators/NumericField.ts b/src/decorators/NumericField.ts index 5a9bfbf4..51df84e8 100644 --- a/src/decorators/NumericField.ts +++ b/src/decorators/NumericField.ts @@ -4,7 +4,7 @@ import { ColumnCommonOptions } from 'typeorm/decorator/options/ColumnCommonOptio import { DecoratorCommonOptions } from '../metadata'; import { composeMethodDecorators } from '../utils'; -import { NumericColumnType } from '../torm'; +import { NumericColumnType, NumericWhereOperator } from '../torm'; import { getCombinedDecorator } from './getCombinedDecorator'; @@ -13,6 +13,7 @@ interface NumericFieldOptions ColumnNumericOptions, DecoratorCommonOptions { dataType?: NumericColumnType; + filter?: boolean | NumericWhereOperator[]; } export function NumericField(options: NumericFieldOptions = {}): any { diff --git a/src/decorators/StringField.ts b/src/decorators/StringField.ts index 0a5ec04a..961bf12c 100644 --- a/src/decorators/StringField.ts +++ b/src/decorators/StringField.ts @@ -2,7 +2,7 @@ import { MaxLength, MinLength } from 'class-validator'; import { DecoratorCommonOptions } from '../metadata'; import { composeMethodDecorators } from '../utils'; -import { StringColumnType } from '../torm'; +import { StringColumnType, StringWhereOperator } from '../torm'; import { getCombinedDecorator } from './getCombinedDecorator'; @@ -12,6 +12,7 @@ interface StringFieldOptions extends DecoratorCommonOptions { minLength?: number; default?: string; unique?: boolean; + filter?: boolean | StringWhereOperator[]; } export function StringField(options: StringFieldOptions = {}): any { diff --git a/src/metadata/metadata-storage.ts b/src/metadata/metadata-storage.ts index 53e81d8f..b205094b 100644 --- a/src/metadata/metadata-storage.ts +++ b/src/metadata/metadata-storage.ts @@ -1,7 +1,7 @@ import { GraphQLEnumType } from 'graphql'; import { Container, Inject, Service } from 'typedi'; -import { ColumnType } from '../torm'; +import { ColumnType, WhereOperator } from '../torm'; import { Config } from '../core'; export type FieldType = @@ -23,7 +23,7 @@ export interface DecoratorCommonOptions { dbOnly?: boolean; description?: string; editable?: boolean; - filter?: boolean; + filter?: boolean | WhereOperator[]; nullable?: boolean; readonly?: boolean; sort?: boolean; diff --git a/src/schema/TypeORMConverter.ts b/src/schema/TypeORMConverter.ts index d307e848..26527c9c 100644 --- a/src/schema/TypeORMConverter.ts +++ b/src/schema/TypeORMConverter.ts @@ -8,6 +8,7 @@ import { columnTypeToGraphQLDataType, columnInfoToTypeScriptType } from './type-conversion'; +import { WhereOperator } from '../torm'; const ignoreBaseModels = ['BaseModel', 'BaseModelUUID']; @@ -249,6 +250,17 @@ export function entityToWhereInput(model: ModelMetadata): string { return; } + function allowFilter(op: WhereOperator) { + if (column.filter === true) { + return true; + } + if (column.filter === false) { + return false; + } + + return !!column.filter?.includes(op); + } + const { tsType } = columnToTypes(column); const graphQLDataType = columnToGraphQLDataType(column); @@ -258,62 +270,108 @@ export function entityToWhereInput(model: ModelMetadata): string { if (column.type === 'id') { const graphQlType = 'ID'; - fieldTemplates += ` - @TypeGraphQLField(() => ${graphQlType},{ nullable: true }) - ${column.propertyName}_eq?: string; - `; + if (allowFilter('eq')) { + fieldTemplates += ` + @TypeGraphQLField(() => ${graphQlType},{ nullable: true }) + ${column.propertyName}_eq?: string; + `; + } - fieldTemplates += ` + if (allowFilter('in')) { + fieldTemplates += ` @TypeGraphQLField(() => [${graphQlType}], { nullable: true }) ${column.propertyName}_in?: string[]; `; + } } else if (column.type === 'boolean') { - fieldTemplates += ` + if (allowFilter('eq')) { + fieldTemplates += ` @TypeGraphQLField(() => ${graphQLDataType},{ nullable: true }) ${column.propertyName}_eq?: Boolean; + `; + } + // V3: kill the boolean "in" clause + if (allowFilter('in')) { + fieldTemplates += ` @TypeGraphQLField(() => [${graphQLDataType}], { nullable: true }) ${column.propertyName}_in?: Boolean[]; `; + } } else if (column.type === 'string' || column.type === 'email') { // TODO: do we need NOT? // `${column.propertyName}_not` - fieldTemplates += ` - @TypeGraphQLField({ nullable: true }) - ${column.propertyName}_eq?: ${tsType}; + if (allowFilter('eq')) { + fieldTemplates += ` + @TypeGraphQLField({ nullable: true }) + ${column.propertyName}_eq?: ${tsType}; + `; + } - @TypeGraphQLField({ nullable: true }) - ${column.propertyName}_contains?: ${tsType}; + if (allowFilter('contains')) { + fieldTemplates += ` + @TypeGraphQLField({ nullable: true }) + ${column.propertyName}_contains?: ${tsType}; + `; + } - @TypeGraphQLField({ nullable: true }) - ${column.propertyName}_startsWith?: ${tsType}; + if (allowFilter('startsWith')) { + fieldTemplates += ` + @TypeGraphQLField({ nullable: true }) + ${column.propertyName}_startsWith?: ${tsType}; + `; + } - @TypeGraphQLField({ nullable: true }) - ${column.propertyName}_endsWith?: ${tsType}; + if (allowFilter('endsWith')) { + fieldTemplates += ` + @TypeGraphQLField({ nullable: true }) + ${column.propertyName}_endsWith?: ${tsType}; + `; + } - @TypeGraphQLField(() => [${graphQLDataType}], { nullable: true }) - ${column.propertyName}_in?: ${tsType}[]; + if (allowFilter('in')) { + fieldTemplates += ` + @TypeGraphQLField(() => [${graphQLDataType}], { nullable: true }) + ${column.propertyName}_in?: ${tsType}[]; `; + } } else if (column.type === 'float' || column.type === 'integer' || column.type === 'numeric') { - fieldTemplates += ` + if (allowFilter('eq')) { + fieldTemplates += ` @TypeGraphQLField(() => ${graphQLDataType}, { nullable: true }) ${column.propertyName}_eq?: ${tsType}; - + `; + } + if (allowFilter('gt')) { + fieldTemplates += ` @TypeGraphQLField(() => ${graphQLDataType}, { nullable: true }) ${column.propertyName}_gt?: ${tsType}; - + `; + } + if (allowFilter('gte')) { + fieldTemplates += ` @TypeGraphQLField(() => ${graphQLDataType}, { nullable: true }) ${column.propertyName}_gte?: ${tsType}; - + `; + } + if (allowFilter('lt')) { + fieldTemplates += ` @TypeGraphQLField(() => ${graphQLDataType}, { nullable: true }) ${column.propertyName}_lt?: ${tsType}; - + `; + } + if (allowFilter('lte')) { + fieldTemplates += ` @TypeGraphQLField(() => ${graphQLDataType}, { nullable: true }) ${column.propertyName}_lte?: ${tsType}; - + `; + } + if (allowFilter('in')) { + fieldTemplates += ` @TypeGraphQLField(() => [${graphQLDataType}], { nullable: true }) ${column.propertyName}_in?: ${tsType}[]; `; + } } 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 @@ -324,30 +382,52 @@ export function entityToWhereInput(model: ModelMetadata): string { `; } - fieldTemplates += ` - @TypeGraphQLField(() => ${graphQLDataType}, { nullable: true }) - ${column.propertyName}_eq?: ${tsType}; - - @TypeGraphQLField(() => ${graphQLDataType}, { nullable: true }) - ${column.propertyName}_lt?: ${tsType}; - - @TypeGraphQLField(() => ${graphQLDataType}, { nullable: true }) - ${column.propertyName}_lte?: ${tsType}; + if (allowFilter('eq')) { + fieldTemplates += ` + @TypeGraphQLField(() => ${graphQLDataType}, { nullable: true }) + ${column.propertyName}_eq?: ${tsType}; + `; + } + if (allowFilter('lt')) { + fieldTemplates += ` + @TypeGraphQLField(() => ${graphQLDataType}, { nullable: true }) + ${column.propertyName}_lt?: ${tsType}; + `; + } - @TypeGraphQLField(() => ${graphQLDataType}, { nullable: true }) - ${column.propertyName}_gt?: ${tsType}; + if (allowFilter('lte')) { + fieldTemplates += ` + @TypeGraphQLField(() => ${graphQLDataType}, { nullable: true }) + ${column.propertyName}_lte?: ${tsType}; + `; + } - @TypeGraphQLField(() => ${graphQLDataType}, { nullable: true }) - ${column.propertyName}_gte?: ${tsType}; + if (allowFilter('gt')) { + fieldTemplates += ` + @TypeGraphQLField(() => ${graphQLDataType}, { nullable: true }) + ${column.propertyName}_gt?: ${tsType}; + `; + } + if (allowFilter('gte')) { + fieldTemplates += ` + @TypeGraphQLField(() => ${graphQLDataType}, { nullable: true }) + ${column.propertyName}_gte?: ${tsType}; `; + } } else if (column.type === 'enum') { - fieldTemplates += ` - @TypeGraphQLField(() => ${graphQLDataType}, { nullable: true }) - ${column.propertyName}_eq?: ${graphQLDataType}; + if (allowFilter('eq')) { + fieldTemplates += ` + @TypeGraphQLField(() => ${graphQLDataType}, { nullable: true }) + ${column.propertyName}_eq?: ${graphQLDataType}; + `; + } - @TypeGraphQLField(() => [${graphQLDataType}], { nullable: true }) - ${column.propertyName}_in?: ${graphQLDataType}[]; + if (allowFilter('in')) { + fieldTemplates += ` + @TypeGraphQLField(() => [${graphQLDataType}], { nullable: true }) + ${column.propertyName}_in?: ${graphQLDataType}[]; `; + } } else if (column.type === 'json') { fieldTemplates += ` @TypeGraphQLField(() => GraphQLJSONObject, { nullable: true }) diff --git a/src/test/functional/__snapshots__/schema.test.ts.snap b/src/test/functional/__snapshots__/schema.test.ts.snap index 0f5c177d..b2b80697 100644 --- a/src/test/functional/__snapshots__/schema.test.ts.snap +++ b/src/test/functional/__snapshots__/schema.test.ts.snap @@ -244,6 +244,8 @@ type KitchenSink implements BaseGraphQLObject { noFilterField: String noSortField: String noFilterOrSortField: String + stringFieldFilterEqContains: String + intFieldFilterLteGte: Int characterField: String customTextFieldNoSortOrFilter: String readonlyField: String @@ -268,6 +270,8 @@ input KitchenSinkCreateInput { noFilterField: String noSortField: String noFilterOrSortField: String + stringFieldFilterEqContains: String + intFieldFilterLteGte: Float characterField: String customTextFieldNoSortOrFilter: String writeonlyField: String @@ -335,6 +339,8 @@ input KitchenSinkUpdateInput { noFilterField: String noSortField: String noFilterOrSortField: String + stringFieldFilterEqContains: String + intFieldFilterLteGte: Float characterField: String customTextFieldNoSortOrFilter: String writeonlyField: String @@ -432,6 +438,10 @@ input KitchenSinkWhereInput { noSortField_startsWith: String noSortField_endsWith: String noSortField_in: [String!] + stringFieldFilterEqContains_eq: String + stringFieldFilterEqContains_contains: String + intFieldFilterLteGte_gte: Int + intFieldFilterLteGte_lte: Int characterField_eq: String characterField_contains: String characterField_startsWith: String diff --git a/src/test/generated/binding.ts b/src/test/generated/binding.ts index daf9b6fb..e0c41d2a 100644 --- a/src/test/generated/binding.ts +++ b/src/test/generated/binding.ts @@ -241,6 +241,8 @@ export interface KitchenSinkCreateInput { noFilterField?: String | null noSortField?: String | null noFilterOrSortField?: String | null + stringFieldFilterEqContains?: String | null + intFieldFilterLteGte?: Float | null characterField?: String | null customTextFieldNoSortOrFilter?: String | null writeonlyField?: String | null @@ -265,6 +267,8 @@ export interface KitchenSinkUpdateInput { noFilterField?: String | null noSortField?: String | null noFilterOrSortField?: String | null + stringFieldFilterEqContains?: String | null + intFieldFilterLteGte?: Float | null characterField?: String | null customTextFieldNoSortOrFilter?: String | null writeonlyField?: String | null @@ -362,6 +366,10 @@ export interface KitchenSinkWhereInput { noSortField_startsWith?: String | null noSortField_endsWith?: String | null noSortField_in?: String[] | String | null + stringFieldFilterEqContains_eq?: String | null + stringFieldFilterEqContains_contains?: String | null + intFieldFilterLteGte_gte?: Int | null + intFieldFilterLteGte_lte?: Int | null characterField_eq?: String | null characterField_contains?: String | null characterField_startsWith?: String | null @@ -479,6 +487,8 @@ export interface KitchenSink extends BaseGraphQLObject { noFilterField?: String | null noSortField?: String | null noFilterOrSortField?: String | null + stringFieldFilterEqContains?: String | null + intFieldFilterLteGte?: Int | null characterField?: String | null customTextFieldNoSortOrFilter?: String | null readonlyField?: String | null diff --git a/src/test/generated/classes.ts b/src/test/generated/classes.ts index 0d37991b..2a3e9581 100644 --- a/src/test/generated/classes.ts +++ b/src/test/generated/classes.ts @@ -520,6 +520,18 @@ export class KitchenSinkWhereInput { @TypeGraphQLField(() => [String], { nullable: true }) noSortField_in?: string[]; + @TypeGraphQLField({ nullable: true }) + stringFieldFilterEqContains_eq?: string; + + @TypeGraphQLField({ nullable: true }) + stringFieldFilterEqContains_contains?: string; + + @TypeGraphQLField(() => Int, { nullable: true }) + intFieldFilterLteGte_gte?: number; + + @TypeGraphQLField(() => Int, { nullable: true }) + intFieldFilterLteGte_lte?: number; + @TypeGraphQLField({ nullable: true }) characterField_eq?: string; @@ -628,6 +640,12 @@ export class KitchenSinkCreateInput { @TypeGraphQLField({ nullable: true }) noFilterOrSortField?: string; + @TypeGraphQLField({ nullable: true }) + stringFieldFilterEqContains?: string; + + @TypeGraphQLField({ nullable: true }) + intFieldFilterLteGte?: number; + @TypeGraphQLField({ nullable: true }) characterField?: string; @@ -694,6 +712,12 @@ export class KitchenSinkUpdateInput { @TypeGraphQLField({ nullable: true }) noFilterOrSortField?: string; + @TypeGraphQLField({ nullable: true }) + stringFieldFilterEqContains?: string; + + @TypeGraphQLField({ nullable: true }) + intFieldFilterLteGte?: number; + @TypeGraphQLField({ nullable: true }) characterField?: string; diff --git a/src/test/generated/schema.graphql b/src/test/generated/schema.graphql index 3bdc7fa9..dc2bc7c8 100644 --- a/src/test/generated/schema.graphql +++ b/src/test/generated/schema.graphql @@ -241,6 +241,8 @@ type KitchenSink implements BaseGraphQLObject { noFilterField: String noSortField: String noFilterOrSortField: String + stringFieldFilterEqContains: String + intFieldFilterLteGte: Int characterField: String customTextFieldNoSortOrFilter: String readonlyField: String @@ -265,6 +267,8 @@ input KitchenSinkCreateInput { noFilterField: String noSortField: String noFilterOrSortField: String + stringFieldFilterEqContains: String + intFieldFilterLteGte: Float characterField: String customTextFieldNoSortOrFilter: String writeonlyField: String @@ -332,6 +336,8 @@ input KitchenSinkUpdateInput { noFilterField: String noSortField: String noFilterOrSortField: String + stringFieldFilterEqContains: String + intFieldFilterLteGte: Float characterField: String customTextFieldNoSortOrFilter: String writeonlyField: String @@ -429,6 +435,10 @@ input KitchenSinkWhereInput { noSortField_startsWith: String noSortField_endsWith: String noSortField_in: [String!] + stringFieldFilterEqContains_eq: String + stringFieldFilterEqContains_contains: String + intFieldFilterLteGte_gte: Int + intFieldFilterLteGte_lte: Int characterField_eq: String characterField_contains: String characterField_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 396d271f..e942185c 100644 --- a/src/test/modules/kitchen-sink/kitchen-sink.model.ts +++ b/src/test/modules/kitchen-sink/kitchen-sink.model.ts @@ -93,6 +93,12 @@ export class KitchenSink extends BaseModel { @StringField({ filter: false, sort: false, nullable: true }) noFilterOrSortField?: string; + @StringField({ filter: ['eq', 'contains'], sort: false, nullable: true }) + stringFieldFilterEqContains?: string; + + @IntField({ filter: ['lte', 'gte'], sort: false, nullable: true }) + intFieldFilterLteGte?: number; + @StringField({ dataType: 'character', nullable: true }) characterField?: string; diff --git a/src/torm/operators.ts b/src/torm/operators.ts index 223d23ff..58b872e4 100644 --- a/src/torm/operators.ts +++ b/src/torm/operators.ts @@ -1,5 +1,35 @@ import { SelectQueryBuilder } from 'typeorm'; +export type WhereOperator = + | 'eq' + | 'not' + | 'lt' + | 'lte' + | 'gt' + | 'gte' + | 'in' + | 'contains' + | 'startsWith' + | 'endsWith' + | 'json'; + +type ExactWhereOperator = 'eq' | 'in'; +type NumberWhereOperator = 'eq' | 'gt' | 'gte' | 'lt' | 'lte' | 'in'; +type TextWhereOperator = 'eq' | 'contains' | 'startsWith' | 'endsWith' | 'in'; +type DateGeneralWhereOperator = 'eq' | 'lt' | 'lte' | 'gt' | 'gte'; + +export type BooleanWhereOperator = ExactWhereOperator; +export type DateWhereOperator = DateGeneralWhereOperator; +export type DateOnlyWhereOperator = DateGeneralWhereOperator; +export type DateTimeWhereOperator = DateGeneralWhereOperator; +export type EmailWhereOperator = TextWhereOperator; +export type EnumWhereOperator = ExactWhereOperator; +export type FloatWhereOperator = NumberWhereOperator; +export type IdWhereOperator = ExactWhereOperator; +export type IntWhereOperator = NumberWhereOperator; +export type NumericWhereOperator = NumberWhereOperator; +export type StringWhereOperator = TextWhereOperator; + export function addQueryBuilderWhereItem( qb: SelectQueryBuilder, // query builder will be mutated (chained) in this function parameterKey: string, // Paremeter key used in query builder