Aller au contenu

QueryOptions

The @QueryOptions() decorator allows you to configure the default behavior of queries for a specific DTO class. This includes pagination strategy, result sizes, default sorting, filtering options, and connection settings.

The @QueryOptions() decorator is applied to a DTO class and affects all queries generated for that class. It provides a way to set defaults and enable/disable features at the DTO level, rather than having to specify them for each query.

Apply the decorator to your DTO class:

import { ObjectType, Field } from '@lib/type-graphql';
import { QueryOptions, PagingStrategies } from '@lib/type-graphql-query';
@ObjectType()
@QueryOptions({
pagingStrategy: PagingStrategies.OFFSET,
maxResultsSize: 100,
defaultSort: [{ field: 'createdAt', direction: SortDirection.DESC }],
})
export class Product {
@Field()
id!: string;
@Field()
name!: string;
@Field()
createdAt!: Date;
}

The pagingStrategy option determines how results are paginated:

  • PagingStrategies.CURSOR (default): Cursor-based pagination using first/last and before/after cursors
  • PagingStrategies.OFFSET: Offset-based pagination using limit and offset
  • PagingStrategies.NONE: No pagination, returns a simple array
@QueryOptions({
pagingStrategy: PagingStrategies.OFFSET, // Use offset pagination
})

Control the default and maximum number of results:

@QueryOptions({
defaultResultSize: 20, // Default number of results (default: 10)
maxResultsSize: 100, // Maximum number of results (default: 50)
// Use -1 for unlimited results
maxResultsSize: -1, // No limit
})

Set the default sort order for queries:

import { SortDirection } from "@lib/type-graphql-query";
@QueryOptions({
defaultSort: [
{ field: 'createdAt', direction: SortDirection.DESC },
{ field: 'name', direction: SortDirection.ASC },
],
})

Control which query features are available:

@QueryOptions({
enableSort: true, // Enable sorting (default: true)
enableFilter: true, // Enable filtering (default: true)
enableFetchAllWithNegative: true, // Allow negative limits to fetch all (default: false)
})

Apply a default filter to all queries:

@QueryOptions({
defaultFilter: {
status: { eq: 'active' },
},
})

Configure filter behavior:

@QueryOptions({
allowedBooleanExpressions: ['and', 'or'], // Allowed boolean operators (default: ['and', 'or'])
filterDepth: 2, // Maximum depth for nested filters (default: 1)
})

Configure connection behavior (applies to cursor and offset pagination):

@QueryOptions({
pagingStrategy: PagingStrategies.CURSOR,
enableTotalCount: true, // Include totalCount in connection (default: false)
connectionName: 'ProductConnection', // Custom connection name
enableAggregate: true, // Enable aggregate queries
})

Keyset pagination is enabled automatically when the DTO declares @KeySetField on one or more properties.

@ObjectType()
@QueryOptions({
pagingStrategy: PagingStrategies.OFFSET,
maxResultsSize: -1, // No limit
})
export class Permission {
@Field()
id!: string;
@Field()
name!: string;
@Field()
order!: number;
}
@ObjectType()
@QueryOptions({
pagingStrategy: PagingStrategies.CURSOR,
defaultResultSize: 20,
maxResultsSize: 100,
defaultSort: [{ field: 'name', direction: SortDirection.ASC }],
enableTotalCount: true,
})
export class Category {
@Field()
id!: string;
@Field()
name!: string;
}
@ObjectType()
@QueryOptions({
pagingStrategy: PagingStrategies.NONE,
defaultFilter: {
isActive: { eq: true },
},
enableFilter: true,
})
export class Status {
@Field()
id!: string;
@Field()
name!: string;
@Field()
isActive!: boolean;
}
@ObjectType()
@QueryOptions({
pagingStrategy: PagingStrategies.OFFSET,
defaultResultSize: 25,
maxResultsSize: 200,
defaultSort: [
{ field: 'priority', direction: SortDirection.DESC },
{ field: 'createdAt', direction: SortDirection.DESC },
],
enableSort: true,
enableFilter: true,
enableFetchAllWithNegative: false,
defaultFilter: {
status: { eq: 'published' },
},
allowedBooleanExpressions: ['and', 'or'],
filterDepth: 3,
enableTotalCount: true,
connectionName: 'ProductConnection',
})
export class Product {
@Field()
id!: string;
@Field()
name!: string;
@Field()
status!: string;
@Field()
priority!: number;
@Field()
createdAt!: Date;
}
Option Type Default Description
defaultResultSize number 10 Default number of results to return
maxResultsSize number 50 Maximum number of results (-1 for unlimited)
defaultSort SortField<DTO>[] [] Default sort order
enableSort boolean true Enable sorting feature
defaultFilter Filter<DTO> {} Default filter to apply
enableFilter boolean true Enable filtering feature
enableFetchAllWithNegative boolean false Allow negative limits to fetch all
allowedBooleanExpressions ('and' | 'or')[] ['and', 'or'] Allowed boolean operators
filterDepth number 1 Maximum depth for nested filters
Option Type Default Description
pagingStrategy PagingStrategies.CURSOR - Use cursor-based pagination
enableTotalCount boolean false Include totalCount in connection
connectionName string Auto-generated Custom connection name
enableAggregate boolean false Enable aggregate queries
AggregateDTOClass ClassType<object> - DTO class for aggregate results
Option Type Default Description
pagingStrategy PagingStrategies.OFFSET - Use offset-based pagination
enableTotalCount boolean false Include totalCount in connection
connectionName string Auto-generated Custom connection name
enableAggregate boolean false Enable aggregate queries
AggregateDTOClass ClassType<object> - DTO class for aggregate results
Option Type Default Description
pagingStrategy PagingStrategies.NONE - No pagination, return array
enableAggregate boolean false Enable aggregate queries
AggregateDTOClass ClassType<object> - DTO class for aggregate results
  1. Choose the Right Pagination Strategy

    • Use CURSOR for large datasets and when you need stable pagination
    • Use OFFSET for simpler use cases and when you need page numbers
    • Use NONE for small, fixed-size datasets
  2. Set Reasonable Limits

    • Always set maxResultsSize to prevent accidental large queries
    • Use -1 only when you’re certain the dataset is manageable
  3. Use Default Filters for Security

    • Apply default filters to automatically exclude soft-deleted or inactive records
    • Combine with @ContextFilter for row-level security
  4. Optimize with Default Sorting

    • Set default sorting to match your most common query patterns
    • This can improve database query performance
  5. Control Filter Depth

    • Limit filterDepth to prevent overly complex queries
    • Higher depths can impact performance

The @QueryOptions() decorator works in conjunction with other decorators:

  • @ContextFilter(): Default filters from @QueryOptions are combined with filters from @ContextFilter
  • @EnhancedField(): Field-level options (like filterable, sortable) are respected by query options
  • @Authorize(): Authorization rules apply regardless of query options