@pothos/plugin-relay
Advanced tools
Comparing version 3.34.0 to 3.35.0
# Change Log | ||
## 3.35.0 | ||
### Minor Changes | ||
- 1c73b585: Add new parse option for id field on nodes, and a `for` option on globalID args | ||
- bf0385ae: Add new PothosError classes | ||
## 3.34.0 | ||
@@ -4,0 +11,0 @@ |
import { FieldKind, FieldNullability, FieldOptionsFromKind, FieldRef, FieldRequiredness, InputFieldMap, InputFieldRef, InputFieldsFromShape, InputShapeFromFields, InputShapeFromTypeParam, inputShapeKey, InterfaceParam, NormalizeArgs, ObjectFieldsShape, ObjectFieldThunk, ObjectParam, OutputShape, OutputType, ParentShape, Resolver, SchemaTypes, ShapeFromTypeParam } from '@pothos/core'; | ||
import { NodeRef } from './node-ref'; | ||
import { ConnectionShape, ConnectionShapeForType, ConnectionShapeFromResolve, GlobalIDFieldOptions, GlobalIDInputFieldOptions, GlobalIDInputShape, GlobalIDListFieldOptions, GlobalIDListInputFieldOptions, GlobalIDShape, InputShapeWithClientMutationId, NodeFieldOptions, NodeListFieldOptions, NodeObjectOptions, PageInfoShape, RelayMutationFieldOptions, RelayMutationInputOptions, RelayMutationPayloadOptions, RelayPluginOptions } from './types'; | ||
@@ -27,3 +28,3 @@ import type { DefaultEdgesNullability, PothosRelayPlugin } from '.'; | ||
nodeInterfaceRef: () => InterfaceRef<unknown>; | ||
node: <Interfaces extends InterfaceParam<Types>[], Param extends ObjectParam<Types>>(param: Param, options: NodeObjectOptions<Types, Param, Interfaces>, fields?: ObjectFieldsShape<Types, ParentShape<Types, Param>>) => ObjectRef<OutputShape<Types, Param>, ParentShape<Types, Param>>; | ||
node: <Interfaces extends InterfaceParam<Types>[], Param extends ObjectParam<Types>, IDShape = string>(param: Param, options: NodeObjectOptions<Types, Param, Interfaces, IDShape>, fields?: ObjectFieldsShape<Types, ParentShape<Types, Param>>) => NodeRef<OutputShape<Types, Param>, ParentShape<Types, Param>, IDShape>; | ||
globalConnectionFields: (fields: ObjectFieldsShape<Types, ConnectionShape<Types, {}, false>>) => void; | ||
@@ -59,8 +60,8 @@ globalConnectionField: (name: string, field: ObjectFieldThunk<Types, ConnectionShape<Types, {}, false>>) => void; | ||
}; | ||
globalID: <Req extends boolean>(...args: NormalizeArgs<[options: GlobalIDInputFieldOptions<Types, Req, Kind>]>) => InputFieldRef<InputShapeFromTypeParam<Types, GlobalIDInputShape, Req>, Kind>; | ||
globalIDList: <Req extends FieldRequiredness<['ID']>>(...args: NormalizeArgs<[options: GlobalIDListInputFieldOptions<Types, Req, Kind>]>) => InputFieldRef<InputShapeFromTypeParam<Types, [ | ||
globalID: <Req extends boolean, For extends ObjectParam<Types>>(...args: NormalizeArgs<[options: GlobalIDInputFieldOptions<Types, Req, Kind, For>]>) => InputFieldRef<InputShapeFromTypeParam<Types, GlobalIDInputShape<For extends NodeRef<unknown, unknown, infer T> ? T : string>, Req>, Kind>; | ||
globalIDList: <Req extends FieldRequiredness<['ID']>, For extends ObjectParam<Types>>(...args: NormalizeArgs<[options: GlobalIDListInputFieldOptions<Types, Req, Kind, For>]>) => InputFieldRef<InputShapeFromTypeParam<Types, [ | ||
{ | ||
[inputShapeKey]: { | ||
typename: string; | ||
id: string; | ||
id: For extends NodeRef<unknown, unknown, infer T> ? T : string; | ||
}; | ||
@@ -67,0 +68,0 @@ } |
@@ -7,2 +7,3 @@ import './global-types'; | ||
import { BasePlugin, PothosOutputFieldConfig, SchemaTypes } from '@pothos/core'; | ||
export * from './node-ref'; | ||
export * from './types'; | ||
@@ -9,0 +10,0 @@ export * from './utils'; |
@@ -111,9 +111,11 @@ import { GraphQLResolveInfo } from 'graphql'; | ||
export type NodeBaseObjectOptionsForParam<Types extends SchemaTypes, Param extends ObjectParam<Types>, Interfaces extends InterfaceParam<Types>[]> = ObjectTypeOptions<Types, Param, ParentShape<Types, Param>, Interfaces>; | ||
export type NodeObjectOptions<Types extends SchemaTypes, Param extends ObjectParam<Types>, Interfaces extends InterfaceParam<Types>[]> = NodeBaseObjectOptionsForParam<Types, Param, Interfaces> & { | ||
id: Omit<FieldOptionsFromKind<Types, ParentShape<Types, Param>, 'ID', false, {}, 'Object', OutputShape<Types, 'ID'>, MaybePromise<OutputShape<Types, 'ID'>>>, 'args' | 'nullable' | 'type'>; | ||
export type NodeObjectOptions<Types extends SchemaTypes, Param extends ObjectParam<Types>, Interfaces extends InterfaceParam<Types>[], IDShape = string> = NodeBaseObjectOptionsForParam<Types, Param, Interfaces> & { | ||
id: Omit<FieldOptionsFromKind<Types, ParentShape<Types, Param>, 'ID', false, {}, 'Object', OutputShape<Types, 'ID'>, MaybePromise<OutputShape<Types, 'ID'>>>, 'args' | 'nullable' | 'type'> & { | ||
parse?: (id: string, ctx: Types['Context']) => IDShape; | ||
}; | ||
brandLoadedObjects?: boolean; | ||
loadOne?: (id: string, context: Types['Context']) => MaybePromise<OutputShape<Types, Param> | null | undefined>; | ||
loadMany?: (ids: string[], context: Types['Context']) => MaybePromise<MaybePromise<OutputShape<Types, Param> | null | undefined>[]>; | ||
loadWithoutCache?: (id: string, context: Types['Context'], info: GraphQLResolveInfo) => MaybePromise<OutputShape<Types, Param> | null | undefined>; | ||
loadManyWithoutCache?: (ids: string[], context: Types['Context']) => MaybePromise<MaybePromise<OutputShape<Types, Param> | null | undefined>[]>; | ||
loadOne?: (id: IDShape, context: Types['Context']) => MaybePromise<OutputShape<Types, Param> | null | undefined>; | ||
loadMany?: (ids: IDShape[], context: Types['Context']) => MaybePromise<MaybePromise<OutputShape<Types, Param> | null | undefined>[]>; | ||
loadWithoutCache?: (id: IDShape, context: Types['Context'], info: GraphQLResolveInfo) => MaybePromise<OutputShape<Types, Param> | null | undefined>; | ||
loadManyWithoutCache?: (ids: IDShape[], context: Types['Context']) => MaybePromise<MaybePromise<OutputShape<Types, Param> | null | undefined>[]>; | ||
}; | ||
@@ -123,4 +125,8 @@ export type GlobalIDFieldOptions<Types extends SchemaTypes, ParentShape, Args extends InputFieldMap, Nullable extends boolean, ResolveReturnShape, Kind extends FieldKind = FieldKind> = Omit<FieldOptionsFromKind<Types, ParentShape, 'ID', Nullable, Args, Kind, ParentShape, ResolveReturnShape>, 'resolve' | 'type'> & { | ||
}; | ||
export type GlobalIDInputFieldOptions<Types extends SchemaTypes, Req extends boolean, Kind extends 'Arg' | 'InputObject'> = Omit<PothosSchemaTypes.InputFieldOptionsByKind<Types, 'ID', Req>[Kind], 'type'>; | ||
export type GlobalIDListInputFieldOptions<Types extends SchemaTypes, Req extends FieldRequiredness<['ID']>, Kind extends 'Arg' | 'InputObject'> = Omit<PothosSchemaTypes.InputFieldOptionsByKind<Types, ['ID'], Req>[Kind], 'type'>; | ||
export type GlobalIDInputFieldOptions<Types extends SchemaTypes, Req extends boolean, Kind extends 'Arg' | 'InputObject', For = unknown> = Omit<PothosSchemaTypes.InputFieldOptionsByKind<Types, 'ID', Req>[Kind], 'type'> & { | ||
for?: For | For[]; | ||
}; | ||
export type GlobalIDListInputFieldOptions<Types extends SchemaTypes, Req extends FieldRequiredness<['ID']>, Kind extends 'Arg' | 'InputObject', For = unknown> = Omit<PothosSchemaTypes.InputFieldOptionsByKind<Types, ['ID'], Req>[Kind], 'type'> & { | ||
for?: For | For[]; | ||
}; | ||
export type NodeIDFieldOptions<Types extends SchemaTypes, ParentShape, Args extends InputFieldMap, Nullable extends boolean, ResolveReturnShape, Kind extends FieldKind = FieldKind> = Omit<FieldOptionsFromKind<Types, ParentShape, 'ID', Nullable, Args, Kind, ParentShape, ResolveReturnShape>, 'resolve' | 'type'> & { | ||
@@ -155,6 +161,6 @@ resolve: Resolver<ParentShape, InputShapeFromFields<Args>, Types['Context'], ShapeFromTypeParam<Types, OutputRefShape<GlobalIDShape<Types> | string>, true>, ResolveReturnShape>; | ||
}; | ||
export interface GlobalIDInputShape { | ||
export interface GlobalIDInputShape<T = string> { | ||
[inputShapeKey]: { | ||
typename: string; | ||
id: string; | ||
id: T; | ||
}; | ||
@@ -161,0 +167,0 @@ } |
@@ -0,7 +1,11 @@ | ||
import { GraphQLResolveInfo } from 'graphql'; | ||
import { SchemaTypes } from '@pothos/core'; | ||
export declare function internalEncodeGlobalID<Types extends SchemaTypes>(builder: PothosSchemaTypes.SchemaBuilder<Types>, typename: string, id: bigint | number | string, ctx: object): string; | ||
export declare function internalDecodeGlobalID<Types extends SchemaTypes>(builder: PothosSchemaTypes.SchemaBuilder<Types>, globalID: string, ctx: object): { | ||
export declare function internalDecodeGlobalID<Types extends SchemaTypes>(builder: PothosSchemaTypes.SchemaBuilder<Types>, globalID: string, ctx: object, info: GraphQLResolveInfo, parseIdsForTypes: boolean | { | ||
typename: string; | ||
id: string; | ||
parseId: (id: string, ctx: object) => unknown; | ||
}[]): { | ||
id: unknown; | ||
typename: string; | ||
}; | ||
//# sourceMappingURL=internal.d.ts.map |
import { GraphQLResolveInfo } from 'graphql'; | ||
import { MaybePromise, OutputType, SchemaTypes } from '@pothos/core'; | ||
export declare function resolveNodes<Types extends SchemaTypes>(builder: PothosSchemaTypes.SchemaBuilder<Types>, context: object, info: GraphQLResolveInfo, globalIDs: ({ | ||
id: string; | ||
id: unknown; | ||
typename: string; | ||
} | null | undefined)[]): Promise<MaybePromise<unknown>[]>; | ||
export declare function resolveUncachedNodesForType<Types extends SchemaTypes>(builder: PothosSchemaTypes.SchemaBuilder<Types>, context: object, info: GraphQLResolveInfo, ids: string[], type: OutputType<Types> | string): Promise<unknown[]>; | ||
export declare function resolveUncachedNodesForType<Types extends SchemaTypes>(builder: PothosSchemaTypes.SchemaBuilder<Types>, context: object, info: GraphQLResolveInfo, ids: unknown[], type: OutputType<Types> | string): Promise<unknown[]>; | ||
//# sourceMappingURL=resolve-nodes.d.ts.map |
@@ -50,3 +50,3 @@ import { assertArray, ObjectRef, RootFieldBuilder } from '@pothos/core'; | ||
} | ||
const globalID = typeof rawID === "string" ? internalDecodeGlobalID(this.builder, rawID, context) : rawID && { | ||
const globalID = typeof rawID === "string" ? internalDecodeGlobalID(this.builder, rawID, context, info, true) : rawID && { | ||
id: String(rawID.id), | ||
@@ -78,3 +78,3 @@ typename: this.builder.configStore.getTypeConfig(rawID.type).name | ||
const rawIds = await Promise.all(rawIDList); | ||
const globalIds = rawIds.map((id) => typeof id === "string" ? internalDecodeGlobalID(this.builder, id, context) : id && { | ||
const globalIds = rawIds.map((id) => typeof id === "string" ? internalDecodeGlobalID(this.builder, id, context, info, true) : id && { | ||
id: String(id.id), | ||
@@ -81,0 +81,0 @@ typename: this.builder.configStore.getTypeConfig(id.type).name |
import { FieldKind, FieldNullability, FieldOptionsFromKind, FieldRef, FieldRequiredness, InputFieldMap, InputFieldRef, InputFieldsFromShape, InputShapeFromFields, InputShapeFromTypeParam, inputShapeKey, InterfaceParam, NormalizeArgs, ObjectFieldsShape, ObjectFieldThunk, ObjectParam, OutputShape, OutputType, ParentShape, Resolver, SchemaTypes, ShapeFromTypeParam } from '@pothos/core'; | ||
import { NodeRef } from './node-ref.js'; | ||
import { ConnectionShape, ConnectionShapeForType, ConnectionShapeFromResolve, GlobalIDFieldOptions, GlobalIDInputFieldOptions, GlobalIDInputShape, GlobalIDListFieldOptions, GlobalIDListInputFieldOptions, GlobalIDShape, InputShapeWithClientMutationId, NodeFieldOptions, NodeListFieldOptions, NodeObjectOptions, PageInfoShape, RelayMutationFieldOptions, RelayMutationInputOptions, RelayMutationPayloadOptions, RelayPluginOptions } from './types.js'; | ||
@@ -31,3 +32,3 @@ import type { DefaultEdgesNullability, PothosRelayPlugin } from './index.js'; | ||
nodeInterfaceRef: () => InterfaceRef<unknown>; | ||
node: <Interfaces extends InterfaceParam<Types>[], Param extends ObjectParam<Types>>(param: Param, options: NodeObjectOptions<Types, Param, Interfaces>, fields?: ObjectFieldsShape<Types, ParentShape<Types, Param>>) => ObjectRef<OutputShape<Types, Param>, ParentShape<Types, Param>>; | ||
node: <Interfaces extends InterfaceParam<Types>[], Param extends ObjectParam<Types>, IDShape = string>(param: Param, options: NodeObjectOptions<Types, Param, Interfaces, IDShape>, fields?: ObjectFieldsShape<Types, ParentShape<Types, Param>>) => NodeRef<OutputShape<Types, Param>, ParentShape<Types, Param>, IDShape>; | ||
globalConnectionFields: (fields: ObjectFieldsShape<Types, ConnectionShape<Types, {}, false>>) => void; | ||
@@ -68,9 +69,9 @@ globalConnectionField: (name: string, field: ObjectFieldThunk<Types, ConnectionShape<Types, {}, false>>) => void; | ||
}; | ||
globalID: <Req extends boolean>(...args: NormalizeArgs<[ | ||
options: GlobalIDInputFieldOptions<Types, Req, Kind> | ||
]>) => InputFieldRef<InputShapeFromTypeParam<Types, GlobalIDInputShape, Req>, Kind>; | ||
globalID: <Req extends boolean, For extends ObjectParam<Types>>(...args: NormalizeArgs<[ | ||
options: GlobalIDInputFieldOptions<Types, Req, Kind, For> | ||
]>) => InputFieldRef<InputShapeFromTypeParam<Types, GlobalIDInputShape<For extends NodeRef<unknown, unknown, infer T> ? T : string>, Req>, Kind>; | ||
globalIDList: <Req extends FieldRequiredness<[ | ||
"ID" | ||
]>>(...args: NormalizeArgs<[ | ||
options: GlobalIDListInputFieldOptions<Types, Req, Kind> | ||
]>, For extends ObjectParam<Types>>(...args: NormalizeArgs<[ | ||
options: GlobalIDListInputFieldOptions<Types, Req, Kind, For> | ||
]>) => InputFieldRef<InputShapeFromTypeParam<Types, [ | ||
@@ -80,3 +81,3 @@ { | ||
typename: string; | ||
id: string; | ||
id: For extends NodeRef<unknown, unknown, infer T> ? T : string; | ||
}; | ||
@@ -83,0 +84,0 @@ } |
@@ -7,2 +7,3 @@ import './global-types.js'; | ||
import { BasePlugin, PothosOutputFieldConfig, SchemaTypes } from '@pothos/core'; | ||
export * from './node-ref.js'; | ||
export * from './types.js'; | ||
@@ -9,0 +10,0 @@ export * from './utils/index.js'; |
@@ -7,2 +7,3 @@ import './global-types.js'; | ||
import { internalDecodeGlobalID } from './utils/internal.js'; | ||
export * from './node-ref.js'; | ||
export * from './types.js'; | ||
@@ -17,3 +18,5 @@ export * from './utils/index.js'; | ||
if ((_inputField_extensions = inputField.extensions) === null || _inputField_extensions === void 0 ? void 0 : _inputField_extensions.isRelayGlobalID) { | ||
return true; | ||
var _inputField_extensions1; | ||
var _inputField_extensions_relayGlobalIDFor; | ||
return (_inputField_extensions_relayGlobalIDFor = (_inputField_extensions1 = inputField.extensions) === null || _inputField_extensions1 === void 0 ? void 0 : _inputField_extensions1.relayGlobalIDFor) !== null && _inputField_extensions_relayGlobalIDFor !== void 0 ? _inputField_extensions_relayGlobalIDFor : true; | ||
} | ||
@@ -25,4 +28,4 @@ return null; | ||
} | ||
const argMapper = createInputValueMapper(argMappings, (globalID, mappings, ctx) => internalDecodeGlobalID(this.builder, String(globalID), ctx)); | ||
return (parent, args, context, info) => resolver(parent, argMapper(args, undefined, context), context, info); | ||
const argMapper = createInputValueMapper(argMappings, (globalID, mappings, ctx, info) => internalDecodeGlobalID(this.builder, String(globalID), ctx, info, Array.isArray(mappings.value) ? mappings.value : false)); | ||
return (parent, args, context, info) => resolver(parent, argMapper(args, undefined, context, info), context, info); | ||
} | ||
@@ -33,3 +36,5 @@ wrapSubscribe(subscribe, fieldConfig) { | ||
if ((_inputField_extensions = inputField.extensions) === null || _inputField_extensions === void 0 ? void 0 : _inputField_extensions.isRelayGlobalID) { | ||
return true; | ||
var _inputField_extensions1; | ||
var _inputField_extensions_relayGlobalIDFor; | ||
return (_inputField_extensions_relayGlobalIDFor = (_inputField_extensions1 = inputField.extensions) === null || _inputField_extensions1 === void 0 ? void 0 : _inputField_extensions1.relayGlobalIDFor) !== null && _inputField_extensions_relayGlobalIDFor !== void 0 ? _inputField_extensions_relayGlobalIDFor : true; | ||
} | ||
@@ -41,4 +46,4 @@ return null; | ||
} | ||
const argMapper = createInputValueMapper(argMappings, (globalID, mappings, ctx) => internalDecodeGlobalID(this.builder, String(globalID), ctx)); | ||
return (parent, args, context, info) => subscribe(parent, argMapper(args, undefined, context), context, info); | ||
const argMapper = createInputValueMapper(argMappings, (globalID, mappings, ctx, info) => internalDecodeGlobalID(this.builder, String(globalID), ctx, info, Array.isArray(mappings.value) ? mappings.value : false)); | ||
return (parent, args, context, info) => subscribe(parent, argMapper(args, undefined, context, info), context, info); | ||
} | ||
@@ -45,0 +50,0 @@ } |
import { InputFieldBuilder } from '@pothos/core'; | ||
import { NodeRef } from './node-ref.js'; | ||
const inputFieldBuilder = InputFieldBuilder.prototype; | ||
inputFieldBuilder.globalIDList = function globalIDList(options = {}) { | ||
inputFieldBuilder.globalIDList = function globalIDList({ for: forTypes, ...options } = {}) { | ||
var _ref; | ||
var _map; | ||
return this.idList({ | ||
@@ -8,7 +11,15 @@ ...options, | ||
...options.extensions, | ||
isRelayGlobalID: true | ||
isRelayGlobalID: true, | ||
relayGlobalIDFor: (_map = (_ref = forTypes && (Array.isArray(forTypes) ? forTypes : [ | ||
forTypes | ||
])) === null || _ref === void 0 ? void 0 : _ref.map((type) => ({ | ||
typename: this.builder.configStore.getTypeConfig(type).name, | ||
parse: type instanceof NodeRef ? type.parseId : undefined | ||
}))) !== null && _map !== void 0 ? _map : null | ||
} | ||
}); | ||
}; | ||
inputFieldBuilder.globalID = function globalID(options = {}) { | ||
inputFieldBuilder.globalID = function globalID({ for: forTypes, ...options } = {}) { | ||
var _ref; | ||
var _map; | ||
return this.id({ | ||
@@ -18,3 +29,9 @@ ...options, | ||
...options.extensions, | ||
isRelayGlobalID: true | ||
isRelayGlobalID: true, | ||
relayGlobalIDFor: (_map = (_ref = forTypes && (Array.isArray(forTypes) ? forTypes : [ | ||
forTypes | ||
])) === null || _ref === void 0 ? void 0 : _ref.map((type) => ({ | ||
typename: this.builder.configStore.getTypeConfig(type).name, | ||
parse: type instanceof NodeRef ? type.parseId : undefined | ||
}))) !== null && _map !== void 0 ? _map : null | ||
} | ||
@@ -21,0 +38,0 @@ }); |
import { defaultTypeResolver } from 'graphql'; | ||
import SchemaBuilder, { createContextCache, getTypeBrand, InputObjectRef, ObjectRef, verifyRef } from '@pothos/core'; | ||
import SchemaBuilder, { createContextCache, getTypeBrand, InputObjectRef, ObjectRef, PothosValidationError, verifyRef } from '@pothos/core'; | ||
import { NodeRef } from './node-ref.js'; | ||
import { capitalize, resolveNodes } from './utils/index.js'; | ||
@@ -88,3 +89,3 @@ const schemaBuilderProto = SchemaBuilder.prototype; | ||
resolve: (parent) => { | ||
throw new Error("id field not implemented"); | ||
throw new PothosValidationError("id field not implemented"); | ||
} | ||
@@ -136,3 +137,3 @@ }) | ||
}; | ||
schemaBuilderProto.node = function node(param, { interfaces, ...options }, fields) { | ||
schemaBuilderProto.node = function node(param, { interfaces, extensions, id, ...options }, fields) { | ||
verifyRef(param); | ||
@@ -147,2 +148,6 @@ const interfacesWithNode = () => [ | ||
...options, | ||
extensions: { | ||
...extensions, | ||
pothosParseGlobalID: id.parse | ||
}, | ||
isTypeOf: (_options_isTypeOf = options.isTypeOf) !== null && _options_isTypeOf !== void 0 ? _options_isTypeOf : typeof param === "function" ? (maybeNode, context, info) => { | ||
@@ -175,3 +180,3 @@ if (!maybeNode) { | ||
...this.options.relayOptions.idFieldOptions, | ||
...options.id, | ||
...id, | ||
args: {}, | ||
@@ -181,7 +186,11 @@ resolve: async (parent, args, context, info) => ({ | ||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument | ||
id: await options.id.resolve(parent, args, context, info) | ||
id: await id.resolve(parent, args, context, info) | ||
}) | ||
})); | ||
}); | ||
return ref; | ||
const nodeRef = new NodeRef(ref.name, { | ||
parseId: id.parse | ||
}); | ||
this.configStore.associateRefWithName(nodeRef, ref.name); | ||
return nodeRef; | ||
}; | ||
@@ -188,0 +197,0 @@ schemaBuilderProto.globalConnectionField = function globalConnectionField(name, field) { |
@@ -119,9 +119,11 @@ import { GraphQLResolveInfo } from 'graphql'; | ||
export type NodeBaseObjectOptionsForParam<Types extends SchemaTypes, Param extends ObjectParam<Types>, Interfaces extends InterfaceParam<Types>[]> = ObjectTypeOptions<Types, Param, ParentShape<Types, Param>, Interfaces>; | ||
export type NodeObjectOptions<Types extends SchemaTypes, Param extends ObjectParam<Types>, Interfaces extends InterfaceParam<Types>[]> = NodeBaseObjectOptionsForParam<Types, Param, Interfaces> & { | ||
id: Omit<FieldOptionsFromKind<Types, ParentShape<Types, Param>, "ID", false, {}, "Object", OutputShape<Types, "ID">, MaybePromise<OutputShape<Types, "ID">>>, "args" | "nullable" | "type">; | ||
export type NodeObjectOptions<Types extends SchemaTypes, Param extends ObjectParam<Types>, Interfaces extends InterfaceParam<Types>[], IDShape = string> = NodeBaseObjectOptionsForParam<Types, Param, Interfaces> & { | ||
id: Omit<FieldOptionsFromKind<Types, ParentShape<Types, Param>, "ID", false, {}, "Object", OutputShape<Types, "ID">, MaybePromise<OutputShape<Types, "ID">>>, "args" | "nullable" | "type"> & { | ||
parse?: (id: string, ctx: Types["Context"]) => IDShape; | ||
}; | ||
brandLoadedObjects?: boolean; | ||
loadOne?: (id: string, context: Types["Context"]) => MaybePromise<OutputShape<Types, Param> | null | undefined>; | ||
loadMany?: (ids: string[], context: Types["Context"]) => MaybePromise<MaybePromise<OutputShape<Types, Param> | null | undefined>[]>; | ||
loadWithoutCache?: (id: string, context: Types["Context"], info: GraphQLResolveInfo) => MaybePromise<OutputShape<Types, Param> | null | undefined>; | ||
loadManyWithoutCache?: (ids: string[], context: Types["Context"]) => MaybePromise<MaybePromise<OutputShape<Types, Param> | null | undefined>[]>; | ||
loadOne?: (id: IDShape, context: Types["Context"]) => MaybePromise<OutputShape<Types, Param> | null | undefined>; | ||
loadMany?: (ids: IDShape[], context: Types["Context"]) => MaybePromise<MaybePromise<OutputShape<Types, Param> | null | undefined>[]>; | ||
loadWithoutCache?: (id: IDShape, context: Types["Context"], info: GraphQLResolveInfo) => MaybePromise<OutputShape<Types, Param> | null | undefined>; | ||
loadManyWithoutCache?: (ids: IDShape[], context: Types["Context"]) => MaybePromise<MaybePromise<OutputShape<Types, Param> | null | undefined>[]>; | ||
}; | ||
@@ -131,8 +133,12 @@ export type GlobalIDFieldOptions<Types extends SchemaTypes, ParentShape, Args extends InputFieldMap, Nullable extends boolean, ResolveReturnShape, Kind extends FieldKind = FieldKind> = Omit<FieldOptionsFromKind<Types, ParentShape, "ID", Nullable, Args, Kind, ParentShape, ResolveReturnShape>, "resolve" | "type"> & { | ||
}; | ||
export type GlobalIDInputFieldOptions<Types extends SchemaTypes, Req extends boolean, Kind extends "Arg" | "InputObject"> = Omit<PothosSchemaTypes.InputFieldOptionsByKind<Types, "ID", Req>[Kind], "type">; | ||
export type GlobalIDInputFieldOptions<Types extends SchemaTypes, Req extends boolean, Kind extends "Arg" | "InputObject", For = unknown> = Omit<PothosSchemaTypes.InputFieldOptionsByKind<Types, "ID", Req>[Kind], "type"> & { | ||
for?: For | For[]; | ||
}; | ||
export type GlobalIDListInputFieldOptions<Types extends SchemaTypes, Req extends FieldRequiredness<[ | ||
"ID" | ||
]>, Kind extends "Arg" | "InputObject"> = Omit<PothosSchemaTypes.InputFieldOptionsByKind<Types, [ | ||
]>, Kind extends "Arg" | "InputObject", For = unknown> = Omit<PothosSchemaTypes.InputFieldOptionsByKind<Types, [ | ||
"ID" | ||
], Req>[Kind], "type">; | ||
], Req>[Kind], "type"> & { | ||
for?: For | For[]; | ||
}; | ||
export type NodeIDFieldOptions<Types extends SchemaTypes, ParentShape, Args extends InputFieldMap, Nullable extends boolean, ResolveReturnShape, Kind extends FieldKind = FieldKind> = Omit<FieldOptionsFromKind<Types, ParentShape, "ID", Nullable, Args, Kind, ParentShape, ResolveReturnShape>, "resolve" | "type"> & { | ||
@@ -169,6 +175,6 @@ resolve: Resolver<ParentShape, InputShapeFromFields<Args>, Types["Context"], ShapeFromTypeParam<Types, OutputRefShape<GlobalIDShape<Types> | string>, true>, ResolveReturnShape>; | ||
}; | ||
export interface GlobalIDInputShape { | ||
export interface GlobalIDInputShape<T = string> { | ||
[inputShapeKey]: { | ||
typename: string; | ||
id: string; | ||
id: T; | ||
}; | ||
@@ -175,0 +181,0 @@ } |
@@ -1,2 +0,2 @@ | ||
import { decodeBase64, encodeBase64 } from '@pothos/core'; | ||
import { decodeBase64, encodeBase64, PothosValidationError } from '@pothos/core'; | ||
const OFFSET_CURSOR_PREFIX = "OffsetConnection:"; | ||
@@ -14,6 +14,6 @@ const DEFAULT_MAX_SIZE = 100; | ||
if (first != null && first < 0) { | ||
throw new TypeError("Argument \"first\" must be a non-negative integer"); | ||
throw new PothosValidationError("Argument \"first\" must be a non-negative integer"); | ||
} | ||
if (last != null && last < 0) { | ||
throw new Error("Argument \"last\" must be a non-negative integer"); | ||
throw new PothosValidationError("Argument \"last\" must be a non-negative integer"); | ||
} | ||
@@ -27,3 +27,3 @@ let startOffset = after ? afterOffset + 1 : 0; | ||
if (endOffset === Number.POSITIVE_INFINITY) { | ||
throw new Error("Argument \"last\" can only be used in combination with \"before\" or \"first\""); | ||
throw new PothosValidationError("Argument \"last\" can only be used in combination with \"before\" or \"first\""); | ||
} | ||
@@ -70,3 +70,3 @@ startOffset = Math.max(startOffset, endOffset - last); | ||
if (!string.startsWith(OFFSET_CURSOR_PREFIX)) { | ||
throw new Error(`Invalid offset cursor ${OFFSET_CURSOR_PREFIX}`); | ||
throw new PothosValidationError(`Invalid offset cursor ${OFFSET_CURSOR_PREFIX}`); | ||
} | ||
@@ -103,6 +103,6 @@ return Number.parseInt(string.slice(OFFSET_CURSOR_PREFIX.length), 10); | ||
if (first != null && first < 0) { | ||
throw new TypeError("Argument \"first\" must be a non-negative integer"); | ||
throw new PothosValidationError("Argument \"first\" must be a non-negative integer"); | ||
} | ||
if (last != null && last < 0) { | ||
throw new Error("Argument \"last\" must be a non-negative integer"); | ||
throw new PothosValidationError("Argument \"last\" must be a non-negative integer"); | ||
} | ||
@@ -109,0 +109,0 @@ var _ref; |
@@ -1,2 +0,2 @@ | ||
import { decodeBase64, encodeBase64 } from '@pothos/core'; | ||
import { decodeBase64, encodeBase64, PothosValidationError } from '@pothos/core'; | ||
export function encodeGlobalID(typename, id) { | ||
@@ -8,3 +8,3 @@ return encodeBase64(`${typename}:${id}`); | ||
if (!typename || !id) { | ||
throw new TypeError(`Invalid global ID: ${globalID}`); | ||
throw new PothosValidationError(`Invalid global ID: ${globalID}`); | ||
} | ||
@@ -11,0 +11,0 @@ return { |
@@ -0,7 +1,11 @@ | ||
import { GraphQLResolveInfo } from 'graphql'; | ||
import { SchemaTypes } from '@pothos/core'; | ||
export declare function internalEncodeGlobalID<Types extends SchemaTypes>(builder: PothosSchemaTypes.SchemaBuilder<Types>, typename: string, id: bigint | number | string, ctx: object): string; | ||
export declare function internalDecodeGlobalID<Types extends SchemaTypes>(builder: PothosSchemaTypes.SchemaBuilder<Types>, globalID: string, ctx: object): { | ||
export declare function internalDecodeGlobalID<Types extends SchemaTypes>(builder: PothosSchemaTypes.SchemaBuilder<Types>, globalID: string, ctx: object, info: GraphQLResolveInfo, parseIdsForTypes: boolean | { | ||
typename: string; | ||
id: string; | ||
parseId: (id: string, ctx: object) => unknown; | ||
}[]): { | ||
id: unknown; | ||
typename: string; | ||
}; | ||
//# sourceMappingURL=internal.d.ts.map |
@@ -0,1 +1,2 @@ | ||
import { PothosValidationError } from '@pothos/core'; | ||
import { decodeGlobalID, encodeGlobalID } from './global-ids.js'; | ||
@@ -8,8 +9,29 @@ export function internalEncodeGlobalID(builder, typename, id, ctx) { | ||
} | ||
export function internalDecodeGlobalID(builder, globalID, ctx) { | ||
if (builder.options.relayOptions.decodeGlobalID) { | ||
return builder.options.relayOptions.decodeGlobalID(globalID, ctx); | ||
export function internalDecodeGlobalID(builder, globalID, ctx, info, parseIdsForTypes) { | ||
const decoded = builder.options.relayOptions.decodeGlobalID ? builder.options.relayOptions.decodeGlobalID(globalID, ctx) : decodeGlobalID(globalID); | ||
if (Array.isArray(parseIdsForTypes)) { | ||
const entry = parseIdsForTypes.find(({ typename }) => typename === decoded.typename); | ||
if (!entry) { | ||
throw new PothosValidationError(`ID: ${globalID} is not of type: ${parseIdsForTypes.map(({ typename }) => typename).join(", ")}`); | ||
} | ||
if (entry.parseId) { | ||
return { | ||
...decoded, | ||
id: entry.parseId(decoded.id, ctx) | ||
}; | ||
} | ||
return decoded; | ||
} | ||
return decodeGlobalID(globalID); | ||
if (parseIdsForTypes) { | ||
var _info_schema_getType, _info_schema_getType_extensions; | ||
const parseID = (_info_schema_getType = info.schema.getType(decoded.typename)) === null || _info_schema_getType === void 0 ? void 0 : (_info_schema_getType_extensions = _info_schema_getType.extensions) === null || _info_schema_getType_extensions === void 0 ? void 0 : _info_schema_getType_extensions.pothosParseGlobalID; | ||
if (parseID) { | ||
return { | ||
...decoded, | ||
id: parseID(decoded.id, ctx) | ||
}; | ||
} | ||
} | ||
return decoded; | ||
} | ||
//# sourceMappingURL=internal.js.map |
import { GraphQLResolveInfo } from 'graphql'; | ||
import { MaybePromise, OutputType, SchemaTypes } from '@pothos/core'; | ||
export declare function resolveNodes<Types extends SchemaTypes>(builder: PothosSchemaTypes.SchemaBuilder<Types>, context: object, info: GraphQLResolveInfo, globalIDs: ({ | ||
id: string; | ||
id: unknown; | ||
typename: string; | ||
} | null | undefined)[]): Promise<MaybePromise<unknown>[]>; | ||
export declare function resolveUncachedNodesForType<Types extends SchemaTypes>(builder: PothosSchemaTypes.SchemaBuilder<Types>, context: object, info: GraphQLResolveInfo, ids: string[], type: OutputType<Types> | string): Promise<unknown[]>; | ||
export declare function resolveUncachedNodesForType<Types extends SchemaTypes>(builder: PothosSchemaTypes.SchemaBuilder<Types>, context: object, info: GraphQLResolveInfo, ids: unknown[], type: OutputType<Types> | string): Promise<unknown[]>; | ||
//# sourceMappingURL=resolve-nodes.d.ts.map |
@@ -1,2 +0,2 @@ | ||
import { brandWithType, createContextCache } from '@pothos/core'; | ||
import { brandWithType, createContextCache, PothosValidationError } from '@pothos/core'; | ||
const getRequestCache = createContextCache(() => new Map()); | ||
@@ -71,4 +71,4 @@ export async function resolveNodes(builder, context, info, globalIDs) { | ||
} | ||
throw new Error(`${config.name} does not support loading by id`); | ||
throw new PothosValidationError(`${config.name} does not support loading by id`); | ||
} | ||
//# sourceMappingURL=resolve-nodes.js.map |
@@ -54,3 +54,3 @@ "use strict"; | ||
} | ||
const globalID = typeof rawID === 'string' ? (0, _internal.internalDecodeGlobalID)(this.builder, rawID, context) : rawID && { | ||
const globalID = typeof rawID === 'string' ? (0, _internal.internalDecodeGlobalID)(this.builder, rawID, context, info, true) : rawID && { | ||
id: String(rawID.id), | ||
@@ -82,3 +82,3 @@ typename: this.builder.configStore.getTypeConfig(rawID.type).name | ||
const rawIds = await Promise.all(rawIDList); | ||
const globalIds = rawIds.map((id)=>typeof id === 'string' ? (0, _internal.internalDecodeGlobalID)(this.builder, id, context) : id && { | ||
const globalIds = rawIds.map((id)=>typeof id === 'string' ? (0, _internal.internalDecodeGlobalID)(this.builder, id, context, info, true) : id && { | ||
id: String(id.id), | ||
@@ -85,0 +85,0 @@ typename: this.builder.configStore.getTypeConfig(id.type).name |
@@ -21,2 +21,3 @@ "use strict"; | ||
const _internal = require("./utils/internal"); | ||
_exportStar(require("./node-ref"), exports); | ||
_exportStar(require("./types"), exports); | ||
@@ -81,3 +82,5 @@ _exportStar(require("./utils"), exports); | ||
if ((_inputField_extensions = inputField.extensions) === null || _inputField_extensions === void 0 ? void 0 : _inputField_extensions.isRelayGlobalID) { | ||
return true; | ||
var _inputField_extensions1; | ||
var _inputField_extensions_relayGlobalIDFor; | ||
return (_inputField_extensions_relayGlobalIDFor = (_inputField_extensions1 = inputField.extensions) === null || _inputField_extensions1 === void 0 ? void 0 : _inputField_extensions1.relayGlobalIDFor) !== null && _inputField_extensions_relayGlobalIDFor !== void 0 ? _inputField_extensions_relayGlobalIDFor : true; | ||
} | ||
@@ -89,4 +92,4 @@ return null; | ||
} | ||
const argMapper = (0, _core.createInputValueMapper)(argMappings, (globalID, mappings, ctx)=>(0, _internal.internalDecodeGlobalID)(this.builder, String(globalID), ctx)); | ||
return (parent, args, context, info)=>resolver(parent, argMapper(args, undefined, context), context, info); | ||
const argMapper = (0, _core.createInputValueMapper)(argMappings, (globalID, mappings, ctx, info)=>(0, _internal.internalDecodeGlobalID)(this.builder, String(globalID), ctx, info, Array.isArray(mappings.value) ? mappings.value : false)); | ||
return (parent, args, context, info)=>resolver(parent, argMapper(args, undefined, context, info), context, info); | ||
} | ||
@@ -97,3 +100,5 @@ wrapSubscribe(subscribe, fieldConfig) { | ||
if ((_inputField_extensions = inputField.extensions) === null || _inputField_extensions === void 0 ? void 0 : _inputField_extensions.isRelayGlobalID) { | ||
return true; | ||
var _inputField_extensions1; | ||
var _inputField_extensions_relayGlobalIDFor; | ||
return (_inputField_extensions_relayGlobalIDFor = (_inputField_extensions1 = inputField.extensions) === null || _inputField_extensions1 === void 0 ? void 0 : _inputField_extensions1.relayGlobalIDFor) !== null && _inputField_extensions_relayGlobalIDFor !== void 0 ? _inputField_extensions_relayGlobalIDFor : true; | ||
} | ||
@@ -105,4 +110,4 @@ return null; | ||
} | ||
const argMapper = (0, _core.createInputValueMapper)(argMappings, (globalID, mappings, ctx)=>(0, _internal.internalDecodeGlobalID)(this.builder, String(globalID), ctx)); | ||
return (parent, args, context, info)=>subscribe(parent, argMapper(args, undefined, context), context, info); | ||
const argMapper = (0, _core.createInputValueMapper)(argMappings, (globalID, mappings, ctx, info)=>(0, _internal.internalDecodeGlobalID)(this.builder, String(globalID), ctx, info, Array.isArray(mappings.value) ? mappings.value : false)); | ||
return (parent, args, context, info)=>subscribe(parent, argMapper(args, undefined, context, info), context, info); | ||
} | ||
@@ -109,0 +114,0 @@ } |
@@ -6,4 +6,7 @@ "use strict"; | ||
const _core = require("@pothos/core"); | ||
const _nodeRef = require("./node-ref"); | ||
const inputFieldBuilder = _core.InputFieldBuilder.prototype; | ||
inputFieldBuilder.globalIDList = function globalIDList(options = {}) { | ||
inputFieldBuilder.globalIDList = function globalIDList({ for: forTypes , ...options } = {}) { | ||
var _ref; | ||
var _map; | ||
return this.idList({ | ||
@@ -13,7 +16,15 @@ ...options, | ||
...options.extensions, | ||
isRelayGlobalID: true | ||
isRelayGlobalID: true, | ||
relayGlobalIDFor: (_map = (_ref = forTypes && (Array.isArray(forTypes) ? forTypes : [ | ||
forTypes | ||
])) === null || _ref === void 0 ? void 0 : _ref.map((type)=>({ | ||
typename: this.builder.configStore.getTypeConfig(type).name, | ||
parse: type instanceof _nodeRef.NodeRef ? type.parseId : undefined | ||
}))) !== null && _map !== void 0 ? _map : null | ||
} | ||
}); | ||
}; | ||
inputFieldBuilder.globalID = function globalID(options = {}) { | ||
inputFieldBuilder.globalID = function globalID({ for: forTypes , ...options } = {}) { | ||
var _ref; | ||
var _map; | ||
return this.id({ | ||
@@ -23,3 +34,9 @@ ...options, | ||
...options.extensions, | ||
isRelayGlobalID: true | ||
isRelayGlobalID: true, | ||
relayGlobalIDFor: (_map = (_ref = forTypes && (Array.isArray(forTypes) ? forTypes : [ | ||
forTypes | ||
])) === null || _ref === void 0 ? void 0 : _ref.map((type)=>({ | ||
typename: this.builder.configStore.getTypeConfig(type).name, | ||
parse: type instanceof _nodeRef.NodeRef ? type.parseId : undefined | ||
}))) !== null && _map !== void 0 ? _map : null | ||
} | ||
@@ -26,0 +43,0 @@ }); |
@@ -17,2 +17,3 @@ "use strict"; | ||
const _core = /*#__PURE__*/ _interopRequireWildcard(require("@pothos/core")); | ||
const _nodeRef = require("./node-ref"); | ||
const _utils = require("./utils"); | ||
@@ -141,3 +142,3 @@ function _getRequireWildcardCache(nodeInterop) { | ||
resolve: (parent)=>{ | ||
throw new Error('id field not implemented'); | ||
throw new _core.PothosValidationError('id field not implemented'); | ||
} | ||
@@ -189,3 +190,3 @@ }) | ||
}; | ||
schemaBuilderProto.node = function node(param, { interfaces , ...options }, fields) { | ||
schemaBuilderProto.node = function node(param, { interfaces , extensions , id , ...options }, fields) { | ||
(0, _core.verifyRef)(param); | ||
@@ -200,2 +201,6 @@ const interfacesWithNode = ()=>[ | ||
...options, | ||
extensions: { | ||
...extensions, | ||
pothosParseGlobalID: id.parse | ||
}, | ||
isTypeOf: (_options_isTypeOf = options.isTypeOf) !== null && _options_isTypeOf !== void 0 ? _options_isTypeOf : typeof param === 'function' ? (maybeNode, context, info)=>{ | ||
@@ -227,3 +232,3 @@ if (!maybeNode) { | ||
...this.options.relayOptions.idFieldOptions, | ||
...options.id, | ||
...id, | ||
args: {}, | ||
@@ -233,7 +238,11 @@ resolve: async (parent, args, context, info)=>({ | ||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument | ||
id: await options.id.resolve(parent, args, context, info) | ||
id: await id.resolve(parent, args, context, info) | ||
}) | ||
})); | ||
}); | ||
return ref; | ||
const nodeRef = new _nodeRef.NodeRef(ref.name, { | ||
parseId: id.parse | ||
}); | ||
this.configStore.associateRefWithName(nodeRef, ref.name); | ||
return nodeRef; | ||
}; | ||
@@ -240,0 +249,0 @@ schemaBuilderProto.globalConnectionField = function globalConnectionField(name, field) { |
@@ -31,6 +31,6 @@ "use strict"; | ||
if (first != null && first < 0) { | ||
throw new TypeError('Argument "first" must be a non-negative integer'); | ||
throw new _core.PothosValidationError('Argument "first" must be a non-negative integer'); | ||
} | ||
if (last != null && last < 0) { | ||
throw new Error('Argument "last" must be a non-negative integer'); | ||
throw new _core.PothosValidationError('Argument "last" must be a non-negative integer'); | ||
} | ||
@@ -44,3 +44,3 @@ let startOffset = after ? afterOffset + 1 : 0; | ||
if (endOffset === Number.POSITIVE_INFINITY) { | ||
throw new Error('Argument "last" can only be used in combination with "before" or "first"'); | ||
throw new _core.PothosValidationError('Argument "last" can only be used in combination with "before" or "first"'); | ||
} | ||
@@ -87,3 +87,3 @@ startOffset = Math.max(startOffset, endOffset - last); | ||
if (!string.startsWith(OFFSET_CURSOR_PREFIX)) { | ||
throw new Error(`Invalid offset cursor ${OFFSET_CURSOR_PREFIX}`); | ||
throw new _core.PothosValidationError(`Invalid offset cursor ${OFFSET_CURSOR_PREFIX}`); | ||
} | ||
@@ -120,6 +120,6 @@ return Number.parseInt(string.slice(OFFSET_CURSOR_PREFIX.length), 10); | ||
if (first != null && first < 0) { | ||
throw new TypeError('Argument "first" must be a non-negative integer'); | ||
throw new _core.PothosValidationError('Argument "first" must be a non-negative integer'); | ||
} | ||
if (last != null && last < 0) { | ||
throw new Error('Argument "last" must be a non-negative integer'); | ||
throw new _core.PothosValidationError('Argument "last" must be a non-negative integer'); | ||
} | ||
@@ -126,0 +126,0 @@ var _ref; |
@@ -22,3 +22,3 @@ "use strict"; | ||
if (!typename || !id) { | ||
throw new TypeError(`Invalid global ID: ${globalID}`); | ||
throw new _core.PothosValidationError(`Invalid global ID: ${globalID}`); | ||
} | ||
@@ -25,0 +25,0 @@ return { |
@@ -15,2 +15,3 @@ "use strict"; | ||
}); | ||
const _core = require("@pothos/core"); | ||
const _globalIds = require("./global-ids"); | ||
@@ -23,9 +24,30 @@ function internalEncodeGlobalID(builder, typename, id, ctx) { | ||
} | ||
function internalDecodeGlobalID(builder, globalID, ctx) { | ||
if (builder.options.relayOptions.decodeGlobalID) { | ||
return builder.options.relayOptions.decodeGlobalID(globalID, ctx); | ||
function internalDecodeGlobalID(builder, globalID, ctx, info, parseIdsForTypes) { | ||
const decoded = builder.options.relayOptions.decodeGlobalID ? builder.options.relayOptions.decodeGlobalID(globalID, ctx) : (0, _globalIds.decodeGlobalID)(globalID); | ||
if (Array.isArray(parseIdsForTypes)) { | ||
const entry = parseIdsForTypes.find(({ typename })=>typename === decoded.typename); | ||
if (!entry) { | ||
throw new _core.PothosValidationError(`ID: ${globalID} is not of type: ${parseIdsForTypes.map(({ typename })=>typename).join(', ')}`); | ||
} | ||
if (entry.parseId) { | ||
return { | ||
...decoded, | ||
id: entry.parseId(decoded.id, ctx) | ||
}; | ||
} | ||
return decoded; | ||
} | ||
return (0, _globalIds.decodeGlobalID)(globalID); | ||
if (parseIdsForTypes) { | ||
var _info_schema_getType, _info_schema_getType_extensions; | ||
const parseID = (_info_schema_getType = info.schema.getType(decoded.typename)) === null || _info_schema_getType === void 0 ? void 0 : (_info_schema_getType_extensions = _info_schema_getType.extensions) === null || _info_schema_getType_extensions === void 0 ? void 0 : _info_schema_getType_extensions.pothosParseGlobalID; | ||
if (parseID) { | ||
return { | ||
...decoded, | ||
id: parseID(decoded.id, ctx) | ||
}; | ||
} | ||
} | ||
return decoded; | ||
} | ||
//# sourceMappingURL=internal.js.map |
@@ -85,5 +85,5 @@ "use strict"; | ||
} | ||
throw new Error(`${config.name} does not support loading by id`); | ||
throw new _core.PothosValidationError(`${config.name} does not support loading by id`); | ||
} | ||
//# sourceMappingURL=resolve-nodes.js.map |
{ | ||
"name": "@pothos/plugin-relay", | ||
"version": "3.34.0", | ||
"version": "3.35.0", | ||
"description": "A Pothos plugin for adding relay style connections, nodes, and cursor based pagination to your GraphQL schema", | ||
@@ -46,4 +46,4 @@ "main": "./lib/index.js", | ||
"graphql-tag": "^2.12.6", | ||
"@pothos/core": "3.24.1", | ||
"@pothos/plugin-complexity": "3.11.7", | ||
"@pothos/core": "3.25.0", | ||
"@pothos/plugin-complexity": "3.12.0", | ||
"@pothos/test-utils": "1.4.7" | ||
@@ -50,0 +50,0 @@ }, |
@@ -119,2 +119,24 @@ # Relay Plugin | ||
#### Limiting global ID args to specific types | ||
`globalID` input's can be configured to validate the type of the globalID. This is useful if you | ||
only want to accept IDs for specific node types. | ||
```typescript | ||
builder.queryType({ | ||
fields: (t) => ({ | ||
fieldThatAcceptsGlobalID: t.boolean({ | ||
args: { | ||
id: t.arg.globalID({ | ||
for: SomeType, | ||
// or allow multiple types | ||
for: [TypeOne, TypeTwo], | ||
required: true, | ||
}), | ||
}, | ||
}), | ||
}), | ||
}); | ||
``` | ||
### Creating Nodes | ||
@@ -172,2 +194,20 @@ | ||
#### parsing node ids | ||
By default all node ids are parsed as string. This behavior can be customized by providing a custom | ||
parse function for your node's ID field: | ||
```ts | ||
builder.node(NumberThing, { | ||
// define an id field | ||
id: { | ||
resolve: (num) => num.id, | ||
parse: (id) => Number.parseInt(id, 10), | ||
}, | ||
// the ID is now a number | ||
loadOne: (id) => new NumberThing(id), | ||
... | ||
}); | ||
``` | ||
### Creating Connections | ||
@@ -174,0 +214,0 @@ |
@@ -129,3 +129,3 @@ import { GraphQLResolveInfo } from 'graphql'; | ||
typeof rawID === 'string' | ||
? internalDecodeGlobalID(this.builder, rawID, context) | ||
? internalDecodeGlobalID(this.builder, rawID, context, info, true) | ||
: rawID && { | ||
@@ -167,3 +167,3 @@ id: String(rawID.id), | ||
typeof id === 'string' | ||
? internalDecodeGlobalID(this.builder, id, context) | ||
? internalDecodeGlobalID(this.builder, id, context, info, true) | ||
: id && { | ||
@@ -170,0 +170,0 @@ id: String(id.id), |
@@ -25,2 +25,3 @@ import { | ||
} from '@pothos/core'; | ||
import { NodeRef } from './node-ref'; | ||
import { | ||
@@ -81,7 +82,11 @@ ConnectionShape, | ||
node: <Interfaces extends InterfaceParam<Types>[], Param extends ObjectParam<Types>>( | ||
node: < | ||
Interfaces extends InterfaceParam<Types>[], | ||
Param extends ObjectParam<Types>, | ||
IDShape = string, | ||
>( | ||
param: Param, | ||
options: NodeObjectOptions<Types, Param, Interfaces>, | ||
options: NodeObjectOptions<Types, Param, Interfaces, IDShape>, | ||
fields?: ObjectFieldsShape<Types, ParentShape<Types, Param>>, | ||
) => ObjectRef<OutputShape<Types, Param>, ParentShape<Types, Param>>; | ||
) => NodeRef<OutputShape<Types, Param>, ParentShape<Types, Param>, IDShape>; | ||
@@ -193,8 +198,15 @@ globalConnectionFields: ( | ||
globalID: <Req extends boolean>( | ||
...args: NormalizeArgs<[options: GlobalIDInputFieldOptions<Types, Req, Kind>]> | ||
) => InputFieldRef<InputShapeFromTypeParam<Types, GlobalIDInputShape, Req>, Kind>; | ||
globalID: <Req extends boolean, For extends ObjectParam<Types>>( | ||
...args: NormalizeArgs<[options: GlobalIDInputFieldOptions<Types, Req, Kind, For>]> | ||
) => InputFieldRef< | ||
InputShapeFromTypeParam< | ||
Types, | ||
GlobalIDInputShape<For extends NodeRef<unknown, unknown, infer T> ? T : string>, | ||
Req | ||
>, | ||
Kind | ||
>; | ||
globalIDList: <Req extends FieldRequiredness<['ID']>>( | ||
...args: NormalizeArgs<[options: GlobalIDListInputFieldOptions<Types, Req, Kind>]> | ||
globalIDList: <Req extends FieldRequiredness<['ID']>, For extends ObjectParam<Types>>( | ||
...args: NormalizeArgs<[options: GlobalIDListInputFieldOptions<Types, Req, Kind, For>]> | ||
) => InputFieldRef< | ||
@@ -207,3 +219,3 @@ InputShapeFromTypeParam< | ||
typename: string; | ||
id: string; | ||
id: For extends NodeRef<unknown, unknown, infer T> ? T : string; | ||
}; | ||
@@ -210,0 +222,0 @@ }, |
@@ -5,3 +5,3 @@ import './global-types'; | ||
import './schema-builder'; | ||
import { GraphQLFieldResolver } from 'graphql'; | ||
import { GraphQLFieldResolver, GraphQLResolveInfo } from 'graphql'; | ||
import SchemaBuilder, { | ||
@@ -16,2 +16,3 @@ BasePlugin, | ||
export * from './node-ref'; | ||
export * from './types'; | ||
@@ -31,3 +32,5 @@ export * from './utils'; | ||
if (inputField.extensions?.isRelayGlobalID) { | ||
return true; | ||
return (inputField.extensions?.relayGlobalIDFor ?? true) as | ||
| true | ||
| { typename: string; parseId: (id: string, ctx: object) => unknown }[]; | ||
} | ||
@@ -44,8 +47,14 @@ | ||
argMappings, | ||
(globalID, mappings, ctx: Types['Context']) => | ||
internalDecodeGlobalID(this.builder, String(globalID), ctx), | ||
(globalID, mappings, ctx: Types['Context'], info: GraphQLResolveInfo) => | ||
internalDecodeGlobalID( | ||
this.builder, | ||
String(globalID), | ||
ctx, | ||
info, | ||
Array.isArray(mappings.value) ? mappings.value : false, | ||
), | ||
); | ||
return (parent, args, context, info) => | ||
resolver(parent, argMapper(args, undefined, context), context, info); | ||
resolver(parent, argMapper(args, undefined, context, info), context, info); | ||
} | ||
@@ -59,3 +68,5 @@ | ||
if (inputField.extensions?.isRelayGlobalID) { | ||
return true; | ||
return (inputField.extensions?.relayGlobalIDFor ?? true) as | ||
| true | ||
| { typename: string; parseId: (id: string, ctx: object) => unknown }[]; | ||
} | ||
@@ -72,8 +83,14 @@ | ||
argMappings, | ||
(globalID, mappings, ctx: Types['Context']) => | ||
internalDecodeGlobalID(this.builder, String(globalID), ctx), | ||
(globalID, mappings, ctx: Types['Context'], info: GraphQLResolveInfo) => | ||
internalDecodeGlobalID( | ||
this.builder, | ||
String(globalID), | ||
ctx, | ||
info, | ||
Array.isArray(mappings.value) ? mappings.value : false, | ||
), | ||
); | ||
return (parent, args, context, info) => | ||
subscribe(parent, argMapper(args, undefined, context), context, info); | ||
subscribe(parent, argMapper(args, undefined, context, info), context, info); | ||
} | ||
@@ -80,0 +97,0 @@ } |
@@ -6,3 +6,6 @@ import { | ||
InputShapeFromTypeParam, | ||
ObjectRef, | ||
SchemaTypes, | ||
} from '@pothos/core'; | ||
import { NodeRef } from './node-ref'; | ||
import { | ||
@@ -22,8 +25,7 @@ GlobalIDInputFieldOptions, | ||
inputFieldBuilder.globalIDList = function globalIDList<Req extends FieldRequiredness<['ID']>>( | ||
options: GlobalIDListInputFieldOptions< | ||
DefaultSchemaTypes, | ||
Req, | ||
'Arg' | 'InputObject' | ||
> = {} as never, | ||
): InputFieldRef<InputShapeFromTypeParam<DefaultSchemaTypes, [GlobalIDInputShape], Req>> { | ||
{ | ||
for: forTypes, | ||
...options | ||
}: GlobalIDListInputFieldOptions<DefaultSchemaTypes, Req, 'Arg' | 'InputObject'> = {} as never, | ||
) { | ||
return this.idList({ | ||
@@ -34,8 +36,19 @@ ...options, | ||
isRelayGlobalID: true, | ||
relayGlobalIDFor: | ||
( | ||
(forTypes && | ||
(Array.isArray(forTypes) ? forTypes : [forTypes])) as ObjectRef<SchemaTypes>[] | ||
)?.map((type: ObjectRef<SchemaTypes>) => ({ | ||
typename: this.builder.configStore.getTypeConfig(type).name, | ||
parse: type instanceof NodeRef ? type.parseId : undefined, | ||
})) ?? null, | ||
}, | ||
}) as InputFieldRef<InputShapeFromTypeParam<DefaultSchemaTypes, [GlobalIDInputShape], Req>>; | ||
}) as never; | ||
}; | ||
inputFieldBuilder.globalID = function globalID<Req extends boolean>( | ||
options: GlobalIDInputFieldOptions<DefaultSchemaTypes, Req, 'Arg' | 'InputObject'> = {} as never, | ||
{ | ||
for: forTypes, | ||
...options | ||
}: GlobalIDInputFieldOptions<DefaultSchemaTypes, Req, 'Arg' | 'InputObject'> = {} as never, | ||
) { | ||
@@ -47,6 +60,14 @@ return this.id({ | ||
isRelayGlobalID: true, | ||
relayGlobalIDFor: | ||
( | ||
(forTypes && | ||
(Array.isArray(forTypes) ? forTypes : [forTypes])) as ObjectRef<SchemaTypes>[] | ||
)?.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> | ||
>; | ||
> as never; | ||
}; | ||
@@ -53,0 +74,0 @@ |
@@ -14,5 +14,7 @@ import { defaultTypeResolver, GraphQLResolveInfo } from 'graphql'; | ||
OutputRef, | ||
PothosValidationError, | ||
SchemaTypes, | ||
verifyRef, | ||
} from '@pothos/core'; | ||
import { NodeRef } from './node-ref'; | ||
import { ConnectionShape, GlobalIDShape, PageInfoShape } from './types'; | ||
@@ -141,3 +143,3 @@ import { capitalize, resolveNodes } from './utils'; | ||
resolve: (parent) => { | ||
throw new Error('id field not implemented'); | ||
throw new PothosValidationError('id field not implemented'); | ||
}, | ||
@@ -227,3 +229,3 @@ }), | ||
schemaBuilderProto.node = function node(param, { interfaces, ...options }, fields) { | ||
schemaBuilderProto.node = function node(param, { interfaces, extensions, id, ...options }, fields) { | ||
verifyRef(param); | ||
@@ -241,2 +243,6 @@ const interfacesWithNode: () => InterfaceParam<SchemaTypes>[] = () => [ | ||
...(options as {}), | ||
extensions: { | ||
...extensions, | ||
pothosParseGlobalID: id.parse, | ||
}, | ||
isTypeOf: | ||
@@ -281,3 +287,3 @@ options.isTypeOf ?? | ||
...this.options.relayOptions.idFieldOptions, | ||
...options.id, | ||
...id, | ||
args: {}, | ||
@@ -287,3 +293,3 @@ resolve: async (parent, args, context, info) => ({ | ||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument | ||
id: await options.id.resolve(parent, args, context, info), | ||
id: await id.resolve(parent, args, context, info), | ||
}), | ||
@@ -294,3 +300,9 @@ }), | ||
return ref; | ||
const nodeRef = new NodeRef(ref.name, { | ||
parseId: id.parse, | ||
}); | ||
this.configStore.associateRefWithName(nodeRef, ref.name); | ||
return nodeRef as never; | ||
}; | ||
@@ -297,0 +309,0 @@ |
@@ -351,2 +351,3 @@ import { GraphQLResolveInfo } from 'graphql'; | ||
Interfaces extends InterfaceParam<Types>[], | ||
IDShape = string, | ||
> = NodeBaseObjectOptionsForParam<Types, Param, Interfaces> & { | ||
@@ -365,14 +366,16 @@ id: Omit< | ||
'args' | 'nullable' | 'type' | ||
>; | ||
> & { | ||
parse?: (id: string, ctx: Types['Context']) => IDShape; | ||
}; | ||
brandLoadedObjects?: boolean; | ||
loadOne?: ( | ||
id: string, | ||
id: IDShape, | ||
context: Types['Context'], | ||
) => MaybePromise<OutputShape<Types, Param> | null | undefined>; | ||
loadMany?: ( | ||
ids: string[], | ||
ids: IDShape[], | ||
context: Types['Context'], | ||
) => MaybePromise<MaybePromise<OutputShape<Types, Param> | null | undefined>[]>; | ||
loadWithoutCache?: ( | ||
id: string, | ||
id: IDShape, | ||
context: Types['Context'], | ||
@@ -382,3 +385,3 @@ info: GraphQLResolveInfo, | ||
loadManyWithoutCache?: ( | ||
ids: string[], | ||
ids: IDShape[], | ||
context: Types['Context'], | ||
@@ -421,3 +424,6 @@ ) => MaybePromise<MaybePromise<OutputShape<Types, Param> | null | undefined>[]>; | ||
Kind extends 'Arg' | 'InputObject', | ||
> = Omit<PothosSchemaTypes.InputFieldOptionsByKind<Types, 'ID', Req>[Kind], 'type'>; | ||
For = unknown, | ||
> = Omit<PothosSchemaTypes.InputFieldOptionsByKind<Types, 'ID', Req>[Kind], 'type'> & { | ||
for?: For | For[]; | ||
}; | ||
@@ -428,3 +434,6 @@ export type GlobalIDListInputFieldOptions< | ||
Kind extends 'Arg' | 'InputObject', | ||
> = Omit<PothosSchemaTypes.InputFieldOptionsByKind<Types, ['ID'], Req>[Kind], 'type'>; | ||
For = unknown, | ||
> = Omit<PothosSchemaTypes.InputFieldOptionsByKind<Types, ['ID'], Req>[Kind], 'type'> & { | ||
for?: For | For[]; | ||
}; | ||
@@ -562,6 +571,6 @@ export type NodeIDFieldOptions< | ||
export interface GlobalIDInputShape { | ||
export interface GlobalIDInputShape<T = string> { | ||
[inputShapeKey]: { | ||
typename: string; | ||
id: string; | ||
id: T; | ||
}; | ||
@@ -568,0 +577,0 @@ } |
@@ -1,2 +0,8 @@ | ||
import { decodeBase64, encodeBase64, MaybePromise, SchemaTypes } from '@pothos/core'; | ||
import { | ||
decodeBase64, | ||
encodeBase64, | ||
MaybePromise, | ||
PothosValidationError, | ||
SchemaTypes, | ||
} from '@pothos/core'; | ||
import { ConnectionShape, DefaultConnectionArguments } from '../types'; | ||
@@ -43,7 +49,7 @@ | ||
if (first != null && first < 0) { | ||
throw new TypeError('Argument "first" must be a non-negative integer'); | ||
throw new PothosValidationError('Argument "first" must be a non-negative integer'); | ||
} | ||
if (last != null && last < 0) { | ||
throw new Error('Argument "last" must be a non-negative integer'); | ||
throw new PothosValidationError('Argument "last" must be a non-negative integer'); | ||
} | ||
@@ -59,3 +65,5 @@ | ||
if (endOffset === Number.POSITIVE_INFINITY) { | ||
throw new Error('Argument "last" can only be used in combination with "before" or "first"'); | ||
throw new PothosValidationError( | ||
'Argument "last" can only be used in combination with "before" or "first"', | ||
); | ||
} | ||
@@ -126,3 +134,3 @@ startOffset = Math.max(startOffset, endOffset - last); | ||
if (!string.startsWith(OFFSET_CURSOR_PREFIX)) { | ||
throw new Error(`Invalid offset cursor ${OFFSET_CURSOR_PREFIX}`); | ||
throw new PothosValidationError(`Invalid offset cursor ${OFFSET_CURSOR_PREFIX}`); | ||
} | ||
@@ -180,7 +188,7 @@ | ||
if (first != null && first < 0) { | ||
throw new TypeError('Argument "first" must be a non-negative integer'); | ||
throw new PothosValidationError('Argument "first" must be a non-negative integer'); | ||
} | ||
if (last != null && last < 0) { | ||
throw new Error('Argument "last" must be a non-negative integer'); | ||
throw new PothosValidationError('Argument "last" must be a non-negative integer'); | ||
} | ||
@@ -187,0 +195,0 @@ |
@@ -1,2 +0,2 @@ | ||
import { decodeBase64, encodeBase64 } from '@pothos/core'; | ||
import { decodeBase64, encodeBase64, PothosValidationError } from '@pothos/core'; | ||
@@ -11,3 +11,3 @@ export function encodeGlobalID(typename: string, id: bigint | number | string) { | ||
if (!typename || !id) { | ||
throw new TypeError(`Invalid global ID: ${globalID}`); | ||
throw new PothosValidationError(`Invalid global ID: ${globalID}`); | ||
} | ||
@@ -14,0 +14,0 @@ |
@@ -1,2 +0,3 @@ | ||
import { SchemaTypes } from '@pothos/core'; | ||
import { GraphQLResolveInfo } from 'graphql'; | ||
import { PothosValidationError, SchemaTypes } from '@pothos/core'; | ||
import { decodeGlobalID, encodeGlobalID } from './global-ids'; | ||
@@ -21,8 +22,44 @@ | ||
ctx: object, | ||
info: GraphQLResolveInfo, | ||
parseIdsForTypes: boolean | { typename: string; parseId: (id: string, ctx: object) => unknown }[], | ||
) { | ||
if (builder.options.relayOptions.decodeGlobalID) { | ||
return builder.options.relayOptions.decodeGlobalID(globalID, ctx); | ||
const decoded = builder.options.relayOptions.decodeGlobalID | ||
? builder.options.relayOptions.decodeGlobalID(globalID, ctx) | ||
: decodeGlobalID(globalID); | ||
if (Array.isArray(parseIdsForTypes)) { | ||
const entry = parseIdsForTypes.find(({ typename }) => typename === decoded.typename); | ||
if (!entry) { | ||
throw new PothosValidationError( | ||
`ID: ${globalID} is not of type: ${parseIdsForTypes | ||
.map(({ typename }) => typename) | ||
.join(', ')}`, | ||
); | ||
} | ||
if (entry.parseId) { | ||
return { | ||
...decoded, | ||
id: entry.parseId(decoded.id, ctx), | ||
}; | ||
} | ||
return decoded; | ||
} | ||
return decodeGlobalID(globalID); | ||
if (parseIdsForTypes) { | ||
const parseID = info.schema.getType(decoded.typename)?.extensions?.pothosParseGlobalID as ( | ||
id: string, | ||
ctx: object, | ||
) => string; | ||
if (parseID) { | ||
return { | ||
...decoded, | ||
id: parseID(decoded.id, ctx), | ||
}; | ||
} | ||
} | ||
return decoded; | ||
} |
@@ -8,2 +8,3 @@ import { GraphQLResolveInfo } from 'graphql'; | ||
OutputType, | ||
PothosValidationError, | ||
SchemaTypes, | ||
@@ -19,7 +20,7 @@ } from '@pothos/core'; | ||
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>> = {}; | ||
@@ -79,3 +80,3 @@ globalIDs.forEach((globalID, i) => { | ||
info: GraphQLResolveInfo, | ||
ids: string[], | ||
ids: unknown[], | ||
type: OutputType<Types> | string, | ||
@@ -85,3 +86,3 @@ ): Promise<unknown[]> { | ||
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>; | ||
@@ -136,3 +137,3 @@ if (options.loadMany) { | ||
throw new Error(`${config.name} does not support loading by id`); | ||
throw new PothosValidationError(`${config.name} does not support loading by id`); | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
401979
113
5164
770