From 42bf6190ae9b2bf975206d3d8ebedb17c37736f0 Mon Sep 17 00:00:00 2001 From: Tim Griesser Date: Wed, 22 Feb 2023 13:39:02 -0500 Subject: [PATCH 01/13] 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; }; ``` From eea54c39495c1787378f5991c08a2dbfc061c115 Mon Sep 17 00:00:00 2001 From: Tim Griesser Date: Wed, 22 Feb 2023 13:42:54 -0500 Subject: [PATCH 02/13] update deno build --- packages/deno/packages/core/build-cache.ts | 5 +--- packages/deno/packages/core/builder.ts | 3 +- packages/deno/packages/core/config-store.ts | 30 +++++++++++++++++++- packages/deno/packages/core/types/configs.ts | 2 +- 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/packages/deno/packages/core/build-cache.ts b/packages/deno/packages/core/build-cache.ts index cecf5c36e..027a048ef 100644 --- a/packages/deno/packages/core/build-cache.ts +++ b/packages/deno/packages/core/build-cache.ts @@ -443,10 +443,7 @@ export default class BuildCache { pothosOptions: config.pothosOptions, pothosConfig: config, }, - types: () => { - const types = typeof config.types === "function" ? config.types() : config.types; - return types.map((member) => this.getTypeOfKind(member, "Object")); - }, + types: () => config.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 5ad649a1a..ad6dadef7 100644 --- a/packages/deno/packages/core/builder.ts +++ b/packages/deno/packages/core/builder.ts @@ -257,13 +257,14 @@ export default class SchemaBuilder { kind: "Union", graphqlKind: "Union", name, - types: (options.types || []) as ObjectParam[] | (() => ObjectParam[]), + types: [], description: options.description, resolveType: options.resolveType as GraphQLTypeResolver, pothosOptions: options as unknown as PothosSchemaTypes.UnionTypeOptions, extensions: options.extensions, }; this.configStore.addTypeConfig(config, ref); + this.configStore.addUnionTypes(name, options.types); return ref; } enumType>(param: Param, options: EnumTypeOptions) { diff --git a/packages/deno/packages/core/config-store.ts b/packages/deno/packages/core/config-store.ts index 29bb80f3a..452c6a3a4 100644 --- a/packages/deno/packages/core/config-store.ts +++ b/packages/deno/packages/core/config-store.ts @@ -11,7 +11,7 @@ import InputFieldRef from './refs/input-field.ts'; import InputListRef from './refs/input-list.ts'; import ListRef from './refs/list.ts'; import OutputTypeRef from './refs/output.ts'; -import type { ConfigurableRef, FieldMap, GraphQLFieldKind, InputFieldMap, InputRef, InputType, InputTypeParam, InterfaceParam, OutputRef, OutputType, PothosFieldConfig, PothosObjectTypeConfig, PothosTypeConfig, SchemaTypes, TypeParam, } from './types/index.ts'; +import type { ConfigurableRef, FieldMap, GraphQLFieldKind, InputFieldMap, InputRef, InputType, InputTypeParam, InterfaceParam, ObjectParam, OutputRef, OutputType, PothosFieldConfig, PothosObjectTypeConfig, PothosTypeConfig, SchemaTypes, TypeParam, } from './types/index.ts'; import { unwrapListParam } from './utils/index.ts'; export default class ConfigStore { typeConfigs = new Map(); @@ -23,6 +23,7 @@ export default class ConfigStore { private fieldRefsToConfigs = new Map[]>(); private pendingFields = new Map | OutputType>(); private pendingInterfaces = new Map InterfaceParam[])[]>(); + private pendingUnionTypes = new Map ObjectParam[])[]>(); private pendingRefResolutions = new Map, ((config: PothosTypeConfig) => void)[]>(); private fieldRefCallbacks = new Map) => void)[]>(); private pending = true; @@ -46,6 +47,28 @@ 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[])) { if (typeof interfaces === "function" && this.pending) { if (this.pendingInterfaces.has(typeName)) { @@ -280,6 +303,11 @@ export default class ConfigStore { .map((ref) => this.describeRef(ref)) .join(", ")}).`); } + 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/deno/packages/core/types/configs.ts b/packages/deno/packages/core/types/configs.ts index dae38f815..9137542ac 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[] | (() => ObjectParam[]); + types: ObjectParam[]; pothosOptions: PothosSchemaTypes.UnionTypeOptions; } export interface PothosEnumTypeConfig extends GraphQLEnumTypeConfig { From 400e496452ebd247ab957c3835f5b3a5266d2851 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 22 Feb 2023 19:03:01 +0000 Subject: [PATCH 03/13] chore: update versions --- .changeset/great-suits-provide.md | 6 ------ examples/envelope-helix-fastify/CHANGELOG.md | 7 +++++++ examples/envelope-helix-fastify/package.json | 2 +- examples/graphql-shield/CHANGELOG.md | 7 +++++++ examples/graphql-shield/package.json | 2 +- examples/helix/CHANGELOG.md | 7 +++++++ examples/helix/package.json | 2 +- examples/nextjs/CHANGELOG.md | 7 +++++++ examples/nextjs/package.json | 2 +- examples/open-telemetry/CHANGELOG.md | 9 +++++++++ examples/open-telemetry/package.json | 2 +- examples/prisma-federation/CHANGELOG.md | 10 ++++++++++ examples/prisma-federation/package.json | 2 +- .../prisma-smart-subscriptions-apollo/CHANGELOG.md | 9 +++++++++ .../prisma-smart-subscriptions-apollo/package.json | 2 +- examples/prisma-subscriptions/CHANGELOG.md | 8 ++++++++ examples/prisma-subscriptions/package.json | 2 +- examples/prisma/CHANGELOG.md | 8 ++++++++ examples/prisma/package.json | 2 +- examples/relay-windowed-pagination/CHANGELOG.md | 8 ++++++++ examples/relay-windowed-pagination/package.json | 2 +- examples/simple-classes/CHANGELOG.md | 7 +++++++ examples/simple-classes/package.json | 2 +- examples/simple-interfaces/CHANGELOG.md | 7 +++++++ examples/simple-interfaces/package.json | 2 +- packages/core/CHANGELOG.md | 6 ++++++ packages/core/package.json | 2 +- packages/deno/CHANGELOG.md | 6 ++++++ packages/deno/package.json | 2 +- website/CHANGELOG.md | 7 +++++++ 30 files changed, 127 insertions(+), 20 deletions(-) delete mode 100644 .changeset/great-suits-provide.md diff --git a/.changeset/great-suits-provide.md b/.changeset/great-suits-provide.md deleted file mode 100644 index cb1b347b7..000000000 --- a/.changeset/great-suits-provide.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@pothos/core': minor -'@pothos/deno': minor ---- - -Allow unionType to receive types as a thunk diff --git a/examples/envelope-helix-fastify/CHANGELOG.md b/examples/envelope-helix-fastify/CHANGELOG.md index 70d4f9cd7..0aa2368c9 100644 --- a/examples/envelope-helix-fastify/CHANGELOG.md +++ b/examples/envelope-helix-fastify/CHANGELOG.md @@ -1,5 +1,12 @@ # @pothos-examples/envelope-helix-fastify +## 2.4.20 + +### Patch Changes + +- Updated dependencies [42bf6190] + - @pothos/core@3.27.0 + ## 2.4.19 ### Patch Changes diff --git a/examples/envelope-helix-fastify/package.json b/examples/envelope-helix-fastify/package.json index cc3c7ce7a..fc28876b0 100644 --- a/examples/envelope-helix-fastify/package.json +++ b/examples/envelope-helix-fastify/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "2.4.19", + "version": "2.4.20", "name": "@pothos-examples/envelope-helix-fastify", "main": "src/index.ts", "types": "src/index.ts", diff --git a/examples/graphql-shield/CHANGELOG.md b/examples/graphql-shield/CHANGELOG.md index c037daf4d..c686aef98 100644 --- a/examples/graphql-shield/CHANGELOG.md +++ b/examples/graphql-shield/CHANGELOG.md @@ -1,5 +1,12 @@ # @pothos-examples/graphql-shield +## 2.2.20 + +### Patch Changes + +- Updated dependencies [42bf6190] + - @pothos/core@3.27.0 + ## 2.2.19 ### Patch Changes diff --git a/examples/graphql-shield/package.json b/examples/graphql-shield/package.json index b82da67b9..959265210 100644 --- a/examples/graphql-shield/package.json +++ b/examples/graphql-shield/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "2.2.19", + "version": "2.2.20", "name": "@pothos-examples/graphql-shield", "main": "src/index.ts", "types": "src/index.ts", diff --git a/examples/helix/CHANGELOG.md b/examples/helix/CHANGELOG.md index 0445a4f8e..7f5ba47c7 100644 --- a/examples/helix/CHANGELOG.md +++ b/examples/helix/CHANGELOG.md @@ -1,5 +1,12 @@ # @pothos-examples/helix +## 2.4.20 + +### Patch Changes + +- Updated dependencies [42bf6190] + - @pothos/core@3.27.0 + ## 2.4.19 ### Patch Changes diff --git a/examples/helix/package.json b/examples/helix/package.json index 31fb5f77a..232aa459b 100644 --- a/examples/helix/package.json +++ b/examples/helix/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "2.4.19", + "version": "2.4.20", "name": "@pothos-examples/helix", "main": "src/index.ts", "types": "src/index.ts", diff --git a/examples/nextjs/CHANGELOG.md b/examples/nextjs/CHANGELOG.md index 5ad10fd6d..3c86a9052 100644 --- a/examples/nextjs/CHANGELOG.md +++ b/examples/nextjs/CHANGELOG.md @@ -1,5 +1,12 @@ # @pothos-examples/nextjs +## 2.6.3 + +### Patch Changes + +- Updated dependencies [42bf6190] + - @pothos/core@3.27.0 + ## 2.6.2 ### Patch Changes diff --git a/examples/nextjs/package.json b/examples/nextjs/package.json index 33511e36a..ff9fdba42 100644 --- a/examples/nextjs/package.json +++ b/examples/nextjs/package.json @@ -1,6 +1,6 @@ { "name": "@pothos-examples/nextjs", - "version": "2.6.2", + "version": "2.6.3", "private": true, "scripts": { "generate": "graphql-codegen", diff --git a/examples/open-telemetry/CHANGELOG.md b/examples/open-telemetry/CHANGELOG.md index c99860f3d..5a58ac021 100644 --- a/examples/open-telemetry/CHANGELOG.md +++ b/examples/open-telemetry/CHANGELOG.md @@ -1,5 +1,14 @@ # @pothos-examples/open-telemetry +## 1.2.20 + +### Patch Changes + +- Updated dependencies [42bf6190] + - @pothos/core@3.27.0 + - @pothos/plugin-tracing@0.5.7 + - @pothos/tracing-opentelemetry@0.6.8 + ## 1.2.19 ### Patch Changes diff --git a/examples/open-telemetry/package.json b/examples/open-telemetry/package.json index fd0bed17b..cccf0bc76 100644 --- a/examples/open-telemetry/package.json +++ b/examples/open-telemetry/package.json @@ -1,6 +1,6 @@ { "name": "@pothos-examples/open-telemetry", - "version": "1.2.19", + "version": "1.2.20", "main": "index.js", "license": "MIT", "dependencies": { diff --git a/examples/prisma-federation/CHANGELOG.md b/examples/prisma-federation/CHANGELOG.md index 08a6f1c32..875f055d2 100644 --- a/examples/prisma-federation/CHANGELOG.md +++ b/examples/prisma-federation/CHANGELOG.md @@ -1,5 +1,15 @@ # @pothos-examples/relay +## 2.7.4 + +### Patch Changes + +- Updated dependencies [42bf6190] + - @pothos/core@3.27.0 + - @pothos/plugin-directives@3.9.2 + - @pothos/plugin-federation@3.9.1 + - @pothos/plugin-prisma@3.41.0 + ## 2.7.3 ### Patch Changes diff --git a/examples/prisma-federation/package.json b/examples/prisma-federation/package.json index dea97a8eb..0454fe78c 100644 --- a/examples/prisma-federation/package.json +++ b/examples/prisma-federation/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "2.7.3", + "version": "2.7.4", "name": "@pothos-examples/prisma-federation", "main": "src/index.ts", "types": "src/index.ts", diff --git a/examples/prisma-smart-subscriptions-apollo/CHANGELOG.md b/examples/prisma-smart-subscriptions-apollo/CHANGELOG.md index 4299b1fcd..20cda5570 100644 --- a/examples/prisma-smart-subscriptions-apollo/CHANGELOG.md +++ b/examples/prisma-smart-subscriptions-apollo/CHANGELOG.md @@ -1,5 +1,14 @@ # @pothos-examples/prisma-smart-subscriptions-apollo +## 2.5.3 + +### Patch Changes + +- Updated dependencies [42bf6190] + - @pothos/core@3.27.0 + - @pothos/plugin-prisma@3.41.0 + - @pothos/plugin-smart-subscriptions@3.7.0 + ## 2.5.2 ### Patch Changes diff --git a/examples/prisma-smart-subscriptions-apollo/package.json b/examples/prisma-smart-subscriptions-apollo/package.json index 821c2acb6..119e18e7b 100644 --- a/examples/prisma-smart-subscriptions-apollo/package.json +++ b/examples/prisma-smart-subscriptions-apollo/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "2.5.2", + "version": "2.5.3", "name": "@pothos-examples/prisma-smart-subscriptions-apollo", "main": "src/index.ts", "types": "src/index.ts", diff --git a/examples/prisma-subscriptions/CHANGELOG.md b/examples/prisma-subscriptions/CHANGELOG.md index 3b0209e07..977631aa1 100644 --- a/examples/prisma-subscriptions/CHANGELOG.md +++ b/examples/prisma-subscriptions/CHANGELOG.md @@ -1,5 +1,13 @@ # @pothos-examples/prisma-subscriptions +## 2.4.25 + +### Patch Changes + +- Updated dependencies [42bf6190] + - @pothos/core@3.27.0 + - @pothos/plugin-prisma@3.41.0 + ## 2.4.24 ### Patch Changes diff --git a/examples/prisma-subscriptions/package.json b/examples/prisma-subscriptions/package.json index be371ac75..248d38c7b 100644 --- a/examples/prisma-subscriptions/package.json +++ b/examples/prisma-subscriptions/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "2.4.24", + "version": "2.4.25", "name": "@pothos-examples/prisma-subscriptions", "main": "src/index.ts", "types": "src/index.ts", diff --git a/examples/prisma/CHANGELOG.md b/examples/prisma/CHANGELOG.md index d0732aaae..29d3973d1 100644 --- a/examples/prisma/CHANGELOG.md +++ b/examples/prisma/CHANGELOG.md @@ -1,5 +1,13 @@ # @pothos-examples/relay +## 2.4.25 + +### Patch Changes + +- Updated dependencies [42bf6190] + - @pothos/core@3.27.0 + - @pothos/plugin-prisma@3.41.0 + ## 2.4.24 ### Patch Changes diff --git a/examples/prisma/package.json b/examples/prisma/package.json index 2ccd46d28..975a72743 100644 --- a/examples/prisma/package.json +++ b/examples/prisma/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "2.4.24", + "version": "2.4.25", "name": "@pothos-examples/prisma", "main": "src/index.ts", "types": "src/index.ts", diff --git a/examples/relay-windowed-pagination/CHANGELOG.md b/examples/relay-windowed-pagination/CHANGELOG.md index 9a38659d2..0500cf750 100644 --- a/examples/relay-windowed-pagination/CHANGELOG.md +++ b/examples/relay-windowed-pagination/CHANGELOG.md @@ -1,5 +1,13 @@ # @pothos-examples/prisma-relay +## 2.7.25 + +### Patch Changes + +- Updated dependencies [42bf6190] + - @pothos/core@3.27.0 + - @pothos/plugin-relay@3.35.0 + ## 2.7.24 ### Patch Changes diff --git a/examples/relay-windowed-pagination/package.json b/examples/relay-windowed-pagination/package.json index 2664722c6..7c989dc30 100644 --- a/examples/relay-windowed-pagination/package.json +++ b/examples/relay-windowed-pagination/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "2.7.24", + "version": "2.7.25", "name": "@pothos-examples/relay-windowed-pagination", "main": "src/index.ts", "types": "src/index.ts", diff --git a/examples/simple-classes/CHANGELOG.md b/examples/simple-classes/CHANGELOG.md index 75302e8ca..195ae639a 100644 --- a/examples/simple-classes/CHANGELOG.md +++ b/examples/simple-classes/CHANGELOG.md @@ -1,5 +1,12 @@ # @pothos-examples/simple-classes +## 2.4.20 + +### Patch Changes + +- Updated dependencies [42bf6190] + - @pothos/core@3.27.0 + ## 2.4.19 ### Patch Changes diff --git a/examples/simple-classes/package.json b/examples/simple-classes/package.json index 7ac533ca6..2de2a0c6a 100644 --- a/examples/simple-classes/package.json +++ b/examples/simple-classes/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "2.4.19", + "version": "2.4.20", "name": "@pothos-examples/simple-classes", "main": "src/index.ts", "types": "src/index.ts", diff --git a/examples/simple-interfaces/CHANGELOG.md b/examples/simple-interfaces/CHANGELOG.md index d0a294170..3134677af 100644 --- a/examples/simple-interfaces/CHANGELOG.md +++ b/examples/simple-interfaces/CHANGELOG.md @@ -1,5 +1,12 @@ # @pothos-examples/simple-interfaces +## 2.4.20 + +### Patch Changes + +- Updated dependencies [42bf6190] + - @pothos/core@3.27.0 + ## 2.4.19 ### Patch Changes diff --git a/examples/simple-interfaces/package.json b/examples/simple-interfaces/package.json index de09047b5..b1caca094 100644 --- a/examples/simple-interfaces/package.json +++ b/examples/simple-interfaces/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "2.4.19", + "version": "2.4.20", "name": "@pothos-examples/simple-interfaces", "main": "src/index.ts", "types": "src/index.ts", diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index 3d74353f9..bef60fb9b 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## 3.27.0 + +### Minor Changes + +- 42bf6190: Allow unionType to receive types as a thunk + ## 3.26.0 ### Minor Changes diff --git a/packages/core/package.json b/packages/core/package.json index b1fb6b2f9..c554fdb9a 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@pothos/core", - "version": "3.26.0", + "version": "3.27.0", "description": "Pothos (formerly GiraphQL) is a plugin based schema builder for creating code-first GraphQL schemas in typescript", "main": "./lib/index.js", "types": "./dts/index.d.ts", diff --git a/packages/deno/CHANGELOG.md b/packages/deno/CHANGELOG.md index 898f52621..7d8946ecd 100644 --- a/packages/deno/CHANGELOG.md +++ b/packages/deno/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## 3.38.0 + +### Minor Changes + +- 42bf6190: Allow unionType to receive types as a thunk + ## 3.37.0 ### Minor Changes diff --git a/packages/deno/package.json b/packages/deno/package.json index 00d77495f..08ce2925f 100644 --- a/packages/deno/package.json +++ b/packages/deno/package.json @@ -1,6 +1,6 @@ { "name": "@pothos/deno", - "version": "3.37.0", + "version": "3.38.0", "description": "Deno compatible versions of Pothos packages", "repository": { "type": "git", diff --git a/website/CHANGELOG.md b/website/CHANGELOG.md index 5262a125a..5e0aa683e 100644 --- a/website/CHANGELOG.md +++ b/website/CHANGELOG.md @@ -4,6 +4,13 @@ ### Patch Changes +- Updated dependencies [42bf6190] + - @pothos/core@3.27.0 + +## null + +### Patch Changes + - Updated dependencies [ec411ea1] - @pothos/core@3.26.0 From d60cb49e7d38f84baaf3d5bb25f7e080d01170cd Mon Sep 17 00:00:00 2001 From: Tim Griesser Date: Wed, 22 Feb 2023 17:21:06 -0500 Subject: [PATCH 04/13] feat: handle string contining ':' in global ID --- .changeset/early-chefs-end.md | 5 +++ .../packages/plugin-relay/utils/global-ids.ts | 5 ++- packages/plugin-relay/src/utils/global-ids.ts | 5 ++- .../tests/__snapshots__/index.test.ts.snap | 7 ++++ .../tests/examples/relay/schema/numbers.ts | 41 +++++++++++++++++++ packages/plugin-relay/tests/index.test.ts | 22 ++++++++++ 6 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 .changeset/early-chefs-end.md diff --git a/.changeset/early-chefs-end.md b/.changeset/early-chefs-end.md new file mode 100644 index 000000000..0813bd450 --- /dev/null +++ b/.changeset/early-chefs-end.md @@ -0,0 +1,5 @@ +--- +'@pothos/plugin-relay': minor +--- + +handle string contining ':' in global ID diff --git a/packages/deno/packages/plugin-relay/utils/global-ids.ts b/packages/deno/packages/plugin-relay/utils/global-ids.ts index 43643d0fc..58c62755b 100644 --- a/packages/deno/packages/plugin-relay/utils/global-ids.ts +++ b/packages/deno/packages/plugin-relay/utils/global-ids.ts @@ -4,9 +4,10 @@ export function encodeGlobalID(typename: string, id: bigint | number | string) { return encodeBase64(`${typename}:${id}`); } export function decodeGlobalID(globalID: string) { - const [typename, id] = decodeBase64(globalID).split(":"); + const decoded = decodeBase64(globalID).split(":"); + const [typename, id] = decoded; if (!typename || !id) { throw new PothosValidationError(`Invalid global ID: ${globalID}`); } - return { typename, id }; + return { typename, id: decoded.length > 2 ? decoded.slice(1).join(":") : id }; } diff --git a/packages/plugin-relay/src/utils/global-ids.ts b/packages/plugin-relay/src/utils/global-ids.ts index 666e3a209..2ec02d9c1 100644 --- a/packages/plugin-relay/src/utils/global-ids.ts +++ b/packages/plugin-relay/src/utils/global-ids.ts @@ -5,11 +5,12 @@ export function encodeGlobalID(typename: string, id: bigint | number | string) { } export function decodeGlobalID(globalID: string) { - const [typename, id] = decodeBase64(globalID).split(':'); + const decoded = decodeBase64(globalID).split(':'); + const [typename, id] = decoded; if (!typename || !id) { throw new PothosValidationError(`Invalid global ID: ${globalID}`); } - return { typename, id }; + return { typename, id: decoded.length > 2 ? decoded.slice(1).join(':') : id }; } diff --git a/packages/plugin-relay/tests/__snapshots__/index.test.ts.snap b/packages/plugin-relay/tests/__snapshots__/index.test.ts.snap index 45ac44025..b49891206 100644 --- a/packages/plugin-relay/tests/__snapshots__/index.test.ts.snap +++ b/packages/plugin-relay/tests/__snapshots__/index.test.ts.snap @@ -46,6 +46,11 @@ input GlobalIDInput { otherList: [OtherInput!] = [{someField: \\"abc\\"}] } +type IDWithColon implements Node { + id: ID! + idString: String! +} + type Mutation { answerPoll(answer: Int!, id: ID!): Poll! createPoll(answers: [String!]!, question: String!): Poll! @@ -129,6 +134,8 @@ type Query { batchNumbers(after: ID, before: ID, first: Int, last: Int): QueryBatchNumbersConnection! cursorConnection(after: ID, before: ID, first: Int, last: Int): QueryCursorConnection! extraNode: Node + idWithColon(id: ID!): IDWithColon! + idsWithColon(ids: [ID!]!): [IDWithColon!]! inputGlobalID(id: ID!, inputObj: GlobalIDInput!, normalId: ID!): String! moreNodes: [Node]! node(id: ID!): Node diff --git a/packages/plugin-relay/tests/examples/relay/schema/numbers.ts b/packages/plugin-relay/tests/examples/relay/schema/numbers.ts index d80b301e0..d7ec4894e 100644 --- a/packages/plugin-relay/tests/examples/relay/schema/numbers.ts +++ b/packages/plugin-relay/tests/examples/relay/schema/numbers.ts @@ -1,6 +1,17 @@ import { resolveArrayConnection, resolveOffsetConnection } from '../../../../src'; import builder from '../builder'; +class IDWithColon { + id: string; + + constructor(id: string) { + if (!id.includes(':')) { + throw new TypeError(`Expected id to have a colon, saw ${id}`); + } + this.id = id; + } +} + class NumberThing { id: number; @@ -17,6 +28,16 @@ class BatchLoadableNumberThing { } } +const IDWithColonRef = builder.node(IDWithColon, { + name: 'IDWithColon', + id: { + resolve: (n) => n.id, + }, + fields: (t) => ({ + idString: t.exposeString('id'), + }), +}); + const NumberThingRef = builder.node(NumberThing, { id: { resolve: (n) => n.id, @@ -207,6 +228,26 @@ builder.queryField('sharedEdgeConnection', (t) => ), ); +builder.queryField('idWithColon', (t) => + t.field({ + type: IDWithColonRef, + args: { + id: t.arg.globalID({ required: true, for: [IDWithColonRef] }), + }, + resolve: (root, args) => new IDWithColon(args.id.id), + }), +); + +builder.queryField('idsWithColon', (t) => + t.field({ + type: [IDWithColonRef], + args: { + ids: t.arg.globalIDList({ required: true, for: [IDWithColonRef] }), + }, + resolve: (root, args) => args.ids.map((id) => new IDWithColon(id.id)), + }), +); + builder.queryField('numberThingByID', (t) => t.field({ type: NumberThing, diff --git a/packages/plugin-relay/tests/index.test.ts b/packages/plugin-relay/tests/index.test.ts index eb9f6322d..0bc43dbbf 100644 --- a/packages/plugin-relay/tests/index.test.ts +++ b/packages/plugin-relay/tests/index.test.ts @@ -513,6 +513,14 @@ describe('relay example schema', () => { it('parses ids', async () => { const query = gql` query { + idWithColon(id: "SURXaXRoQ29sb246MTp0ZXN0") { + id + idString + } + idsWithColon(ids: ["SURXaXRoQ29sb246MTp0ZXN0", "SURXaXRoQ29sb246Mjp0ZXN0OmV4YW1wbGU="]) { + id + idString + } numberThingByID(id: "TnVtYmVyOjE=") { id number @@ -541,6 +549,20 @@ describe('relay example schema', () => { expect(result).toMatchInlineSnapshot(` { "data": { + "idWithColon": { + "id": "SURXaXRoQ29sb246MTp0ZXN0", + "idString": "1:test", + }, + "idsWithColon": [ + { + "id": "SURXaXRoQ29sb246MTp0ZXN0", + "idString": "1:test", + }, + { + "id": "SURXaXRoQ29sb246Mjp0ZXN0OmV4YW1wbGU=", + "idString": "2:test:example", + }, + ], "invalid": null, "invalidList": null, "numberThingByID": { From 40ba035b50da742cacf4e091ddbffcf0a1d0c298 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 22 Feb 2023 22:57:54 +0000 Subject: [PATCH 05/13] chore: update versions --- .changeset/early-chefs-end.md | 5 ----- examples/complex-app/CHANGELOG.md | 10 ++++++++++ examples/complex-app/package.json | 2 +- examples/prisma-relay/CHANGELOG.md | 8 ++++++++ examples/prisma-relay/package.json | 2 +- examples/relay-windowed-pagination/CHANGELOG.md | 7 +++++++ examples/relay-windowed-pagination/package.json | 2 +- packages/plugin-relay/CHANGELOG.md | 6 ++++++ packages/plugin-relay/package.json | 2 +- 9 files changed, 35 insertions(+), 9 deletions(-) delete mode 100644 .changeset/early-chefs-end.md diff --git a/.changeset/early-chefs-end.md b/.changeset/early-chefs-end.md deleted file mode 100644 index 0813bd450..000000000 --- a/.changeset/early-chefs-end.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@pothos/plugin-relay': minor ---- - -handle string contining ':' in global ID diff --git a/examples/complex-app/CHANGELOG.md b/examples/complex-app/CHANGELOG.md index b0f57de68..9bb1f6bac 100644 --- a/examples/complex-app/CHANGELOG.md +++ b/examples/complex-app/CHANGELOG.md @@ -1,5 +1,15 @@ # @pothos-examples/complex-app +## 1.4.28 + +### Patch Changes + +- Updated dependencies [d60cb49e] + - @pothos/plugin-relay@3.36.0 + - @pothos/plugin-dataloader@3.14.0 + - @pothos/plugin-prisma@3.41.0 + - @pothos/plugin-scope-auth@3.18.0 + ## 1.4.27 ### Patch Changes diff --git a/examples/complex-app/package.json b/examples/complex-app/package.json index 27018adbc..1b3927231 100644 --- a/examples/complex-app/package.json +++ b/examples/complex-app/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.4.27", + "version": "1.4.28", "name": "@pothos-examples/complex-app", "main": "src/index.ts", "types": "src/index.ts", diff --git a/examples/prisma-relay/CHANGELOG.md b/examples/prisma-relay/CHANGELOG.md index 55e67f0eb..c8e2f2e65 100644 --- a/examples/prisma-relay/CHANGELOG.md +++ b/examples/prisma-relay/CHANGELOG.md @@ -1,5 +1,13 @@ # @pothos-examples/prisma-relay +## 2.7.26 + +### Patch Changes + +- Updated dependencies [d60cb49e] + - @pothos/plugin-relay@3.36.0 + - @pothos/plugin-prisma@3.41.0 + ## 2.7.25 ### Patch Changes diff --git a/examples/prisma-relay/package.json b/examples/prisma-relay/package.json index 0f003c272..f09cc86d5 100644 --- a/examples/prisma-relay/package.json +++ b/examples/prisma-relay/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "2.7.25", + "version": "2.7.26", "name": "@pothos-examples/prisma-relay", "main": "src/index.ts", "types": "src/index.ts", diff --git a/examples/relay-windowed-pagination/CHANGELOG.md b/examples/relay-windowed-pagination/CHANGELOG.md index 0500cf750..68cdc6e27 100644 --- a/examples/relay-windowed-pagination/CHANGELOG.md +++ b/examples/relay-windowed-pagination/CHANGELOG.md @@ -1,5 +1,12 @@ # @pothos-examples/prisma-relay +## 2.7.26 + +### Patch Changes + +- Updated dependencies [d60cb49e] + - @pothos/plugin-relay@3.36.0 + ## 2.7.25 ### Patch Changes diff --git a/examples/relay-windowed-pagination/package.json b/examples/relay-windowed-pagination/package.json index 7c989dc30..f1bae9ffe 100644 --- a/examples/relay-windowed-pagination/package.json +++ b/examples/relay-windowed-pagination/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "2.7.25", + "version": "2.7.26", "name": "@pothos-examples/relay-windowed-pagination", "main": "src/index.ts", "types": "src/index.ts", diff --git a/packages/plugin-relay/CHANGELOG.md b/packages/plugin-relay/CHANGELOG.md index deeb54d5c..08b2b6ca9 100644 --- a/packages/plugin-relay/CHANGELOG.md +++ b/packages/plugin-relay/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## 3.36.0 + +### Minor Changes + +- d60cb49e: handle string contining ':' in global ID + ## 3.35.0 ### Minor Changes diff --git a/packages/plugin-relay/package.json b/packages/plugin-relay/package.json index 9ac934625..da763fee5 100644 --- a/packages/plugin-relay/package.json +++ b/packages/plugin-relay/package.json @@ -1,6 +1,6 @@ { "name": "@pothos/plugin-relay", - "version": "3.35.0", + "version": "3.36.0", "description": "A Pothos plugin for adding relay style connections, nodes, and cursor based pagination to your GraphQL schema", "main": "./lib/index.js", "types": "./dts/index.d.ts", From 30c37a20037d7c0c27fb89377faaef8cf39b6b83 Mon Sep 17 00:00:00 2001 From: mathemare Date: Thu, 23 Feb 2023 11:13:55 +0100 Subject: [PATCH 06/13] Fixed typo in documentation --- website/pages/docs/guide/circular-references.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/pages/docs/guide/circular-references.mdx b/website/pages/docs/guide/circular-references.mdx index 933f9ff05..963d55676 100644 --- a/website/pages/docs/guide/circular-references.mdx +++ b/website/pages/docs/guide/circular-references.mdx @@ -45,7 +45,7 @@ loaded, these types of Circular imports should work without causing any issues. import { Post } from './post' export const User = builder.objectType('User', { - fields: t => ({ posts: t.t.expose('posts', { type: [Post]}) }), + fields: t => ({ posts: t.expose('posts', { type: [Post]}) }), }) // post.ts From 07d8df5ce8ccfb256bc4b5c076fb59692bc9a1b8 Mon Sep 17 00:00:00 2001 From: Michael Hayes Date: Thu, 23 Feb 2023 11:19:32 -1000 Subject: [PATCH 07/13] add tests for more id parsing cases --- packages/plugin-relay/src/index.ts | 14 +++----- packages/plugin-relay/src/schema-builder.ts | 14 ++++++-- .../tests/__snapshots__/index.test.ts.snap | 8 +++++ .../tests/examples/relay/schema/numbers.ts | 35 +++++++++++++++++++ packages/plugin-relay/tests/index.test.ts | 30 ++++++++++++++++ 5 files changed, 89 insertions(+), 12 deletions(-) diff --git a/packages/plugin-relay/src/index.ts b/packages/plugin-relay/src/index.ts index 2d01a96ae..25928321a 100644 --- a/packages/plugin-relay/src/index.ts +++ b/packages/plugin-relay/src/index.ts @@ -27,9 +27,9 @@ export class PothosRelayPlugin extends BasePlugin { const argMappings = mapInputFields(fieldConfig.args, this.buildCache, (inputField) => { if (inputField.extensions?.isRelayGlobalID) { - return (inputField.extensions?.relayGlobalIDFor ?? true) as - | true - | { typename: string; parseId: (id: string, ctx: object) => unknown }[]; + return (inputField.extensions?.relayGlobalIDFor ?? + inputField.extensions?.alwaysParse ?? + false) as boolean | { typename: string; parseId: (id: string, ctx: object) => unknown }[]; } return null; @@ -42,13 +42,7 @@ export class PothosRelayPlugin extends BasePlugin - internalDecodeGlobalID( - this.builder, - String(globalID), - ctx, - info, - Array.isArray(mappings.value) ? mappings.value : true, - ), + internalDecodeGlobalID(this.builder, String(globalID), ctx, info, mappings.value ?? false), ); return (parent, args, context, info) => diff --git a/packages/plugin-relay/src/schema-builder.ts b/packages/plugin-relay/src/schema-builder.ts index 0d2f656f4..bfab4d94b 100644 --- a/packages/plugin-relay/src/schema-builder.ts +++ b/packages/plugin-relay/src/schema-builder.ts @@ -158,7 +158,12 @@ schemaBuilderProto.nodeInterfaceRef = function nodeInterfaceRef() { ...this.options.relayOptions.nodeQueryOptions, type: ref as InterfaceRef, args: { - id: t.arg.globalID({ required: true }), + id: t.arg.globalID({ + required: true, + extensions: { + alwaysParse: true, + }, + }), }, resolve: resolveNodeFn ? (root, args, context, info) => @@ -198,7 +203,12 @@ schemaBuilderProto.nodeInterfaceRef = function nodeInterfaceRef() { ...this.options.relayOptions.nodesQueryOptions, type: [ref], args: { - ids: t.arg.globalIDList({ required: true }), + ids: t.arg.globalIDList({ + required: true, + extensions: { + alwaysParse: true, + }, + }), }, resolve: resolveNodesFn ? (root, args, context, info) => diff --git a/packages/plugin-relay/tests/__snapshots__/index.test.ts.snap b/packages/plugin-relay/tests/__snapshots__/index.test.ts.snap index 45ac44025..ea0bd4526 100644 --- a/packages/plugin-relay/tests/__snapshots__/index.test.ts.snap +++ b/packages/plugin-relay/tests/__snapshots__/index.test.ts.snap @@ -46,6 +46,13 @@ input GlobalIDInput { otherList: [OtherInput!] = [{someField: \\"abc\\"}] } +type IDResult { + arg: String! + id: String! + idType: String! + typename: String! +} + type Mutation { answerPoll(answer: Int!, id: ID!): Poll! createPoll(answers: [String!]!, question: String!): Poll! @@ -128,6 +135,7 @@ type PollAnswersUsingOffsetConnectionEdge { type Query { batchNumbers(after: ID, before: ID, first: Int, last: Int): QueryBatchNumbersConnection! cursorConnection(after: ID, before: ID, first: Int, last: Int): QueryCursorConnection! + echoIDs(genericNumberThingID: ID!, globalID: ID!, numberThingID: ID!): [IDResult!]! extraNode: Node inputGlobalID(id: ID!, inputObj: GlobalIDInput!, normalId: ID!): String! moreNodes: [Node]! diff --git a/packages/plugin-relay/tests/examples/relay/schema/numbers.ts b/packages/plugin-relay/tests/examples/relay/schema/numbers.ts index e7a5846a4..cd151ecc5 100644 --- a/packages/plugin-relay/tests/examples/relay/schema/numbers.ts +++ b/packages/plugin-relay/tests/examples/relay/schema/numbers.ts @@ -236,3 +236,38 @@ builder.queryField('numberThingsByIDs', (t) => resolve: (root, args) => args.ids.map(({ id }) => new NumberThing(id)), }), ); + +const IDResult = builder + .objectRef<{ + id: unknown; + typename: string; + arg: string; + }>('IDResult') + .implement({ + fields: (t) => ({ + id: t.string({ + resolve: (n) => String(n.id), + }), + typename: t.exposeString('typename', {}), + arg: t.exposeString('arg', {}), + idType: t.string({ + resolve: (n) => typeof n.id, + }), + }), + }); + +builder.queryField('echoIDs', (t) => + t.field({ + type: [IDResult], + args: { + globalID: t.arg.globalID({ required: true }), + numberThingID: t.arg.globalID({ required: true, for: [NumberThingRef] }), + genericNumberThingID: t.arg.globalID({ required: true, for: [NumberThing] }), + }, + resolve: (_, args) => [ + { ...args.globalID, arg: 'globalID' }, + { ...args.numberThingID, arg: 'numberThingID' }, + { ...args.genericNumberThingID, arg: 'genericNumberThingID' }, + ], + }), +); diff --git a/packages/plugin-relay/tests/index.test.ts b/packages/plugin-relay/tests/index.test.ts index eb9f6322d..d362bd7e1 100644 --- a/packages/plugin-relay/tests/index.test.ts +++ b/packages/plugin-relay/tests/index.test.ts @@ -529,6 +529,16 @@ describe('relay example schema', () => { id number } + echoIDs( + globalID: "TnVtYmVyOjE=" + numberThingID: "TnVtYmVyOjE=" + genericNumberThingID: "TnVtYmVyOjE=" + ) { + id + typename + arg + idType + } } `; @@ -541,6 +551,26 @@ describe('relay example schema', () => { expect(result).toMatchInlineSnapshot(` { "data": { + "echoIDs": [ + { + "arg": "globalID", + "id": "1", + "idType": "string", + "typename": "Number", + }, + { + "arg": "numberThingID", + "id": "1", + "idType": "number", + "typename": "Number", + }, + { + "arg": "genericNumberThingID", + "id": "1", + "idType": "string", + "typename": "Number", + }, + ], "invalid": null, "invalidList": null, "numberThingByID": { From d2b02b79ab3ae029f70b451c75ef4aaacdeb616d Mon Sep 17 00:00:00 2001 From: Michael Hayes Date: Thu, 23 Feb 2023 11:30:10 -1000 Subject: [PATCH 08/13] add changeset --- .changeset/eight-ligers-develop.md | 6 ++++++ packages/deno/packages/plugin-relay/index.ts | 6 ++++-- .../deno/packages/plugin-relay/schema-builder.ts | 14 ++++++++++++-- packages/plugin-relay/src/index.ts | 2 +- packages/plugin-relay/src/schema-builder.ts | 4 ++-- 5 files changed, 25 insertions(+), 7 deletions(-) create mode 100644 .changeset/eight-ligers-develop.md diff --git a/.changeset/eight-ligers-develop.md b/.changeset/eight-ligers-develop.md new file mode 100644 index 000000000..38bea0586 --- /dev/null +++ b/.changeset/eight-ligers-develop.md @@ -0,0 +1,6 @@ +--- +'@pothos/plugin-relay': patch +'@pothos/deno': patch +--- + +Fix a few issues with globalID parsing diff --git a/packages/deno/packages/plugin-relay/index.ts b/packages/deno/packages/plugin-relay/index.ts index cfb2cd8b0..19b501c50 100644 --- a/packages/deno/packages/plugin-relay/index.ts +++ b/packages/deno/packages/plugin-relay/index.ts @@ -15,7 +15,9 @@ export class PothosRelayPlugin extends BasePlugin, fieldConfig: PothosOutputFieldConfig): GraphQLFieldResolver { const argMappings = mapInputFields(fieldConfig.args, this.buildCache, (inputField) => { if (inputField.extensions?.isRelayGlobalID) { - return (inputField.extensions?.relayGlobalIDFor ?? true) as true | { + return (inputField.extensions?.relayGlobalIDFor ?? + inputField.extensions?.relayGlobalIDAlwaysParse ?? + false) as boolean | { typename: string; parseId: (id: string, ctx: object) => unknown; }[]; @@ -25,7 +27,7 @@ export class PothosRelayPlugin extends BasePlugin internalDecodeGlobalID(this.builder, String(globalID), ctx, info, Array.isArray(mappings.value) ? mappings.value : true)); + const argMapper = createInputValueMapper(argMappings, (globalID, mappings, ctx: Types["Context"], info: GraphQLResolveInfo) => internalDecodeGlobalID(this.builder, String(globalID), ctx, info, mappings.value ?? false)); return (parent, args, context, info) => resolver(parent, argMapper(args, undefined, context, info), context, info); } override wrapSubscribe(subscribe: GraphQLFieldResolver | undefined, fieldConfig: PothosOutputFieldConfig): GraphQLFieldResolver | undefined { diff --git a/packages/deno/packages/plugin-relay/schema-builder.ts b/packages/deno/packages/plugin-relay/schema-builder.ts index 57230920b..4d0aa554b 100644 --- a/packages/deno/packages/plugin-relay/schema-builder.ts +++ b/packages/deno/packages/plugin-relay/schema-builder.ts @@ -101,7 +101,12 @@ schemaBuilderProto.nodeInterfaceRef = function nodeInterfaceRef() { ...this.options.relayOptions.nodeQueryOptions, type: ref as InterfaceRef, args: { - id: t.arg.globalID({ required: true }), + id: t.arg.globalID({ + required: true, + extensions: { + relayGlobalIDAlwaysParse: true, + }, + }), }, resolve: resolveNodeFn ? (root, args, context, info) => resolveNodeFn(root, args as { @@ -134,7 +139,12 @@ schemaBuilderProto.nodeInterfaceRef = function nodeInterfaceRef() { ...this.options.relayOptions.nodesQueryOptions, type: [ref], args: { - ids: t.arg.globalIDList({ required: true }), + ids: t.arg.globalIDList({ + required: true, + extensions: { + relayGlobalIDAlwaysParse: true, + }, + }), }, resolve: resolveNodesFn ? (root, args, context, info) => resolveNodesFn(root, args as { diff --git a/packages/plugin-relay/src/index.ts b/packages/plugin-relay/src/index.ts index 25928321a..245863b7c 100644 --- a/packages/plugin-relay/src/index.ts +++ b/packages/plugin-relay/src/index.ts @@ -28,7 +28,7 @@ export class PothosRelayPlugin extends BasePlugin { if (inputField.extensions?.isRelayGlobalID) { return (inputField.extensions?.relayGlobalIDFor ?? - inputField.extensions?.alwaysParse ?? + inputField.extensions?.relayGlobalIDAlwaysParse ?? false) as boolean | { typename: string; parseId: (id: string, ctx: object) => unknown }[]; } diff --git a/packages/plugin-relay/src/schema-builder.ts b/packages/plugin-relay/src/schema-builder.ts index bfab4d94b..b7f06e831 100644 --- a/packages/plugin-relay/src/schema-builder.ts +++ b/packages/plugin-relay/src/schema-builder.ts @@ -161,7 +161,7 @@ schemaBuilderProto.nodeInterfaceRef = function nodeInterfaceRef() { id: t.arg.globalID({ required: true, extensions: { - alwaysParse: true, + relayGlobalIDAlwaysParse: true, }, }), }, @@ -206,7 +206,7 @@ schemaBuilderProto.nodeInterfaceRef = function nodeInterfaceRef() { ids: t.arg.globalIDList({ required: true, extensions: { - alwaysParse: true, + relayGlobalIDAlwaysParse: true, }, }), }, From 592ffd3be1c93226a900aa6f5e7ca1a403e673da Mon Sep 17 00:00:00 2001 From: Michael Hayes Date: Thu, 23 Feb 2023 11:45:54 -1000 Subject: [PATCH 09/13] fix name option for prisma node --- .changeset/tricky-suns-bake.md | 5 +++++ packages/plugin-prisma/src/schema-builder.ts | 1 + .../tests/__snapshots__/index.test.ts.snap | 14 +++++++------- .../plugin-prisma/tests/example/schema/index.ts | 1 + 4 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 .changeset/tricky-suns-bake.md diff --git a/.changeset/tricky-suns-bake.md b/.changeset/tricky-suns-bake.md new file mode 100644 index 000000000..4d908efc9 --- /dev/null +++ b/.changeset/tricky-suns-bake.md @@ -0,0 +1,5 @@ +--- +'@pothos/plugin-prisma': patch +--- + +Fix name option for prismaNode diff --git a/packages/plugin-prisma/src/schema-builder.ts b/packages/plugin-prisma/src/schema-builder.ts index 75fcc11f2..dc0e0043c 100644 --- a/packages/plugin-prisma/src/schema-builder.ts +++ b/packages/plugin-prisma/src/schema-builder.ts @@ -93,6 +93,7 @@ schemaBuilderProto.prismaNode = function prismaNode( const extendedOptions = { ...options, + name, variant, interfaces: [interfaceRef], findUnique, diff --git a/packages/plugin-prisma/tests/__snapshots__/index.test.ts.snap b/packages/plugin-prisma/tests/__snapshots__/index.test.ts.snap index 52b69c798..0ae5da722 100644 --- a/packages/plugin-prisma/tests/__snapshots__/index.test.ts.snap +++ b/packages/plugin-prisma/tests/__snapshots__/index.test.ts.snap @@ -61,11 +61,6 @@ type FindUniqueRelations { withUniqueNode: WithUniqueNode! } -type Follow { - from: User! - to: User! -} - type Media { url: String! } @@ -300,7 +295,7 @@ type SelectUserFollowingConnection { type SelectUserFollowingConnectionEdge { cursor: String! - node: Follow! + node: UserFollow! } type SelectUserPostsConnection { @@ -362,6 +357,11 @@ type UserCommentsConnectionEdge { union UserDirectProfileWithErrorsResult = BaseError | Profile +type UserFollow { + from: User! + to: User! +} + type UserFollowingConnection { edges: [UserFollowingConnectionEdge]! pageInfo: PageInfo! @@ -369,7 +369,7 @@ type UserFollowingConnection { type UserFollowingConnectionEdge { cursor: String! - node: Follow! + node: UserFollow! } union UserOrProfile = Profile | User diff --git a/packages/plugin-prisma/tests/example/schema/index.ts b/packages/plugin-prisma/tests/example/schema/index.ts index bbe6eb4af..63fe737f3 100644 --- a/packages/plugin-prisma/tests/example/schema/index.ts +++ b/packages/plugin-prisma/tests/example/schema/index.ts @@ -107,6 +107,7 @@ const ViewerNode = builder.prismaNode('User', { }); builder.prismaObject('Follow', { + name: 'UserFollow', fields: (t) => ({ to: t.relation('to'), from: t.relation('from'), From cdf6237a87cb3ac52a57d0e79aaab8c6dfab0583 Mon Sep 17 00:00:00 2001 From: Tim Griesser Date: Tue, 21 Feb 2023 16:40:55 -0500 Subject: [PATCH 10/13] feat: implement default isTypeOf on loadableNode --- .../plugin-dataloader/src/schema-builder.ts | 34 ++++++++++++++++++- .../tests/__snapshots__/index.test.ts.snap | 6 +++- .../tests/example/schema/nodes.ts | 15 +++++--- .../plugin-dataloader/tests/index.test.ts | 4 +++ 4 files changed, 52 insertions(+), 7 deletions(-) diff --git a/packages/plugin-dataloader/src/schema-builder.ts b/packages/plugin-dataloader/src/schema-builder.ts index e8c279cc7..6246ce15a 100644 --- a/packages/plugin-dataloader/src/schema-builder.ts +++ b/packages/plugin-dataloader/src/schema-builder.ts @@ -1,6 +1,8 @@ +import type { GraphQLResolveInfo } from 'graphql'; import SchemaBuilder, { InterfaceParam, ObjectParam, + OutputRef, PothosSchemaError, SchemaTypes, ShapeFromTypeParam, @@ -159,7 +161,37 @@ schemaBuilderProto.loadableNode = function loadableNode< options, ); - ref.implement(options); + // ref.implement(options); + ref.implement({ + ...options, + isTypeOf: + options.isTypeOf ?? + (typeof nameOrRef === 'function' + ? (maybeNode: unknown, context: object, info: GraphQLResolveInfo) => { + if (!maybeNode) { + return false; + } + + if (maybeNode instanceof (nameOrRef as Function)) { + return true; + } + + const proto = Object.getPrototypeOf(maybeNode) as { constructor: unknown }; + + try { + if (proto?.constructor) { + const config = this.configStore.getTypeConfig(proto.constructor as OutputRef); + + return config.name === name; + } + } catch { + // ignore + } + + return false; + } + : undefined), + }); if (typeof nameOrRef !== 'string') { this.configStore.associateRefWithName(nameOrRef, name); diff --git a/packages/plugin-dataloader/tests/__snapshots__/index.test.ts.snap b/packages/plugin-dataloader/tests/__snapshots__/index.test.ts.snap index c2c45283f..613042543 100644 --- a/packages/plugin-dataloader/tests/__snapshots__/index.test.ts.snap +++ b/packages/plugin-dataloader/tests/__snapshots__/index.test.ts.snap @@ -319,8 +319,12 @@ exports[`dataloader > queries > valid queries 1`] = ` "classThing": { "id": "Q2xhc3NMb2FkYWJsZVRoaW5nOjEyMw==", }, + "classThingNode": { + "__typename": "ClassLoadableThing", + "id": "Q2xhc3NMb2FkYWJsZVRoaW5nOjE=", + }, "classThingRef": { - "id": "Q2xhc3NMb2FkYWJsZVRoaW5nOjEyMw==", + "id": "Q2xhc3NMb2FkYWJsZVRoaW5nOjE=", }, "counts": [ { diff --git a/packages/plugin-dataloader/tests/example/schema/nodes.ts b/packages/plugin-dataloader/tests/example/schema/nodes.ts index b842e230c..a2a2374d5 100644 --- a/packages/plugin-dataloader/tests/example/schema/nodes.ts +++ b/packages/plugin-dataloader/tests/example/schema/nodes.ts @@ -11,21 +11,25 @@ const UserNode = builder.loadableNodeRef('UserNode', { load: (keys: string[], context: ContextType) => { countCall(context, userNodeCounts, keys.length); return Promise.resolve( - keys.map((id) => (Number(id) > 0 ? { id: Number(id) } : new Error(`Invalid ID ${id}`))), + keys.map((id) => + Number(id) > 0 ? { objType: 'UserNode', id: Number(id) } : new Error(`Invalid ID ${id}`), + ), ); }, }); builder.objectType(UserNode, { interfaces: [TestInterface], - isTypeOf: (obj) => - typeof obj === 'object' && obj !== null && Object.prototype.hasOwnProperty.call(obj, 'id'), + isTypeOf: (obj) => (obj as any).objType === 'UserNode', fields: (t) => ({}), }); class ClassThing { - id: number = 123; + id: number; name: string = 'some name'; + constructor(id = 123) { + this.id = id; + } } const ClassThingRef = builder.loadableNode(ClassThing, { @@ -36,7 +40,8 @@ const ClassThingRef = builder.loadableNode(ClassThing, { }, loaderOptions: { maxBatchSize: 20 }, // eslint-disable-next-line @typescript-eslint/require-await - load: async (keys: string[], context: ContextType) => [new ClassThing()], + load: async (keys: string[], context: ContextType) => + keys.map((k) => new ClassThing(Number.parseInt(k, 10))), fields: (t) => ({}), }); diff --git a/packages/plugin-dataloader/tests/index.test.ts b/packages/plugin-dataloader/tests/index.test.ts index 68edc06cb..a0ccb6ea7 100644 --- a/packages/plugin-dataloader/tests/index.test.ts +++ b/packages/plugin-dataloader/tests/index.test.ts @@ -158,6 +158,10 @@ describe('dataloader', () => { threeToMany: oneToMany(id: 3) { id } + classThingNode: node(id: "Q2xhc3NMb2FkYWJsZVRoaW5nOjE=") { + __typename + id + } } `; From 36d93a4fd743beb5b176147393c1dfd8be15e3f4 Mon Sep 17 00:00:00 2001 From: Tim Griesser Date: Tue, 21 Feb 2023 16:45:10 -0500 Subject: [PATCH 11/13] update docs, remove comment line --- packages/plugin-dataloader/src/schema-builder.ts | 1 - website/pages/docs/plugins/dataloader.mdx | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/plugin-dataloader/src/schema-builder.ts b/packages/plugin-dataloader/src/schema-builder.ts index 6246ce15a..26fabe7ec 100644 --- a/packages/plugin-dataloader/src/schema-builder.ts +++ b/packages/plugin-dataloader/src/schema-builder.ts @@ -161,7 +161,6 @@ schemaBuilderProto.loadableNode = function loadableNode< options, ); - // ref.implement(options); ref.implement({ ...options, isTypeOf: diff --git a/website/pages/docs/plugins/dataloader.mdx b/website/pages/docs/plugins/dataloader.mdx index 3248fff9d..5a04bb01c 100644 --- a/website/pages/docs/plugins/dataloader.mdx +++ b/website/pages/docs/plugins/dataloader.mdx @@ -320,7 +320,7 @@ const UserNode = builder.loadableNode('UserNode', { id: { resolve: (user) => user.id, }, - // For loadable objects we always need to include an isTypeOf check + // For loadable nodes, we need to include an isTypeOf check if the first arg is a string isTypeOf: (obj) => obj instanceof User, load: (ids: string[], context: ContextType) => context.loadUsersById(ids), fields: (t) => ({}), From 8d5ac033ac3b9a454bef97ec95e3efe2e6654ad8 Mon Sep 17 00:00:00 2001 From: Michael Hayes Date: Thu, 23 Feb 2023 11:52:45 -1000 Subject: [PATCH 12/13] update readmes --- .../deno/packages/plugin-dataloader/README.md | 2 +- .../plugin-dataloader/schema-builder.ts | 31 +++++++++++++++++-- packages/plugin-dataloader/README.md | 2 +- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/packages/deno/packages/plugin-dataloader/README.md b/packages/deno/packages/plugin-dataloader/README.md index 64254bc85..c7836ee40 100644 --- a/packages/deno/packages/plugin-dataloader/README.md +++ b/packages/deno/packages/plugin-dataloader/README.md @@ -306,7 +306,7 @@ const UserNode = builder.loadableNode('UserNode', { id: { resolve: (user) => user.id, }, - // For loadable objects we always need to include an isTypeOf check + // For loadable nodes, we need to include an isTypeOf check if the first arg is a string isTypeOf: (obj) => obj instanceof User, load: (ids: string[], context: ContextType) => context.loadUsersById(ids), fields: (t) => ({}), diff --git a/packages/deno/packages/plugin-dataloader/schema-builder.ts b/packages/deno/packages/plugin-dataloader/schema-builder.ts index 77fb0b6b0..4c1a25aaa 100644 --- a/packages/deno/packages/plugin-dataloader/schema-builder.ts +++ b/packages/deno/packages/plugin-dataloader/schema-builder.ts @@ -1,5 +1,6 @@ // @ts-nocheck -import SchemaBuilder, { InterfaceParam, ObjectParam, PothosSchemaError, SchemaTypes, ShapeFromTypeParam, } from '../core/index.ts'; +import type { GraphQLResolveInfo } from 'https://cdn.skypack.dev/graphql?dts'; +import SchemaBuilder, { InterfaceParam, ObjectParam, OutputRef, PothosSchemaError, SchemaTypes, ShapeFromTypeParam, } from '../core/index.ts'; import { ImplementableLoadableNodeRef } from './refs/index.ts'; import { ImplementableLoadableInterfaceRef } from './refs/interface.ts'; import { ImplementableLoadableObjectRef } from './refs/object.ts'; @@ -74,7 +75,33 @@ schemaBuilderProto.loadableNode = function loadableNode(this, name, options); - ref.implement(options); + ref.implement({ + ...options, + isTypeOf: options.isTypeOf ?? + (typeof nameOrRef === "function" + ? (maybeNode: unknown, context: object, info: GraphQLResolveInfo) => { + if (!maybeNode) { + return false; + } + if (maybeNode instanceof (nameOrRef as Function)) { + return true; + } + const proto = Object.getPrototypeOf(maybeNode) as { + constructor: unknown; + }; + try { + if (proto?.constructor) { + const config = this.configStore.getTypeConfig(proto.constructor as OutputRef); + return config.name === name; + } + } + catch { + // ignore + } + return false; + } + : undefined), + }); if (typeof nameOrRef !== "string") { this.configStore.associateRefWithName(nameOrRef, name); } diff --git a/packages/plugin-dataloader/README.md b/packages/plugin-dataloader/README.md index 64254bc85..c7836ee40 100644 --- a/packages/plugin-dataloader/README.md +++ b/packages/plugin-dataloader/README.md @@ -306,7 +306,7 @@ const UserNode = builder.loadableNode('UserNode', { id: { resolve: (user) => user.id, }, - // For loadable objects we always need to include an isTypeOf check + // For loadable nodes, we need to include an isTypeOf check if the first arg is a string isTypeOf: (obj) => obj instanceof User, load: (ids: string[], context: ContextType) => context.loadUsersById(ids), fields: (t) => ({}), From 22041db0aee237b2068b8d79f604c27808535101 Mon Sep 17 00:00:00 2001 From: Michael Hayes Date: Thu, 23 Feb 2023 11:54:21 -1000 Subject: [PATCH 13/13] Add changeset --- .changeset/kind-snails-pull.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/kind-snails-pull.md diff --git a/.changeset/kind-snails-pull.md b/.changeset/kind-snails-pull.md new file mode 100644 index 000000000..e29620a57 --- /dev/null +++ b/.changeset/kind-snails-pull.md @@ -0,0 +1,6 @@ +--- +'@pothos/plugin-dataloader': minor +'@pothos/deno': minor +--- + +Add default isTypeOf for loadableNode