UNPKG

nexus

Version:

Scalable, strongly typed GraphQL schema development

416 lines (408 loc) 17.9 kB
import type { GraphQLResolveInfo } from 'graphql' import type { Maybe } from './definitions/_types' import type { AbstractTypeResolver, GetGen, GetGen2, IsFeatureEnabled2, MaybePromise, SourceValue, } from './typegenTypeHelpers' import type { ConditionalKeys, ConditionalPick, ValueOf } from './typeHelpersInternal' /** * Returns a union of all the type names of the members of an abstract type * * @example * union D = A | B | C * PossibleTypeNames<'D> // 'A' | 'B' | 'C' */ export type PossibleTypeNames<AbstractTypeName extends string> = ValueOf< ConditionalPick<GetGen<'abstractTypeMembers'>, AbstractTypeName> > /** * Returns a union of all the members of an abstract type * * @example * union D = A | B | C * PossibleTypes<'D> // A | B | C */ export type PossibleTypes<AbstractTypeName extends string> = SourceValue<PossibleTypeNames<AbstractTypeName>> /** * Returns a union of all the abstract type names where TypeName is used * * @example * union D = A | B * union E = A * AbstractTypeNames<'A'> // 'D' | 'E' */ export type AbstractTypeNames<TypeName extends string> = ConditionalKeys< GetGen<'abstractTypeMembers'>, TypeName > /** Returns whether all the abstract type names where TypeName is used have implemented `resolveType` */ export type IsStrategyResolveTypeImplementedInAllAbstractTypes<TypeName extends string> = AbstractTypeNames<TypeName> extends GetGen<'abstractsUsingStrategyResolveType'> ? true : false /** Returns whether all the members of an abstract type have implemented `isTypeOf` */ export type IsStrategyIsTypeOfImplementedInAllMembers<AbstractTypeName extends string> = GetGen2< 'abstractTypeMembers', AbstractTypeName > extends GetGen<'objectsUsingAbstractStrategyIsTypeOf'> ? true : false export type IsTypeOfHandler<TypeName extends string> = ( source: PossibleTypes<TypeName>, // typed as never if TypeName is not a member of any abstract type context: GetGen<'context'>, info: GraphQLResolveInfo ) => MaybePromise<boolean> /** * Get an object with the `isTypeOf` field if applicable for the given object Type. * * @remarks * Intersect the result of this with other things to build up the final options for a type def. */ export type MaybeTypeDefConfigFieldIsTypeOf<TypeName extends string> = // is isTypeOf strategy disabled ? // then hide isTypeOf property entirely IsFeatureEnabled2<'abstractTypeStrategies', 'isTypeOf'> extends false ? {} : // is TypeName not part of any abstract type? // then make isTypeOf optional AbstractTypeNames<TypeName> extends never ? { /** * [Abstract Types guide](https://nxs.li/guides/abstract-types) * * Implement the [modular strategy](https://nxs.li/guides/abstract-types/modular-strategy). * * This type does not show up in any abstract types. Implementing this ***will do nothing*** until you * have added it to an abstract type. * * @example * // Add your type to an abstract * // type like Song in this example * * makeSchema({ * features: { * abstractTypeStrategies: { * isTypeOf: true, * }, * }, * types: [ * objectType({ * name: 'Song', * isTypeOf(data) { * return Boolean(data.album) * }, * definition(t) { * t.string('url') * t.string('album') * }, * }), * unionType({ * name: 'SearchResult', * definition(t) { * t.members('Song') //... * }, * }), * queryType({ * definition(t) { * t.field('search', { * type: 'SearchResult', * // ... * }) * }, * }), * ], * }) * * @param source The [source data](https://nxs.li/guides/source-types) for the GraphQL objects that * are members of the abstract types that this type is a member of. For example for some type A * in two union types whose members are A,B.C and A,D,E respectively then isTypeOf method for A * would receive source data from A, B, C, D, & E at runtime. * @param context The context data for this request. * * The context data is typically a singleton scoped to the lifecycle of the request. This means * created at the beginning of a request and then passed to all the resolvers that execute while * resolving the request. It is often used to store information like the current user making the * request. Nexus is not responsible for this however. That is typically something you'll do with * e.g. [Mercurius](https://mercurius.dev) or [Apollo * Server](https://apollographql.com/docs/apollo-server/api/apollo-server). * * Note that the type here will be whatever you have specified for "contextType" in your makeSchema * configuration. * @param info The GraphQL resolve info. * * This is an advanced parameter seldom used. It includes things like the AST of the [GraphQL * document](https://spec.graphql.org/June2018/#sec-Language.Document) sent by the client. * @returns A boolean indicating if the received source data is of this type or not. */ isTypeOf?: IsTypeOfHandler<TypeName> } : // is resolveType implemented in all abstract types where TypeName is a member? // then make isTypeOf optional IsStrategyResolveTypeImplementedInAllAbstractTypes<TypeName> extends true ? { /** * [Abstract Types guide](https://nxs.li/guides/abstract-types) * * Implement the [modular strategy](https://nxs.li/guides/abstract-types/modular-strategy). * * You have implemented the [centralized strategy * (resolveType)](https://nxs.li/guides/abstract-types/centralized-strategy) in all abstract types * that this type shows up in therefore, implementing this ***will do nothing***. * * @example * makeSchema({ * features: { * abstractTypeStrategies: { * isTypeOf: true, * resolveType: true, * }, * }, * types: [ * objectType({ * name: 'Song', * // SearchResult has resolveType * // so this will be ignored! * isTypeOf(data) { * return Boolean(data.album) * }, * definition(t) { * t.string('url') * t.string('album') * }, * }), * unionType({ * name: 'SearchResult', * resolveType() { * if (Boolean(data.album)) { * return 'Song' * } * }, * definition(t) { * t.members('Song') //... * }, * }), * queryType({ * definition(t) { * t.field('search', { * type: 'SearchResult', * // ... * }) * }, * }), * ], * }) * * @param source The [source data](https://nxs.li/guides/source-types) for the GraphQL objects that * are members of the abstract types that this type is a member of. For example for some type A * in two union types whose members are A,B.C and A,D,E respectively then isTypeOf method for A * would receive source data from A, B, C, D, & E at runtime. * @param context The context data for this request. * * The context data is typically a singleton scoped to the lifecycle of the request. This means * created at the beginning of a request and then passed to all the resolvers that execute while * resolving the request. It is often used to store information like the current user making the * request. Nexus is not responsible for this however. That is typically something you'll do with * e.g. [Mercurius](https://mercurius.dev) or [Apollo * Server](https://apollographql.com/docs/apollo-server/api/apollo-server). * * Note that the type here will be whatever you have specified for "contextType" in your makeSchema * configuration. * @param info The GraphQL resolve info. * * This is an advanced parameter seldom used. It includes things like the AST of the [GraphQL * document](https://spec.graphql.org/June2018/#sec-Language.Document) sent by the client. * @returns A boolean indicating if the received source data is of this type or not. */ isTypeOf?: IsTypeOfHandler<TypeName> } : // is __typename strategy is enabled? // then make isTypeOf optional IsFeatureEnabled2<'abstractTypeStrategies', '__typename'> extends true ? { /** * [Abstract Types guide](https://nxs.li/guides/abstract-types) * * Implement the [modular strategy](https://nxs.li/guides/abstract-types/modular-strategy). * * You have enabled the [Discriminant Model Field (DMF) * Strategy](https://nxs.li/guides/abstract-types/discriminant-model-field-strategy) which prevents * Nexus from statically knowing if this method is required or not. Therefore it is optional. * * @example * makeSchema({ * features: { * abstractTypeStrategies: { * isTypeOf: true, * __typename: true, * }, * }, * types: [ * objectType({ * name: 'Song', * // Only used at runtime if you * // didn't provide __typename below * isTypeOf(data) { * return Boolean(data.album) * }, * definition(t) { * t.string('url') * t.string('album') * }, * }), * unionType({ * name: 'SearchResult', * definition(t) { * t.members('Song') //... * }, * }), * queryType({ * definition(t) { * t.field('search', { * type: 'SearchResult', * resolve() { * // You _might_ provide typename * // in data returned here * return // ... * }, * }) * }, * }), * ], * }) * * @param source The [source data](https://nxs.li/guides/source-types) for the GraphQL objects that * are members of the abstract types that this type is a member of. For example for some type A * in two union types whose members are A,B.C and A,D,E respectively then isTypeOf method for A * would receive source data from A, B, C, D, & E at runtime. * @param context The context data for this request. * * The context data is typically a singleton scoped to the lifecycle of the request. This means * created at the beginning of a request and then passed to all the resolvers that execute while * resolving the request. It is often used to store information like the current user making the * request. Nexus is not responsible for this however. That is typically something you'll do with * e.g. [Mercurius](https://mercurius.dev) or [Apollo * Server](https://apollographql.com/docs/apollo-server/api/apollo-server). * * Note that the type here will be whatever you have specified for "contextType" in your makeSchema * configuration. * @param info The GraphQL resolve info. * * This is an advanced parameter seldom used. It includes things like the AST of the [GraphQL * document](https://spec.graphql.org/June2018/#sec-Language.Document) sent by the client. * @returns A boolean indicating if the received source data is of this type or not. */ isTypeOf?: IsTypeOfHandler<TypeName> } : // otherwise, make it required { /** * [Abstract Types guide](https://nxs.li/guides/abstract-types) * * Implement the [modular strategy](https://nxs.li/guides/abstract-types/modular-strategy). * * You must implement this because your type shows up in one or more abstract types that do not * implement the [centralized strategy](https://nxs.li/guides/abstract-types/centralized-strategy). * * @example * makeSchema({ * features: { * abstractTypeStrategies: { * isTypeOf: true, * }, * }, * types: [ * objectType({ * name: 'Song', * isTypeOf(data) { * return Boolean(data.album) * }, * definition(t) { * t.string('url') * t.string('album') * }, * }), * unionType({ * name: 'SearchResult', * definition(t) { * t.members('Song') //... * }, * }), * queryType({ * definition(t) { * t.field('search', { * type: 'SearchResult', * // ... * }) * }, * }), * ], * }) * * @param source The [source data](https://nxs.li/guides/source-types) for the GraphQL objects that * are members of the abstract types that this type is a member of. For example for some type A * in two union types whose members are A,B.C and A,D,E respectively then isTypeOf method for A * would receive source data from A, B, C, D, & E at runtime. * @param context The context data for this request. * * The context data is typically a singleton scoped to the lifecycle of the request. This means * created at the beginning of a request and then passed to all the resolvers that execute while * resolving the request. It is often used to store information like the current user making the * request. Nexus is not responsible for this however. That is typically something you'll do with * e.g. [Mercurius](https://mercurius.dev) or [Apollo * Server](https://apollographql.com/docs/apollo-server/api/apollo-server). * * Note that the type here will be whatever you have specified for "contextType" in your makeSchema * configuration. * @param info The GraphQL resolve info. * * This is an advanced parameter seldom used. It includes things like the AST of the [GraphQL * document](https://spec.graphql.org/June2018/#sec-Language.Document) sent by the client. * @returns A boolean indicating if the received source data is of this type or not. */ isTypeOf: IsTypeOfHandler<TypeName> } /** * Get an object with the `resolveType` field if applicable for the given abstract Type. * * @remarks * Intersect the result of this with other things to build up the final options for a type def. */ export type MaybeTypeDefConfigFieldResolveType<TypeName extends string> = IsFeatureEnabled2< 'abstractTypeStrategies', 'resolveType' > extends false ? {} // remove field altogether is resolveType strategy is disabled : IsStrategyIsTypeOfImplementedInAllMembers<TypeName> extends true ? { /** * [Abstract Types Guide](https://nxs.li/guides/abstract-types) * * Optionally provide a custom type resolver function. If one is not provided, the default * implementation will first look for __typename, then fallback to calling `isTypeOf` on each * implementing Object type. */ resolveType?: Maybe<AbstractTypeResolver<TypeName>> } // Make resolveType optional when __typename strategy is enabled : IsFeatureEnabled2<'abstractTypeStrategies', '__typename'> extends true ? { /** * [Abstract Types Guide](https://nxs.li/guides/abstract-types) * * Optionally provide a custom type resolver function. If one is not provided, the default * implementation will first look for __typename, then fallback to calling `isTypeOf` on each * implementing Object type. */ resolveType?: Maybe<AbstractTypeResolver<TypeName>> } : { /** * [Abstract Types Guide](https://nxs.li/guides/abstract-types) * * Optionally provide a custom type resolver function. If one is not provided, the default * implementation will first look for __typename, then fallback to calling `isTypeOf` on each * implementing Object type. */ resolveType: AbstractTypeResolver<TypeName> }