1 | 'use strict';
|
2 |
|
3 | Object.defineProperty(exports, '__esModule', { value: true });
|
4 |
|
5 | function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
|
6 |
|
7 | const DataLoader = _interopDefault(require('dataloader'));
|
8 | const graphql = require('graphql');
|
9 | const utils = require('@graphql-tools/utils');
|
10 |
|
11 |
|
12 | function createPrefix(index) {
|
13 | return `graphqlTools${index}_`;
|
14 | }
|
15 | function parseKey(prefixedKey) {
|
16 | const match = /^graphqlTools([\d]+)_(.*)$/.exec(prefixedKey);
|
17 | if (match && match.length === 3 && !isNaN(Number(match[1])) && match[2]) {
|
18 | return { index: Number(match[1]), originalKey: match[2] };
|
19 | }
|
20 | throw new Error(`Key ${prefixedKey} is not correctly prefixed`);
|
21 | }
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 | function mergeRequests(requests, extensionsReducer) {
|
59 | const mergedVariables = Object.create(null);
|
60 | const mergedVariableDefinitions = [];
|
61 | const mergedSelections = [];
|
62 | const mergedFragmentDefinitions = [];
|
63 | let mergedExtensions = Object.create(null);
|
64 | for (const index in requests) {
|
65 | const request = requests[index];
|
66 | const prefixedRequests = prefixRequest(createPrefix(index), request);
|
67 | for (const def of prefixedRequests.document.definitions) {
|
68 | if (isOperationDefinition(def)) {
|
69 | mergedSelections.push(...def.selectionSet.selections);
|
70 | if (def.variableDefinitions) {
|
71 | mergedVariableDefinitions.push(...def.variableDefinitions);
|
72 | }
|
73 | }
|
74 | if (isFragmentDefinition(def)) {
|
75 | mergedFragmentDefinitions.push(def);
|
76 | }
|
77 | }
|
78 | Object.assign(mergedVariables, prefixedRequests.variables);
|
79 | mergedExtensions = extensionsReducer(mergedExtensions, request);
|
80 | }
|
81 | const mergedOperationDefinition = {
|
82 | kind: graphql.Kind.OPERATION_DEFINITION,
|
83 | operation: requests[0].operationType,
|
84 | variableDefinitions: mergedVariableDefinitions,
|
85 | selectionSet: {
|
86 | kind: graphql.Kind.SELECTION_SET,
|
87 | selections: mergedSelections,
|
88 | },
|
89 | };
|
90 | return {
|
91 | document: {
|
92 | kind: graphql.Kind.DOCUMENT,
|
93 | definitions: [mergedOperationDefinition, ...mergedFragmentDefinitions],
|
94 | },
|
95 | variables: mergedVariables,
|
96 | extensions: mergedExtensions,
|
97 | context: requests[0].context,
|
98 | info: requests[0].info,
|
99 | operationType: requests[0].operationType,
|
100 | };
|
101 | }
|
102 | function prefixRequest(prefix, request) {
|
103 | var _a;
|
104 | const executionVariables = (_a = request.variables) !== null && _a !== void 0 ? _a : {};
|
105 | function prefixNode(node) {
|
106 | return prefixNodeName(node, prefix);
|
107 | }
|
108 | let prefixedDocument = aliasTopLevelFields(prefix, request.document);
|
109 | const executionVariableNames = Object.keys(executionVariables);
|
110 | if (executionVariableNames.length > 0) {
|
111 | prefixedDocument = graphql.visit(prefixedDocument, {
|
112 | [graphql.Kind.VARIABLE]: prefixNode,
|
113 | [graphql.Kind.FRAGMENT_DEFINITION]: prefixNode,
|
114 | [graphql.Kind.FRAGMENT_SPREAD]: prefixNode,
|
115 | });
|
116 | }
|
117 | const prefixedVariables = {};
|
118 | for (const variableName of executionVariableNames) {
|
119 | prefixedVariables[prefix + variableName] = executionVariables[variableName];
|
120 | }
|
121 | return {
|
122 | document: prefixedDocument,
|
123 | variables: prefixedVariables,
|
124 | operationType: request.operationType,
|
125 | };
|
126 | }
|
127 |
|
128 |
|
129 |
|
130 |
|
131 |
|
132 | function aliasTopLevelFields(prefix, document) {
|
133 | const transformer = {
|
134 | [graphql.Kind.OPERATION_DEFINITION]: (def) => {
|
135 | const { selections } = def.selectionSet;
|
136 | return {
|
137 | ...def,
|
138 | selectionSet: {
|
139 | ...def.selectionSet,
|
140 | selections: aliasFieldsInSelection(prefix, selections, document),
|
141 | },
|
142 | };
|
143 | },
|
144 | };
|
145 | return graphql.visit(document, transformer, {
|
146 | [graphql.Kind.DOCUMENT]: [`definitions`],
|
147 | });
|
148 | }
|
149 |
|
150 |
|
151 |
|
152 |
|
153 |
|
154 |
|
155 |
|
156 |
|
157 |
|
158 |
|
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 |
|
165 |
|
166 |
|
167 |
|
168 |
|
169 | function aliasFieldsInSelection(prefix, selections, document) {
|
170 | return selections.map(selection => {
|
171 | switch (selection.kind) {
|
172 | case graphql.Kind.INLINE_FRAGMENT:
|
173 | return aliasFieldsInInlineFragment(prefix, selection, document);
|
174 | case graphql.Kind.FRAGMENT_SPREAD: {
|
175 | const inlineFragment = inlineFragmentSpread(selection, document);
|
176 | return aliasFieldsInInlineFragment(prefix, inlineFragment, document);
|
177 | }
|
178 | case graphql.Kind.FIELD:
|
179 | default:
|
180 | return aliasField(selection, prefix);
|
181 | }
|
182 | });
|
183 | }
|
184 |
|
185 |
|
186 |
|
187 |
|
188 |
|
189 |
|
190 |
|
191 |
|
192 |
|
193 | function aliasFieldsInInlineFragment(prefix, fragment, document) {
|
194 | const { selections } = fragment.selectionSet;
|
195 | return {
|
196 | ...fragment,
|
197 | selectionSet: {
|
198 | ...fragment.selectionSet,
|
199 | selections: aliasFieldsInSelection(prefix, selections, document),
|
200 | },
|
201 | };
|
202 | }
|
203 |
|
204 |
|
205 |
|
206 |
|
207 |
|
208 |
|
209 |
|
210 |
|
211 |
|
212 |
|
213 | function inlineFragmentSpread(spread, document) {
|
214 | const fragment = document.definitions.find(def => isFragmentDefinition(def) && def.name.value === spread.name.value);
|
215 | if (!fragment) {
|
216 | throw new Error(`Fragment ${spread.name.value} does not exist`);
|
217 | }
|
218 | const { typeCondition, selectionSet } = fragment;
|
219 | return {
|
220 | kind: graphql.Kind.INLINE_FRAGMENT,
|
221 | typeCondition,
|
222 | selectionSet,
|
223 | directives: spread.directives,
|
224 | };
|
225 | }
|
226 | function prefixNodeName(namedNode, prefix) {
|
227 | return {
|
228 | ...namedNode,
|
229 | name: {
|
230 | ...namedNode.name,
|
231 | value: prefix + namedNode.name.value,
|
232 | },
|
233 | };
|
234 | }
|
235 |
|
236 |
|
237 |
|
238 |
|
239 |
|
240 |
|
241 |
|
242 | function aliasField(field, aliasPrefix) {
|
243 | const aliasNode = field.alias ? field.alias : field.name;
|
244 | return {
|
245 | ...field,
|
246 | alias: {
|
247 | ...aliasNode,
|
248 | value: aliasPrefix + aliasNode.value,
|
249 | },
|
250 | };
|
251 | }
|
252 | function isOperationDefinition(def) {
|
253 | return def.kind === graphql.Kind.OPERATION_DEFINITION;
|
254 | }
|
255 | function isFragmentDefinition(def) {
|
256 | return def.kind === graphql.Kind.FRAGMENT_DEFINITION;
|
257 | }
|
258 |
|
259 |
|
260 |
|
261 |
|
262 |
|
263 | function splitResult({ data, errors }, numResults) {
|
264 | const splitResults = [];
|
265 | for (let i = 0; i < numResults; i++) {
|
266 | splitResults.push({});
|
267 | }
|
268 | if (data) {
|
269 | for (const prefixedKey in data) {
|
270 | const { index, originalKey } = parseKey(prefixedKey);
|
271 | const result = splitResults[index];
|
272 | if (result == null) {
|
273 | continue;
|
274 | }
|
275 | if (result.data == null) {
|
276 | result.data = { [originalKey]: data[prefixedKey] };
|
277 | }
|
278 | else {
|
279 | result.data[originalKey] = data[prefixedKey];
|
280 | }
|
281 | }
|
282 | }
|
283 | if (errors) {
|
284 | for (const error of errors) {
|
285 | if (error.path) {
|
286 | const parsedKey = parseKey(error.path[0]);
|
287 | const { index, originalKey } = parsedKey;
|
288 | const newError = utils.relocatedError(error, [originalKey, ...error.path.slice(1)]);
|
289 | const errors = (splitResults[index].errors = (splitResults[index].errors || []));
|
290 | errors.push(newError);
|
291 | }
|
292 | }
|
293 | }
|
294 | return splitResults;
|
295 | }
|
296 |
|
297 | function createBatchingExecutor(executor, dataLoaderOptions, extensionsReducer = defaultExtensionsReducer) {
|
298 | const loader = new DataLoader(createLoadFn(executor, extensionsReducer), dataLoaderOptions);
|
299 | return (request) => {
|
300 | return request.operationType === 'subscription' ? executor(request) : loader.load(request);
|
301 | };
|
302 | }
|
303 | function createLoadFn(executor, extensionsReducer) {
|
304 | return async function batchExecuteLoadFn(requests) {
|
305 | const execBatches = [];
|
306 | let index = 0;
|
307 | const request = requests[index];
|
308 | let currentBatch = [request];
|
309 | execBatches.push(currentBatch);
|
310 | const operationType = request.operationType;
|
311 | while (++index < requests.length) {
|
312 | const currentOperationType = requests[index].operationType;
|
313 | if (operationType == null) {
|
314 | throw new Error('Could not identify operation type of document.');
|
315 | }
|
316 | if (operationType === currentOperationType) {
|
317 | currentBatch.push(requests[index]);
|
318 | }
|
319 | else {
|
320 | currentBatch = [requests[index]];
|
321 | execBatches.push(currentBatch);
|
322 | }
|
323 | }
|
324 | const results = await Promise.all(execBatches.map(async (execBatch) => {
|
325 | const mergedRequests = mergeRequests(execBatch, extensionsReducer);
|
326 | const resultBatches = (await executor(mergedRequests));
|
327 | return splitResult(resultBatches, execBatch.length);
|
328 | }));
|
329 | return results.flat();
|
330 | };
|
331 | }
|
332 | function defaultExtensionsReducer(mergedExtensions, request) {
|
333 | const newExtensions = request.extensions;
|
334 | if (newExtensions != null) {
|
335 | Object.assign(mergedExtensions, newExtensions);
|
336 | }
|
337 | return mergedExtensions;
|
338 | }
|
339 |
|
340 | function memoize2of4(fn) {
|
341 | let cache1;
|
342 | function memoized(a1, a2, a3, a4) {
|
343 | if (!cache1) {
|
344 | cache1 = new WeakMap();
|
345 | const cache2 = new WeakMap();
|
346 | cache1.set(a1, cache2);
|
347 | const newValue = fn(a1, a2, a3, a4);
|
348 | cache2.set(a2, newValue);
|
349 | return newValue;
|
350 | }
|
351 | let cache2 = cache1.get(a1);
|
352 | if (!cache2) {
|
353 | cache2 = new WeakMap();
|
354 | cache1.set(a1, cache2);
|
355 | const newValue = fn(a1, a2, a3, a4);
|
356 | cache2.set(a2, newValue);
|
357 | return newValue;
|
358 | }
|
359 | const cachedValue = cache2.get(a2);
|
360 | if (cachedValue === undefined) {
|
361 | const newValue = fn(a1, a2, a3, a4);
|
362 | cache2.set(a2, newValue);
|
363 | return newValue;
|
364 | }
|
365 | return cachedValue;
|
366 | }
|
367 | return memoized;
|
368 | }
|
369 |
|
370 | const getBatchingExecutor = memoize2of4(function getBatchingExecutor(_context, executor, dataLoaderOptions, extensionsReducer) {
|
371 | return createBatchingExecutor(executor, dataLoaderOptions, extensionsReducer);
|
372 | });
|
373 |
|
374 | exports.createBatchingExecutor = createBatchingExecutor;
|
375 | exports.getBatchingExecutor = getBatchingExecutor;
|