From 42bf6190ae9b2bf975206d3d8ebedb17c37736f0 Mon Sep 17 00:00:00 2001 From: Tim Griesser Date: Wed, 22 Feb 2023 13:39:02 -0500 Subject: [PATCH] feat: allow unionType types to be a thunk --- .changeset/great-suits-provide.md | 6 ++++ packages/core/src/builder.ts | 11 +++--- packages/core/src/config-store.ts | 34 +++++++++++++++++++ .../core/src/types/global/type-options.ts | 2 +- .../core/tests/examples/giraffes/unions.ts | 2 +- packages/deno/packages/core/build-cache.ts | 5 ++- packages/deno/packages/core/builder.ts | 10 +++--- packages/deno/packages/core/types/configs.ts | 2 +- .../core/types/global/type-options.ts | 2 +- .../deno/packages/plugin-tracing/README.md | 8 +---- website/pages/docs/api/schema-builder.mdx | 2 +- 11 files changed, 63 insertions(+), 21 deletions(-) create mode 100644 .changeset/great-suits-provide.md diff --git a/.changeset/great-suits-provide.md b/.changeset/great-suits-provide.md new file mode 100644 index 000000000..cb1b347b7 --- /dev/null +++ b/.changeset/great-suits-provide.md @@ -0,0 +1,6 @@ +--- +'@pothos/core': minor +'@pothos/deno': minor +--- + +Allow unionType to receive types as a thunk diff --git a/packages/core/src/builder.ts b/packages/core/src/builder.ts index 8ebe7bfae..46ea21d27 100644 --- a/packages/core/src/builder.ts +++ b/packages/core/src/builder.ts @@ -423,15 +423,17 @@ export default class SchemaBuilder { ParentShape >(name); - options.types.forEach((type) => { - verifyRef(type); - }); + if (Array.isArray(options.types)) { + options.types.forEach((type) => { + verifyRef(type); + }); + } const config: PothosUnionTypeConfig = { kind: 'Union', graphqlKind: 'Union', name, - types: (options.types || []) as ObjectParam[], + types: [], description: options.description, resolveType: options.resolveType as GraphQLTypeResolver, pothosOptions: options as unknown as PothosSchemaTypes.UnionTypeOptions, @@ -439,6 +441,7 @@ export default class SchemaBuilder { }; this.configStore.addTypeConfig(config, ref); + this.configStore.addUnionTypes(name, options.types); return ref; } diff --git a/packages/core/src/config-store.ts b/packages/core/src/config-store.ts index ef7bb0a66..6e2210812 100644 --- a/packages/core/src/config-store.ts +++ b/packages/core/src/config-store.ts @@ -26,6 +26,7 @@ import type { InputType, InputTypeParam, InterfaceParam, + ObjectParam, OutputRef, OutputType, PothosFieldConfig, @@ -62,6 +63,8 @@ export default class ConfigStore { private pendingInterfaces = new Map InterfaceParam[])[]>(); + private pendingUnionTypes = new Map ObjectParam[])[]>(); + private pendingRefResolutions = new Map< ConfigurableRef, ((config: PothosTypeConfig) => void)[] @@ -98,6 +101,31 @@ export default class ConfigStore { return this.refsToName.has(typeParam); } + addUnionTypes(typeName: string, unionTypes: ObjectParam[] | (() => ObjectParam[])) { + if (typeof unionTypes === 'function' && this.pending) { + if (this.pendingUnionTypes.has(typeName)) { + this.pendingUnionTypes.get(typeName)!.push(unionTypes); + } else { + this.pendingUnionTypes.set(typeName, [unionTypes]); + } + } else { + const typeConfig = this.getTypeConfig(typeName); + + if (typeConfig.graphqlKind !== 'Union') { + throw new PothosSchemaError( + `Can not add types to ${typeName} because it is a ${typeConfig.kind}`, + ); + } + + typeConfig.types = [ + ...typeConfig.types, + ...((typeof unionTypes === 'function' + ? unionTypes() + : unionTypes) as ObjectParam[]), + ]; + } + } + addInterfaces( typeName: string, interfaces: InterfaceParam[] | (() => InterfaceParam[]), @@ -428,6 +456,12 @@ export default class ConfigStore { ); } + for (const [typeName, unionFns] of this.pendingUnionTypes) { + for (const fn of unionFns) { + this.addUnionTypes(typeName, fn); + } + } + for (const [typeName, interfacesFns] of this.pendingInterfaces) { for (const fn of interfacesFns) { this.addInterfaces(typeName, fn); diff --git a/packages/core/src/types/global/type-options.ts b/packages/core/src/types/global/type-options.ts index bb6818ed9..4d3342caa 100644 --- a/packages/core/src/types/global/type-options.ts +++ b/packages/core/src/types/global/type-options.ts @@ -98,7 +98,7 @@ declare global { Member extends ObjectParam = ObjectParam, ResolveType = unknown, > extends BaseTypeOptions { - types: Member[]; + types: Member[] | (() => Member[]); resolveType?: ResolveType & (( parent: ParentShape, diff --git a/packages/core/tests/examples/giraffes/unions.ts b/packages/core/tests/examples/giraffes/unions.ts index e42b191f1..774acdfb9 100644 --- a/packages/core/tests/examples/giraffes/unions.ts +++ b/packages/core/tests/examples/giraffes/unions.ts @@ -14,7 +14,7 @@ const GiraffeNumericFact = builder.objectType('GiraffeNumericFact', { }); const GiraffeFact = builder.unionType('GiraffeFact', { - types: ['GiraffeStringFact', GiraffeNumericFact], + types: () => ['GiraffeStringFact', GiraffeNumericFact], resolveType: (fact) => { switch (fact.factKind) { case 'number': diff --git a/packages/deno/packages/core/build-cache.ts b/packages/deno/packages/core/build-cache.ts index 027a048ef..cecf5c36e 100644 --- a/packages/deno/packages/core/build-cache.ts +++ b/packages/deno/packages/core/build-cache.ts @@ -443,7 +443,10 @@ export default class BuildCache { pothosOptions: config.pothosOptions, pothosConfig: config, }, - types: () => config.types.map((member) => this.getTypeOfKind(member, "Object")), + types: () => { + const types = typeof config.types === "function" ? config.types() : config.types; + return types.map((member) => this.getTypeOfKind(member, "Object")); + }, resolveType: this.plugin.wrapResolveType(resolveType, config), }); } diff --git a/packages/deno/packages/core/builder.ts b/packages/deno/packages/core/builder.ts index ead29f850..5ad649a1a 100644 --- a/packages/deno/packages/core/builder.ts +++ b/packages/deno/packages/core/builder.ts @@ -248,14 +248,16 @@ export default class SchemaBuilder { } unionType, ResolveType>(name: string, options: PothosSchemaTypes.UnionTypeOptions) { const ref = new UnionRef, ParentShape>(name); - options.types.forEach((type) => { - verifyRef(type); - }); + if (Array.isArray(options.types)) { + options.types.forEach((type) => { + verifyRef(type); + }); + } const config: PothosUnionTypeConfig = { kind: "Union", graphqlKind: "Union", name, - types: (options.types || []) as ObjectParam[], + types: (options.types || []) as ObjectParam[] | (() => ObjectParam[]), description: options.description, resolveType: options.resolveType as GraphQLTypeResolver, pothosOptions: options as unknown as PothosSchemaTypes.UnionTypeOptions, diff --git a/packages/deno/packages/core/types/configs.ts b/packages/deno/packages/core/types/configs.ts index 9137542ac..dae38f815 100644 --- a/packages/deno/packages/core/types/configs.ts +++ b/packages/deno/packages/core/types/configs.ts @@ -34,7 +34,7 @@ export interface PothosInterfaceTypeConfig extends Omit, "types"> { kind: "Union"; graphqlKind: "Union"; - types: ObjectParam[]; + types: ObjectParam[] | (() => ObjectParam[]); pothosOptions: PothosSchemaTypes.UnionTypeOptions; } export interface PothosEnumTypeConfig extends GraphQLEnumTypeConfig { diff --git a/packages/deno/packages/core/types/global/type-options.ts b/packages/deno/packages/core/types/global/type-options.ts index c796aac2b..fc4f1c10f 100644 --- a/packages/deno/packages/core/types/global/type-options.ts +++ b/packages/deno/packages/core/types/global/type-options.ts @@ -42,7 +42,7 @@ declare global { resolveType?: ResolveType & ((parent: Shape, context: Types["Context"], info: GraphQLResolveInfo, type: GraphQLUnionType) => MaybePromise | string | null | undefined>); } export interface UnionTypeOptions = ObjectParam, ResolveType = unknown> extends BaseTypeOptions { - types: Member[]; + types: Member[] | (() => Member[]); resolveType?: ResolveType & ((parent: ParentShape, context: Types["Context"], info: GraphQLResolveInfo, type: GraphQLUnionType) => MaybePromise); } export interface ScalarTypeOptions extends BaseTypeOptions { diff --git a/packages/deno/packages/plugin-tracing/README.md b/packages/deno/packages/plugin-tracing/README.md index a6ac1c782..486be3320 100644 --- a/packages/deno/packages/plugin-tracing/README.md +++ b/packages/deno/packages/plugin-tracing/README.md @@ -767,13 +767,7 @@ import { schema } from './schema'; const yoga = createYoga({ schema, - plugins: [ - useSentry({ - // Disable resolver tracking since this is covered by the pothos tracing plugin - // If all resolvers are being traced, you could use the Sentry envelop plug instead of the pothos tracing plugin - trackResolvers: false, - }), - ], + plugins: [useSentry({})], }); const server = createServer(yoga); diff --git a/website/pages/docs/api/schema-builder.mdx b/website/pages/docs/api/schema-builder.mdx index 07c3796cc..7724c1c5b 100644 --- a/website/pages/docs/api/schema-builder.mdx +++ b/website/pages/docs/api/schema-builder.mdx @@ -295,7 +295,7 @@ all types in SchemaTypes, or import the actual implementation of each interface ```typescript type UnionTypeOptions = { description?: string; - types: Member[]; + types: Member[] | (() => Member[]); resolveType: (parent: UnionShape, context) => MaybePromise; }; ```