nexus
Version:
Scalable, strongly typed GraphQL schema development
626 lines (625 loc) • 33.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeResolveFn = exports.connectionPlugin = exports.BackwardOnlyStrictArgs = exports.BackwardPaginateArgs = exports.ForwardOnlyStrictArgs = exports.ForwardPaginateArgs = void 0;
const tslib_1 = require("tslib");
const graphql_1 = require("graphql");
const args_1 = require("../definitions/args");
const nonNull_1 = require("../definitions/nonNull");
const nullable_1 = require("../definitions/nullable");
const objectType_1 = require("../definitions/objectType");
const wrapping_1 = require("../definitions/wrapping");
const dynamicMethod_1 = require("../dynamicMethod");
const plugin_1 = require("../plugin");
const utils_1 = require("../utils");
exports.ForwardPaginateArgs = {
first: (0, nullable_1.nullable)((0, args_1.intArg)({ description: 'Returns the first n elements from the list.' })),
after: (0, nullable_1.nullable)((0, args_1.stringArg)({ description: 'Returns the elements in the list that come after the specified cursor' })),
};
exports.ForwardOnlyStrictArgs = Object.assign(Object.assign({}, exports.ForwardPaginateArgs), { first: (0, nonNull_1.nonNull)((0, args_1.intArg)({ description: 'Returns the first n elements from the list.' })) });
exports.BackwardPaginateArgs = {
last: (0, nullable_1.nullable)((0, args_1.intArg)({ description: 'Returns the last n elements from the list.' })),
before: (0, nullable_1.nullable)((0, args_1.stringArg)({ description: 'Returns the elements in the list that come before the specified cursor' })),
};
exports.BackwardOnlyStrictArgs = Object.assign(Object.assign({}, exports.BackwardPaginateArgs), { last: (0, nonNull_1.nonNull)((0, args_1.intArg)({ description: 'Returns the last n elements from the list.' })) });
function base64Encode(str) {
return Buffer.from(str, 'utf8').toString('base64');
}
function base64Decode(str) {
return Buffer.from(str, 'base64').toString('utf8');
}
const connectionPlugin = (connectionPluginConfig) => {
var _a;
const pluginConfig = Object.assign({}, connectionPluginConfig);
// Define the plugin with the appropriate configuration.
return (0, plugin_1.plugin)({
name: 'ConnectionPlugin',
fieldDefTypes: [
(0, utils_1.printedGenTypingImport)({
module: (_a = connectionPluginConfig === null || connectionPluginConfig === void 0 ? void 0 : connectionPluginConfig.nexusSchemaImportId) !== null && _a !== void 0 ? _a : (0, utils_1.getOwnPackage)().name,
bindings: ['core', 'connectionPluginCore'],
}),
],
// Defines the field added to the definition block:
// t.connectionField('users', {
// type: User
// })
onInstall(b) {
let dynamicConfig = [];
const { additionalArgs = {}, extendConnection: pluginExtendConnection, extendEdge: pluginExtendEdge, includeNodesField = false, nexusFieldName = 'connectionField', } = pluginConfig;
// If to add fields to every connection, we require the resolver be defined on the
// field definition, unless fromResolve: true is passed in the config
if (pluginExtendConnection) {
(0, utils_1.eachObj)(pluginExtendConnection, (val, key) => {
dynamicConfig.push(`${key}${val.requireResolver === false ? '?:' : ':'} connectionPluginCore.ConnectionFieldResolver<TypeName, FieldName, "${key}">`);
});
}
if (pluginExtendEdge) {
const edgeFields = (0, utils_1.mapObj)(pluginExtendEdge, (val, key) => `${key}${val.requireResolver === false ? '?:' : ':'} connectionPluginCore.EdgeFieldResolver<TypeName, FieldName, "${key}">`);
dynamicConfig.push(`edgeFields: { ${edgeFields.join(', ')} }`);
}
let printedDynamicConfig = '';
if (dynamicConfig.length > 0) {
printedDynamicConfig = ` & { ${dynamicConfig.join(', ')} }`;
}
// Add the t.connectionField (or something else if we've changed the name)
b.addType((0, dynamicMethod_1.dynamicOutputMethod)({
name: nexusFieldName,
typeDescription: `
Adds a Relay-style connection to the type, with numerous options for configuration
@see https://nexusjs.org/docs/plugins/connection
`,
typeDefinition: `<FieldName extends string>(
fieldName: FieldName,
config: connectionPluginCore.ConnectionFieldConfig<TypeName, FieldName>${printedDynamicConfig}
): void`,
factory({ typeName: parentTypeName, typeDef: t, args: factoryArgs, stage, builder, wrapping }) {
var _a, _b;
const [fieldName, fieldConfig] = factoryArgs;
const targetType = fieldConfig.type;
/* istanbul ignore if */
if (wrapping === null || wrapping === void 0 ? void 0 : wrapping.includes('List')) {
throw new Error(`Cannot chain .list with connectionField (on ${parentTypeName}.${fieldName})`);
}
const { targetTypeName, connectionName, edgeName } = getTypeNames(fieldName, parentTypeName, fieldConfig, pluginConfig);
if (stage === 'build') {
assertCorrectConfig(parentTypeName, fieldName, pluginConfig, fieldConfig);
}
// Add the "Connection" type to the schema if it doesn't exist already
if (!b.hasType(connectionName)) {
b.addType((0, objectType_1.objectType)({
name: connectionName,
definition(t2) {
t2.list.field('edges', {
type: edgeName,
description: `https://facebook.github.io/relay/graphql/connections.htm#sec-Edge-Types`,
});
t2.nonNull.field('pageInfo', {
type: 'PageInfo',
description: `https://facebook.github.io/relay/graphql/connections.htm#sec-undefined.PageInfo`,
});
if (includeNodesField) {
t2.list.field('nodes', {
type: targetType,
description: `Flattened list of ${targetTypeName} type`,
});
}
if (pluginExtendConnection) {
(0, utils_1.eachObj)(pluginExtendConnection, (extensionFieldConfig, extensionFieldName) => {
t2.field(extensionFieldName, extensionFieldConfig);
});
}
provideSourceAndArgs(t2, () => {
if (fieldConfig.extendConnection instanceof Function) {
fieldConfig.extendConnection(t2);
}
});
},
nonNullDefaults: (_a = fieldConfig.nonNullDefaults) !== null && _a !== void 0 ? _a : pluginConfig.nonNullDefaults,
}));
}
// Add the "Edge" type to the schema if it doesn't exist already
if (!b.hasType(edgeName)) {
b.addType((0, objectType_1.objectType)({
name: edgeName,
definition(t2) {
t2.field('cursor', {
type: cursorType !== null && cursorType !== void 0 ? cursorType : (0, nonNull_1.nonNull)('String'),
description: 'https://facebook.github.io/relay/graphql/connections.htm#sec-Cursor',
});
t2.field('node', {
type: targetType,
description: 'https://facebook.github.io/relay/graphql/connections.htm#sec-Node',
});
if (pluginExtendEdge) {
(0, utils_1.eachObj)(pluginExtendEdge, (val, key) => {
t2.field(key, val);
});
}
provideArgs(t2, () => {
if (fieldConfig.extendEdge instanceof Function) {
fieldConfig.extendEdge(t2);
}
});
},
nonNullDefaults: (_b = fieldConfig.nonNullDefaults) !== null && _b !== void 0 ? _b : pluginConfig.nonNullDefaults,
}));
}
// Add the "PageInfo" type to the schema if it doesn't exist already
if (!b.hasType('PageInfo')) {
b.addType((0, objectType_1.objectType)({
name: 'PageInfo',
description: 'PageInfo cursor, as defined in https://facebook.github.io/relay/graphql/connections.htm#sec-undefined.PageInfo',
definition(t2) {
t2.nonNull.field('hasNextPage', {
type: 'Boolean',
description: `Used to indicate whether more edges exist following the set defined by the clients arguments.`,
});
t2.nonNull.field('hasPreviousPage', {
type: 'Boolean',
description: `Used to indicate whether more edges exist prior to the set defined by the clients arguments.`,
});
t2.nullable.field('startCursor', {
type: 'String',
description: `The cursor corresponding to the first nodes in edges. Null if the connection is empty.`,
});
t2.nullable.field('endCursor', {
type: 'String',
description: `The cursor corresponding to the last nodes in edges. Null if the connection is empty.`,
});
},
}));
}
const { disableBackwardPagination, disableForwardPagination, validateArgs = defaultValidateArgs, strictArgs = true, cursorType, } = Object.assign(Object.assign({}, pluginConfig), fieldConfig);
let specArgs = {};
if (disableForwardPagination !== true && disableBackwardPagination !== true) {
specArgs = Object.assign(Object.assign({}, exports.ForwardPaginateArgs), exports.BackwardPaginateArgs);
}
else if (disableForwardPagination !== true) {
specArgs = strictArgs ? Object.assign({}, exports.ForwardOnlyStrictArgs) : Object.assign({}, exports.ForwardPaginateArgs);
}
else if (disableBackwardPagination !== true) {
specArgs = strictArgs ? Object.assign({}, exports.BackwardOnlyStrictArgs) : Object.assign({}, exports.BackwardPaginateArgs);
}
// If we have additional args,
let fieldAdditionalArgs = {};
if (fieldConfig.additionalArgs) {
if (additionalArgs && fieldConfig.inheritAdditionalArgs) {
fieldAdditionalArgs = Object.assign(Object.assign({}, additionalArgs), fieldConfig.additionalArgs);
}
else {
fieldAdditionalArgs = Object.assign({}, fieldConfig.additionalArgs);
}
}
else if (additionalArgs) {
fieldAdditionalArgs = Object.assign({}, additionalArgs);
}
const fieldArgs = Object.assign(Object.assign({}, fieldAdditionalArgs), specArgs);
let resolveFn;
if (fieldConfig.resolve) {
if (includeNodesField) {
resolveFn = (root, args, ctx, info) => {
return (0, plugin_1.completeValue)(fieldConfig.resolve(root, args, ctx, info), (val) => {
if (val && val.nodes === undefined) {
return withArgs(args, Object.assign({ get nodes() {
return (0, plugin_1.completeValue)(val.edges, (edges) => edges.map((edge) => edge.node));
} }, val));
}
return withArgs(args, Object.assign({}, val));
});
};
}
else {
resolveFn = fieldConfig.resolve;
}
}
else {
resolveFn = makeResolveFn(pluginConfig, fieldConfig);
}
let wrappedConnectionName = connectionName;
if (wrapping) {
if (typeof fieldConfig.nullable === 'boolean') {
throw new Error('[connectionPlugin]: You cannot chain .null/.nonNull and also set the nullable in the connectionField definition.');
}
wrappedConnectionName = (0, wrapping_1.applyNexusWrapping)(connectionName, wrapping);
}
else {
if (fieldConfig.nullable === true) {
wrappedConnectionName = (0, nullable_1.nullable)(wrappedConnectionName);
}
else if (fieldConfig.nullable === false) {
wrappedConnectionName = (0, nonNull_1.nonNull)(wrappedConnectionName);
}
}
// Add the field to the type.
t.field(fieldName, Object.assign(Object.assign({}, nonConnectionFieldProps(fieldConfig)), { args: fieldArgs, type: wrappedConnectionName, resolve(root, args, ctx, info) {
// TODO(2.0): Maybe switch the arguments around here to be consistent w/ resolver (breaking change)?
validateArgs(args, info, root, ctx);
return resolveFn(root, args, ctx, info);
} }));
},
}));
},
});
};
exports.connectionPlugin = connectionPlugin;
// Extract all of the non-connection related field config we may want to apply for plugin purposes
function nonConnectionFieldProps(fieldConfig) {
const { additionalArgs, cursorFromNode, disableBackwardPagination, disableForwardPagination, extendConnection, extendEdge, inheritAdditionalArgs, nodes, pageInfoFromNodes, resolve, type, validateArgs, strictArgs, nullable } = fieldConfig, rest = (0, tslib_1.__rest)(fieldConfig, ["additionalArgs", "cursorFromNode", "disableBackwardPagination", "disableForwardPagination", "extendConnection", "extendEdge", "inheritAdditionalArgs", "nodes", "pageInfoFromNodes", "resolve", "type", "validateArgs", "strictArgs", "nullable"]);
return rest;
}
function makeResolveFn(pluginConfig, fieldConfig) {
const mergedConfig = Object.assign(Object.assign({}, pluginConfig), fieldConfig);
return (root, args, ctx, info) => {
const { nodes: nodesResolve } = fieldConfig;
const { decodeCursor = base64Decode, encodeCursor = base64Encode } = pluginConfig;
const { pageInfoFromNodes = defaultPageInfoFromNodes, cursorFromNode = defaultCursorFromNode } = mergedConfig;
if (!nodesResolve) {
return null;
}
const formattedArgs = Object.assign({}, args);
if (args.before) {
formattedArgs.before = decodeCursor(args.before).replace(CURSOR_PREFIX, '');
}
if (args.after) {
formattedArgs.after = decodeCursor(args.after).replace(CURSOR_PREFIX, '');
}
if (args.last && !args.before && cursorFromNode === defaultCursorFromNode) {
throw new Error(`Cannot paginate backward without a "before" cursor by default.`);
}
// Local variable to cache the execution of fetching the nodes,
// which is needed for all fields.
let cachedNodes;
let cachedEdges;
let hasPromise = false;
// Get all the nodes, before any pagination slicing
const resolveAllNodes = () => {
var _a;
if (cachedNodes !== undefined) {
return cachedNodes;
}
cachedNodes = (0, plugin_1.completeValue)((_a = nodesResolve(root, formattedArgs, ctx, info)) !== null && _a !== void 0 ? _a : null, (allNodes) => {
return allNodes ? Array.from(allNodes) : allNodes;
});
return cachedNodes;
};
const resolveEdgesAndNodes = () => {
if (cachedEdges !== undefined) {
return cachedEdges;
}
cachedEdges = (0, plugin_1.completeValue)(resolveAllNodes(), (allNodes) => {
if (!allNodes) {
const arrPath = JSON.stringify((0, utils_1.pathToArray)(info.path));
console.warn(`You resolved null/undefined from nodes() at path ${arrPath}, this is likely an error. Return an empty array to suppress this warning.`);
return { edges: [], nodes: [] };
}
const resolvedEdgeList = [];
const resolvedNodeList = [];
iterateNodes(allNodes, args, (maybeNode, i) => {
if ((0, utils_1.isPromiseLike)(maybeNode)) {
hasPromise = true;
resolvedNodeList.push(maybeNode);
resolvedEdgeList.push(maybeNode.then((node) => {
return (0, plugin_1.completeValue)(cursorFromNode(maybeNode, formattedArgs, ctx, info, {
index: i,
nodes: allNodes,
}), (rawCursor) => wrapEdge(pluginConfig, fieldConfig, formattedArgs, {
cursor: encodeCursor(rawCursor),
node,
}));
}));
}
else {
resolvedNodeList.push(maybeNode);
resolvedEdgeList.push(wrapEdge(pluginConfig, fieldConfig, formattedArgs, {
node: maybeNode,
cursor: (0, plugin_1.completeValue)(cursorFromNode(maybeNode, formattedArgs, ctx, info, {
index: i,
nodes: allNodes,
}), (rawCursor) => encodeCursor(rawCursor)),
}));
}
});
if (hasPromise) {
return Promise.all([Promise.all(resolvedEdgeList), Promise.all(resolvedNodeList)]).then(([edges, nodes]) => ({ edges, nodes }));
}
return {
nodes: resolvedNodeList,
// todo find type-safe way of doing this
edges: resolvedEdgeList,
};
});
return cachedEdges;
};
const resolvePageInfo = () => {
return (0, plugin_1.completeValue)(resolveAllNodes(), (allNodes) => (0, plugin_1.completeValue)(resolveEdgesAndNodes(), ({ edges }) => (0, plugin_1.completeValue)(allNodes
? pageInfoFromNodes(allNodes, args, ctx, info)
: {
hasNextPage: false,
hasPreviousPage: false,
}, (basePageInfo) => {
var _a, _b, _c;
return (Object.assign(Object.assign({}, basePageInfo), { startCursor: ((_a = edges === null || edges === void 0 ? void 0 : edges[0]) === null || _a === void 0 ? void 0 : _a.cursor) ? edges[0].cursor : null, endCursor: (_c = (_b = edges === null || edges === void 0 ? void 0 : edges[edges.length - 1]) === null || _b === void 0 ? void 0 : _b.cursor) !== null && _c !== void 0 ? _c : null }));
})));
};
const connectionResult = withSource(root, formattedArgs, {
get nodes() {
return (0, plugin_1.completeValue)(resolveEdgesAndNodes(), (o) => o.nodes);
},
get edges() {
return (0, plugin_1.completeValue)(resolveEdgesAndNodes(), (o) => o.edges);
},
get pageInfo() {
return resolvePageInfo();
},
});
if (pluginConfig.extendConnection) {
Object.keys(pluginConfig.extendConnection).forEach((connectionField) => {
var _a;
const resolve = (_a = fieldConfig[connectionField]) !== null && _a !== void 0 ? _a : graphql_1.defaultFieldResolver;
Object.defineProperty(connectionResult, connectionField, {
value: (args, ctx, info) => {
return resolve(root, Object.assign(Object.assign({}, formattedArgs), args), ctx, info);
},
});
});
}
return connectionResult;
};
}
exports.makeResolveFn = makeResolveFn;
function wrapEdge(pluginConfig, fieldConfig, formattedArgs, edgeParentType) {
const edge = withArgs(formattedArgs, edgeParentType);
if (pluginConfig.extendEdge) {
Object.keys(pluginConfig.extendEdge).forEach((edgeField) => {
var _a, _b;
const resolve = (_b = (_a = fieldConfig.edgeFields) === null || _a === void 0 ? void 0 : _a[edgeField]) !== null && _b !== void 0 ? _b : graphql_1.defaultFieldResolver;
Object.defineProperty(edge, edgeField, {
value: (args, ctx, info) => {
return resolve(edge, Object.assign(Object.assign({}, formattedArgs), args), ctx, info);
},
});
});
}
return edge;
}
/**
* Adds __connectionArgs to the object representing the Connection type, so it can be accessed by other fields
* in the top level
*
* @param args
* @param connectionParentType
*/
function withArgs(args, connectionParentType) {
Object.defineProperty(connectionParentType, '__connectionArgs', {
value: args,
enumerable: false,
});
return connectionParentType;
}
/**
* Adds __connectionSource to the object representing the Connection type, so it can be accessed by other
* fields in the top level
*
* @param args
* @param connectionParentType
*/
function withSource(source, args, connectionParentType) {
Object.defineProperty(connectionParentType, '__connectionSource', {
value: source,
enumerable: false,
});
return withArgs(args, connectionParentType);
}
/** Takes __connectionArgs from the source object and merges with the args provided by the */
function mergeArgs(obj, fieldArgs) {
return Object.assign(Object.assign({}, obj.__connectionArgs), fieldArgs);
}
/**
* Takes a "builder", and a function which takes a builder, and ensures that all fields defined within that
* function invocation are provided the __connectionArgs defined by the connection
*/
function provideArgs(block, fn) {
const fieldDef = block.field;
block.field = function (...args) {
let config = args.length === 2 ? Object.assign({ name: args[0] }, args[1]) : args[0];
const { resolve = graphql_1.defaultFieldResolver } = config;
fieldDef.call(this, Object.assign(Object.assign({}, config), { resolve(root, args, ctx, info) {
return resolve(root, mergeArgs(root, args), ctx, info);
} }));
};
fn();
block.field = fieldDef;
}
function provideSourceAndArgs(block, fn) {
const fieldDef = block.field;
block.field = function (...args) {
let config = args.length === 2 ? Object.assign({ name: args[0] }, args[1]) : args[0];
const { resolve = graphql_1.defaultFieldResolver } = config;
fieldDef.call(this, Object.assign(Object.assign({}, config), { resolve(root, args, ctx, info) {
return resolve(root.__connectionSource, mergeArgs(root, args), ctx, info);
} }));
};
fn();
block.field = fieldDef;
}
function iterateNodes(nodes, args, cb) {
// If we want the first N of an array of nodes, it's pretty straightforward.
if (typeof args.first === 'number') {
const len = Math.min(args.first, nodes.length);
for (let i = 0; i < len; i++) {
cb(nodes[i], i);
}
}
else if (typeof args.last === 'number') {
const len = Math.min(args.last, nodes.length);
for (let i = 0; i < len; i++) {
cb(nodes[i], i);
}
}
else {
// Only happens if we have a custom validateArgs that ignores first/last
for (let i = 0; i < nodes.length; i++) {
cb(nodes[i], i);
}
}
}
function defaultPageInfoFromNodes(nodes, args) {
return {
hasNextPage: defaultHasNextPage(nodes, args),
hasPreviousPage: defaultHasPreviousPage(nodes, args),
};
}
function defaultHasNextPage(nodes, args) {
// If we're paginating forward, and we don't have an "after", we'll assume that we don't have
// a previous page, otherwise we will assume we have one, unless the after cursor === "0".
if (typeof args.first === 'number') {
return nodes.length > args.first;
}
// If we're paginating backward, and there are as many results as we asked for, then we'll assume
// that we have a previous page
if (typeof args.last === 'number') {
if (args.before && args.before !== '0') {
return true;
}
return false;
}
/* istanbul ignore next */
throw new Error('Unreachable');
}
/** A sensible default for determining "previous page". */
function defaultHasPreviousPage(nodes, args) {
// If we're paginating forward, and we don't have an "after", we'll assume that we don't have
// a previous page, otherwise we will assume we have one, unless the after cursor === "0".
if (typeof args.first === 'number') {
if (args.after && args.after !== '0') {
return true;
}
return false;
}
// If we're paginating backward, and there are as many results as we asked for, then we'll assume
// that we have a previous page
if (typeof args.last === 'number') {
return nodes.length >= args.last;
}
/* istanbul ignore next */
throw new Error('Unreachable');
}
const CURSOR_PREFIX = 'cursor:';
// Assumes we're only paginating in one direction.
function defaultCursorFromNode(node, args, ctx, info, { index, nodes }) {
let cursorIndex = index;
// If we're paginating forward, assume we're incrementing from the offset provided via "after",
// e.g. [0...20] (first: 5, after: "cursor:5") -> [cursor:6, cursor:7, cursor:8, cursor:9, cursor: 10]
if (typeof args.first === 'number') {
if (args.after) {
const offset = parseInt(args.after, 10);
cursorIndex = offset + index + 1;
}
}
// If we're paginating backward, assume we're working backward from the assumed length
// e.g. [0...20] (last: 5, before: "cursor:20") -> [cursor:15, cursor:16, cursor:17, cursor:18, cursor:19]
if (typeof args.last === 'number') {
if (args.before) {
const offset = parseInt(args.before, 10);
const len = Math.min(nodes.length, args.last);
cursorIndex = offset - len + index;
}
else {
/* istanbul ignore next */
throw new Error('Unreachable');
}
}
return `${CURSOR_PREFIX}${cursorIndex}`;
}
const getTypeNames = (fieldName, parentTypeName, fieldConfig, pluginConfig) => {
const targetTypeName = typeof fieldConfig.type === 'string' ? fieldConfig.type : fieldConfig.type.name;
// If we have changed the config specific to this field, on either the connection,
// edge, or page info, then we need a custom type for the connection & edge.
let connectionName;
if (fieldConfig.getConnectionName) {
connectionName = fieldConfig.getConnectionName(fieldName, parentTypeName);
}
else if (pluginConfig.getConnectionName) {
connectionName = pluginConfig.getConnectionName(fieldName, parentTypeName);
}
else if (isConnectionFieldExtended(fieldConfig)) {
connectionName = `${parentTypeName}${upperFirst(fieldName)}_Connection`;
}
else {
connectionName = `${pluginConfig.typePrefix || ''}${targetTypeName}Connection`;
}
// If we have modified the "edge" at all, then we need
let edgeName;
if (fieldConfig.getEdgeName) {
edgeName = fieldConfig.getEdgeName(fieldName, parentTypeName);
}
else if (pluginConfig.getEdgeName) {
edgeName = pluginConfig.getEdgeName(fieldName, parentTypeName);
}
else if (isEdgeFieldExtended(fieldConfig)) {
edgeName = `${parentTypeName}${upperFirst(fieldName)}_Edge`;
}
else {
edgeName = `${pluginConfig.typePrefix || ''}${targetTypeName}Edge`;
}
return {
edgeName,
targetTypeName,
connectionName,
};
};
const isConnectionFieldExtended = (fieldConfig) => {
if (fieldConfig.extendConnection || isEdgeFieldExtended(fieldConfig)) {
return true;
}
return false;
};
const isEdgeFieldExtended = (fieldConfig) => {
if (fieldConfig.extendEdge || fieldConfig.cursorType) {
return true;
}
return false;
};
const upperFirst = (fieldName) => {
return fieldName.slice(0, 1).toUpperCase().concat(fieldName.slice(1));
};
// Add some sanity checking beyond the normal type checks.
const assertCorrectConfig = (typeName, fieldName, pluginConfig, fieldConfig) => {
if (typeof fieldConfig.nodes !== 'function' && typeof fieldConfig.resolve !== 'function') {
console.error(new Error(`Nexus Connection Plugin: Missing nodes or resolve property for ${typeName}.${fieldName}`));
}
(0, utils_1.eachObj)(pluginConfig.extendConnection || {}, (val, key) => {
if (typeof fieldConfig[key] !== 'function' && val.requireResolver !== false) {
console.error(new Error(`Nexus Connection Plugin: Missing ${key} resolver property for ${typeName}.${fieldName}. Set requireResolver to "false" on the field config if you do not need a resolver.`));
}
});
(0, utils_1.eachObj)(pluginConfig.extendEdge || {}, (val, key) => {
var _a;
if (typeof ((_a = fieldConfig.edgeFields) === null || _a === void 0 ? void 0 : _a[key]) !== 'function' && val.requireResolver !== false) {
console.error(new Error(`Nexus Connection Plugin: Missing edgeFields.${key} resolver property for ${typeName}.${fieldName}. Set requireResolver to "false" on the edge field config if you do not need a resolver.`));
}
});
};
function defaultValidateArgs(args = {}, info) {
if (!(args.first || args.first === 0) && !(args.last || args.last === 0)) {
throw new Error(`The ${info.parentType}.${info.fieldName} connection field requires a "first" or "last" argument`);
}
if (args.first && args.last) {
throw new Error(`The ${info.parentType}.${info.fieldName} connection field requires a "first" or "last" argument, not both`);
}
if (args.first && args.before) {
throw new Error(`The ${info.parentType}.${info.fieldName} connection field does not allow a "before" argument with "first"`);
}
if (args.last && args.after) {
throw new Error(`The ${info.parentType}.${info.fieldName} connection field does not allow a "last" argument with "after"`);
}
}
// Provided for use if you create a custom implementation and want to call the original.
exports.connectionPlugin.defaultCursorFromNode = defaultCursorFromNode;
exports.connectionPlugin.defaultValidateArgs = defaultValidateArgs;
exports.connectionPlugin.defaultHasPreviousPage = defaultHasPreviousPage;
exports.connectionPlugin.defaultHasNextPage = defaultHasNextPage;
exports.connectionPlugin.base64Encode = base64Encode;
exports.connectionPlugin.base64Decode = base64Decode;
exports.connectionPlugin.CURSOR_PREFIX = CURSOR_PREFIX;
//# sourceMappingURL=connectionPlugin.js.map