Skip to content

Commit

Permalink
make default execute incremental
Browse files Browse the repository at this point in the history
  • Loading branch information
saihaj committed Oct 31, 2022
1 parent 5d80cad commit c7b9db4
Show file tree
Hide file tree
Showing 16 changed files with 72 additions and 118 deletions.
8 changes: 7 additions & 1 deletion packages/batch-delegate/tests/basic.example.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { execute } from '@graphql-tools/executor';
import { execute, isIncrementalResult } from '@graphql-tools/executor';
import { OperationTypeNode, parse } from 'graphql';

import { makeExecutableSchema } from '@graphql-tools/schema';
Expand Down Expand Up @@ -89,6 +89,9 @@ describe('batch delegation within basic stitching example', () => {
const result = await execute({ schema: stitchedSchema, document: parse(query) });

expect(numCalls).toEqual(1);

if (isIncrementalResult(result)) throw Error('result is incremental');

expect(result.errors).toBeUndefined();
const chirps: any = result.data!['trendingChirps'];
expect(chirps[0].chirpedAtUser.email).not.toBe(null);
Expand Down Expand Up @@ -182,6 +185,9 @@ describe('batch delegation within basic stitching example', () => {

const result = await execute({ schema: stitchedSchema, document: parse(query) });
expect(numCalls).toEqual(1);

if (isIncrementalResult(result)) throw Error('result is incremental');

expect(result.data).toEqual({
users: [
{
Expand Down
3 changes: 2 additions & 1 deletion packages/batch-delegate/tests/withTransforms.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { execute } from '@graphql-tools/executor';
import { execute, isIncrementalResult } from '@graphql-tools/executor';
import { GraphQLList, GraphQLObjectType, Kind, OperationTypeNode, parse } from 'graphql';

import { makeExecutableSchema } from '@graphql-tools/schema';
Expand Down Expand Up @@ -121,6 +121,7 @@ describe('works with complex transforms', () => {
`;

const result = await execute({ schema: stitchedSchema, document: parse(query) });
if (isIncrementalResult(result)) throw Error('result is incremental');

expect(result.errors).toBeUndefined();
expect(result.data).toEqual({
Expand Down
47 changes: 2 additions & 45 deletions packages/executor/src/execution/__tests__/defer-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ import {
} from 'graphql';
import { expectJSON } from '../../__testUtils__/expectJSON.js';
import { resolveOnNextTick } from '../../__testUtils__/resolveOnNextTick.js';
import { expectPromise } from '../../__testUtils__/expectPromise.js';

import type { InitialIncrementalExecutionResult, SubsequentIncrementalExecutionResult } from '../execute.js';
import { execute, experimentalExecuteIncrementally } from '../execute.js';
import { execute } from '../execute.js';

const friendType = new GraphQLObjectType({
fields: {
Expand Down Expand Up @@ -87,7 +86,7 @@ const query = new GraphQLObjectType({
const schema = new GraphQLSchema({ query });

async function complete(document: DocumentNode) {
const result = await experimentalExecuteIncrementally({
const result = await execute({
schema,
document,
rootValue: {},
Expand Down Expand Up @@ -698,46 +697,4 @@ describe('Execute: defer directive', () => {
],
});
});

it('original execute function throws error if anything is deferred and everything else is sync', () => {
const doc = `
query Deferred {
... @defer { hero { id } }
}
`;
expect(() =>
execute({
schema,
document: parse(doc),
rootValue: {},
})
).toThrow(
'Executing this GraphQL operation would unexpectedly produce multiple payloads (due to @defer or @stream directive)'
);
});

it('original execute function resolves to error if anything is deferred and something else is async', async () => {
const doc = `
query Deferred {
hero { slowField }
... @defer { hero { id } }
}
`;
expectJSON(
await expectPromise(
execute({
schema,
document: parse(doc),
rootValue: {},
})
).toResolve()
).toDeepEqual({
errors: [
{
message:
'Executing this GraphQL operation would unexpectedly produce multiple payloads (due to @defer or @stream directive)',
},
],
});
});
});
6 changes: 3 additions & 3 deletions packages/executor/src/execution/__tests__/mutations-test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { parse, GraphQLObjectType, GraphQLInt, GraphQLSchema } from 'graphql';
import { expectJSON } from '../../__testUtils__/expectJSON.js';
import { resolveOnNextTick } from '../../__testUtils__/resolveOnNextTick.js';
import { execute, executeSync, experimentalExecuteIncrementally } from '../execute.js';
import { execute, executeSync } from '../execute.js';

class NumberHolder {
theNumber: number;
Expand Down Expand Up @@ -206,7 +206,7 @@ describe('Execute: Handles mutation execution ordering', () => {
`);

const rootValue = new Root(6);
const mutationResult = await experimentalExecuteIncrementally({
const mutationResult = await execute({
schema,
document,
rootValue,
Expand Down Expand Up @@ -286,7 +286,7 @@ describe('Execute: Handles mutation execution ordering', () => {
`);

const rootValue = new Root(6);
const mutationResult = await experimentalExecuteIncrementally({
const mutationResult = await execute({
schema,
document,
rootValue,
Expand Down
20 changes: 10 additions & 10 deletions packages/executor/src/execution/__tests__/stream-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
} from 'graphql';
import { expectJSON } from '../../__testUtils__/expectJSON.js';
import type { InitialIncrementalExecutionResult, SubsequentIncrementalExecutionResult } from '../execute.js';
import { experimentalExecuteIncrementally } from '../execute.js';
import { execute } from '../execute.js';

const friendType = new GraphQLObjectType({
fields: {
Expand Down Expand Up @@ -74,7 +74,7 @@ const query = new GraphQLObjectType({
const schema = new GraphQLSchema({ query });

async function complete(document: DocumentNode, rootValue: unknown = {}) {
const result = await experimentalExecuteIncrementally({
const result = await execute({
schema,
document,
rootValue,
Expand All @@ -93,7 +93,7 @@ async function complete(document: DocumentNode, rootValue: unknown = {}) {
}

async function completeAsync(document: DocumentNode, numCalls: number, rootValue: unknown = {}) {
const result = await experimentalExecuteIncrementally({
const result = await execute({
schema,
document,
rootValue,
Expand Down Expand Up @@ -1304,7 +1304,7 @@ describe('Execute: stream directive', () => {
}
`);

const executeResult = await experimentalExecuteIncrementally({
const executeResult = await execute({
schema,
document,
rootValue: {
Expand Down Expand Up @@ -1423,7 +1423,7 @@ describe('Execute: stream directive', () => {
}
}
`);
const executeResult = await experimentalExecuteIncrementally({
const executeResult = await execute({
schema,
document,
rootValue: {
Expand Down Expand Up @@ -1518,7 +1518,7 @@ describe('Execute: stream directive', () => {
}
`);

const executeResult = await experimentalExecuteIncrementally({
const executeResult = await execute({
schema,
document,
rootValue: {
Expand Down Expand Up @@ -1606,7 +1606,7 @@ describe('Execute: stream directive', () => {
}
`);

const executeResult = await experimentalExecuteIncrementally({
const executeResult = await execute({
schema,
document,
rootValue: {
Expand Down Expand Up @@ -1713,7 +1713,7 @@ describe('Execute: stream directive', () => {
}
`);

const executeResult = await experimentalExecuteIncrementally({
const executeResult = await execute({
schema,
document,
rootValue: {
Expand Down Expand Up @@ -1769,7 +1769,7 @@ describe('Execute: stream directive', () => {
}
`);

const executeResult = await experimentalExecuteIncrementally({
const executeResult = await execute({
schema,
document,
rootValue: {
Expand Down Expand Up @@ -1831,7 +1831,7 @@ describe('Execute: stream directive', () => {
}
`);

const executeResult = await experimentalExecuteIncrementally({
const executeResult = await execute({
schema,
document,
rootValue: {
Expand Down
60 changes: 13 additions & 47 deletions packages/executor/src/execution/execute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,7 @@ export interface FormattedExecutionResult<TData = Record<string, unknown>, TExte
extensions?: TExtensions;
}

export interface ExperimentalIncrementalExecutionResults<
TData = Record<string, unknown>,
TExtensions = Record<string, unknown>
> {
export interface IncrementalExecutionResults<TData = Record<string, unknown>, TExtensions = Record<string, unknown>> {
initialResult: InitialIncrementalExecutionResult<TData, TExtensions>;
subsequentResults: AsyncGenerator<SubsequentIncrementalExecutionResult<TData, TExtensions>, void, void>;
}
Expand Down Expand Up @@ -209,58 +206,21 @@ export interface ExecutionArgs<TData = any, TVariables = any, TContext = any> {
const UNEXPECTED_MULTIPLE_PAYLOADS =
'Executing this GraphQL operation would unexpectedly produce multiple payloads (due to @defer or @stream directive)';

/**
* Implements the "Executing requests" section of the GraphQL specification.
*
* Returns either a synchronous ExecutionResult (if all encountered resolvers
* are synchronous), or a Promise of an ExecutionResult that will eventually be
* resolved and never rejected.
*
* If the arguments to this function do not result in a legal execution context,
* a GraphQLError will be thrown immediately explaining the invalid input.
*
* This function does not support incremental delivery (`@defer` and `@stream`).
* If an operation which would defer or stream data is executed with this
* function, it will throw or resolve to an object containing an error instead.
* Use `experimentalExecuteIncrementally` if you want to support incremental
* delivery.
*/
export function execute<TData = any, TVariables = any, TContext = any>(
args: ExecutionArgs<TData, TVariables, TContext>
): MaybePromise<ExecutionResult<TData>> {
const result = experimentalExecuteIncrementally(args);
if (!isPromise(result)) {
if ('initialResult' in result) {
throw new Error(UNEXPECTED_MULTIPLE_PAYLOADS);
}
return result;
}

return result.then(incrementalResult => {
if ('initialResult' in incrementalResult) {
return {
errors: [createGraphQLError(UNEXPECTED_MULTIPLE_PAYLOADS)],
};
}
return incrementalResult;
});
}

/**
* Implements the "Executing requests" section of the GraphQL specification,
* including `@defer` and `@stream` as proposed in
* https://github.com/graphql/graphql-spec/pull/742
*
* This function returns a Promise of an ExperimentalIncrementalExecutionResults
* This function returns a Promise of an IncrementalExecutionResults
* object. This object either consists of a single ExecutionResult, or an
* object containing an `initialResult` and a stream of `subsequentResults`.
*
* If the arguments to this function do not result in a legal execution context,
* a GraphQLError will be thrown immediately explaining the invalid input.
*/
export function experimentalExecuteIncrementally<TData = any, TVariables = any, TContext = any>(
export function execute<TData = any, TVariables = any, TContext = any>(
args: ExecutionArgs<TData, TVariables, TContext>
): MaybePromise<ExecutionResult<TData> | ExperimentalIncrementalExecutionResults<TData>> {
): MaybePromise<ExecutionResult<TData> | IncrementalExecutionResults<TData>> {
// If a valid execution context cannot be created due to incorrect arguments,
// a "Response" with only errors is returned.
const exeContext = buildExecutionContext(args);
Expand All @@ -275,7 +235,7 @@ export function experimentalExecuteIncrementally<TData = any, TVariables = any,

function executeImpl<TData = any, TVariables = any, TContext = any>(
exeContext: ExecutionContext<TVariables, TContext>
): MaybePromise<ExecutionResult<TData> | ExperimentalIncrementalExecutionResults<TData>> {
): MaybePromise<ExecutionResult<TData> | IncrementalExecutionResults<TData>> {
// Return a Promise that will eventually resolve to the data described by
// The "Response" section of the GraphQL specification.
//
Expand Down Expand Up @@ -333,7 +293,7 @@ function executeImpl<TData = any, TVariables = any, TContext = any>(
* that all field resolvers are also synchronous.
*/
export function executeSync(args: ExecutionArgs): ExecutionResult {
const result = experimentalExecuteIncrementally(args);
const result = execute(args);

// Assert that the execution was synchronous.
if (isPromise(result) || 'initialResult' in result) {
Expand Down Expand Up @@ -1375,7 +1335,7 @@ export function experimentalSubscribeIncrementally(
}

async function* ensureAsyncIterable(
someExecutionResult: ExecutionResult | ExperimentalIncrementalExecutionResults
someExecutionResult: ExecutionResult | IncrementalExecutionResults
): AsyncGenerator<
ExecutionResult | InitialIncrementalExecutionResult | SubsequentIncrementalExecutionResult,
void,
Expand Down Expand Up @@ -2008,3 +1968,9 @@ export function getFieldDef(
}
return parentType.getFields()[fieldName];
}

export function isIncrementalResult<TData>(
result: ExecutionResult<TData> | IncrementalExecutionResults<TData>
): result is IncrementalExecutionResults<TData> {
return 'incremental' in result;
}
4 changes: 2 additions & 2 deletions packages/loaders/url/tests/graphql-upload.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { File } from '@whatwg-node/fetch';
import { readFileSync } from 'fs';
import { execute } from '@graphql-tools/executor';
import { execute, isIncrementalResult } from '@graphql-tools/executor';
import { GraphQLSchema, parse } from 'graphql';
import { join } from 'path';
import { assertNonMaybe, testSchema } from './test-utils';
Expand Down Expand Up @@ -85,7 +85,7 @@ describe('GraphQL Upload compatibility', () => {
nonObjectVar: 'somefilename.txt',
},
});

if (isIncrementalResult(result)) throw Error('result is incremental');
expect(result.errors).toBeFalsy();
assertNonMaybe(result.data);
const uploadFileData: any = result.data?.['uploadFile'];
Expand Down
4 changes: 3 additions & 1 deletion packages/loaders/url/tests/url-loader.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { AsyncFetchFn, defaultAsyncFetch } from '../src/defaultAsyncFetch.js';
import { Response, Headers } from '@whatwg-node/fetch';
import { loadSchema } from '@graphql-tools/load';
import { testUrl, testSchema, testTypeDefs, assertNonMaybe } from './test-utils';
import { execute, subscribe } from '@graphql-tools/executor';
import { execute, isIncrementalResult, subscribe } from '@graphql-tools/executor';

describe('Schema URL Loader', () => {
const loader = new UrlLoader();
Expand Down Expand Up @@ -180,6 +180,8 @@ describe('Schema URL Loader', () => {
},
});

if (isIncrementalResult(result)) throw Error('result is incremental');

expect(result?.errors).toBeFalsy();

expect(result?.data?.['a']).toBe(testVariableValue);
Expand Down
Loading

0 comments on commit c7b9db4

Please sign in to comment.