Skip to content

Commit

Permalink
only parse when passing node refs
Browse files Browse the repository at this point in the history
  • Loading branch information
hayes committed Feb 7, 2023
1 parent f999beb commit 0737488
Show file tree
Hide file tree
Showing 12 changed files with 117 additions and 36 deletions.
10 changes: 8 additions & 2 deletions packages/deno/packages/plugin-relay/index.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 9 additions & 2 deletions packages/deno/packages/plugin-relay/input-field-builder.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 9 additions & 2 deletions packages/deno/packages/plugin-relay/node-ref.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion packages/deno/packages/plugin-relay/schema-builder.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 19 additions & 4 deletions packages/deno/packages/plugin-relay/utils/internal.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions packages/deno/packages/plugin-relay/utils/resolve-nodes.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions packages/plugin-relay/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ export class PothosRelayPlugin<Types extends SchemaTypes> extends BasePlugin<Typ
): GraphQLFieldResolver<unknown, Types['Context'], object> {
const argMappings = mapInputFields(fieldConfig.args, this.buildCache, (inputField) => {
if (inputField.extensions?.isRelayGlobalID) {
return (inputField.extensions?.relayGlobalIDFor ?? true) as true | string[];
return (inputField.extensions?.relayGlobalIDFor ?? true) as
| true
| { typename: string; parseId: (id: string, ctx: object) => unknown }[];
}

return null;
Expand Down Expand Up @@ -59,7 +61,9 @@ export class PothosRelayPlugin<Types extends SchemaTypes> extends BasePlugin<Typ
): GraphQLFieldResolver<unknown, Types['Context'], object> | undefined {
const argMappings = mapInputFields(fieldConfig.args, this.buildCache, (inputField) => {
if (inputField.extensions?.isRelayGlobalID) {
return (inputField.extensions?.relayGlobalIDFor ?? true) as true | string[];
return (inputField.extensions?.relayGlobalIDFor ?? true) as
| true
| { typename: string; parseId: (id: string, ctx: object) => unknown }[];
}

return null;
Expand Down
15 changes: 9 additions & 6 deletions packages/plugin-relay/src/input-field-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
ObjectRef,
SchemaTypes,
} from '@pothos/core';
import { NodeRef } from './node-ref';
import {
GlobalIDInputFieldOptions,
GlobalIDInputShape,
Expand Down Expand Up @@ -34,9 +35,10 @@ inputFieldBuilder.globalIDList = function globalIDList<Req extends FieldRequired
(
(forTypes &&
(Array.isArray(forTypes) ? forTypes : [forTypes])) as ObjectRef<SchemaTypes>[]
)?.map(
(type: ObjectRef<SchemaTypes>) => this.builder.configStore.getTypeConfig(type).name,
) ?? null,
)?.map((type: ObjectRef<SchemaTypes>) => ({
typename: this.builder.configStore.getTypeConfig(type).name,
parse: type instanceof NodeRef ? type.parseId : undefined,
})) ?? null,
},
}) as never;
};
Expand All @@ -56,9 +58,10 @@ inputFieldBuilder.globalID = function globalID<Req extends boolean>(
(
(forTypes &&
(Array.isArray(forTypes) ? forTypes : [forTypes])) as ObjectRef<SchemaTypes>[]
)?.map(
(type: ObjectRef<SchemaTypes>) => this.builder.configStore.getTypeConfig(type).name,
) ?? null,
)?.map((type: ObjectRef<SchemaTypes>) => ({
typename: this.builder.configStore.getTypeConfig(type).name,
parse: type instanceof NodeRef ? type.parseId : undefined,
})) ?? null,
},
}) as unknown as InputFieldRef<
InputShapeFromTypeParam<DefaultSchemaTypes, GlobalIDInputShape, Req>
Expand Down
15 changes: 13 additions & 2 deletions packages/plugin-relay/src/node-ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@ import { ObjectRef } from '@pothos/core';

export const relayIDShapeKey = Symbol.for('Pothos.relayIDShapeKey');

export class NodeRef<T, P = T, K = string> extends ObjectRef<T, P> {
[relayIDShapeKey]!: K;
export class NodeRef<T, P = T, IDShape = string> extends ObjectRef<T, P> {
[relayIDShapeKey]!: IDShape;
parseId: ((id: string, ctx: object) => IDShape) | undefined;

constructor(
name: string,
options: {
parseId?: (id: string, ctx: object) => IDShape;
},
) {
super(name);
this.parseId = options.parseId;
}
}
9 changes: 8 additions & 1 deletion packages/plugin-relay/src/schema-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import SchemaBuilder, {
SchemaTypes,
verifyRef,
} from '@pothos/core';
import { NodeRef } from './node-ref';
import { ConnectionShape, GlobalIDShape, PageInfoShape } from './types';
import { capitalize, resolveNodes } from './utils';

Expand Down Expand Up @@ -289,7 +290,13 @@ schemaBuilderProto.node = function node(param, { interfaces, extensions, id, ...
);
});

return ref as never;
const nodeRef = new NodeRef(ref.name, {
parseId: id.parse,
});

this.configStore.associateRefWithName(nodeRef, ref.name);

return nodeRef as never;
};

schemaBuilderProto.globalConnectionField = function globalConnectionField(name, field) {
Expand Down
24 changes: 20 additions & 4 deletions packages/plugin-relay/src/utils/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,33 @@ export function internalDecodeGlobalID<Types extends SchemaTypes>(
globalID: string,
ctx: object,
info: GraphQLResolveInfo,
parseIdsForTypes: boolean | string[],
parseIdsForTypes: boolean | { typename: string; parseId: (id: string, ctx: object) => unknown }[],
) {
const decoded = builder.options.relayOptions.decodeGlobalID
? builder.options.relayOptions.decodeGlobalID(globalID, ctx)
: decodeGlobalID(globalID);

if (Array.isArray(parseIdsForTypes) && !parseIdsForTypes.includes(decoded.typename)) {
throw new Error(`ID: ${globalID} is not of type: ${parseIdsForTypes.join(', ')}`);
if (Array.isArray(parseIdsForTypes)) {
const entry = parseIdsForTypes.find(({ typename }) => typename === decoded.typename);
if (!entry) {
throw new Error(
`ID: ${globalID} is not of type: ${parseIdsForTypes
.map(({ typename }) => typename)
.join(', ')}`,
);
}

if (entry.parseId) {
return {
...decoded,
id: entry.parseId(decoded.id, ctx),
};
}

return decoded;
}

if (parseIdsForTypes !== false) {
if (parseIdsForTypes) {
const parseID = info.schema.getType(decoded.typename)?.extensions?.pothosParseGlobalID as (
id: string,
ctx: object,
Expand Down
10 changes: 5 additions & 5 deletions packages/plugin-relay/src/utils/resolve-nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ export async function resolveNodes<Types extends SchemaTypes>(
builder: PothosSchemaTypes.SchemaBuilder<Types>,
context: object,
info: GraphQLResolveInfo,
globalIDs: ({ id: string; typename: string } | null | undefined)[],
globalIDs: ({ id: unknown; typename: string } | null | undefined)[],
): Promise<MaybePromise<unknown>[]> {
const requestCache = getRequestCache(context);
const idsByType: Record<string, Set<string>> = {};
const results: Record<string, unknown> = {};
const idsByType: Record<string, Set<unknown>> = {};
const results: Record<string, MaybePromise<unknown>> = {};

globalIDs.forEach((globalID, i) => {
if (globalID == null) {
Expand Down Expand Up @@ -74,12 +74,12 @@ export async function resolveUncachedNodesForType<Types extends SchemaTypes>(
builder: PothosSchemaTypes.SchemaBuilder<Types>,
context: object,
info: GraphQLResolveInfo,
ids: string[],
ids: unknown[],
type: OutputType<Types> | string,
): Promise<unknown[]> {
const requestCache = getRequestCache(context);
const config = builder.configStore.getTypeConfig(type, 'Object');
const options = config.pothosOptions as NodeObjectOptions<Types, ObjectParam<Types>, []>;
const options = config.pothosOptions as NodeObjectOptions<Types, ObjectParam<Types>, [], unknown>;

if (options.loadMany) {
const loadManyPromise = Promise.resolve(options.loadMany(ids, context));
Expand Down

0 comments on commit 0737488

Please sign in to comment.