grafast
Version:
Cutting edge GraphQL planning and execution engine
179 lines • 7.07 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GraphQLResolveTypeStep = exports.GraphQLResolverStep = void 0;
exports.graphqlResolveType = graphqlResolveType;
exports.graphqlResolver = graphqlResolver;
const tslib_1 = require("tslib");
const graphql = tslib_1.__importStar(require("graphql"));
const index_js_1 = require("../index.js");
const step_js_1 = require("../step.js");
const utils_js_1 = require("../utils.js");
const { defaultTypeResolver } = graphql;
/**
* Calls the given GraphQL resolver for each input - emulates GraphQL
* resolution.
*
* @internal
*/
class GraphQLResolverStep extends step_js_1.UnbatchedStep {
static { this.$$export = {
moduleName: "grafast",
exportName: "GraphQLResolverStep",
}; }
constructor(resolver, subscriber, $plan, $args, resolveInfoBase) {
super();
this.resolver = resolver;
this.subscriber = subscriber;
this.resolveInfoBase = resolveInfoBase;
this.isSyncAndSafe = false;
this.allowMultipleOptimizations = false;
this.addDependency($plan);
this.addDependency($args);
this.addDependency((0, index_js_1.context)());
this.addDependency(this.operationPlan.variableValuesStep);
this.addDependency(this.operationPlan.rootValueStep);
this.isNotRoot = ![
this.operationPlan.queryType,
this.operationPlan.mutationType,
this.operationPlan.subscriptionType,
].includes(resolveInfoBase.parentType);
}
toStringMeta() {
const resolverName = this.resolver?.displayName ||
this.resolver?.name ||
this.subscriber?.displayName ||
this.subscriber?.name ||
null;
return `${this.resolveInfoBase.parentType.name}.${this.resolveInfoBase.fieldName}${resolverName && resolverName !== "resolve" ? `:${resolverName}` : ""}`;
}
unbatchedExecute(extra, source, args, context, variableValues, rootValue) {
if (!extra.stream) {
if (this.isNotRoot && source == null) {
return source;
}
const resolveInfo = Object.assign(Object.create(this.resolveInfoBase), {
variableValues,
rootValue,
path: {
typename: this.resolveInfoBase.parentType.name,
key: this.resolveInfoBase.fieldName,
// ENHANCE: add full support for path (requires runtime indexes)
prev: undefined,
},
});
const data = this.resolver?.(source, args, context, resolveInfo);
return flagErrorIfErrorAsync(data);
}
else {
if (this.isNotRoot) {
return Promise.reject(new Error(`Invalid non-root subscribe`));
}
if (this.subscriber == null) {
return Promise.reject(new Error(`Cannot subscribe to field`));
}
const resolveInfo = Object.assign(Object.create(this.resolveInfoBase), {
// ENHANCE: add support for path
variableValues,
rootValue,
});
// TODO: we also need to call the resolver on each result?
const data = this.subscriber(source, args, context, resolveInfo);
// TODO: should apply flagErrorIfError to each value data yields
return flagErrorIfErrorAsync(data);
}
}
}
exports.GraphQLResolverStep = GraphQLResolverStep;
/** @internal */
class GraphQLResolveTypeStep extends step_js_1.Step {
static { this.$$export = {
moduleName: "grafast",
exportName: "GraphQLResolveTypeStep",
}; }
constructor($stepOrSpecifier, info) {
super();
// Could be promises
this.isSyncAndSafe = false;
const { abstractType } = info;
this.abstractType = abstractType;
this.resolveInfoBase = {
...this.operationPlan.resolveInfoOperationBase,
// TODO: this resolveInfo is seriously hacked, we don't know a number of
// things that _shouldn't_ be necessary for figuring out the type, so
// we'll run in this crippled state.
// Really we should inherit the resolveInfo from the field itself, but
// currently that doesn't get passed through. Maybe it should have its
// own step which we pass through as a dependency?
fieldName: null,
parentType: null,
path: null,
fieldNodes: null,
// Even this is a lie
returnType: abstractType,
};
this.addDataDependency($stepOrSpecifier);
this.addUnaryDependency((0, index_js_1.context)());
this.addUnaryDependency(this.operationPlan.variableValuesStep);
this.addUnaryDependency(this.operationPlan.rootValueStep);
}
/**
* Akin to graphql-js' completeAbstractValue... but just the typeName
* resolution part.
*/
figureOutTheTypeOf(data, context, resolveInfo) {
const abstractType = this.abstractType;
if (abstractType.resolveType != null) {
return abstractType.resolveType(data, context, resolveInfo, abstractType);
}
else {
return defaultTypeResolver(data, context, resolveInfo, abstractType);
}
}
execute({ indexMap, values: [values0, contextVal, variableValuesVal, rootValueVal], }) {
const context = contextVal.unaryValue();
const variableValues = variableValuesVal.unaryValue();
const rootValue = rootValueVal.unaryValue();
const resolveInfo = {
...this.resolveInfoBase,
rootValue,
variableValues,
};
return indexMap((i) => {
const data = values0.at(i);
if (data == null) {
return data;
}
else if ((0, utils_js_1.isPromiseLike)(data)) {
return data.then((resolvedData) => this.figureOutTheTypeOf(resolvedData, context, resolveInfo));
}
else {
return this.figureOutTheTypeOf(data, context, resolveInfo);
}
});
}
}
exports.GraphQLResolveTypeStep = GraphQLResolveTypeStep;
function graphqlResolveType($stepOrSpecifier, info) {
return new GraphQLResolveTypeStep($stepOrSpecifier, info);
}
/**
* Emulates what GraphQL does when calling a resolver, including handling of
* polymorphism.
*
* @internal
*/
function graphqlResolver(resolver, subscriber, $step, $args, resolveInfoBase) {
return new GraphQLResolverStep(resolver, subscriber, $step, $args, resolveInfoBase);
}
function flagErrorIfError(data) {
return data instanceof Error ? (0, index_js_1.flagError)(data) : data;
}
function flagErrorIfErrorAsync(data) {
if ((0, utils_js_1.isPromiseLike)(data)) {
return data.then(flagErrorIfError);
}
else {
return flagErrorIfError(data);
}
}
//# sourceMappingURL=graphqlResolver.js.map