diff --git a/packages/query-graphql/__tests__/__fixtures__/cursor-query-args-required-filter-type.graphql b/packages/query-graphql/__tests__/__fixtures__/cursor-query-args-required-filter-type.graphql new file mode 100644 index 000000000..f365f1d69 --- /dev/null +++ b/packages/query-graphql/__tests__/__fixtures__/cursor-query-args-required-filter-type.graphql @@ -0,0 +1,74 @@ +type Query { + test( + """Limit or page results.""" + paging: CursorPaging = {first: 10} + + """Specify to filter the records returned.""" + filter: TestFilterRequiredDtoFilter! + + """Specify to sort results.""" + sorting: [TestFilterRequiredDtoSort!] = [] + ): String! +} + +input CursorPaging { + """Paginate before opaque cursor""" + before: ConnectionCursor + + """Paginate after opaque cursor""" + after: ConnectionCursor + + """Paginate first""" + first: Int + + """Paginate last""" + last: Int +} + +"""Cursor for paging through collections""" +scalar ConnectionCursor + +input TestFilterRequiredDtoFilter { + and: [TestFilterRequiredDtoFilter!] + or: [TestFilterRequiredDtoFilter!] + requiredFilterableField: StringFieldComparison! +} + +input StringFieldComparison { + is: Boolean + isNot: Boolean + eq: String + neq: String + gt: String + gte: String + lt: String + lte: String + like: String + notLike: String + iLike: String + notILike: String + in: [String!] + notIn: [String!] +} + +input TestFilterRequiredDtoSort { + field: TestFilterRequiredDtoSortFields! + direction: SortDirection! + nulls: SortNulls +} + +enum TestFilterRequiredDtoSortFields { + requiredFilterableField +} + +"""Sort Directions""" +enum SortDirection { + ASC + DESC +} + +"""Sort Nulls Options""" +enum SortNulls { + NULLS_FIRST + NULLS_LAST +} diff --git a/packages/query-graphql/__tests__/__fixtures__/filter-required-field-input-type.graphql b/packages/query-graphql/__tests__/__fixtures__/filter-required-field-input-type.graphql new file mode 100644 index 000000000..f173ccb29 --- /dev/null +++ b/packages/query-graphql/__tests__/__fixtures__/filter-required-field-input-type.graphql @@ -0,0 +1,71 @@ +type Query { + test(input: TestComparisonDtoFilter!): Int! +} + +input TestComparisonDtoFilter { + and: [TestFilterRequiredComparisonFilter!] + or: [TestFilterRequiredComparisonFilter!] + id: NumberFieldComparison + requiredField: BooleanFieldComparison! + nonRequiredField: DateFieldComparison + notSpecifiedField: NumberFieldComparison +} + +input TestFilterRequiredComparisonFilter { + and: [TestFilterRequiredComparisonFilter!] + or: [TestFilterRequiredComparisonFilter!] + id: NumberFieldComparison + requiredField: BooleanFieldComparison! + nonRequiredField: DateFieldComparison + notSpecifiedField: NumberFieldComparison +} + +input NumberFieldComparison { + is: Boolean + isNot: Boolean + eq: Float + neq: Float + gt: Float + gte: Float + lt: Float + lte: Float + in: [Float!] + notIn: [Float!] + between: NumberFieldComparisonBetween + notBetween: NumberFieldComparisonBetween +} + +input NumberFieldComparisonBetween { + lower: Float! + upper: Float! +} + +input BooleanFieldComparison { + is: Boolean + isNot: Boolean +} + +input DateFieldComparison { + is: Boolean + isNot: Boolean + eq: DateTime + neq: DateTime + gt: DateTime + gte: DateTime + lt: DateTime + lte: DateTime + in: [DateTime!] + notIn: [DateTime!] + between: DateFieldComparisonBetween + notBetween: DateFieldComparisonBetween +} + +""" +A date-time string at UTC, such as 2019-12-03T09:54:33Z, compliant with the date-time format. +""" +scalar DateTime + +input DateFieldComparisonBetween { + lower: DateTime! + upper: DateTime! +} diff --git a/packages/query-graphql/__tests__/__fixtures__/index.ts b/packages/query-graphql/__tests__/__fixtures__/index.ts index c8cd8f1b3..0293c474f 100644 --- a/packages/query-graphql/__tests__/__fixtures__/index.ts +++ b/packages/query-graphql/__tests__/__fixtures__/index.ts @@ -42,6 +42,9 @@ export const filterInputTypeSDL = readGraphql(resolve(__dirname, './filter-input export const filterAllowedComparisonsInputTypeSDL = readGraphql( resolve(__dirname, './filter-allowed-comparisons-input-type.graphql'), ); +export const filterRequiredFieldInputTypeSDL = readGraphql( + resolve(__dirname, './filter-required-field-input-type.graphql'), +); export const updateFilterInputTypeSDL = readGraphql(resolve(__dirname, './update-filter-input-type.graphql')); export const deleteFilterInputTypeSDL = readGraphql(resolve(__dirname, './delete-filter-input-type.graphql')); export const subscriptionFilterInputTypeSDL = readGraphql( @@ -51,8 +54,17 @@ export const pagingInputTypeSDL = readGraphql(resolve(__dirname, './paging-input export const pageInfoObjectTypeSDL = readGraphql(resolve(__dirname, './page-info-object-type.graphql')); export const sortingInputTypeSDL = readGraphql(resolve(__dirname, './sorting-input-type.graphql')); export const cursorQueryArgsTypeSDL = readGraphql(resolve(__dirname, './cursor-query-args-type.graphql')); +export const cursorQueryArgsFilterRequiredTypeSDL = readGraphql( + resolve(__dirname, './cursor-query-args-required-filter-type.graphql'), +); export const offsetQueryArgsTypeSDL = readGraphql(resolve(__dirname, './offset-query-args-type.graphql')); +export const offsetQueryArgsFilterRequiredTypeSDL = readGraphql( + resolve(__dirname, './offset-query-args-required-filter-type.graphql'), +); export const noPagingQueryArgsTypeSDL = readGraphql(resolve(__dirname, './no-paging-query-args-type.graphql')); +export const noPagingQueryArgsFilterRequiredTypeSDL = readGraphql( + resolve(__dirname, './no-paging-query-args-required-filter-type.graphql'), +); export const connectionObjectTypeSDL = readGraphql(resolve(__dirname, './connection-object-type.graphql')); export const connectionObjectTypeWithTotalCountSDL = readGraphql( resolve(__dirname, './connection-object-type-with-total-count.graphql'), diff --git a/packages/query-graphql/__tests__/__fixtures__/no-paging-query-args-required-filter-type.graphql b/packages/query-graphql/__tests__/__fixtures__/no-paging-query-args-required-filter-type.graphql new file mode 100644 index 000000000..9e2fdaad4 --- /dev/null +++ b/packages/query-graphql/__tests__/__fixtures__/no-paging-query-args-required-filter-type.graphql @@ -0,0 +1,54 @@ +type Query { + test( + """Specify to filter the records returned.""" + filter: TestFilterRequiredDtoFilter! + + """Specify to sort results.""" + sorting: [TestFilterRequiredDtoSort!] = [] + ): String! +} + +input TestFilterRequiredDtoFilter { + and: [TestFilterRequiredDtoFilter!] + or: [TestFilterRequiredDtoFilter!] + requiredFilterableField: StringFieldComparison! +} + +input StringFieldComparison { + is: Boolean + isNot: Boolean + eq: String + neq: String + gt: String + gte: String + lt: String + lte: String + like: String + notLike: String + iLike: String + notILike: String + in: [String!] + notIn: [String!] +} + +input TestFilterRequiredDtoSort { + field: TestFilterRequiredDtoSortFields! + direction: SortDirection! + nulls: SortNulls +} + +enum TestFilterRequiredDtoSortFields { + requiredFilterableField +} + +"""Sort Directions""" +enum SortDirection { + ASC + DESC +} + +"""Sort Nulls Options""" +enum SortNulls { + NULLS_FIRST + NULLS_LAST +} diff --git a/packages/query-graphql/__tests__/__fixtures__/offset-query-args-required-filter-type.graphql b/packages/query-graphql/__tests__/__fixtures__/offset-query-args-required-filter-type.graphql new file mode 100644 index 000000000..46a3cf11a --- /dev/null +++ b/packages/query-graphql/__tests__/__fixtures__/offset-query-args-required-filter-type.graphql @@ -0,0 +1,65 @@ +type Query { + test( + """Limit or page results.""" + paging: OffsetPaging = {limit: 10} + + """Specify to filter the records returned.""" + filter: TestFilterRequiredDtoFilter! + + """Specify to sort results.""" + sorting: [TestFilterRequiredDtoSort!] = [] + ): String! +} + +input OffsetPaging { + """Limit the number of records returned""" + limit: Int + + """Offset to start returning records from""" + offset: Int +} + +input TestFilterRequiredDtoFilter { + and: [TestFilterRequiredDtoFilter!] + or: [TestFilterRequiredDtoFilter!] + requiredFilterableField: StringFieldComparison! +} + +input StringFieldComparison { + is: Boolean + isNot: Boolean + eq: String + neq: String + gt: String + gte: String + lt: String + lte: String + like: String + notLike: String + iLike: String + notILike: String + in: [String!] + notIn: [String!] +} + +input TestFilterRequiredDtoSort { + field: TestFilterRequiredDtoSortFields! + direction: SortDirection! + nulls: SortNulls +} + +enum TestFilterRequiredDtoSortFields { + requiredFilterableField +} + +"""Sort Directions""" +enum SortDirection { + ASC + DESC +} + +"""Sort Nulls Options""" +enum SortNulls { + NULLS_FIRST + NULLS_LAST +} diff --git a/packages/query-graphql/__tests__/types/query/filter.type.spec.ts b/packages/query-graphql/__tests__/types/query/filter.type.spec.ts index 7279e33d8..91bc310b0 100644 --- a/packages/query-graphql/__tests__/types/query/filter.type.spec.ts +++ b/packages/query-graphql/__tests__/types/query/filter.type.spec.ts @@ -31,6 +31,7 @@ import { deleteFilterInputTypeSDL, subscriptionFilterInputTypeSDL, filterAllowedComparisonsInputTypeSDL, + filterRequiredFieldInputTypeSDL, } from '../../__fixtures__'; describe('filter types', (): void => { @@ -210,6 +211,36 @@ describe('filter types', (): void => { return expectSDL([FilterTypeSpec], filterAllowedComparisonsInputTypeSDL); }); }); + + describe('filterRequired option', () => { + @ObjectType('TestFilterRequiredComparison') + class TestFilterRequiredDto extends BaseType { + @FilterableField({ filterRequired: true }) + requiredField!: boolean; + + @FilterableField({ filterRequired: false }) + nonRequiredField!: Date; + + @FilterableField() + notSpecifiedField!: number; + } + + const TestGraphQLComparisonFilter: Class> = FilterType(TestFilterRequiredDto); + @InputType() + class TestComparisonDtoFilter extends TestGraphQLComparisonFilter {} + + it('should only expose allowed comparisons', () => { + @Resolver() + class FilterTypeSpec { + @Query(() => Int) + // eslint-disable-next-line @typescript-eslint/no-unused-vars + test(@Args('input') input: TestComparisonDtoFilter): number { + return 1; + } + } + return expectSDL([FilterTypeSpec], filterRequiredFieldInputTypeSDL); + }); + }); }); describe('UpdateFilterType', () => { diff --git a/packages/query-graphql/__tests__/types/query/query-args.type.spec.ts b/packages/query-graphql/__tests__/types/query/query-args.type.spec.ts index 50432a88c..3494e2270 100644 --- a/packages/query-graphql/__tests__/types/query/query-args.type.spec.ts +++ b/packages/query-graphql/__tests__/types/query/query-args.type.spec.ts @@ -9,6 +9,9 @@ import { cursorQueryArgsTypeSDL, offsetQueryArgsTypeSDL, noPagingQueryArgsTypeSDL, + cursorQueryArgsFilterRequiredTypeSDL, + offsetQueryArgsFilterRequiredTypeSDL, + noPagingQueryArgsFilterRequiredTypeSDL, } from '../../__fixtures__'; describe('QueryType', (): void => { @@ -66,6 +69,12 @@ describe('QueryType', (): void => { dateOptional?: Date; } + @nestjsGraphql.ObjectType() + class TestFilterRequiredDto { + @FilterableField({ filterRequired: true }) + requiredFilterableField!: string; + } + describe('cursor query args', () => { @nestjsGraphql.ArgsType() class TestCursorQuery extends QueryArgsType(TestDto) {} @@ -114,6 +123,21 @@ describe('QueryType', (): void => { expect(queryInstance.filter).toBeInstanceOf(TestCursorQuery.FilterType); }); + it('should make the filter required if there is a filterRequired field', () => { + @nestjsGraphql.ArgsType() + class TestFilterRequiredQuery extends QueryArgsType(TestFilterRequiredDto) {} + + @nestjsGraphql.Resolver() + class TestResolver { + @nestjsGraphql.Query(() => String) + // eslint-disable-next-line @typescript-eslint/no-unused-vars + test(@nestjsGraphql.Args() query: TestFilterRequiredQuery): string { + return 'hello'; + } + } + return expectSDL([TestResolver], cursorQueryArgsFilterRequiredTypeSDL); + }); + describe('options', () => { it('by default first should be set to 10 in the paging object', () => { QueryArgsType(TestDto); @@ -124,6 +148,7 @@ describe('QueryType', (): void => { expect(fieldSpy).toHaveBeenCalledWith(expect.any(Function), { defaultValue: {}, description: 'Specify to filter the records returned.', + nullable: false, }); expect(fieldSpy).toHaveBeenCalledWith(expect.any(Function), { defaultValue: [], @@ -140,6 +165,7 @@ describe('QueryType', (): void => { expect(fieldSpy).toHaveBeenCalledWith(expect.any(Function), { defaultValue: {}, description: 'Specify to filter the records returned.', + nullable: false, }); expect(fieldSpy).toHaveBeenCalledWith(expect.any(Function), { defaultValue: [], @@ -195,6 +221,7 @@ describe('QueryType', (): void => { expect(fieldSpy).toHaveBeenCalledWith(expect.any(Function), { defaultValue: filter, description: 'Specify to filter the records returned.', + nullable: false, }); expect(fieldSpy).toHaveBeenCalledWith(expect.any(Function), { defaultValue: [], @@ -212,6 +239,7 @@ describe('QueryType', (): void => { expect(fieldSpy).toHaveBeenCalledWith(expect.any(Function), { defaultValue: {}, description: 'Specify to filter the records returned.', + nullable: false, }); expect(fieldSpy).toHaveBeenCalledWith(expect.any(Function), { defaultValue: sort, @@ -269,6 +297,23 @@ describe('QueryType', (): void => { expect(queryInstance.filter).toBeInstanceOf(TestOffsetQuery.FilterType); }); + it('should make the filter required if there is a filterRequired field', () => { + @nestjsGraphql.ArgsType() + class TestFilterRequiredQuery extends QueryArgsType(TestFilterRequiredDto, { + pagingStrategy: PagingStrategies.OFFSET, + }) {} + + @nestjsGraphql.Resolver() + class TestResolver { + @nestjsGraphql.Query(() => String) + // eslint-disable-next-line @typescript-eslint/no-unused-vars + test(@nestjsGraphql.Args() query: TestFilterRequiredQuery): string { + return 'hello'; + } + } + return expectSDL([TestResolver], offsetQueryArgsFilterRequiredTypeSDL); + }); + describe('options', () => { it('by default limit should be set to 10 in the paging object', () => { QueryArgsType(TestDto, { pagingStrategy: PagingStrategies.OFFSET }); @@ -279,6 +324,7 @@ describe('QueryType', (): void => { expect(fieldSpy).toHaveBeenCalledWith(expect.any(Function), { defaultValue: {}, description: 'Specify to filter the records returned.', + nullable: false, }); expect(fieldSpy).toHaveBeenCalledWith(expect.any(Function), { defaultValue: [], @@ -295,6 +341,7 @@ describe('QueryType', (): void => { expect(fieldSpy).toHaveBeenCalledWith(expect.any(Function), { defaultValue: {}, description: 'Specify to filter the records returned.', + nullable: false, }); expect(fieldSpy).toHaveBeenCalledWith(expect.any(Function), { defaultValue: [], @@ -331,6 +378,7 @@ describe('QueryType', (): void => { expect(fieldSpy).toHaveBeenCalledWith(expect.any(Function), { defaultValue: filter, description: 'Specify to filter the records returned.', + nullable: false, }); expect(fieldSpy).toHaveBeenCalledWith(expect.any(Function), { defaultValue: [], @@ -348,6 +396,7 @@ describe('QueryType', (): void => { expect(fieldSpy).toHaveBeenCalledWith(expect.any(Function), { defaultValue: {}, description: 'Specify to filter the records returned.', + nullable: false, }); expect(fieldSpy).toHaveBeenCalledWith(expect.any(Function), { defaultValue: sort, @@ -393,6 +442,23 @@ describe('QueryType', (): void => { expect(queryInstance.filter).toBeInstanceOf(TestNoPagingQuery.FilterType); }); + it('should make the filter required if there is a filterRequired field', () => { + @nestjsGraphql.ArgsType() + class TestFilterRequiredQuery extends QueryArgsType(TestFilterRequiredDto, { + pagingStrategy: PagingStrategies.NONE, + }) {} + + @nestjsGraphql.Resolver() + class TestResolver { + @nestjsGraphql.Query(() => String) + // eslint-disable-next-line @typescript-eslint/no-unused-vars + test(@nestjsGraphql.Args() query: TestFilterRequiredQuery): string { + return 'hello'; + } + } + return expectSDL([TestResolver], noPagingQueryArgsFilterRequiredTypeSDL); + }); + describe('options', () => { it('allow specifying a default filter', () => { const filter = { booleanField: { is: true } }; @@ -400,6 +466,7 @@ describe('QueryType', (): void => { expect(fieldSpy).toHaveBeenCalledWith(expect.any(Function), { defaultValue: filter, description: 'Specify to filter the records returned.', + nullable: false, }); expect(fieldSpy).toHaveBeenCalledWith(expect.any(Function), { defaultValue: [], @@ -413,6 +480,7 @@ describe('QueryType', (): void => { expect(fieldSpy).toHaveBeenCalledWith(expect.any(Function), { defaultValue: {}, description: 'Specify to filter the records returned.', + nullable: false, }); expect(fieldSpy).toHaveBeenCalledWith(expect.any(Function), { defaultValue: sort, diff --git a/packages/query-graphql/src/decorators/filterable-field.decorator.ts b/packages/query-graphql/src/decorators/filterable-field.decorator.ts index 7ae6aa956..05fe5cc31 100644 --- a/packages/query-graphql/src/decorators/filterable-field.decorator.ts +++ b/packages/query-graphql/src/decorators/filterable-field.decorator.ts @@ -4,6 +4,7 @@ import { getMetadataStorage } from '../metadata'; export type FilterableFieldOptions = { allowedComparisons?: FilterComparisonOperators[]; + filterRequired?: boolean; } & FieldOptions; /** * Decorator for Fields that should be filterable through a [[FilterType]] diff --git a/packages/query-graphql/src/metadata/metadata-storage.ts b/packages/query-graphql/src/metadata/metadata-storage.ts index 1703b4311..51a2550ac 100644 --- a/packages/query-graphql/src/metadata/metadata-storage.ts +++ b/packages/query-graphql/src/metadata/metadata-storage.ts @@ -1,12 +1,13 @@ import { LazyMetadataStorage } from '@nestjs/graphql/dist/schema-builder/storages/lazy-metadata.storage'; import { ObjectTypeMetadata } from '@nestjs/graphql/dist/schema-builder/metadata/object-type.metadata'; import { EnumMetadata } from '@nestjs/graphql/dist/schema-builder/metadata'; -import { AggregateResponse, Class, Filter, SortField } from '@nestjs-query/core'; +import { AggregateResponse, Class, SortField } from '@nestjs-query/core'; import { ReturnTypeFunc, TypeMetadataStorage } from '@nestjs/graphql'; import { ReferencesOpts, RelationsOpts, ResolverRelation, ResolverRelationReference } from '../resolvers/relations'; import { ReferencesKeys } from '../resolvers/relations/relations.interface'; import { EdgeType, StaticConnectionType } from '../types/connection'; import { FilterableFieldOptions } from '../decorators'; +import { FilterConstructor } from '../types/query/filter.type'; /** * @internal @@ -40,7 +41,7 @@ type ConnectionTypes = 'cursor' | 'array'; export class GraphQLQueryMetadataStorage { private readonly filterableObjectStorage: Map, FilterableFieldDescriptor[]>; - private readonly filterTypeStorage: Map>>; + private readonly filterTypeStorage: Map>; private readonly sortTypeStorage: Map, Class>>; @@ -56,7 +57,7 @@ export class GraphQLQueryMetadataStorage { constructor() { this.filterableObjectStorage = new Map, FilterableFieldDescriptor[]>(); - this.filterTypeStorage = new Map>>(); + this.filterTypeStorage = new Map>(); this.sortTypeStorage = new Map, Class>>(); this.connectionTypeStorage = new Map>(); this.edgeTypeStorage = new Map, Class>>(); @@ -90,11 +91,11 @@ export class GraphQLQueryMetadataStorage { return typeFields; } - addFilterType(name: string, filterType: Class>): void { + addFilterType(name: string, filterType: FilterConstructor): void { this.filterTypeStorage.set(name, filterType); } - getFilterType(name: string): Class> | undefined { + getFilterType(name: string): FilterConstructor | undefined { return this.getValue(this.filterTypeStorage, name); } diff --git a/packages/query-graphql/src/types/query/filter.type.ts b/packages/query-graphql/src/types/query/filter.type.ts index e3c63a900..9f8503758 100644 --- a/packages/query-graphql/src/types/query/filter.type.ts +++ b/packages/query-graphql/src/types/query/filter.type.ts @@ -11,11 +11,16 @@ import { getDTONames } from '../../common'; export type FilterableRelations = Record>; +export interface FilterConstructor { + hasRequiredFilters: boolean; + new (): Filter; +} + function getOrCreateFilterType( TClass: Class, name: string, filterableRelations: FilterableRelations = {}, -): Class> { +): FilterConstructor { const metadataStorage = getMetadataStorage(); const existing = metadataStorage.getFilterType(name); if (existing) { @@ -25,9 +30,12 @@ function getOrCreateFilterType( if (!fields) { throw new Error(`No fields found to create GraphQLFilter for ${TClass.name}`); } + const hasRequiredFilters = fields.some((f) => f.advancedOptions?.filterRequired === true); @InputType(name) class GraphQLFilter { + static hasRequiredFilters: boolean = hasRequiredFilters; + @ValidateNested() @Field(() => [GraphQLFilter], { nullable: true }) @Type(() => GraphQLFilter) @@ -47,8 +55,9 @@ function getOrCreateFilterType( allowedComparisons: advancedOptions?.allowedComparisons, returnTypeFunc, }); + const nullable = advancedOptions?.filterRequired !== true; ValidateNested()(GraphQLFilter.prototype, propertyName); - Field(() => FC, { nullable: true })(GraphQLFilter.prototype, propertyName); + Field(() => FC, { nullable })(GraphQLFilter.prototype, propertyName); Type(() => FC)(GraphQLFilter.prototype, propertyName); }); Object.keys(filterableRelations).forEach((field) => { @@ -61,8 +70,8 @@ function getOrCreateFilterType( Type(() => FC)(GraphQLFilter.prototype, field); } }); - metadataStorage.addFilterType(name, GraphQLFilter as Class>); - return GraphQLFilter as Class>; + metadataStorage.addFilterType(name, GraphQLFilter as FilterConstructor); + return GraphQLFilter as FilterConstructor; } function getObjectTypeName(DTOClass: Class): string { @@ -84,24 +93,24 @@ function getFilterableRelations(relations: Record(TClass: Class): Class> { +export function FilterType(TClass: Class): FilterConstructor { const { one = {}, many = {} } = getMetadataStorage().getRelations(TClass); const filterableRelations: FilterableRelations = { ...getFilterableRelations(one), ...getFilterableRelations(many) }; return getOrCreateFilterType(TClass, `${getObjectTypeName(TClass)}Filter`, filterableRelations); } -export function DeleteFilterType(TClass: Class): Class> { +export function DeleteFilterType(TClass: Class): FilterConstructor { return getOrCreateFilterType(TClass, `${getObjectTypeName(TClass)}DeleteFilter`); } -export function UpdateFilterType(TClass: Class): Class> { +export function UpdateFilterType(TClass: Class): FilterConstructor { return getOrCreateFilterType(TClass, `${getObjectTypeName(TClass)}UpdateFilter`); } -export function SubscriptionFilterType(TClass: Class): Class> { +export function SubscriptionFilterType(TClass: Class): FilterConstructor { return getOrCreateFilterType(TClass, `${getObjectTypeName(TClass)}SubscriptionFilter`); } -export function AggregateFilterType(TClass: Class): Class> { +export function AggregateFilterType(TClass: Class): FilterConstructor { return getOrCreateFilterType(TClass, `${getObjectTypeName(TClass)}AggregateFilter`); } diff --git a/packages/query-graphql/src/types/query/query-args/cursor-query-args.type.ts b/packages/query-graphql/src/types/query/query-args/cursor-query-args.type.ts index 8134c8e3b..569431fc2 100644 --- a/packages/query-graphql/src/types/query/query-args/cursor-query-args.type.ts +++ b/packages/query-graphql/src/types/query/query-args/cursor-query-args.type.ts @@ -38,8 +38,9 @@ export function CursorQueryArgsType( paging?: CursorPagingType; @Field(() => F, { - defaultValue: opts.defaultFilter ?? DEFAULT_QUERY_OPTS.defaultFilter, + defaultValue: !F.hasRequiredFilters ? opts.defaultFilter ?? DEFAULT_QUERY_OPTS.defaultFilter : undefined, description: 'Specify to filter the records returned.', + nullable: false, }) @ValidateNested() @Type(() => F) diff --git a/packages/query-graphql/src/types/query/query-args/no-paging-query-args.type.ts b/packages/query-graphql/src/types/query/query-args/no-paging-query-args.type.ts index 1c102d307..4274f95a4 100644 --- a/packages/query-graphql/src/types/query/query-args/no-paging-query-args.type.ts +++ b/packages/query-graphql/src/types/query/query-args/no-paging-query-args.type.ts @@ -23,8 +23,9 @@ export function NoPagingQueryArgsType( static FilterType = F; @Field(() => F, { - defaultValue: opts.defaultFilter ?? DEFAULT_QUERY_OPTS.defaultFilter, + defaultValue: !F.hasRequiredFilters ? opts.defaultFilter ?? DEFAULT_QUERY_OPTS.defaultFilter : undefined, description: 'Specify to filter the records returned.', + nullable: false, }) @ValidateNested() @Type(() => F) diff --git a/packages/query-graphql/src/types/query/query-args/offset-query-args.type.ts b/packages/query-graphql/src/types/query/query-args/offset-query-args.type.ts index d80b45607..1afcba425 100644 --- a/packages/query-graphql/src/types/query/query-args/offset-query-args.type.ts +++ b/packages/query-graphql/src/types/query/query-args/offset-query-args.type.ts @@ -37,8 +37,9 @@ export function OffsetQueryArgsType( paging?: Paging; @Field(() => F, { - defaultValue: opts.defaultFilter ?? DEFAULT_QUERY_OPTS.defaultFilter, + defaultValue: !F.hasRequiredFilters ? opts.defaultFilter ?? DEFAULT_QUERY_OPTS.defaultFilter : undefined, description: 'Specify to filter the records returned.', + nullable: false, }) @ValidateNested() @Type(() => F)