Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/@graphql-tools_delegate-5477-dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@graphql-tools/delegate": patch
---
dependencies updates:
- Removed dependency [`value-or-promise@^1.0.12` ↗︎](https://www.npmjs.com/package/value-or-promise/v/1.0.12) (from `dependencies`)
56 changes: 20 additions & 36 deletions packages/batch-execute/src/createBatchingExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
ExecutionResult,
Executor,
getOperationASTFromRequest,
isAsyncIterable,
} from '@graphql-tools/utils';
import { mergeRequests } from './mergeRequests.js';
import { splitResult } from './splitResult.js';
Expand All @@ -18,10 +19,20 @@ export function createBatchingExecutor(
) => Record<string, any> = defaultExtensionsReducer,
): Executor {
const loadFn = createLoadFn(executor, extensionsReducer);
const loader = new DataLoader(loadFn, dataLoaderOptions);
const queryLoader = new DataLoader(loadFn, dataLoaderOptions);
const mutationLoader = new DataLoader(loadFn, dataLoaderOptions);
return function batchingExecutor(request: ExecutionRequest) {
const operationAst = getOperationASTFromRequest(request);
return operationAst.operation === 'subscription' ? executor(request) : loader.load(request);
const operationType = request.operationType ?? getOperationASTFromRequest(request)?.operation;
switch (operationType) {
case 'query':
return queryLoader.load(request);
case 'mutation':
return mutationLoader.load(request);
case 'subscription':
return executor(request);
default:
throw new Error(`Invalid operation type "${operationType}"`);
}
};
}

Expand All @@ -40,40 +51,13 @@ function createLoadFn(
.then((result: ExecutionResult) => [result])
.catch((err: any) => [err]);
}
const execBatches: Array<Array<ExecutionRequest>> = [];
let index = 0;
const request = requests[index];
let currentBatch: Array<ExecutionRequest> = [request];
execBatches.push(currentBatch);

const operationAst = getOperationASTFromRequest(request);
const operationType = operationAst.operation;

if (operationType == null) {
throw new Error('could not identify operation type of document');
}

while (++index < requests.length) {
const currentRequest = requests[index];
const currentOperationAST = getOperationASTFromRequest(currentRequest);
const currentOperationType = currentOperationAST.operation;

if (operationType === currentOperationType) {
currentBatch.push(currentRequest);
} else {
currentBatch = [currentRequest];
execBatches.push(currentBatch);
const mergedRequests = mergeRequests(requests, extensionsReducer);
return new ValueOrPromise(() => executor(mergedRequests)).then(resultBatches => {
if (isAsyncIterable(resultBatches)) {
throw new Error('Executor must not return incremental results for batching');
}
}

return ValueOrPromise.all(
execBatches.map(execBatch =>
new ValueOrPromise(() => {
const mergedRequests = mergeRequests(execBatch, extensionsReducer);
return executor(mergedRequests) as ExecutionResult;
}).then(resultBatches => splitResult(resultBatches, execBatch.length)),
),
).then(results => results.flat());
return splitResult(resultBatches, requests.length);
});
};
}

Expand Down
3 changes: 2 additions & 1 deletion packages/batch-execute/src/mergeRequests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ import { createPrefix } from './prefix.js';
* }
*/
export function mergeRequests(
requests: Array<ExecutionRequest>,
requests: ReadonlyArray<ExecutionRequest>,
extensionsReducer: (
mergedExtensions: Record<string, any>,
request: ExecutionRequest,
Expand Down Expand Up @@ -113,6 +113,7 @@ export function mergeRequests(
context: requests[0].context,
info: requests[0].info,
operationType,
rootValue: requests[0].rootValue,
};
}

Expand Down
3 changes: 1 addition & 2 deletions packages/delegate/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@
"@graphql-tools/schema": "^10.0.0",
"@graphql-tools/utils": "^10.0.0",
"dataloader": "^2.2.2",
"tslib": "^2.5.0",
"value-or-promise": "^1.0.12"
"tslib": "^2.5.0"
},
"publishConfig": {
"directory": "dist",
Expand Down
29 changes: 18 additions & 11 deletions packages/delegate/src/delegateToSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@ import {
OperationTypeNode,
validate,
} from 'graphql';
import { ValueOrPromise } from 'value-or-promise';
import { getBatchingExecutor } from '@graphql-tools/batch-execute';
import { normalizedExecutor } from '@graphql-tools/executor';
import {
ExecutionRequest,
ExecutionResult,
Executor,
getDefinedRootType,
getOperationASTFromRequest,
isAsyncIterable,
isPromise,
mapAsyncIterator,
Maybe,
MaybeAsyncIterable,
memoize1,
} from '@graphql-tools/utils';
import { applySchemaTransforms } from './applySchemaTransforms.js';
Expand Down Expand Up @@ -100,16 +102,21 @@ export function delegateRequest<

const executor = getExecutor(delegationContext);

return new ValueOrPromise(() => executor(processedRequest))
.then(originalResult => {
if (isAsyncIterable(originalResult)) {
const iterator = originalResult[Symbol.asyncIterator]();
// "subscribe" to the subscription result and map the result through the transforms
return mapAsyncIterator(iterator, result => transformer.transformResult(result));
}
return transformer.transformResult(originalResult);
})
.resolve();
const result$ = executor(processedRequest);

function handleExecutorResult(executorResult: MaybeAsyncIterable<ExecutionResult<any>>) {
if (isAsyncIterable(executorResult)) {
const iterator = executorResult[Symbol.asyncIterator]();
// "subscribe" to the subscription result and map the result through the transforms
return mapAsyncIterator(iterator, result => transformer.transformResult(result));
}
return transformer.transformResult(executorResult);
}

if (isPromise(result$)) {
return result$.then(handleExecutorResult);
}
return handleExecutorResult(result$);
}

function getDelegationContext<TContext extends Record<string, any>>({
Expand Down
Loading