Types
type-graphql-query provides a number of types. Most will be automatically generated for you when you create a resolver using buildSchema or buildTypeDefsAndResolvers. However, you can use many of the types in your own code for custom endpoints.
The following examples are based on the following ProductDTO:
import { ObjectType, ID, GraphQLISODateTime } from '@lib/type-graphql';import { EnhancedField, IDField } from '@lib/type-graphql-query';
@ObjectType('Product')export class ProductDTO { @IDField(() => ID) id!: string;
@EnhancedField(() => String) name!: string;
@EnhancedField(() => Boolean) canBeSold!: boolean;
@EnhancedField(() => GraphQLISODateTime) createdAt!: Date;
@EnhancedField(() => GraphQLISODateTime) updatedAt!: Date;}ArgsTypes
Section intitulée « ArgsTypes »QueryArgsType
Section intitulée « QueryArgsType »Args type used in read endpoints to allow filtering, paging, and sorting.
The QueryArgsType will generate an ArgsType that will require the user to provide three arguments.
filter?- A filter that should be used to find records. See FilterTypepaging?- Options to page results.sorting?- Optional array to allow sorting of results. See SortType.
import { QueryArgsType } from '@lib/type-graphql-query';import { ArgsType } from '@lib/type-graphql';import { ProductDTO } from './dto/product.dto';
@ArgsType()export class ProductQuery extends QueryArgsType(ProductDTO) {}The QueryArgsType function returns a class with static properties:
FilterType- The filter type for the DTOSortType- The sort type for the DTOPageType- The paging type (CursorPaging, OffsetPaging, or NonePaging)ConnectionType- The connection type for the DTO
import { QueryArgsType } from '@lib/type-graphql-query';import { ProductDTO } from './dto/product.dto';
export const ProductQueryArgs = QueryArgsType(ProductDTO);
// Access static typesexport const ProductFilter = ProductQueryArgs.FilterType;export const ProductSort = ProductQueryArgs.SortType;export const ProductPaging = ProductQueryArgs.PageType;export const ProductConnection = ProductQueryArgs.ConnectionType;ObjectTypes
Section intitulée « ObjectTypes »ConnectionType
Section intitulée « ConnectionType »Implementation of connections. Useful for large result sets where the end user should be able to page through the results.
import { QueryArgsType } from '@lib/type-graphql-query';import { ProductDTO } from './dto/product.dto';
export const ProductQueryArgs = QueryArgsType(ProductDTO);export const ProductConnection = ProductQueryArgs.ConnectionType;Cursor Connection Schema:
scalar ConnectionCursor
type ProductConnection { pageInfo: PageInfo! edges: [ProductEdge!]! totalCount: Int}
type ProductEdge { node: Product! cursor: ConnectionCursor!}
type PageInfo { hasNextPage: Boolean! hasPreviousPage: Boolean! startCursor: ConnectionCursor endCursor: ConnectionCursor}Offset Connection Schema:
type ProductConnection { pageInfo: OffsetPageInfo! nodes: [Product!]! totalCount: Int}
type OffsetPageInfo { hasNextPage: Boolean!}UpdateManyResponseType
Section intitulée « UpdateManyResponseType »Response from updateMany mutations.
import { UpdateManyResponseType } from '@lib/type-graphql-query';
export const UpdateManyResponse = UpdateManyResponseType();Schema:
type UpdateManyResponse { updatedCount: Int!}DeleteManyResponseType
Section intitulée « DeleteManyResponseType »Response from deleteMany mutations.
import { DeleteManyResponseType } from '@lib/type-graphql-query';
export const DeleteManyResponse = DeleteManyResponseType();Schema:
type DeleteManyResponse { deletedCount: Int!}InputTypes
Section intitulée « InputTypes »FilterType
Section intitulée « FilterType »GraphQL implementation of the Filter type.
The FilterType is dynamically created based on the fields in the DTO annotated with @EnhancedField({ filterable: true }).
Along with the dynamically created fields, filter also has the following static fields:
-
and- Allows for joining multipleFiltersusing anANDcondition.
For example, find all products thatstart with 'Chicken' AND can be sold.query {queryManyProduct(filter: { and: [{ name: { like: "Chicken%" } }, { canBeSold: { is: true } }] }) {idname}} -
or- Allows for joining multipleFiltersusing anORcondition.
For example, find all products that(can be sold AND start with 'Chicken') OR (cannot be sold and end in 'Egg').query {queryManyProduct(filter: {or: [{ name: { like: "Chicken%" }, canBeSold: { is: true } }{ name: { like: "%Egg" }, canBeSold: { is: false } }]}) {idname}}
import { FilterType } from '@lib/type-graphql-query';import { ProductDTO } from './dto/product.dto';
export const ProductFilter = FilterType(ProductDTO);Schema:
input ProductFilter { and: [ProductFilter!] or: [ProductFilter!] id: IDFilterComparison name: StringFilterComparison canBeSold: BooleanFilterComparison createdAt: DateFilterComparison updatedAt: DateFilterComparison}
input IDFilterComparison { is: Boolean isNot: Boolean eq: ID neq: ID gt: ID gte: ID lt: ID lte: ID like: ID notLike: ID iLike: ID notILike: ID in: [ID!] notIn: [ID!]}
input StringFilterComparison { 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 BooleanFilterComparison { is: Boolean isNot: Boolean}
input DateFilterComparison { is: Boolean isNot: Boolean eq: DateTime neq: DateTime gt: DateTime gte: DateTime lt: DateTime lte: DateTime in: [DateTime!] notIn: [DateTime!]}SortType
Section intitulée « SortType »The SortType allows you to sort results.
NOTE This type is automatically created when using QueryArgsType.
For more comprehensive examples take a look at the Sorting Docs.
field- The field to sort on. This is an ENUM of fields defined in the DTO with@EnhancedField({ sortable: true }).direction- The direction to sort the fieldASCorDESC.nulls?- On supported storage engines you can specify the null sort orderNULLS_FIRST,NULLS_LAST
import { QueryArgsType } from '@lib/type-graphql-query';import { ProductDTO } from './dto/product.dto';
export const ProductQueryArgs = QueryArgsType(ProductDTO);export const ProductSort = ProductQueryArgs.SortType;Schema:
input ProductSort { field: ProductSortFields! direction: SortDirection! nulls: SortNulls}
enum ProductSortFields { id name canBeSold createdAt updatedAt}
enum SortDirection { ASC DESC}
enum SortNulls { NULLS_FIRST NULLS_LAST}CreateOneInputType
Section intitulée « CreateOneInputType »Input type for createOne mutations.
NOTE Don’t forget to annotate your DTO with @InputType() from type-graphql.
NOTE Your DTO should be one that you want to use for input. For example you may not want to let the end user specify the createdAt or updatedAt fields so you would create a new DTO just for input.
import { CreateOneInputType } from '@lib/type-graphql-query';import { InputType, Field } from '@lib/type-graphql';import { IsString, IsBoolean } from 'class-validator';
@InputType('ProductInput')export class ProductInputDTO { @IsString() @Field() name!: string;
@IsBoolean() @Field() canBeSold!: boolean;}
@InputType()export class CreateOneProductInput extends CreateOneInputType('product', ProductInputDTO) {}Schema:
input CreateOneProductInput { product: ProductInput!}
input ProductInput { name: String! canBeSold: Boolean!}CreateManyInputType
Section intitulée « CreateManyInputType »Input type for createMany mutations.
NOTE Don’t forget to annotate your DTO with @InputType() from type-graphql.
NOTE Your DTO should be one that you want to use for input. For example you may not want to let the end user specify the createdAt or updatedAt fields so you would create a new DTO just for input.
import { CreateManyInputType } from '@lib/type-graphql-query';import { InputType, Field } from '@lib/type-graphql';import { IsString, IsBoolean } from 'class-validator';
@InputType('ProductInput')export class ProductInputDTO { @IsString() @Field() name!: string;
@IsBoolean() @Field() canBeSold!: boolean;}
@InputType()export class CreateManyProductsInput extends CreateManyInputType('products', ProductInputDTO) {}Schema:
input CreateManyProductsInput { products: [ProductInput!]!}
input ProductInput { name: String! canBeSold: Boolean!}UpdateOneInputType
Section intitulée « UpdateOneInputType »InputType for updateOne mutations.
The UpdateOneInputType will generate an InputType that will require the user to provide two fields.
id- The id of the record to updateupdate- A record with fields to update.
import { UpdateOneInputType } from '@lib/type-graphql-query';import { InputType, Field } from '@lib/type-graphql';import { IsOptional, IsString, IsBoolean } from 'class-validator';import { ProductDTO } from './dto/product.dto';
@InputType('ProductUpdateInput')export class ProductUpdateDTO { @IsOptional() @IsString() @Field({ nullable: true }) name?: string;
@IsOptional() @IsBoolean() @Field({ nullable: true }) canBeSold?: boolean;}
@InputType()export class UpdateOneProductInput extends UpdateOneInputType(ProductDTO, ProductUpdateDTO) {}Schema:
input UpdateOneProductInput { id: ID! update: ProductUpdateInput!}
input ProductUpdateInput { name: String canBeSold: Boolean}UpdateManyInputType
Section intitulée « UpdateManyInputType »Input type for updateMany mutations.
The UpdateManyInputType will generate an InputType that will require the user to provide two arguments.
filter- The filter that should be used to find records to update. See FilterTypeupdate- The update to apply to each record found.
NOTE Don’t forget to annotate your DTO with @InputType() from type-graphql.
NOTE Your DTO should be one that you want to use for input. For example you may not want to let the end user specify the createdAt or updatedAt fields so you would create a new DTO just for input.
In this example we use the read DTO for the FilterType, and a different update DTO.
import { UpdateManyInputType, FilterType } from '@lib/type-graphql-query';import { InputType, Field } from '@lib/type-graphql';import { IsOptional, IsString, IsBoolean } from 'class-validator';import { ProductDTO } from './dto/product.dto';
@InputType('ProductUpdate')export class ProductUpdateDTO { @IsOptional() @IsString() @Field({ nullable: true }) name?: string;
@IsOptional() @IsBoolean() @Field({ nullable: true }) canBeSold?: boolean;}
@InputType()export class UpdateManyProductsInput extends UpdateManyInputType( ProductDTO, // filter ProductUpdateDTO, // update DTO) {}Schema:
input UpdateManyProductsInput { filter: ProductFilter! update: ProductUpdate!}
input ProductUpdate { name: String canBeSold: Boolean}DeleteOneInputType
Section intitulée « DeleteOneInputType »InputType for deleteOne mutations.
The DeleteOneInputType will generate an InputType that will require the user to provide the id of the record to delete.
import { DeleteOneInputType } from '@lib/type-graphql-query';import { InputType } from '@lib/type-graphql';import { ProductDTO } from './dto/product.dto';
@InputType()export class DeleteOneProductInput extends DeleteOneInputType(ProductDTO) {}Schema:
input DeleteOneProductInput { id: ID!}DeleteManyInputType
Section intitulée « DeleteManyInputType »Input type for deleteMany mutations.
The DeleteManyInputType will generate an InputType that will require the user to provide:
filter- A filter used to find records to delete. See FilterType
import { DeleteManyInputType } from '@lib/type-graphql-query';import { InputType } from '@lib/type-graphql';import { ProductDTO } from './dto/product.dto';
@InputType()export class DeleteManyProductsInput extends DeleteManyInputType(ProductDTO) {}Schema:
input DeleteManyProductsInput { filter: ProductFilter!}UpsertOneInputType
Section intitulée « UpsertOneInputType »Input type for upsertOne mutations.
The UpsertOneInputType will generate an InputType that will require the user to provide an input record. If a record with the same unique identifier exists, it will be updated; otherwise, it will be created.
NOTE Don’t forget to annotate your DTO with @InputType() from type-graphql.
import { UpsertOneInputType } from '@lib/type-graphql-query';import { InputType, Field } from '@lib/type-graphql';import { IsString, IsBoolean } from 'class-validator';
@InputType('ProductInput')export class ProductInputDTO { @IsString() @Field() name!: string;
@IsBoolean() @Field() canBeSold!: boolean;}
@InputType()export class UpsertOneProductInput extends UpsertOneInputType('product', ProductInputDTO) {}Schema:
input UpsertOneProductInput { product: ProductInput!}
input ProductInput { name: String! canBeSold: Boolean!}UpsertManyInputType
Section intitulée « UpsertManyInputType »Input type for upsertMany mutations.
The UpsertManyInputType will generate an InputType that will require the user to provide an array of input records. Records with matching unique identifiers will be updated; others will be created.
NOTE Don’t forget to annotate your DTO with @InputType() from type-graphql.
import { UpsertManyInputType } from '@lib/type-graphql-query';import { InputType, Field } from '@lib/type-graphql';import { IsString, IsBoolean } from 'class-validator';
@InputType('ProductInput')export class ProductInputDTO { @IsString() @Field() name!: string;
@IsBoolean() @Field() canBeSold!: boolean;}
@InputType()export class UpsertManyProductsInput extends UpsertManyInputType('products', ProductInputDTO) {}Schema:
input UpsertManyProductsInput { products: [ProductInput!]!}
input ProductInput { name: String! canBeSold: Boolean!}Additional Types
Section intitulée « Additional Types »TranslationType
Section intitulée « TranslationType »Type for handling localized fields in queries. See Translations for more information.
TranslationInputType
Section intitulée « TranslationInputType »Type for handling localized fields in mutation inputs. See Translations for more information.
MutationArgsType
Section intitulée « MutationArgsType »Wrapper type for mutation arguments that includes authorization context.
FindOneArgsType
Section intitulée « FindOneArgsType »Args type for findById queries.
SubscriptionArgsType
Section intitulée « SubscriptionArgsType »Args type for subscriptions.
SubscriptionFilterInputType
Section intitulée « SubscriptionFilterInputType »Filter type for subscriptions.
RelationInputType
Section intitulée « RelationInputType »Input type for setting a single relation.
RelationsInputType
Section intitulée « RelationsInputType »Input type for setting multiple relations.
AggregateArgsType
Section intitulée « AggregateArgsType »Args type for aggregate queries.
AggregateResponseType
Section intitulée « AggregateResponseType »Response type for aggregate queries.
Complete Example
Section intitulée « Complete Example »Here’s a complete example showing how to use types in a custom resolver:
import { Resolver, Query, Args, Mutation } from '@lib/type-graphql';import { QueryArgsType, FilterType, CreateOneInputType, UpdateOneInputType, DeleteOneInputType, ProductDTO,} from '@lib/type-graphql-query';
// Generate typesconst ProductQueryArgs = QueryArgsType(ProductDTO);const ProductFilter = FilterType(ProductDTO);
@Resolver(() => ProductDTO)export class CustomProductResolver { @Query(() => [ProductDTO]) async customQuery( @Args(() => ProductQueryArgs) queryArgs: InstanceType<typeof ProductQueryArgs>, ): Promise<ProductDTO[]> { // Use queryArgs.filter, queryArgs.paging, queryArgs.sorting // ... }
@Query(() => ProductDTO, { nullable: true }) async findById(@Args('id') id: string): Promise<ProductDTO | null> { // ... }}Best Practices
Section intitulée « Best Practices »-
Use Generated Types When Possible
- Most types are automatically generated when using
buildSchemaorbuildTypeDefsAndResolvers - Only create custom types when you need custom behavior
- Most types are automatically generated when using
-
Separate Input DTOs
- Create separate DTOs for create/update operations
- Don’t expose internal fields like
createdAt,updatedAtin input types
-
Reuse Types
- Use
QueryArgsTypeto get all related types (FilterType, SortType, etc.) - This ensures consistency across your API
- Use
-
Type Safety
- Always use TypeScript types when working with these classes
- Use
InstanceType<typeof TypeClass>to get the instance type