UNPKG

15.3 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
7const tslib = require('tslib');
8const graphql = require('graphql');
9const isPromise = _interopDefault(require('is-promise'));
10const DataLoader = _interopDefault(require('dataloader'));
11const utils = require('@graphql-tools/utils/es5');
12
13// adapted from https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-source-graphql/src/batching/merge-queries.js
14function createPrefix(index) {
15 return "graphqlTools" + index + "_";
16}
17function parseKey(prefixedKey) {
18 var match = /^graphqlTools([\d]+)_(.*)$/.exec(prefixedKey);
19 if (match && match.length === 3 && !isNaN(Number(match[1])) && match[2]) {
20 return { index: Number(match[1]), originalKey: match[2] };
21 }
22 return null;
23}
24
25// adapted from https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-source-graphql/src/batching/merge-queries.js
26/**
27 * Merge multiple queries into a single query in such a way that query results
28 * can be split and transformed as if they were obtained by running original queries.
29 *
30 * Merging algorithm involves several transformations:
31 * 1. Replace top-level fragment spreads with inline fragments (... on Query {})
32 * 2. Add unique aliases to all top-level query fields (including those on inline fragments)
33 * 3. Prefix all variable definitions and variable usages
34 * 4. Prefix names (and spreads) of fragments
35 *
36 * i.e transform:
37 * [
38 * `query Foo($id: ID!) { foo, bar(id: $id), ...FooQuery }
39 * fragment FooQuery on Query { baz }`,
40 *
41 * `query Bar($id: ID!) { foo: baz, bar(id: $id), ... on Query { baz } }`
42 * ]
43 * to:
44 * query (
45 * $graphqlTools1_id: ID!
46 * $graphqlTools2_id: ID!
47 * ) {
48 * graphqlTools1_foo: foo,
49 * graphqlTools1_bar: bar(id: $graphqlTools1_id)
50 * ... on Query {
51 * graphqlTools1__baz: baz
52 * }
53 * graphqlTools1__foo: baz
54 * graphqlTools1__bar: bar(id: $graphqlTools1__id)
55 * ... on Query {
56 * graphqlTools1__baz: baz
57 * }
58 * }
59 */
60function mergeExecutionParams(execs, extensionsReducer) {
61 var mergedVariables = Object.create(null);
62 var mergedVariableDefinitions = [];
63 var mergedSelections = [];
64 var mergedFragmentDefinitions = [];
65 var mergedExtensions = Object.create(null);
66 var operation;
67 execs.forEach(function (executionParams, index) {
68 var prefixedExecutionParams = prefixExecutionParams(createPrefix(index), executionParams);
69 prefixedExecutionParams.document.definitions.forEach(function (def) {
70 var _a;
71 if (isOperationDefinition(def)) {
72 operation = def.operation;
73 mergedSelections.push.apply(mergedSelections, tslib.__spread(def.selectionSet.selections));
74 mergedVariableDefinitions.push.apply(mergedVariableDefinitions, tslib.__spread(((_a = def.variableDefinitions) !== null && _a !== void 0 ? _a : [])));
75 }
76 if (isFragmentDefinition(def)) {
77 mergedFragmentDefinitions.push(def);
78 }
79 });
80 Object.assign(mergedVariables, prefixedExecutionParams.variables);
81 mergedExtensions = extensionsReducer(mergedExtensions, executionParams);
82 });
83 var mergedOperationDefinition = {
84 kind: graphql.Kind.OPERATION_DEFINITION,
85 operation: operation,
86 variableDefinitions: mergedVariableDefinitions,
87 selectionSet: {
88 kind: graphql.Kind.SELECTION_SET,
89 selections: mergedSelections,
90 },
91 };
92 return {
93 document: {
94 kind: graphql.Kind.DOCUMENT,
95 definitions: tslib.__spread([mergedOperationDefinition], mergedFragmentDefinitions),
96 },
97 variables: mergedVariables,
98 extensions: mergedExtensions,
99 context: execs[0].context,
100 info: execs[0].info,
101 };
102}
103function prefixExecutionParams(prefix, executionParams) {
104 var _a;
105 var document = aliasTopLevelFields(prefix, executionParams.document);
106 var variableNames = Object.keys(executionParams.variables);
107 if (variableNames.length === 0) {
108 return tslib.__assign(tslib.__assign({}, executionParams), { document: document });
109 }
110 document = graphql.visit(document, (_a = {},
111 _a[graphql.Kind.VARIABLE] = function (node) { return prefixNodeName(node, prefix); },
112 _a[graphql.Kind.FRAGMENT_DEFINITION] = function (node) { return prefixNodeName(node, prefix); },
113 _a[graphql.Kind.FRAGMENT_SPREAD] = function (node) { return prefixNodeName(node, prefix); },
114 _a));
115 var prefixedVariables = variableNames.reduce(function (acc, name) {
116 acc[prefix + name] = executionParams.variables[name];
117 return acc;
118 }, Object.create(null));
119 return {
120 document: document,
121 variables: prefixedVariables,
122 };
123}
124/**
125 * Adds prefixed aliases to top-level fields of the query.
126 *
127 * @see aliasFieldsInSelection for implementation details
128 */
129function aliasTopLevelFields(prefix, document) {
130 var _a, _b;
131 var transformer = (_a = {},
132 _a[graphql.Kind.OPERATION_DEFINITION] = function (def) {
133 var selections = def.selectionSet.selections;
134 return tslib.__assign(tslib.__assign({}, def), { selectionSet: tslib.__assign(tslib.__assign({}, def.selectionSet), { selections: aliasFieldsInSelection(prefix, selections, document) }) });
135 },
136 _a);
137 return graphql.visit(document, transformer, (_b = {}, _b[graphql.Kind.DOCUMENT] = ["definitions"], _b));
138}
139/**
140 * Add aliases to fields of the selection, including top-level fields of inline fragments.
141 * Fragment spreads are converted to inline fragments and their top-level fields are also aliased.
142 *
143 * Note that this method is shallow. It adds aliases only to the top-level fields and doesn't
144 * descend to field sub-selections.
145 *
146 * For example, transforms:
147 * {
148 * foo
149 * ... on Query { foo }
150 * ...FragmentWithBarField
151 * }
152 * To:
153 * {
154 * graphqlTools1_foo: foo
155 * ... on Query { graphqlTools1_foo: foo }
156 * ... on Query { graphqlTools1_bar: bar }
157 * }
158 */
159function aliasFieldsInSelection(prefix, selections, document) {
160 return selections.map(function (selection) {
161 switch (selection.kind) {
162 case graphql.Kind.INLINE_FRAGMENT:
163 return aliasFieldsInInlineFragment(prefix, selection, document);
164 case graphql.Kind.FRAGMENT_SPREAD: {
165 var inlineFragment = inlineFragmentSpread(selection, document);
166 return aliasFieldsInInlineFragment(prefix, inlineFragment, document);
167 }
168 case graphql.Kind.FIELD:
169 default:
170 return aliasField(selection, prefix);
171 }
172 });
173}
174/**
175 * Add aliases to top-level fields of the inline fragment.
176 * Returns new inline fragment node.
177 *
178 * For Example, transforms:
179 * ... on Query { foo, ... on Query { bar: foo } }
180 * To
181 * ... on Query { graphqlTools1_foo: foo, ... on Query { graphqlTools1_bar: foo } }
182 */
183function aliasFieldsInInlineFragment(prefix, fragment, document) {
184 var selections = fragment.selectionSet.selections;
185 return tslib.__assign(tslib.__assign({}, fragment), { selectionSet: tslib.__assign(tslib.__assign({}, fragment.selectionSet), { selections: aliasFieldsInSelection(prefix, selections, document) }) });
186}
187/**
188 * Replaces fragment spread with inline fragment
189 *
190 * Example:
191 * query { ...Spread }
192 * fragment Spread on Query { bar }
193 *
194 * Transforms to:
195 * query { ... on Query { bar } }
196 */
197function inlineFragmentSpread(spread, document) {
198 var fragment = document.definitions.find(function (def) { return isFragmentDefinition(def) && def.name.value === spread.name.value; });
199 if (!fragment) {
200 throw new Error("Fragment " + spread.name.value + " does not exist");
201 }
202 var typeCondition = fragment.typeCondition, selectionSet = fragment.selectionSet;
203 return {
204 kind: graphql.Kind.INLINE_FRAGMENT,
205 typeCondition: typeCondition,
206 selectionSet: selectionSet,
207 directives: spread.directives,
208 };
209}
210function prefixNodeName(namedNode, prefix) {
211 return tslib.__assign(tslib.__assign({}, namedNode), { name: tslib.__assign(tslib.__assign({}, namedNode.name), { value: prefix + namedNode.name.value }) });
212}
213/**
214 * Returns a new FieldNode with prefixed alias
215 *
216 * Example. Given prefix === "graphqlTools1_" transforms:
217 * { foo } -> { graphqlTools1_foo: foo }
218 * { foo: bar } -> { graphqlTools1_foo: bar }
219 */
220function aliasField(field, aliasPrefix) {
221 var aliasNode = field.alias ? field.alias : field.name;
222 return tslib.__assign(tslib.__assign({}, field), { alias: tslib.__assign(tslib.__assign({}, aliasNode), { value: aliasPrefix + aliasNode.value }) });
223}
224function isOperationDefinition(def) {
225 return def.kind === graphql.Kind.OPERATION_DEFINITION;
226}
227function isFragmentDefinition(def) {
228 return def.kind === graphql.Kind.FRAGMENT_DEFINITION;
229}
230
231// adapted from https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-source-graphql/src/batching/merge-queries.js
232/**
233 * Split and transform result of the query produced by the `merge` function
234 */
235function splitResult(mergedResult, numResults) {
236 var splitResults = [];
237 for (var i = 0; i < numResults; i++) {
238 splitResults.push({});
239 }
240 var data = mergedResult.data;
241 if (data) {
242 Object.keys(data).forEach(function (prefixedKey) {
243 var _a;
244 var _b = parseKey(prefixedKey), index = _b.index, originalKey = _b.originalKey;
245 if (!splitResults[index].data) {
246 splitResults[index].data = (_a = {}, _a[originalKey] = data[prefixedKey], _a);
247 }
248 else {
249 splitResults[index].data[originalKey] = data[prefixedKey];
250 }
251 });
252 }
253 var errors = mergedResult.errors;
254 if (errors) {
255 var newErrors_1 = Object.create(null);
256 errors.forEach(function (error) {
257 if (error.path) {
258 var parsedKey = parseKey(error.path[0]);
259 if (parsedKey) {
260 var index = parsedKey.index, originalKey = parsedKey.originalKey;
261 var newError = utils.relocatedError(error, tslib.__spread([originalKey], error.path.slice(1)));
262 if (!newErrors_1[index]) {
263 newErrors_1[index] = [newError];
264 }
265 else {
266 newErrors_1[index].push(newError);
267 }
268 return;
269 }
270 }
271 splitResults.forEach(function (_splitResult, index) {
272 if (!newErrors_1[index]) {
273 newErrors_1[index] = [error];
274 }
275 else {
276 newErrors_1[index].push(error);
277 }
278 });
279 });
280 Object.keys(newErrors_1).forEach(function (index) {
281 splitResults[index].errors = newErrors_1[index];
282 });
283 }
284 return splitResults;
285}
286
287function createBatchingExecutor(executor, dataLoaderOptions, extensionsReducer) {
288 var loader = new DataLoader(createLoadFn(executor, extensionsReducer !== null && extensionsReducer !== void 0 ? extensionsReducer : defaultExtensionsReducer), dataLoaderOptions);
289 return function (executionParams) { return loader.load(executionParams); };
290}
291function createLoadFn(executor, extensionsReducer) {
292 var _this = this;
293 return function (execs) { return tslib.__awaiter(_this, void 0, void 0, function () {
294 var execBatches, index, exec, currentBatch, operationType, currentOperationType, containsPromises, executionResults, results;
295 return tslib.__generator(this, function (_a) {
296 execBatches = [];
297 index = 0;
298 exec = execs[index];
299 currentBatch = [exec];
300 execBatches.push(currentBatch);
301 operationType = graphql.getOperationAST(exec.document, undefined).operation;
302 while (++index < execs.length) {
303 currentOperationType = graphql.getOperationAST(execs[index].document, undefined).operation;
304 if (operationType === currentOperationType) {
305 currentBatch.push(execs[index]);
306 }
307 else {
308 currentBatch = [execs[index]];
309 execBatches.push(currentBatch);
310 }
311 }
312 containsPromises = false;
313 executionResults = [];
314 execBatches.forEach(function (execBatch) {
315 var mergedExecutionParams = mergeExecutionParams(execBatch, extensionsReducer);
316 var executionResult = executor(mergedExecutionParams);
317 if (isPromise(executionResult)) {
318 containsPromises = true;
319 }
320 executionResults.push(executionResult);
321 });
322 if (containsPromises) {
323 return [2 /*return*/, Promise.all(executionResults).then(function (resultBatches) {
324 var results = [];
325 resultBatches.forEach(function (resultBatch, index) {
326 results = results.concat(splitResult(resultBatch, execBatches[index].length));
327 });
328 return results;
329 })];
330 }
331 results = [];
332 executionResults.forEach(function (resultBatch, index) {
333 results = results.concat(splitResult(resultBatch, execBatches[index].length));
334 });
335 return [2 /*return*/, results];
336 });
337 }); };
338}
339function defaultExtensionsReducer(mergedExtensions, executionParams) {
340 var newExtensions = executionParams.extensions;
341 if (newExtensions != null) {
342 Object.assign(mergedExtensions, newExtensions);
343 }
344 return mergedExtensions;
345}
346
347function memoize2of4(fn) {
348 var cache1;
349 function memoized(a1, a2, a3, a4) {
350 if (!cache1) {
351 cache1 = new WeakMap();
352 var cache2_1 = new WeakMap();
353 cache1.set(a1, cache2_1);
354 var newValue = fn(a1, a2, a3, a4);
355 cache2_1.set(a2, newValue);
356 return newValue;
357 }
358 var cache2 = cache1.get(a1);
359 if (!cache2) {
360 cache2 = new WeakMap();
361 cache1.set(a1, cache2);
362 var newValue = fn(a1, a2, a3, a4);
363 cache2.set(a2, newValue);
364 return newValue;
365 }
366 var cachedValue = cache2.get(a2);
367 if (cachedValue === undefined) {
368 var newValue = fn(a1, a2, a3, a4);
369 cache2.set(a2, newValue);
370 return newValue;
371 }
372 return cachedValue;
373 }
374 return memoized;
375}
376
377var getBatchingExecutor = memoize2of4(function (_context, executor, dataLoaderOptions, extensionsReducer) {
378 return createBatchingExecutor(executor, dataLoaderOptions, extensionsReducer);
379});
380
381exports.createBatchingExecutor = createBatchingExecutor;
382exports.getBatchingExecutor = getBatchingExecutor;
383//# sourceMappingURL=index.cjs.js.map