From 09f183e65a06d438faaa0b0fdc6f1fef4a85e1ac Mon Sep 17 00:00:00 2001 From: Tim Griesser Date: Tue, 21 Feb 2023 13:35:33 -0500 Subject: [PATCH 1/6] feat: add parse to loadableNode id --- .../plugin-dataloader/global-types.ts | 4 +- .../packages/plugin-dataloader/refs/node.ts | 4 +- .../plugin-dataloader/schema-builder.ts | 8 +++- .../deno/packages/plugin-dataloader/types.ts | 8 ++-- .../packages/plugin-relay/global-types.ts | 8 +++- .../plugin-relay/input-field-builder.ts | 5 +-- .../plugin-dataloader/src/global-types.ts | 7 +++- packages/plugin-dataloader/src/refs/node.ts | 4 +- .../plugin-dataloader/src/schema-builder.ts | 8 +++- packages/plugin-dataloader/src/types.ts | 8 ++-- .../tests/__snapshots__/index.test.ts.snap | 32 +++++++++++++++ .../tests/example/builder.ts | 2 +- .../tests/example/schema/nodes.ts | 39 ++++++++++++++++++- .../plugin-dataloader/tests/index.test.ts | 29 ++++++++++++++ packages/plugin-relay/src/global-types.ts | 4 +- .../plugin-relay/src/input-field-builder.ts | 5 +-- 16 files changed, 149 insertions(+), 26 deletions(-) diff --git a/packages/deno/packages/plugin-dataloader/global-types.ts b/packages/deno/packages/plugin-dataloader/global-types.ts index 79ad00153..f5610e40c 100644 --- a/packages/deno/packages/plugin-dataloader/global-types.ts +++ b/packages/deno/packages/plugin-dataloader/global-types.ts @@ -16,9 +16,9 @@ declare global { loadableInterface: ? ShapeFromTypeParam : object, Key extends bigint | number | string, Interfaces extends InterfaceParam[], NameOrRef extends InterfaceParam | string, CacheKey = Key>(nameOrRef: NameOrRef, options: LoadableInterfaceOptions) => LoadableInterfaceRef; loadableObjectRef: (name: string, options: DataLoaderOptions) => ImplementableLoadableObjectRef; loadableInterfaceRef: (name: string, options: DataLoaderOptions) => ImplementableLoadableInterfaceRef; - loadableNodeRef: (name: string, options: DataLoaderOptions & LoadableNodeId) => ImplementableLoadableNodeRef; + loadableNodeRef: (name: string, options: DataLoaderOptions & LoadableNodeId) => ImplementableLoadableNodeRef; loadableUnion: , CacheKey = Key, Shape = ShapeFromTypeParam>(name: string, options: LoadableUnionOptions) => LoadableUnionRef; - loadableNode: "relay" extends PluginName ? ? ShapeFromTypeParam : object, Key extends bigint | number | string, Interfaces extends InterfaceParam[], NameOrRef extends ObjectParam | string, CacheKey = Key>(nameOrRef: NameOrRef, options: LoadableNodeOptions) => Omit, "implement"> : "@pothos/plugin-relay is required to use this method"; + loadableNode: "relay" extends PluginName ? ? ShapeFromTypeParam : object, Key extends bigint | number | string, Interfaces extends InterfaceParam[], NameOrRef extends ObjectParam | string, CacheKey = Key>(nameOrRef: NameOrRef, options: LoadableNodeOptions) => Omit, "implement"> : "@pothos/plugin-relay is required to use this method"; } export interface RootFieldBuilder { loadable: , Key, CacheKey, ResolveReturnShape, Nullable extends FieldNullability = Types["DefaultFieldNullability"]>(options: LoadableFieldOptions) => FieldRef; diff --git a/packages/deno/packages/plugin-dataloader/refs/node.ts b/packages/deno/packages/plugin-dataloader/refs/node.ts index dfbfbe841..fb7ea72a8 100644 --- a/packages/deno/packages/plugin-dataloader/refs/node.ts +++ b/packages/deno/packages/plugin-dataloader/refs/node.ts @@ -4,10 +4,12 @@ import { FieldRef, InterfaceRef, PothosObjectTypeConfig, SchemaTypes } from '../ import { DataLoaderOptions, LoadableNodeId } from '../types.ts'; import { ImplementableLoadableObjectRef } from './object.ts'; export class ImplementableLoadableNodeRef extends ImplementableLoadableObjectRef { + parseId: ((id: string, ctx: object) => Key) | undefined; private idOptions; - constructor(builder: PothosSchemaTypes.SchemaBuilder, name: string, { id, ...options }: DataLoaderOptions & LoadableNodeId) { + constructor(builder: PothosSchemaTypes.SchemaBuilder, name: string, { id, ...options }: DataLoaderOptions & LoadableNodeId) { super(builder, name, options); this.idOptions = id; + this.parseId = id.parse; this.builder.configStore.onTypeConfig(this, (config) => { const nodeInterface = (this.builder as PothosSchemaTypes.SchemaBuilder & { nodeInterfaceRef: () => InterfaceRef; diff --git a/packages/deno/packages/plugin-dataloader/schema-builder.ts b/packages/deno/packages/plugin-dataloader/schema-builder.ts index 77fb0b6b0..eb6449e3f 100644 --- a/packages/deno/packages/plugin-dataloader/schema-builder.ts +++ b/packages/deno/packages/plugin-dataloader/schema-builder.ts @@ -74,7 +74,13 @@ schemaBuilderProto.loadableNode = function loadableNode(this, name, options); - ref.implement(options); + ref.implement({ + ...options, + extensions: { + ...options.extensions, + pothosParseGlobalID: options.id.parse, + }, + }); if (typeof nameOrRef !== "string") { this.configStore.associateRefWithName(nameOrRef, name); } diff --git a/packages/deno/packages/plugin-dataloader/types.ts b/packages/deno/packages/plugin-dataloader/types.ts index f99dcc4c1..5b2d70b6d 100644 --- a/packages/deno/packages/plugin-dataloader/types.ts +++ b/packages/deno/packages/plugin-dataloader/types.ts @@ -50,7 +50,9 @@ export type LoaderShapeFromType { getDataloader: (context: C) => DataLoader; } -export interface LoadableNodeId { - id: Omit>>, "args" | "nullable" | "type">; +export interface LoadableNodeId { + id: Omit>>, "args" | "nullable" | "type"> & { + parse?: (id: string, ctx: Types["Context"]) => IDShape; + }; } -export type LoadableNodeOptions[], NameOrRef extends ObjectParam | string, CacheKey> = DataloaderObjectTypeOptions & LoadableNodeId; +export type LoadableNodeOptions[], NameOrRef extends ObjectParam | string, CacheKey> = DataloaderObjectTypeOptions & LoadableNodeId; diff --git a/packages/deno/packages/plugin-relay/global-types.ts b/packages/deno/packages/plugin-relay/global-types.ts index 55adf620a..2c00a4b7d 100644 --- a/packages/deno/packages/plugin-relay/global-types.ts +++ b/packages/deno/packages/plugin-relay/global-types.ts @@ -68,7 +68,9 @@ declare global { }; globalID: >(...args: NormalizeArgs<[ options: GlobalIDInputFieldOptions - ]>) => InputFieldRef ? T : string>, Req>, Kind>; + ]>) => InputFieldRef infer T; + } ? T : string>, Req>, Kind>; globalIDList: , For extends ObjectParam>(...args: NormalizeArgs<[ @@ -77,7 +79,9 @@ declare global { { [inputShapeKey]: { typename: string; - id: For extends NodeRef ? T : string; + id: For extends { + parseId?: (...args: any[]) => infer T; + } ? T : string; }; } ], Req>, Kind>; diff --git a/packages/deno/packages/plugin-relay/input-field-builder.ts b/packages/deno/packages/plugin-relay/input-field-builder.ts index 3132ff5a9..411f66616 100644 --- a/packages/deno/packages/plugin-relay/input-field-builder.ts +++ b/packages/deno/packages/plugin-relay/input-field-builder.ts @@ -1,6 +1,5 @@ // @ts-nocheck import { FieldRequiredness, InputFieldBuilder, InputFieldRef, InputShapeFromTypeParam, ObjectRef, SchemaTypes, } from '../core/index.ts'; -import { NodeRef } from './node-ref.ts'; import { GlobalIDInputFieldOptions, GlobalIDInputShape, GlobalIDListInputFieldOptions, } from './types.ts'; type DefaultSchemaTypes = PothosSchemaTypes.ExtendDefaultTypes<{}>; const inputFieldBuilder = InputFieldBuilder.prototype as PothosSchemaTypes.InputFieldBuilder; @@ -15,7 +14,7 @@ inputFieldBuilder.globalIDList = function globalIDList[])?.map((type: ObjectRef) => ({ typename: this.builder.configStore.getTypeConfig(type).name, - parseId: type instanceof NodeRef ? type.parseId : undefined, + parseId: "parseId" in type ? type.parseId : undefined, })) ?? null, }, }) as never; @@ -29,7 +28,7 @@ inputFieldBuilder.globalID = function globalID({ for: forTy relayGlobalIDFor: ((forTypes && (Array.isArray(forTypes) ? forTypes : [forTypes])) as ObjectRef[])?.map((type: ObjectRef) => ({ typename: this.builder.configStore.getTypeConfig(type).name, - parseId: type instanceof NodeRef ? type.parseId : undefined, + parseId: "parseId" in type ? type.parseId : undefined, })) ?? null, }, }) as unknown as InputFieldRef> as never; diff --git a/packages/plugin-dataloader/src/global-types.ts b/packages/plugin-dataloader/src/global-types.ts index 3b912e897..7f525cc71 100644 --- a/packages/plugin-dataloader/src/global-types.ts +++ b/packages/plugin-dataloader/src/global-types.ts @@ -83,7 +83,7 @@ declare global { loadableNodeRef: ( name: string, - options: DataLoaderOptions & LoadableNodeId, + options: DataLoaderOptions & LoadableNodeId, ) => ImplementableLoadableNodeRef; loadableUnion: < @@ -108,7 +108,10 @@ declare global { >( nameOrRef: NameOrRef, options: LoadableNodeOptions, - ) => Omit, 'implement'> + ) => Omit< + ImplementableLoadableNodeRef, + 'implement' + > : '@pothos/plugin-relay is required to use this method'; } diff --git a/packages/plugin-dataloader/src/refs/node.ts b/packages/plugin-dataloader/src/refs/node.ts index 9656f6245..5cea40288 100644 --- a/packages/plugin-dataloader/src/refs/node.ts +++ b/packages/plugin-dataloader/src/refs/node.ts @@ -10,6 +10,7 @@ export class ImplementableLoadableNodeRef< Key extends bigint | number | string, CacheKey, > extends ImplementableLoadableObjectRef { + parseId: ((id: string, ctx: object) => Key) | undefined; private idOptions; constructor( @@ -18,10 +19,11 @@ export class ImplementableLoadableNodeRef< { id, ...options - }: DataLoaderOptions & LoadableNodeId, + }: DataLoaderOptions & LoadableNodeId, ) { super(builder, name, options); this.idOptions = id; + this.parseId = id.parse; this.builder.configStore.onTypeConfig(this, (config) => { const nodeInterface = ( diff --git a/packages/plugin-dataloader/src/schema-builder.ts b/packages/plugin-dataloader/src/schema-builder.ts index e8c279cc7..7972702c6 100644 --- a/packages/plugin-dataloader/src/schema-builder.ts +++ b/packages/plugin-dataloader/src/schema-builder.ts @@ -159,7 +159,13 @@ schemaBuilderProto.loadableNode = function loadableNode< options, ); - ref.implement(options); + ref.implement({ + ...options, + extensions: { + ...options.extensions, + pothosParseGlobalID: options.id.parse, + }, + }); if (typeof nameOrRef !== 'string') { this.configStore.associateRefWithName(nameOrRef, name); diff --git a/packages/plugin-dataloader/src/types.ts b/packages/plugin-dataloader/src/types.ts index 12a9f15a6..85fbca566 100644 --- a/packages/plugin-dataloader/src/types.ts +++ b/packages/plugin-dataloader/src/types.ts @@ -162,7 +162,7 @@ export interface LoadableRef { getDataloader: (context: C) => DataLoader; } -export interface LoadableNodeId { +export interface LoadableNodeId { id: Omit< FieldOptionsFromKind< Types, @@ -175,7 +175,9 @@ export interface LoadableNodeId MaybePromise> >, 'args' | 'nullable' | 'type' - >; + > & { + parse?: (id: string, ctx: Types['Context']) => IDShape; + }; } export type LoadableNodeOptions< @@ -186,4 +188,4 @@ export type LoadableNodeOptions< NameOrRef extends ObjectParam | string, CacheKey, > = DataloaderObjectTypeOptions & - LoadableNodeId; + LoadableNodeId; diff --git a/packages/plugin-dataloader/tests/__snapshots__/index.test.ts.snap b/packages/plugin-dataloader/tests/__snapshots__/index.test.ts.snap index c2c45283f..f59ed595f 100644 --- a/packages/plugin-dataloader/tests/__snapshots__/index.test.ts.snap +++ b/packages/plugin-dataloader/tests/__snapshots__/index.test.ts.snap @@ -34,6 +34,11 @@ interface Error { message: String! } +type LoadableParseTest implements Node { + id: ID! + idNumber: Int! +} + interface Node { id: ID! } @@ -72,6 +77,8 @@ type Query { fromContext3: User! fromContext4: [User!]! fromContext5: [User!]! + loadableParse: LoadableParseTest! + loadableParseNodes(ids: [ID!]): [LoadableParseTest!]! node(id: ID!): Node nodes(ids: [ID!]!): [Node]! nullableUser(id: String): NullableUser @@ -255,6 +262,31 @@ exports[`dataloader > queries > query with errors 1`] = ` } `; +exports[`dataloader > queries > query with global ids 1`] = ` +{ + "data": { + "loadableParse": { + "id": "TG9hZGFibGVQYXJzZVRlc3Q6MQ==", + "idNumber": 1, + }, + "loadableParseNodes": [ + { + "id": "TG9hZGFibGVQYXJzZVRlc3Q6MQ==", + "idNumber": 1, + }, + { + "id": "TG9hZGFibGVQYXJzZVRlc3Q6Mg==", + "idNumber": 2, + }, + { + "id": "TG9hZGFibGVQYXJzZVRlc3Q6MTA=", + "idNumber": 10, + }, + ], + }, +} +`; + exports[`dataloader > queries > sorts loaded results 1`] = ` { "counts": [ diff --git a/packages/plugin-dataloader/tests/example/builder.ts b/packages/plugin-dataloader/tests/example/builder.ts index 7c2d4baeb..19ddf9617 100644 --- a/packages/plugin-dataloader/tests/example/builder.ts +++ b/packages/plugin-dataloader/tests/example/builder.ts @@ -11,7 +11,7 @@ export default new SchemaBuilder<{ Context: ContextType }>({ nodeQueryOptions: {}, nodesQueryOptions: {}, }, - plugins: [RelayPlugin, ErrorsPlugin, DataloaderPlugin], + plugins: [ErrorsPlugin, DataloaderPlugin, RelayPlugin], errorOptions: { defaultTypes: [Error], }, diff --git a/packages/plugin-dataloader/tests/example/schema/nodes.ts b/packages/plugin-dataloader/tests/example/schema/nodes.ts index b842e230c..ef5287efd 100644 --- a/packages/plugin-dataloader/tests/example/schema/nodes.ts +++ b/packages/plugin-dataloader/tests/example/schema/nodes.ts @@ -33,13 +33,38 @@ const ClassThingRef = builder.loadableNode(ClassThing, { interfaces: [TestInterface], id: { resolve: (user) => user.id, + parse: (id) => id, }, loaderOptions: { maxBatchSize: 20 }, // eslint-disable-next-line @typescript-eslint/require-await - load: async (keys: string[], context: ContextType) => [new ClassThing()], + load: async (keys, context: ContextType) => [new ClassThing()], fields: (t) => ({}), }); +class LoadableParseTest { + readonly id: number; + constructor(id: number) { + if (typeof id !== 'number') { + throw new TypeError(`Expected id to be a number, saw ${id}`); + } + this.id = id; + } +} + +const LoadableParseRef = builder.loadableNode(LoadableParseTest, { + name: 'LoadableParseTest', + id: { + resolve: (user) => user.id, + parse: (id) => Number.parseInt(id, 10), + }, + loaderOptions: { maxBatchSize: 20 }, + // eslint-disable-next-line @typescript-eslint/require-await + load: async (keys, context: ContextType) => keys.map((k) => new LoadableParseTest(k)), + fields: (t) => ({ + idNumber: t.exposeInt('id'), + }), +}); + builder.queryFields((t) => ({ userNode: t.field({ type: UserNode, @@ -68,4 +93,16 @@ builder.queryFields((t) => ({ type: ClassThingRef, resolve: () => '1', }), + loadableParse: t.field({ + type: LoadableParseRef, + resolve: () => 1, + }), + loadableParseNodes: t.field({ + type: [LoadableParseRef], + args: { + ids: t.arg.globalIDList({ for: [LoadableParseRef] }), + }, + // TODO: type & implement this correctly based on the "for" + resolve: (source, args) => args.ids?.map((id) => id.id) ?? [], + }), })); diff --git a/packages/plugin-dataloader/tests/index.test.ts b/packages/plugin-dataloader/tests/index.test.ts index 68edc06cb..ea4f5294f 100644 --- a/packages/plugin-dataloader/tests/index.test.ts +++ b/packages/plugin-dataloader/tests/index.test.ts @@ -170,6 +170,35 @@ describe('dataloader', () => { expect(result).toMatchSnapshot(); }); + it('query with global ids', async () => { + const query = gql` + query { + loadableParse { + id + idNumber + } + loadableParseNodes( + ids: [ + "TG9hZGFibGVQYXJzZVRlc3Q6MQ==" + "TG9hZGFibGVQYXJzZVRlc3Q6Mg==" + "TG9hZGFibGVQYXJzZVRlc3Q6MTA=" + ] + ) { + id + idNumber + } + } + `; + + const result = await execute({ + schema, + document: query, + contextValue: createContext(), + }); + + expect(result).toMatchSnapshot(); + }); + it('query with errors', async () => { const query = gql` query { diff --git a/packages/plugin-relay/src/global-types.ts b/packages/plugin-relay/src/global-types.ts index 17386f2cd..f9a41f168 100644 --- a/packages/plugin-relay/src/global-types.ts +++ b/packages/plugin-relay/src/global-types.ts @@ -198,7 +198,7 @@ declare global { ) => InputFieldRef< InputShapeFromTypeParam< Types, - GlobalIDInputShape ? T : string>, + GlobalIDInputShape infer T } ? T : string>, Req >, Kind @@ -213,7 +213,7 @@ declare global { { [inputShapeKey]: { typename: string; - id: For extends NodeRef ? T : string; + id: For extends { parseId?: (...args: any[]) => infer T } ? T : string; }; }, ], diff --git a/packages/plugin-relay/src/input-field-builder.ts b/packages/plugin-relay/src/input-field-builder.ts index ec1d47200..6c768168f 100644 --- a/packages/plugin-relay/src/input-field-builder.ts +++ b/packages/plugin-relay/src/input-field-builder.ts @@ -6,7 +6,6 @@ import { ObjectRef, SchemaTypes, } from '@pothos/core'; -import { NodeRef } from './node-ref'; import { GlobalIDInputFieldOptions, GlobalIDInputShape, @@ -37,7 +36,7 @@ inputFieldBuilder.globalIDList = function globalIDList[] )?.map((type: ObjectRef) => ({ typename: this.builder.configStore.getTypeConfig(type).name, - parseId: type instanceof NodeRef ? type.parseId : undefined, + parseId: 'parseId' in type ? type.parseId : undefined, })) ?? null, }, }) as never; @@ -60,7 +59,7 @@ inputFieldBuilder.globalID = function globalID( (Array.isArray(forTypes) ? forTypes : [forTypes])) as ObjectRef[] )?.map((type: ObjectRef) => ({ typename: this.builder.configStore.getTypeConfig(type).name, - parseId: type instanceof NodeRef ? type.parseId : undefined, + parseId: 'parseId' in type ? type.parseId : undefined, })) ?? null, }, }) as unknown as InputFieldRef< From 0b226b85d778ee1ae8b6f340b7ccd4073a9f92b0 Mon Sep 17 00:00:00 2001 From: Tim Griesser Date: Tue, 21 Feb 2023 13:47:51 -0500 Subject: [PATCH 2/6] Remove TODO --- packages/plugin-dataloader/tests/example/schema/nodes.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/plugin-dataloader/tests/example/schema/nodes.ts b/packages/plugin-dataloader/tests/example/schema/nodes.ts index ef5287efd..b0c153027 100644 --- a/packages/plugin-dataloader/tests/example/schema/nodes.ts +++ b/packages/plugin-dataloader/tests/example/schema/nodes.ts @@ -102,7 +102,6 @@ builder.queryFields((t) => ({ args: { ids: t.arg.globalIDList({ for: [LoadableParseRef] }), }, - // TODO: type & implement this correctly based on the "for" resolve: (source, args) => args.ids?.map((id) => id.id) ?? [], }), })); From 9d9369285066063d2ef95e8c10d382b15752e329 Mon Sep 17 00:00:00 2001 From: Tim Griesser Date: Tue, 21 Feb 2023 14:22:17 -0500 Subject: [PATCH 3/6] properly manage IDShape in generic slots --- .../plugin-dataloader/src/global-types.ts | 27 ++++++++++++++----- packages/plugin-dataloader/src/refs/node.ts | 9 ++++--- .../plugin-dataloader/src/schema-builder.ts | 7 ++--- packages/plugin-dataloader/src/types.ts | 7 ++--- 4 files changed, 34 insertions(+), 16 deletions(-) diff --git a/packages/plugin-dataloader/src/global-types.ts b/packages/plugin-dataloader/src/global-types.ts index 7f525cc71..118b29b98 100644 --- a/packages/plugin-dataloader/src/global-types.ts +++ b/packages/plugin-dataloader/src/global-types.ts @@ -81,10 +81,16 @@ declare global { options: DataLoaderOptions, ) => ImplementableLoadableInterfaceRef; - loadableNodeRef: ( + loadableNodeRef: < + Shape extends object, + IDShape extends bigint | number | string = string, + Key extends bigint | number | string = IDShape, + CacheKey = Key, + >( name: string, - options: DataLoaderOptions & LoadableNodeId, - ) => ImplementableLoadableNodeRef; + options: DataLoaderOptions & + LoadableNodeId, + ) => ImplementableLoadableNodeRef; loadableUnion: < Key extends bigint | number | string, @@ -101,15 +107,24 @@ declare global { Shape extends NameOrRef extends ObjectParam ? ShapeFromTypeParam : object, - Key extends bigint | number | string, Interfaces extends InterfaceParam[], NameOrRef extends ObjectParam | string, + IDShape extends bigint | number | string = string, + Key extends bigint | number | string = IDShape, CacheKey = Key, >( nameOrRef: NameOrRef, - options: LoadableNodeOptions, + options: LoadableNodeOptions< + Types, + Shape, + Interfaces, + NameOrRef, + IDShape, + Key, + CacheKey + >, ) => Omit< - ImplementableLoadableNodeRef, + ImplementableLoadableNodeRef, 'implement' > : '@pothos/plugin-relay is required to use this method'; diff --git a/packages/plugin-dataloader/src/refs/node.ts b/packages/plugin-dataloader/src/refs/node.ts index 5cea40288..67a675f37 100644 --- a/packages/plugin-dataloader/src/refs/node.ts +++ b/packages/plugin-dataloader/src/refs/node.ts @@ -7,10 +7,11 @@ export class ImplementableLoadableNodeRef< Types extends SchemaTypes, RefShape, Shape extends object, - Key extends bigint | number | string, - CacheKey, + IDShape extends bigint | number | string = string, + Key extends bigint | number | string = IDShape, + CacheKey = Key, > extends ImplementableLoadableObjectRef { - parseId: ((id: string, ctx: object) => Key) | undefined; + parseId: ((id: string, ctx: object) => IDShape) | undefined; private idOptions; constructor( @@ -19,7 +20,7 @@ export class ImplementableLoadableNodeRef< { id, ...options - }: DataLoaderOptions & LoadableNodeId, + }: DataLoaderOptions & LoadableNodeId, ) { super(builder, name, options); this.idOptions = id; diff --git a/packages/plugin-dataloader/src/schema-builder.ts b/packages/plugin-dataloader/src/schema-builder.ts index 7972702c6..0a67f9584 100644 --- a/packages/plugin-dataloader/src/schema-builder.ts +++ b/packages/plugin-dataloader/src/schema-builder.ts @@ -130,14 +130,15 @@ schemaBuilderProto.loadableNode = function loadableNode< Shape extends NameOrRef extends ObjectParam ? ShapeFromTypeParam : object, - Key extends DataloaderKey, Interfaces extends InterfaceParam[], NameOrRef extends ObjectParam | string, + IDShape extends bigint | number | string = string, + Key extends bigint | number | string = IDShape, CacheKey = Key, >( this: PothosSchemaTypes.SchemaBuilder, nameOrRef: NameOrRef, - options: LoadableNodeOptions, + options: LoadableNodeOptions, ) { if ( typeof (this as PothosSchemaTypes.SchemaBuilder & Record) @@ -153,7 +154,7 @@ schemaBuilderProto.loadableNode = function loadableNode< ? nameOrRef : (options as { name?: string }).name ?? (nameOrRef as { name: string }).name; - const ref = new ImplementableLoadableNodeRef( + const ref = new ImplementableLoadableNodeRef( this, name, options, diff --git a/packages/plugin-dataloader/src/types.ts b/packages/plugin-dataloader/src/types.ts index 85fbca566..744be6042 100644 --- a/packages/plugin-dataloader/src/types.ts +++ b/packages/plugin-dataloader/src/types.ts @@ -183,9 +183,10 @@ export interface LoadableNodeId[], NameOrRef extends ObjectParam | string, - CacheKey, + IDShape extends bigint | number | string = string, + Key extends bigint | number | string = IDShape, + CacheKey = Key, > = DataloaderObjectTypeOptions & - LoadableNodeId; + LoadableNodeId; From ea9baed6da9d42bbe3a418a73370d184051ad378 Mon Sep 17 00:00:00 2001 From: Michael Hayes Date: Thu, 23 Feb 2023 12:06:17 -1000 Subject: [PATCH 4/6] fix rebase --- packages/plugin-dataloader/tests/example/schema/nodes.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/plugin-dataloader/tests/example/schema/nodes.ts b/packages/plugin-dataloader/tests/example/schema/nodes.ts index e4ef9393b..aafbc4c92 100644 --- a/packages/plugin-dataloader/tests/example/schema/nodes.ts +++ b/packages/plugin-dataloader/tests/example/schema/nodes.ts @@ -41,7 +41,8 @@ const ClassThingRef = builder.loadableNode(ClassThing, { }, loaderOptions: { maxBatchSize: 20 }, // eslint-disable-next-line @typescript-eslint/require-await - load: async (keys, context: ContextType) => [new ClassThing()], + load: async (keys, context: ContextType) => + keys.map((k) => new ClassThing(Number.parseInt(k, 10))), fields: (t) => ({}), }); From aab5e5cbf848cd935dcf09a5ca2084ad08ae3a3e Mon Sep 17 00:00:00 2001 From: Michael Hayes Date: Thu, 23 Feb 2023 12:09:06 -1000 Subject: [PATCH 5/6] restore plugin order --- packages/plugin-dataloader/tests/example/builder.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-dataloader/tests/example/builder.ts b/packages/plugin-dataloader/tests/example/builder.ts index 19ddf9617..7c2d4baeb 100644 --- a/packages/plugin-dataloader/tests/example/builder.ts +++ b/packages/plugin-dataloader/tests/example/builder.ts @@ -11,7 +11,7 @@ export default new SchemaBuilder<{ Context: ContextType }>({ nodeQueryOptions: {}, nodesQueryOptions: {}, }, - plugins: [ErrorsPlugin, DataloaderPlugin, RelayPlugin], + plugins: [RelayPlugin, ErrorsPlugin, DataloaderPlugin], errorOptions: { defaultTypes: [Error], }, From 68c94e4f6c4e650cc6289c1fdd69399e0e72bef3 Mon Sep 17 00:00:00 2001 From: Michael Hayes Date: Thu, 23 Feb 2023 12:15:10 -1000 Subject: [PATCH 6/6] Add changeset --- .changeset/slimy-brooms-hunt.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/slimy-brooms-hunt.md diff --git a/.changeset/slimy-brooms-hunt.md b/.changeset/slimy-brooms-hunt.md new file mode 100644 index 000000000..1b26f2926 --- /dev/null +++ b/.changeset/slimy-brooms-hunt.md @@ -0,0 +1,7 @@ +--- +'@pothos/plugin-dataloader': minor +'@pothos/plugin-relay': minor +'@pothos/deno': minor +--- + +Support parsing globalIDs for loadableNode