execute.mjs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  1. import inspect from "../jsutils/inspect.mjs";
  2. import memoize3 from "../jsutils/memoize3.mjs";
  3. import invariant from "../jsutils/invariant.mjs";
  4. import devAssert from "../jsutils/devAssert.mjs";
  5. import isPromise from "../jsutils/isPromise.mjs";
  6. import isObjectLike from "../jsutils/isObjectLike.mjs";
  7. import safeArrayFrom from "../jsutils/safeArrayFrom.mjs";
  8. import promiseReduce from "../jsutils/promiseReduce.mjs";
  9. import promiseForObject from "../jsutils/promiseForObject.mjs";
  10. import { addPath, pathToArray } from "../jsutils/Path.mjs";
  11. import { GraphQLError } from "../error/GraphQLError.mjs";
  12. import { locatedError } from "../error/locatedError.mjs";
  13. import { Kind } from "../language/kinds.mjs";
  14. import { assertValidSchema } from "../type/validate.mjs";
  15. import { SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef } from "../type/introspection.mjs";
  16. import { GraphQLIncludeDirective, GraphQLSkipDirective } from "../type/directives.mjs";
  17. import { isNamedType, isObjectType, isAbstractType, isLeafType, isListType, isNonNullType } from "../type/definition.mjs";
  18. import { typeFromAST } from "../utilities/typeFromAST.mjs";
  19. import { getOperationRootType } from "../utilities/getOperationRootType.mjs";
  20. import { getVariableValues, getArgumentValues, getDirectiveValues } from "./values.mjs";
  21. /**
  22. * Terminology
  23. *
  24. * "Definitions" are the generic name for top-level statements in the document.
  25. * Examples of this include:
  26. * 1) Operations (such as a query)
  27. * 2) Fragments
  28. *
  29. * "Operations" are a generic name for requests in the document.
  30. * Examples of this include:
  31. * 1) query,
  32. * 2) mutation
  33. *
  34. * "Selections" are the definitions that can appear legally and at
  35. * single level of the query. These include:
  36. * 1) field references e.g "a"
  37. * 2) fragment "spreads" e.g. "...c"
  38. * 3) inline fragment "spreads" e.g. "...on Type { a }"
  39. */
  40. /**
  41. * Data that must be available at all points during query execution.
  42. *
  43. * Namely, schema of the type system that is currently executing,
  44. * and the fragments defined in the query document
  45. */
  46. export function execute(argsOrSchema, document, rootValue, contextValue, variableValues, operationName, fieldResolver, typeResolver) {
  47. /* eslint-enable no-redeclare */
  48. // Extract arguments from object args if provided.
  49. return arguments.length === 1 ? executeImpl(argsOrSchema) : executeImpl({
  50. schema: argsOrSchema,
  51. document: document,
  52. rootValue: rootValue,
  53. contextValue: contextValue,
  54. variableValues: variableValues,
  55. operationName: operationName,
  56. fieldResolver: fieldResolver,
  57. typeResolver: typeResolver
  58. });
  59. }
  60. /**
  61. * Also implements the "Evaluating requests" section of the GraphQL specification.
  62. * However, it guarantees to complete synchronously (or throw an error) assuming
  63. * that all field resolvers are also synchronous.
  64. */
  65. export function executeSync(args) {
  66. var result = executeImpl(args); // Assert that the execution was synchronous.
  67. if (isPromise(result)) {
  68. throw new Error('GraphQL execution failed to complete synchronously.');
  69. }
  70. return result;
  71. }
  72. function executeImpl(args) {
  73. var schema = args.schema,
  74. document = args.document,
  75. rootValue = args.rootValue,
  76. contextValue = args.contextValue,
  77. variableValues = args.variableValues,
  78. operationName = args.operationName,
  79. fieldResolver = args.fieldResolver,
  80. typeResolver = args.typeResolver; // If arguments are missing or incorrect, throw an error.
  81. assertValidExecutionArguments(schema, document, variableValues); // If a valid execution context cannot be created due to incorrect arguments,
  82. // a "Response" with only errors is returned.
  83. var exeContext = buildExecutionContext(schema, document, rootValue, contextValue, variableValues, operationName, fieldResolver, typeResolver); // Return early errors if execution context failed.
  84. if (Array.isArray(exeContext)) {
  85. return {
  86. errors: exeContext
  87. };
  88. } // Return a Promise that will eventually resolve to the data described by
  89. // The "Response" section of the GraphQL specification.
  90. //
  91. // If errors are encountered while executing a GraphQL field, only that
  92. // field and its descendants will be omitted, and sibling fields will still
  93. // be executed. An execution which encounters errors will still result in a
  94. // resolved Promise.
  95. var data = executeOperation(exeContext, exeContext.operation, rootValue);
  96. return buildResponse(exeContext, data);
  97. }
  98. /**
  99. * Given a completed execution context and data, build the { errors, data }
  100. * response defined by the "Response" section of the GraphQL specification.
  101. */
  102. function buildResponse(exeContext, data) {
  103. if (isPromise(data)) {
  104. return data.then(function (resolved) {
  105. return buildResponse(exeContext, resolved);
  106. });
  107. }
  108. return exeContext.errors.length === 0 ? {
  109. data: data
  110. } : {
  111. errors: exeContext.errors,
  112. data: data
  113. };
  114. }
  115. /**
  116. * Essential assertions before executing to provide developer feedback for
  117. * improper use of the GraphQL library.
  118. *
  119. * @internal
  120. */
  121. export function assertValidExecutionArguments(schema, document, rawVariableValues) {
  122. document || devAssert(0, 'Must provide document.'); // If the schema used for execution is invalid, throw an error.
  123. assertValidSchema(schema); // Variables, if provided, must be an object.
  124. rawVariableValues == null || isObjectLike(rawVariableValues) || devAssert(0, 'Variables must be provided as an Object where each property is a variable value. Perhaps look to see if an unparsed JSON string was provided.');
  125. }
  126. /**
  127. * Constructs a ExecutionContext object from the arguments passed to
  128. * execute, which we will pass throughout the other execution methods.
  129. *
  130. * Throws a GraphQLError if a valid execution context cannot be created.
  131. *
  132. * @internal
  133. */
  134. export function buildExecutionContext(schema, document, rootValue, contextValue, rawVariableValues, operationName, fieldResolver, typeResolver) {
  135. var _definition$name, _operation$variableDe;
  136. var operation;
  137. var fragments = Object.create(null);
  138. for (var _i2 = 0, _document$definitions2 = document.definitions; _i2 < _document$definitions2.length; _i2++) {
  139. var definition = _document$definitions2[_i2];
  140. switch (definition.kind) {
  141. case Kind.OPERATION_DEFINITION:
  142. if (operationName == null) {
  143. if (operation !== undefined) {
  144. return [new GraphQLError('Must provide operation name if query contains multiple operations.')];
  145. }
  146. operation = definition;
  147. } else if (((_definition$name = definition.name) === null || _definition$name === void 0 ? void 0 : _definition$name.value) === operationName) {
  148. operation = definition;
  149. }
  150. break;
  151. case Kind.FRAGMENT_DEFINITION:
  152. fragments[definition.name.value] = definition;
  153. break;
  154. }
  155. }
  156. if (!operation) {
  157. if (operationName != null) {
  158. return [new GraphQLError("Unknown operation named \"".concat(operationName, "\"."))];
  159. }
  160. return [new GraphQLError('Must provide an operation.')];
  161. } // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
  162. var variableDefinitions = (_operation$variableDe = operation.variableDefinitions) !== null && _operation$variableDe !== void 0 ? _operation$variableDe : [];
  163. var coercedVariableValues = getVariableValues(schema, variableDefinitions, rawVariableValues !== null && rawVariableValues !== void 0 ? rawVariableValues : {}, {
  164. maxErrors: 50
  165. });
  166. if (coercedVariableValues.errors) {
  167. return coercedVariableValues.errors;
  168. }
  169. return {
  170. schema: schema,
  171. fragments: fragments,
  172. rootValue: rootValue,
  173. contextValue: contextValue,
  174. operation: operation,
  175. variableValues: coercedVariableValues.coerced,
  176. fieldResolver: fieldResolver !== null && fieldResolver !== void 0 ? fieldResolver : defaultFieldResolver,
  177. typeResolver: typeResolver !== null && typeResolver !== void 0 ? typeResolver : defaultTypeResolver,
  178. errors: []
  179. };
  180. }
  181. /**
  182. * Implements the "Evaluating operations" section of the spec.
  183. */
  184. function executeOperation(exeContext, operation, rootValue) {
  185. var type = getOperationRootType(exeContext.schema, operation);
  186. var fields = collectFields(exeContext, type, operation.selectionSet, Object.create(null), Object.create(null));
  187. var path = undefined; // Errors from sub-fields of a NonNull type may propagate to the top level,
  188. // at which point we still log the error and null the parent field, which
  189. // in this case is the entire response.
  190. try {
  191. var result = operation.operation === 'mutation' ? executeFieldsSerially(exeContext, type, rootValue, path, fields) : executeFields(exeContext, type, rootValue, path, fields);
  192. if (isPromise(result)) {
  193. return result.then(undefined, function (error) {
  194. exeContext.errors.push(error);
  195. return Promise.resolve(null);
  196. });
  197. }
  198. return result;
  199. } catch (error) {
  200. exeContext.errors.push(error);
  201. return null;
  202. }
  203. }
  204. /**
  205. * Implements the "Evaluating selection sets" section of the spec
  206. * for "write" mode.
  207. */
  208. function executeFieldsSerially(exeContext, parentType, sourceValue, path, fields) {
  209. return promiseReduce(Object.keys(fields), function (results, responseName) {
  210. var fieldNodes = fields[responseName];
  211. var fieldPath = addPath(path, responseName, parentType.name);
  212. var result = resolveField(exeContext, parentType, sourceValue, fieldNodes, fieldPath);
  213. if (result === undefined) {
  214. return results;
  215. }
  216. if (isPromise(result)) {
  217. return result.then(function (resolvedResult) {
  218. results[responseName] = resolvedResult;
  219. return results;
  220. });
  221. }
  222. results[responseName] = result;
  223. return results;
  224. }, Object.create(null));
  225. }
  226. /**
  227. * Implements the "Evaluating selection sets" section of the spec
  228. * for "read" mode.
  229. */
  230. function executeFields(exeContext, parentType, sourceValue, path, fields) {
  231. var results = Object.create(null);
  232. var containsPromise = false;
  233. for (var _i4 = 0, _Object$keys2 = Object.keys(fields); _i4 < _Object$keys2.length; _i4++) {
  234. var responseName = _Object$keys2[_i4];
  235. var fieldNodes = fields[responseName];
  236. var fieldPath = addPath(path, responseName, parentType.name);
  237. var result = resolveField(exeContext, parentType, sourceValue, fieldNodes, fieldPath);
  238. if (result !== undefined) {
  239. results[responseName] = result;
  240. if (isPromise(result)) {
  241. containsPromise = true;
  242. }
  243. }
  244. } // If there are no promises, we can just return the object
  245. if (!containsPromise) {
  246. return results;
  247. } // Otherwise, results is a map from field name to the result of resolving that
  248. // field, which is possibly a promise. Return a promise that will return this
  249. // same map, but with any promises replaced with the values they resolved to.
  250. return promiseForObject(results);
  251. }
  252. /**
  253. * Given a selectionSet, adds all of the fields in that selection to
  254. * the passed in map of fields, and returns it at the end.
  255. *
  256. * CollectFields requires the "runtime type" of an object. For a field which
  257. * returns an Interface or Union type, the "runtime type" will be the actual
  258. * Object type returned by that field.
  259. *
  260. * @internal
  261. */
  262. export function collectFields(exeContext, runtimeType, selectionSet, fields, visitedFragmentNames) {
  263. for (var _i6 = 0, _selectionSet$selecti2 = selectionSet.selections; _i6 < _selectionSet$selecti2.length; _i6++) {
  264. var selection = _selectionSet$selecti2[_i6];
  265. switch (selection.kind) {
  266. case Kind.FIELD:
  267. {
  268. if (!shouldIncludeNode(exeContext, selection)) {
  269. continue;
  270. }
  271. var name = getFieldEntryKey(selection);
  272. if (!fields[name]) {
  273. fields[name] = [];
  274. }
  275. fields[name].push(selection);
  276. break;
  277. }
  278. case Kind.INLINE_FRAGMENT:
  279. {
  280. if (!shouldIncludeNode(exeContext, selection) || !doesFragmentConditionMatch(exeContext, selection, runtimeType)) {
  281. continue;
  282. }
  283. collectFields(exeContext, runtimeType, selection.selectionSet, fields, visitedFragmentNames);
  284. break;
  285. }
  286. case Kind.FRAGMENT_SPREAD:
  287. {
  288. var fragName = selection.name.value;
  289. if (visitedFragmentNames[fragName] || !shouldIncludeNode(exeContext, selection)) {
  290. continue;
  291. }
  292. visitedFragmentNames[fragName] = true;
  293. var fragment = exeContext.fragments[fragName];
  294. if (!fragment || !doesFragmentConditionMatch(exeContext, fragment, runtimeType)) {
  295. continue;
  296. }
  297. collectFields(exeContext, runtimeType, fragment.selectionSet, fields, visitedFragmentNames);
  298. break;
  299. }
  300. }
  301. }
  302. return fields;
  303. }
  304. /**
  305. * Determines if a field should be included based on the @include and @skip
  306. * directives, where @skip has higher precedence than @include.
  307. */
  308. function shouldIncludeNode(exeContext, node) {
  309. var skip = getDirectiveValues(GraphQLSkipDirective, node, exeContext.variableValues);
  310. if ((skip === null || skip === void 0 ? void 0 : skip.if) === true) {
  311. return false;
  312. }
  313. var include = getDirectiveValues(GraphQLIncludeDirective, node, exeContext.variableValues);
  314. if ((include === null || include === void 0 ? void 0 : include.if) === false) {
  315. return false;
  316. }
  317. return true;
  318. }
  319. /**
  320. * Determines if a fragment is applicable to the given type.
  321. */
  322. function doesFragmentConditionMatch(exeContext, fragment, type) {
  323. var typeConditionNode = fragment.typeCondition;
  324. if (!typeConditionNode) {
  325. return true;
  326. }
  327. var conditionalType = typeFromAST(exeContext.schema, typeConditionNode);
  328. if (conditionalType === type) {
  329. return true;
  330. }
  331. if (isAbstractType(conditionalType)) {
  332. return exeContext.schema.isSubType(conditionalType, type);
  333. }
  334. return false;
  335. }
  336. /**
  337. * Implements the logic to compute the key of a given field's entry
  338. */
  339. function getFieldEntryKey(node) {
  340. return node.alias ? node.alias.value : node.name.value;
  341. }
  342. /**
  343. * Resolves the field on the given source object. In particular, this
  344. * figures out the value that the field returns by calling its resolve function,
  345. * then calls completeValue to complete promises, serialize scalars, or execute
  346. * the sub-selection-set for objects.
  347. */
  348. function resolveField(exeContext, parentType, source, fieldNodes, path) {
  349. var _fieldDef$resolve;
  350. var fieldNode = fieldNodes[0];
  351. var fieldName = fieldNode.name.value;
  352. var fieldDef = getFieldDef(exeContext.schema, parentType, fieldName);
  353. if (!fieldDef) {
  354. return;
  355. }
  356. var returnType = fieldDef.type;
  357. var resolveFn = (_fieldDef$resolve = fieldDef.resolve) !== null && _fieldDef$resolve !== void 0 ? _fieldDef$resolve : exeContext.fieldResolver;
  358. var info = buildResolveInfo(exeContext, fieldDef, fieldNodes, parentType, path); // Get the resolve function, regardless of if its result is normal or abrupt (error).
  359. try {
  360. // Build a JS object of arguments from the field.arguments AST, using the
  361. // variables scope to fulfill any variable references.
  362. // TODO: find a way to memoize, in case this field is within a List type.
  363. var args = getArgumentValues(fieldDef, fieldNodes[0], exeContext.variableValues); // The resolve function's optional third argument is a context value that
  364. // is provided to every resolve function within an execution. It is commonly
  365. // used to represent an authenticated user, or request-specific caches.
  366. var _contextValue = exeContext.contextValue;
  367. var result = resolveFn(source, args, _contextValue, info);
  368. var completed;
  369. if (isPromise(result)) {
  370. completed = result.then(function (resolved) {
  371. return completeValue(exeContext, returnType, fieldNodes, info, path, resolved);
  372. });
  373. } else {
  374. completed = completeValue(exeContext, returnType, fieldNodes, info, path, result);
  375. }
  376. if (isPromise(completed)) {
  377. // Note: we don't rely on a `catch` method, but we do expect "thenable"
  378. // to take a second callback for the error case.
  379. return completed.then(undefined, function (rawError) {
  380. var error = locatedError(rawError, fieldNodes, pathToArray(path));
  381. return handleFieldError(error, returnType, exeContext);
  382. });
  383. }
  384. return completed;
  385. } catch (rawError) {
  386. var error = locatedError(rawError, fieldNodes, pathToArray(path));
  387. return handleFieldError(error, returnType, exeContext);
  388. }
  389. }
  390. /**
  391. * @internal
  392. */
  393. export function buildResolveInfo(exeContext, fieldDef, fieldNodes, parentType, path) {
  394. // The resolve function's optional fourth argument is a collection of
  395. // information about the current execution state.
  396. return {
  397. fieldName: fieldDef.name,
  398. fieldNodes: fieldNodes,
  399. returnType: fieldDef.type,
  400. parentType: parentType,
  401. path: path,
  402. schema: exeContext.schema,
  403. fragments: exeContext.fragments,
  404. rootValue: exeContext.rootValue,
  405. operation: exeContext.operation,
  406. variableValues: exeContext.variableValues
  407. };
  408. }
  409. function handleFieldError(error, returnType, exeContext) {
  410. // If the field type is non-nullable, then it is resolved without any
  411. // protection from errors, however it still properly locates the error.
  412. if (isNonNullType(returnType)) {
  413. throw error;
  414. } // Otherwise, error protection is applied, logging the error and resolving
  415. // a null value for this field if one is encountered.
  416. exeContext.errors.push(error);
  417. return null;
  418. }
  419. /**
  420. * Implements the instructions for completeValue as defined in the
  421. * "Field entries" section of the spec.
  422. *
  423. * If the field type is Non-Null, then this recursively completes the value
  424. * for the inner type. It throws a field error if that completion returns null,
  425. * as per the "Nullability" section of the spec.
  426. *
  427. * If the field type is a List, then this recursively completes the value
  428. * for the inner type on each item in the list.
  429. *
  430. * If the field type is a Scalar or Enum, ensures the completed value is a legal
  431. * value of the type by calling the `serialize` method of GraphQL type
  432. * definition.
  433. *
  434. * If the field is an abstract type, determine the runtime type of the value
  435. * and then complete based on that type
  436. *
  437. * Otherwise, the field type expects a sub-selection set, and will complete the
  438. * value by evaluating all sub-selections.
  439. */
  440. function completeValue(exeContext, returnType, fieldNodes, info, path, result) {
  441. // If result is an Error, throw a located error.
  442. if (result instanceof Error) {
  443. throw result;
  444. } // If field type is NonNull, complete for inner type, and throw field error
  445. // if result is null.
  446. if (isNonNullType(returnType)) {
  447. var completed = completeValue(exeContext, returnType.ofType, fieldNodes, info, path, result);
  448. if (completed === null) {
  449. throw new Error("Cannot return null for non-nullable field ".concat(info.parentType.name, ".").concat(info.fieldName, "."));
  450. }
  451. return completed;
  452. } // If result value is null or undefined then return null.
  453. if (result == null) {
  454. return null;
  455. } // If field type is List, complete each item in the list with the inner type
  456. if (isListType(returnType)) {
  457. return completeListValue(exeContext, returnType, fieldNodes, info, path, result);
  458. } // If field type is a leaf type, Scalar or Enum, serialize to a valid value,
  459. // returning null if serialization is not possible.
  460. if (isLeafType(returnType)) {
  461. return completeLeafValue(returnType, result);
  462. } // If field type is an abstract type, Interface or Union, determine the
  463. // runtime Object type and complete for that type.
  464. if (isAbstractType(returnType)) {
  465. return completeAbstractValue(exeContext, returnType, fieldNodes, info, path, result);
  466. } // If field type is Object, execute and complete all sub-selections.
  467. // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
  468. if (isObjectType(returnType)) {
  469. return completeObjectValue(exeContext, returnType, fieldNodes, info, path, result);
  470. } // istanbul ignore next (Not reachable. All possible output types have been considered)
  471. false || invariant(0, 'Cannot complete value of unexpected output type: ' + inspect(returnType));
  472. }
  473. /**
  474. * Complete a list value by completing each item in the list with the
  475. * inner type
  476. */
  477. function completeListValue(exeContext, returnType, fieldNodes, info, path, result) {
  478. // This is specified as a simple map, however we're optimizing the path
  479. // where the list contains no Promises by avoiding creating another Promise.
  480. var itemType = returnType.ofType;
  481. var containsPromise = false;
  482. var completedResults = safeArrayFrom(result, function (item, index) {
  483. // No need to modify the info object containing the path,
  484. // since from here on it is not ever accessed by resolver functions.
  485. var itemPath = addPath(path, index, undefined);
  486. try {
  487. var completedItem;
  488. if (isPromise(item)) {
  489. completedItem = item.then(function (resolved) {
  490. return completeValue(exeContext, itemType, fieldNodes, info, itemPath, resolved);
  491. });
  492. } else {
  493. completedItem = completeValue(exeContext, itemType, fieldNodes, info, itemPath, item);
  494. }
  495. if (isPromise(completedItem)) {
  496. containsPromise = true; // Note: we don't rely on a `catch` method, but we do expect "thenable"
  497. // to take a second callback for the error case.
  498. return completedItem.then(undefined, function (rawError) {
  499. var error = locatedError(rawError, fieldNodes, pathToArray(itemPath));
  500. return handleFieldError(error, itemType, exeContext);
  501. });
  502. }
  503. return completedItem;
  504. } catch (rawError) {
  505. var error = locatedError(rawError, fieldNodes, pathToArray(itemPath));
  506. return handleFieldError(error, itemType, exeContext);
  507. }
  508. });
  509. if (completedResults == null) {
  510. throw new GraphQLError("Expected Iterable, but did not find one for field \"".concat(info.parentType.name, ".").concat(info.fieldName, "\"."));
  511. }
  512. return containsPromise ? Promise.all(completedResults) : completedResults;
  513. }
  514. /**
  515. * Complete a Scalar or Enum by serializing to a valid value, returning
  516. * null if serialization is not possible.
  517. */
  518. function completeLeafValue(returnType, result) {
  519. var serializedResult = returnType.serialize(result);
  520. if (serializedResult === undefined) {
  521. throw new Error("Expected a value of type \"".concat(inspect(returnType), "\" but ") + "received: ".concat(inspect(result)));
  522. }
  523. return serializedResult;
  524. }
  525. /**
  526. * Complete a value of an abstract type by determining the runtime object type
  527. * of that value, then complete the value for that type.
  528. */
  529. function completeAbstractValue(exeContext, returnType, fieldNodes, info, path, result) {
  530. var _returnType$resolveTy;
  531. var resolveTypeFn = (_returnType$resolveTy = returnType.resolveType) !== null && _returnType$resolveTy !== void 0 ? _returnType$resolveTy : exeContext.typeResolver;
  532. var contextValue = exeContext.contextValue;
  533. var runtimeType = resolveTypeFn(result, contextValue, info, returnType);
  534. if (isPromise(runtimeType)) {
  535. return runtimeType.then(function (resolvedRuntimeType) {
  536. return completeObjectValue(exeContext, ensureValidRuntimeType(resolvedRuntimeType, exeContext, returnType, fieldNodes, info, result), fieldNodes, info, path, result);
  537. });
  538. }
  539. return completeObjectValue(exeContext, ensureValidRuntimeType(runtimeType, exeContext, returnType, fieldNodes, info, result), fieldNodes, info, path, result);
  540. }
  541. function ensureValidRuntimeType(runtimeTypeOrName, exeContext, returnType, fieldNodes, info, result) {
  542. if (runtimeTypeOrName == null) {
  543. throw new GraphQLError("Abstract type \"".concat(returnType.name, "\" must resolve to an Object type at runtime for field \"").concat(info.parentType.name, ".").concat(info.fieldName, "\". Either the \"").concat(returnType.name, "\" type should provide a \"resolveType\" function or each possible type should provide an \"isTypeOf\" function."), fieldNodes);
  544. } // FIXME: temporary workaround until support for passing object types would be removed in v16.0.0
  545. var runtimeTypeName = isNamedType(runtimeTypeOrName) ? runtimeTypeOrName.name : runtimeTypeOrName;
  546. if (typeof runtimeTypeName !== 'string') {
  547. throw new GraphQLError("Abstract type \"".concat(returnType.name, "\" must resolve to an Object type at runtime for field \"").concat(info.parentType.name, ".").concat(info.fieldName, "\" with ") + "value ".concat(inspect(result), ", received \"").concat(inspect(runtimeTypeOrName), "\"."));
  548. }
  549. var runtimeType = exeContext.schema.getType(runtimeTypeName);
  550. if (runtimeType == null) {
  551. throw new GraphQLError("Abstract type \"".concat(returnType.name, "\" was resolve to a type \"").concat(runtimeTypeName, "\" that does not exist inside schema."), fieldNodes);
  552. }
  553. if (!isObjectType(runtimeType)) {
  554. throw new GraphQLError("Abstract type \"".concat(returnType.name, "\" was resolve to a non-object type \"").concat(runtimeTypeName, "\"."), fieldNodes);
  555. }
  556. if (!exeContext.schema.isSubType(returnType, runtimeType)) {
  557. throw new GraphQLError("Runtime Object type \"".concat(runtimeType.name, "\" is not a possible type for \"").concat(returnType.name, "\"."), fieldNodes);
  558. }
  559. return runtimeType;
  560. }
  561. /**
  562. * Complete an Object value by executing all sub-selections.
  563. */
  564. function completeObjectValue(exeContext, returnType, fieldNodes, info, path, result) {
  565. // If there is an isTypeOf predicate function, call it with the
  566. // current result. If isTypeOf returns false, then raise an error rather
  567. // than continuing execution.
  568. if (returnType.isTypeOf) {
  569. var isTypeOf = returnType.isTypeOf(result, exeContext.contextValue, info);
  570. if (isPromise(isTypeOf)) {
  571. return isTypeOf.then(function (resolvedIsTypeOf) {
  572. if (!resolvedIsTypeOf) {
  573. throw invalidReturnTypeError(returnType, result, fieldNodes);
  574. }
  575. return collectAndExecuteSubfields(exeContext, returnType, fieldNodes, path, result);
  576. });
  577. }
  578. if (!isTypeOf) {
  579. throw invalidReturnTypeError(returnType, result, fieldNodes);
  580. }
  581. }
  582. return collectAndExecuteSubfields(exeContext, returnType, fieldNodes, path, result);
  583. }
  584. function invalidReturnTypeError(returnType, result, fieldNodes) {
  585. return new GraphQLError("Expected value of type \"".concat(returnType.name, "\" but got: ").concat(inspect(result), "."), fieldNodes);
  586. }
  587. function collectAndExecuteSubfields(exeContext, returnType, fieldNodes, path, result) {
  588. // Collect sub-fields to execute to complete this value.
  589. var subFieldNodes = collectSubfields(exeContext, returnType, fieldNodes);
  590. return executeFields(exeContext, returnType, result, path, subFieldNodes);
  591. }
  592. /**
  593. * A memoized collection of relevant subfields with regard to the return
  594. * type. Memoizing ensures the subfields are not repeatedly calculated, which
  595. * saves overhead when resolving lists of values.
  596. */
  597. var collectSubfields = memoize3(_collectSubfields);
  598. function _collectSubfields(exeContext, returnType, fieldNodes) {
  599. var subFieldNodes = Object.create(null);
  600. var visitedFragmentNames = Object.create(null);
  601. for (var _i8 = 0; _i8 < fieldNodes.length; _i8++) {
  602. var node = fieldNodes[_i8];
  603. if (node.selectionSet) {
  604. subFieldNodes = collectFields(exeContext, returnType, node.selectionSet, subFieldNodes, visitedFragmentNames);
  605. }
  606. }
  607. return subFieldNodes;
  608. }
  609. /**
  610. * If a resolveType function is not given, then a default resolve behavior is
  611. * used which attempts two strategies:
  612. *
  613. * First, See if the provided value has a `__typename` field defined, if so, use
  614. * that value as name of the resolved type.
  615. *
  616. * Otherwise, test each possible type for the abstract type by calling
  617. * isTypeOf for the object being coerced, returning the first type that matches.
  618. */
  619. export var defaultTypeResolver = function defaultTypeResolver(value, contextValue, info, abstractType) {
  620. // First, look for `__typename`.
  621. if (isObjectLike(value) && typeof value.__typename === 'string') {
  622. return value.__typename;
  623. } // Otherwise, test each possible type.
  624. var possibleTypes = info.schema.getPossibleTypes(abstractType);
  625. var promisedIsTypeOfResults = [];
  626. for (var i = 0; i < possibleTypes.length; i++) {
  627. var type = possibleTypes[i];
  628. if (type.isTypeOf) {
  629. var isTypeOfResult = type.isTypeOf(value, contextValue, info);
  630. if (isPromise(isTypeOfResult)) {
  631. promisedIsTypeOfResults[i] = isTypeOfResult;
  632. } else if (isTypeOfResult) {
  633. return type.name;
  634. }
  635. }
  636. }
  637. if (promisedIsTypeOfResults.length) {
  638. return Promise.all(promisedIsTypeOfResults).then(function (isTypeOfResults) {
  639. for (var _i9 = 0; _i9 < isTypeOfResults.length; _i9++) {
  640. if (isTypeOfResults[_i9]) {
  641. return possibleTypes[_i9].name;
  642. }
  643. }
  644. });
  645. }
  646. };
  647. /**
  648. * If a resolve function is not given, then a default resolve behavior is used
  649. * which takes the property of the source object of the same name as the field
  650. * and returns it as the result, or if it's a function, returns the result
  651. * of calling that function while passing along args and context value.
  652. */
  653. export var defaultFieldResolver = function defaultFieldResolver(source, args, contextValue, info) {
  654. // ensure source is a value for which property access is acceptable.
  655. if (isObjectLike(source) || typeof source === 'function') {
  656. var property = source[info.fieldName];
  657. if (typeof property === 'function') {
  658. return source[info.fieldName](args, contextValue, info);
  659. }
  660. return property;
  661. }
  662. };
  663. /**
  664. * This method looks up the field on the given type definition.
  665. * It has special casing for the three introspection fields,
  666. * __schema, __type and __typename. __typename is special because
  667. * it can always be queried as a field, even in situations where no
  668. * other fields are allowed, like on a Union. __schema and __type
  669. * could get automatically added to the query type, but that would
  670. * require mutating type definitions, which would cause issues.
  671. *
  672. * @internal
  673. */
  674. export function getFieldDef(schema, parentType, fieldName) {
  675. if (fieldName === SchemaMetaFieldDef.name && schema.getQueryType() === parentType) {
  676. return SchemaMetaFieldDef;
  677. } else if (fieldName === TypeMetaFieldDef.name && schema.getQueryType() === parentType) {
  678. return TypeMetaFieldDef;
  679. } else if (fieldName === TypeNameMetaFieldDef.name) {
  680. return TypeNameMetaFieldDef;
  681. }
  682. return parentType.getFields()[fieldName];
  683. }