UNPKG

nexus

Version:

Scalable, strongly typed GraphQL schema development

851 lines (804 loc) 31.8 kB
import type { GraphQLFieldConfig, GraphQLFieldResolver, GraphQLInputFieldConfig } from 'graphql' import { messages } from '../messages' import type { AllInputTypes, FieldResolver, GetGen, GetGen3, HasGen3, NeedsResolver, } from '../typegenTypeHelpers' import type { ArgsRecord } from './args' import type { NexusMetaType } from './nexusMeta' import type { AllNexusInputTypeDefs, AllNexusOutputTypeDefs, NexusWrapKind } from './wrapping' import type { BaseScalars, Maybe } from './_types' export interface CommonFieldConfig { /** The description to annotate the GraphQL SDL */ description?: Maybe<string> /** * Info about a field deprecation. Formatted as a string and provided with the deprecated directive on * field/enum types and as a comment on input fields. */ deprecation?: Maybe<string> // | DeprecationInfo; } export type CommonOutputFieldConfig<TypeName extends string, FieldName extends string> = CommonFieldConfig & { /** * [GraphQL.org Docs](https://graphql.github.io/learn/schema/#arguments) | [GraphQL 2018 * Spec](https://spec.graphql.org/June2018/#sec-Language.Arguments) * * Define arguments for this field. * * All fields in GraphQL can have arguments defined for them. Nexus provides a number of helpers for * defining arguments. All builtin GraphQL scalar types have helpers named "{scalarName}Arg" such as * "stringArg" and "intArg". You can also use type modifier helpers "[list](https://nxs.li/docs/api/list)" * "[nullable](https://nxs.li/docs/api/nullable)" and "[nonNull](https://nxs.li/docs/api/nonNull)". For * details about nonNull/nullable refer to the [nullability guide](https://nxs.li/guides/nullability). * * @example * export const Mutation = mutationType({ * definition(t) { * t.field('createDraft', { * type: 'Post', * args: { * title: nonNull(stringArg()), * body: nonNull(stringArg()), * }, * // ... * }) * }, * }) * * @example * export const Mutation = mutationType({ * definition(t) { * t.field('createDraft', { * type: 'Post', * args: { * title: arg({ * type: 'String', * default: 'Untitled', * description: 'The title of this draft post.', * }), * body: nonNull( * arg({ * type: 'String', * description: 'The content of this draft post.', * }) * ), * }, * // ... * }) * }, * }) */ args?: Maybe<ArgsRecord> /** * Data that will be added to the field-level [extensions field on the graphql-js type def * instances](https://github.com/graphql/graphql-js/issues/1527) resulting from makeSchema. Useful for some * graphql-js based tools like [join-monster](https://github.com/join-monster/join-monster) which rely on * looking for special data here. * * @example * // taken from: https://github.com/graphql-nexus/schema/issues/683#issuecomment-735711640 * * const User = objectType({ * name: 'User', * extensions: { * joinMonster: { * sqlTable: 'USERS', * uniqueKey: 'USER_ID', * }, * }, * definition(t) { * t.id('id', { * extensions: { * joinMonster: { * sqlColumn: 'USER_ID', * }, * }, * }) * }, * }) */ extensions?: GraphQLFieldConfig<any, any>['extensions'] } & NexusGenPluginFieldConfig<TypeName, FieldName> export type CommonInputFieldConfig<TypeName extends string, FieldName extends string> = CommonFieldConfig & { /** The default value for the field, if any */ default?: GetGen3<'inputTypes', TypeName, FieldName> /** * Data that will be added to the field-level [extensions field on the graphql-js type def * instances](https://github.com/graphql/graphql-js/issues/1527) resulting from makeSchema. Useful for some * graphql-js based tools which rely on looking for special data here. */ extensions?: GraphQLInputFieldConfig['extensions'] } & NexusGenPluginFieldConfig<TypeName, FieldName> & NexusGenPluginInputFieldConfig<TypeName, FieldName> export interface OutputScalarConfig<TypeName extends string, FieldName extends string> extends CommonOutputFieldConfig<TypeName, FieldName> { /** * [GraphQL.org Docs](https://graphql.org/learn/execution/#root-fields-resolvers) * * The actual implementation for this field. * * Every field has a resolver and they are the basis for resolving queries at runtime. You do not need to * explicitly implement every resolver however. If the [source typing](https://nxs.li/guides/backing-types) includes: * * 1. A field whose name matches this one 2. And whose type is compatible 3. And is a scalar * * ...then the default resolver will be available, whose behaviour is to simply return that field from the * received source type. * * @example * export const Query = queryType({ * definition(t) { * t.list.field('posts', { * type: 'Post', * resolve(_, __, ctx) { * return ctx.db.post.findMany({ where: { published: true } }) * }, * }) * }, * }) * * @param source The [source data](https://nxs.li/guides/source-types) for the GraphQL object that this * field belongs to, unless this is a root field (any field on a [root operation * type](https://spec.graphql.org/June2018/#sec-Root-Operation-Types): Query, Mutation, Subscription), * in which case there is no source data and this will be undefined. * @param args If you have defined arguments on this field then this parameter will contain any arguments * passed by the client. If you specified default values for any arguments and the client did not * explicitly pass *any* value (including null) for those arguments then you will see the defaults here. * * Note that thanks to [Nexus' reflection system](https://nxs.li/guides/reflection) this parameter's type * will always be type safe. * @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. */ resolve?: FieldResolver<TypeName, FieldName> } // prettier-ignore export interface NexusOutputFieldConfig<TypeName extends string, FieldName extends string> extends OutputScalarConfig<TypeName, FieldName> { /** * [GraphQL 2018 Spec](https://spec.graphql.org/June2018/#sec-Types) * * The type that this field should be. * * Object type fields may be typed as scalars or other output types in your schema, often object types. They * may also use type modifiers like list and non-null types. * * Types may be expressed in one of three ways: * * 1. As string literals matching the name of a builtin scalar. * * 2. As string literals matching the name of another type. Thanks to [Nexus' reflection * system](https://nxs.li/guides/reflection) this is typesafe and autocompletable. This is the idiomatic * approach in Nexus because it avoids excessive importing and circular references. * * 3. As references to other enums or object type definitions. * * You may also use type modifier helpers like list() and nonNull() which in turn accept one of the three * methods listed above. * * Note that both type modifier and scalar helpers are available as chainable shorthands which you can see * in the examples below. * * @example * objectType({ * name: 'User', * definition(t) { * t.field('location', { * // reference the friend type via typegen * type: 'Location', * }) * }, * }) * * @example * objectType({ * name: 'User', * definition(t) { * t.field('location', { * // reference the friend type via type def reference * type: Location, * }) * }, * }) * * @example * objectType({ * name: 'User', * definition(t) { * t.field('friends', { * // create a non-null list of non-null friends * // using typegen type referencing * type: nonNull(list(nonNull('Friend'))), * }) * }, * }) * * @example * objectType({ * name: 'User', * definition(t) { * // create a non-null list of non-null friends * // using chaining API and typegen type referencing * t.nonNull.list.nonNull.field('friends', { * type: 'Friend', * }) * }, * }) * * @example * objectType({ * name: 'User', * definition(t) { * t.field('friends', { * // create a non-null list of non-null friends * // using type def referencing * type: nonNull(list(nonNull(Friend))), * }) * }, * }) * * @example * objectType({ * name: 'User', * definition(t) { * t.field('id', { * // Refer to builtin scalars by string reference * type: 'ID', * }) * }, * }) */ type: GetGen<'allOutputTypes', string> | AllNexusOutputTypeDefs | NexusMetaType } // prettier-ignore export interface NexusOutputFieldConfigWithName<TypeName extends string, FieldName extends string> extends NexusOutputFieldConfig<TypeName, FieldName> { /** * The name of this field. Must conform to the regex pattern: [_A-Za-z][_0-9A-Za-z]* */ name: FieldName } export type NexusOutputFieldDef = NexusOutputFieldConfig<string, any> & { name: string configFor: 'outputField' parentType: string subscribe?: GraphQLFieldResolver<any, any> wrapping?: NexusWrapKind[] } // prettier-ignore export type ScalarOutSpread<TypeName extends string, FieldName extends string> = NeedsResolver<TypeName, FieldName> extends true ? [ScalarOutConfig<TypeName, FieldName>] : HasGen3<'argTypes', TypeName, FieldName> extends true ? [ScalarOutConfig<TypeName, FieldName>] : [ScalarOutConfig<TypeName, FieldName>] | [] // prettier-ignore export type ScalarOutConfig<TypeName extends string, FieldName extends string> = NeedsResolver<TypeName, FieldName> extends true ? OutputScalarConfig<TypeName, FieldName> & { resolve: FieldResolver<TypeName, FieldName> } : OutputScalarConfig<TypeName, FieldName> // prettier-ignore export type FieldOutConfig<TypeName extends string, FieldName extends string> = NeedsResolver<TypeName, FieldName> extends true ? NexusOutputFieldConfig<TypeName, FieldName> & { resolve: FieldResolver<TypeName, FieldName> } : NexusOutputFieldConfig<TypeName, FieldName> // prettier-ignore export type FieldOutConfigWithName<TypeName extends string, FieldName extends string> = NeedsResolver<TypeName, FieldName> extends true ? NexusOutputFieldConfigWithName<TypeName, FieldName> & { resolve: FieldResolver<TypeName, FieldName> } : NexusOutputFieldConfigWithName<TypeName, FieldName> export interface OutputDefinitionBuilder { typeName: string addField(config: NexusOutputFieldDef): void addDynamicOutputMembers(block: OutputDefinitionBlock<any>, wrapping?: NexusWrapKind[]): void warn(msg: string): void } export interface InputDefinitionBuilder { typeName: string addField(config: NexusInputFieldDef): void addDynamicInputFields(block: InputDefinitionBlock<any>, wrapping?: NexusWrapKind[]): void warn(msg: string): void } // prettier-ignore export interface OutputDefinitionBlock<TypeName extends string> extends NexusGenCustomOutputMethods<TypeName>, NexusGenCustomOutputProperties<TypeName> {} /** The output definition block is passed to the "definition" function property of the "objectType" / "interfaceType" */ export class OutputDefinitionBlock<TypeName extends string> { /** The name of the enclosing object type. */ readonly typeName: string constructor(protected typeBuilder: OutputDefinitionBuilder, protected wrapping?: NexusWrapKind[]) { this.typeName = typeBuilder.typeName this.typeBuilder.addDynamicOutputMembers(this, this.wrapping) } /** * [API Docs](https://nxs.li/docs/api/list) | [GraphQL 2018 * Spec](https://spec.graphql.org/June2018/#sec-Type-System.List) * * Chain this property to wrap the right-hand-side type (the field type, another list, nonNull, etc.) with a * List type. * * Chains are read backwards, right to left, like function composition. In other words the thing on the left * wraps the thing on the right. * * This is a shorthand equivalent to: * * `t.field('...', { type: list('...') })` * * @example * objectType({ * name: 'User', * definition(t) { * t.list.nonNull.string('aliases') * }, * }) * * // GraphQL SDL * // ----------- * // * // type User { * // aliases: [String!] * // } */ get list() { return this._wrapClass('List') } /** * [API Docs](https://nxs.li/docs/api/nonNull) | [Nullability * Guide](https://nexusjs.org/docs/guides/nullability) | [GraphQL 2018 * Spec](https://spec.graphql.org/June2018/#sec-Type-System.Non-Null) * * Chain this property to wrap the right-hand-side type (the field type or a list) with a Non-Null type. * * In Nexus output types are nullable by default so this is useful to configure a field differently. Note if * you find yourself using this most of the time then what you probably what is to change the * nonNullDefaults configuration either globally in your makeSchema config or at the type definition level * in one of your type configs to be false for outputs. * * Chains are read backwards, right to left, like function composition. In other words the thing on the left * wraps the thing on the right. * * This is a shorthand equivalent to: * * `t.field('...', { type: nonNull('...') })` * * @example * objectType({ * name: 'User', * definition(t) { * t.nonNull.list.string('aliases') * }, * }) * * // GraphQL SDL * // ----------- * // * // type User { * // aliases: [String]! * // } */ get nonNull(): Omit<OutputDefinitionBlock<TypeName>, 'nonNull' | 'nullable'> { return this._wrapClass('NonNull') } /** * [API Docs](https://nxs.li/docs/api/null) | [Nullability * Guide](https://nexusjs.org/docs/guides/nullability) | [GraphQL 2018 * Spec](https://spec.graphql.org/June2018/#sec-Type-System.Non-Null) * * Chain this property to *unwrap* the right-hand-side type (the field type or a list) of a Non-Null type. * * In Nexus output types are nullable by default so this is only useful when you have changed your * nonNullDefaults configuration either globally in your makeSchema config or at the type definition level * in one of your type configs to be false for outputs. * * Chains are read backwards, right to left, like function composition. In other words the thing on the left * wraps the thing on the right. * * This is a shorthand equivalent to: * * `t.field('...', { type: nullable('...') })` * * @example * objectType({ * name: 'User', * nonNullDefaults: { * outputs: true, * }, * definition(t) { * t.id('id') * t.nullable.string('bio') * }, * }) * * // GraphQL SDL * // ----------- * // * // type User { * // id: ID! * // bio: String * // } */ get nullable(): Omit<OutputDefinitionBlock<TypeName>, 'nonNull' | 'nullable'> { return this._wrapClass('Null') } /** * [GraphQL 2018 spec](https://spec.graphql.org/June2018/#sec-Boolean) * * Define a field whose type is Boolean. * * Boolean types are [scalars](https://spec.graphql.org/June2018/#sec-Scalars) representing true or false. * They are represented in JavaScript using the [boolean primitive * type](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean). * * This is a shorthand equivalent to: * * `t.field('...', { type: boolean() })` * * @example * objectType({ * name: 'User', * definition(t) { * t.boolean('active') * }, * }) * * @param name The name of this field. Must conform to the regex pattern: [_A-Za-z][_0-9A-Za-z]* * @param config The configuration for things like the field's type, its description, its arguments, its * resolver, and more. See jsdoc on each field within for details. * * This parameter is optional if no resolver is required. No resolver is required if the [source * typing](https://nxs.li/guides/backing-types): * * 1. Has a field whose name matches this one 2. And whose type is compatible 3. And is a scalar * * ...in which case the default resolver will be available whose behaviour is to simply return that field * from the received source type. */ boolean<FieldName extends string>(name: FieldName, ...config: ScalarOutSpread<TypeName, FieldName>) { this.addScalarField(name, 'Boolean', config) } /** * [GraphQL 2018 spec](https://spec.graphql.org/June2018/#sec-String) * * Define a field whose type is String. * * String types are [scalars](https://spec.graphql.org/June2018/#sec-Scalars) representing UTF-8 (aka. * unicode) character sequences. It is most often used to represent free-form human-readable text. They are * represented in JavaScript using the [string primitive * type](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String). * * This is a shorthand, equivalent to: * * `t.field('...', { type: string() })` * * @example * objectType({ * name: 'User', * definition(t) { * t.string('bio') * }, * }) * * @param name The name of this field. Must conform to the regex pattern: [_A-Za-z][_0-9A-Za-z]* * @param config The configuration for things like the field's type, its description, its arguments, its * resolver, and more. See jsdoc on each field within for details. * * This parameter is optional if no resolver is required. No resolver is required if the [source * typing](https://nxs.li/guides/backing-types): * * 1. Has a field whose name matches this one 2. And whose type is compatible 3. And is a scalar * * ...in which case the default resolver will be available whose behaviour is to simply return that field * from the received source type. */ string<FieldName extends string>(name: FieldName, ...config: ScalarOutSpread<TypeName, FieldName>) { this.addScalarField(name, 'String', config) } /** * [GraphQL 2018 spec](https://spec.graphql.org/June2018/#sec-ID) * * Define a field whose type is ID. * * ID types are [scalars](https://spec.graphql.org/June2018/#sec-Scalars) representing unique identifiers * often used to refetch an object or as the key for a cache. It is serialized in the same way as the * [String](https://spec.graphql.org/June2018/#sec-String) type but unlike String not intended to be * human-readable. They are represented in JavaScript using the [string primitive * type](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String). * * This is a shorthand, equivalent to: * * `t.field('...', { type: id() })` * * @example * objectType({ * name: 'User', * definition(t) { * t.id('id') * }, * }) * * @param name The name of this field. Must conform to the regex pattern: [_A-Za-z][_0-9A-Za-z]* * @param config The configuration for things like the field's type, its description, its arguments, its * resolver, and more. See jsdoc on each field within for details. * * This parameter is optional if no resolver is required. No resolver is required if the [source * typing](https://nxs.li/guides/backing-types): * * 1. Has a field whose name matches this one 2. And whose type is compatible 3. And is a scalar * * ...in which case the default resolver will be available whose behaviour is to simply return that field * from the received source type. */ id<FieldName extends string>(name: FieldName, ...config: ScalarOutSpread<TypeName, FieldName>) { this.addScalarField(name, 'ID', config) } /** * [GraphQL 2018 spec](https://spec.graphql.org/June2018/#sec-Int) * * Define a field whose type is Int. * * Int types are [scalars](https://spec.graphql.org/June2018/#sec-Scalars) representing a signed 32-bit * numeric non-fractional value. They are represented in JavaScript using the [number primitive * type](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number). * * This is a shorthand equivalent to: * * `t.field('...', { type: int() })` * * @example * objectType({ * name: 'User', * definition(t) { * t.int('age') * }, * }) * * @param name The name of this field. Must conform to the regex pattern: [_A-Za-z][_0-9A-Za-z]* * @param config The configuration for things like the field's type, its description, its arguments, its * resolver, and more. See jsdoc on each field within for details. * * This parameter is optional if no resolver is required. No resolver is required if the [source * typing](https://nxs.li/guides/backing-types): * * 1. Has a field whose name matches this one 2. And whose type is compatible 3. And is a scalar * * ...in which case the default resolver will be available whose behaviour is to simply return that field * from the received source type. */ int<FieldName extends string>(name: FieldName, ...config: ScalarOutSpread<TypeName, FieldName>) { this.addScalarField(name, 'Int', config) } /** * [GraphQL 2018 spec](https://spec.graphql.org/June2018/#sec-Float) * * Define a field whose type is Float. * * Float types are [scalars](https://spec.graphql.org/June2018/#sec-Scalars) representing signed * double‐precision fractional values as specified by IEEE 754. They are represented in JavaScript using * the [number primitive * type](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number). * * This is a shorthand, equivalent to: * * `t.field('...', { type: float() })` * * @example * objectType({ * name: 'User', * definition(t) { * t.float('height') * }, * }) * * @param name The name of this field. Must conform to the regex pattern: [_A-Za-z][_0-9A-Za-z]* * @param config The configuration for things like the field's type, its description, its arguments, its * resolver, and more. See jsdoc on each field within for details. * * This parameter is optional if no resolver is required. No resolver is required if the [source * typing](https://nxs.li/guides/backing-types): * * 1. Has a field whose name matches this one 2. And whose type is compatible 3. And is a scalar * * ...in which case the default resolver will be available whose behaviour is to simply return that field * from the received source type. */ float<FieldName extends string>(name: FieldName, ...config: ScalarOutSpread<TypeName, FieldName>) { this.addScalarField(name, 'Float', config) } /** * [GraphQL 2018 Spec](https://spec.graphql.org/June2018/#sec-Language.Fields) * * Define a field on this object. * * A field describes one discrete piece of information available to request within a [selection * set](https://spec.graphql.org/June2018/#sec-Selection-Sets). They are in fact most of what any selection * set will contain. Fields can be typed as scalars (marking the terminal point of a branch of a selection * set) or as other object types in your schema thus allowing you to model relationships between things. * * @example * objectType({ * name: 'User', * definition(t) { * t.field('id', { * type: id(), * description: 'The unique identification number for this user', * }) * }, * }) * * @param name The name of this field. Must conform to the regex pattern: [_A-Za-z][_0-9A-Za-z]* * @param config The configuration for things like the field's type, its description, its arguments, its * resolver, and more. See jsdoc on each field within for details. */ field<FieldName extends string>(name: FieldName, config: FieldOutConfig<TypeName, FieldName>): void /** * [GraphQL 2018 Spec](https://spec.graphql.org/June2018/#sec-Language.Fields) * * Define a field on this object. * * A field describes one discrete piece of information available to request within a [selection * set](https://spec.graphql.org/June2018/#sec-Selection-Sets). They are in fact most of what any selection * set will contain. Fields can be typed as scalars (marking the terminal point of a branch of a selection * set) or as other object types in your schema thus allowing you to model relationships between things. * * @example * objectType({ * name: 'User', * definition(t) { * t.field({ * name: 'id', * type: id(), * description: 'The unique identification number for this user', * }) * }, * }) * * @param config The configuration for things like the field's type, its description, its arguments, its * resolver, and more. See jsdoc on each field within for details. */ field<FieldName extends string>(config: FieldOutConfigWithName<TypeName, FieldName>): void field<FieldName extends string>( ...args: | [name: FieldName, config: FieldOutConfig<TypeName, FieldName>] | [config: FieldOutConfigWithName<TypeName, FieldName>] ): void { const config = args.length === 2 ? { name: args[0], ...args[1] } : args[0] this.typeBuilder.addField({ ...config, configFor: 'outputField', wrapping: this.wrapping, parentType: this.typeName, } as any) } private _wrapClass(kind: NexusWrapKind): OutputDefinitionBlock<TypeName> { const previousWrapping = this.wrapping?.[0] if ( (kind === 'NonNull' || kind === 'Null') && (previousWrapping === 'NonNull' || previousWrapping === 'Null') ) { return new OutputDefinitionBlock(this.typeBuilder, this.wrapping || []) } return new OutputDefinitionBlock(this.typeBuilder, [kind].concat(this.wrapping || [])) } private addScalarField<FieldName extends string>( fieldName: FieldName, typeName: BaseScalars, opts: [] | ScalarOutSpread<TypeName, any> ) { let fieldConfig: FieldOutConfig<any, any> = { type: typeName, } /* istanbul ignore if */ if (typeof opts[0] === 'function') { throw new Error(messages.removedFunctionShorthand(typeName, fieldName)) } else { fieldConfig = { ...fieldConfig, ...opts[0] } } this.field(fieldName, fieldConfig as any) } } /** TODO move the code below to definitionBlocks/input.ts Input */ // prettier-ignore export interface NexusInputFieldConfig<TypeName extends string, FieldName extends string> extends CommonInputFieldConfig<TypeName, FieldName> { type: AllInputTypes | AllNexusInputTypeDefs } // prettier-ignore export interface NexusInputFieldConfigWithName<TypeName extends string, FieldName extends string> extends NexusInputFieldConfig<TypeName, FieldName> { /** * The name of this field. Must conform to the regex pattern: [_A-Za-z][_0-9A-Za-z]* */ name: FieldName } export type NexusInputFieldDef = NexusInputFieldConfig<string, string> & { configFor: 'inputField' name: string wrapping?: NexusWrapKind[] parentType: string } export interface InputDefinitionBlock<TypeName extends string> extends NexusGenCustomInputMethods<TypeName> {} export class InputDefinitionBlock<TypeName extends string> { readonly typeName: string constructor(protected typeBuilder: InputDefinitionBuilder, protected wrapping?: NexusWrapKind[]) { this.typeName = typeBuilder.typeName this.typeBuilder.addDynamicInputFields(this, this.wrapping) } get list() { return this._wrapClass('List') } get nonNull(): Omit<InputDefinitionBlock<TypeName>, 'nonNull' | 'nullable'> { return this._wrapClass('NonNull') } get nullable(): Omit<InputDefinitionBlock<TypeName>, 'nonNull' | 'nullable'> { return this._wrapClass('Null') } string<FieldName extends string>( fieldName: FieldName, config?: CommonInputFieldConfig<TypeName, FieldName> ) { this.field(fieldName, { ...config, type: 'String' }) } int<FieldName extends string>(fieldName: FieldName, config?: CommonInputFieldConfig<TypeName, FieldName>) { this.field(fieldName, { ...config, type: 'Int' }) } boolean<FieldName extends string>( fieldName: FieldName, opts?: CommonInputFieldConfig<TypeName, FieldName> ) { this.field(fieldName, { ...opts, type: 'Boolean' }) } id<FieldName extends string>(fieldName: FieldName, config?: CommonInputFieldConfig<TypeName, FieldName>) { this.field(fieldName, { ...config, type: 'ID' }) } float<FieldName extends string>( fieldName: FieldName, config?: CommonInputFieldConfig<TypeName, FieldName> ) { this.field(fieldName, { ...config, type: 'Float' }) } field<FieldName extends string>(config: NexusInputFieldConfigWithName<TypeName, FieldName>): void field<FieldName extends string>(name: FieldName, config: NexusInputFieldConfig<TypeName, FieldName>): void field<FieldName extends string>( ...args: | [FieldName, NexusInputFieldConfig<TypeName, FieldName>] | [NexusInputFieldConfigWithName<TypeName, FieldName>] ): void { const config = args.length === 2 ? { name: args[0], ...args[1] } : args[0] this.typeBuilder.addField({ ...config, wrapping: this.wrapping, parentType: this.typeName, configFor: 'inputField', }) } private _wrapClass(kind: NexusWrapKind) { const previousWrapping = this.wrapping?.[0] if ( (kind === 'NonNull' || kind === 'Null') && (previousWrapping === 'NonNull' || previousWrapping === 'Null') ) { return new InputDefinitionBlock(this.typeBuilder, this.wrapping || []) } return new InputDefinitionBlock(this.typeBuilder, [kind].concat(this.wrapping || [])) } }