Skip to content

Commit

Permalink
original execute should throw if defer/stream directives are present (
Browse files Browse the repository at this point in the history
  • Loading branch information
yaacovCR authored Dec 29, 2022
1 parent 1bf71ee commit 522f495
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 20 deletions.
25 changes: 9 additions & 16 deletions src/execution/__tests__/defer-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -723,21 +723,14 @@ describe('Execute: defer directive', () => {
... @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)',
},
],
});
await expectPromise(
execute({
schema,
document: parse(doc),
rootValue: {},
}),
).toRejectWith(
'Executing this GraphQL operation would unexpectedly produce multiple payloads (due to @defer or @stream directive)',
);
});
});
38 changes: 38 additions & 0 deletions src/execution/__tests__/executor-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ import {
GraphQLScalarType,
GraphQLUnionType,
} from '../../type/definition.js';
import {
GraphQLDeferDirective,
GraphQLStreamDirective,
} from '../../type/directives.js';
import {
GraphQLBoolean,
GraphQLInt,
Expand Down Expand Up @@ -914,6 +918,40 @@ describe('Execute: Handles basic execution tasks', () => {
expect(result).to.deep.equal({ data: { a: 'b' } });
});

it('errors when using original execute with schemas including experimental @defer directive', () => {
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'Q',
fields: {
a: { type: GraphQLString },
},
}),
directives: [GraphQLDeferDirective],
});
const document = parse('query Q { a }');

expect(() => execute({ schema, document })).to.throw(
'The provided schema unexpectedly contains experimental directives (@defer or @stream). These directives may only be utilized if experimental execution features are explicitly enabled.',
);
});

it('errors when using original execute with schemas including experimental @stream directive', () => {
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'Q',
fields: {
a: { type: GraphQLString },
},
}),
directives: [GraphQLStreamDirective],
});
const document = parse('query Q { a }');

expect(() => execute({ schema, document })).to.throw(
'The provided schema unexpectedly contains experimental directives (@defer or @stream). These directives may only be utilized if experimental execution features are explicitly enabled.',
);
});

it('resolves to an error if schema does not support operation', () => {
const schema = new GraphQLSchema({ assumeValid: true });

Expand Down
17 changes: 13 additions & 4 deletions src/execution/execute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,9 @@ export interface ExecutionArgs {
subscribeFieldResolver?: Maybe<GraphQLFieldResolver<any, any>>;
}

const UNEXPECTED_EXPERIMENTAL_DIRECTIVES =
'The provided schema unexpectedly contains experimental directives (@defer or @stream). These directives may only be utilized if experimental execution features are explicitly enabled.';

const UNEXPECTED_MULTIPLE_PAYLOADS =
'Executing this GraphQL operation would unexpectedly produce multiple payloads (due to @defer or @stream directive)';

Expand All @@ -278,24 +281,30 @@ const UNEXPECTED_MULTIPLE_PAYLOADS =
*
* 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.
* function, it will throw or return a rejected promise.
* Use `experimentalExecuteIncrementally` if you want to support incremental
* delivery.
*/
export function execute(args: ExecutionArgs): PromiseOrValue<ExecutionResult> {
if (args.schema.getDirective('defer') || args.schema.getDirective('stream')) {
throw new Error(UNEXPECTED_EXPERIMENTAL_DIRECTIVES);
}

const result = experimentalExecuteIncrementally(args);
if (!isPromise(result)) {
if ('initialResult' in result) {
// This can happen if the operation contains @defer or @stream directives
// and is not validated prior to execution
throw new Error(UNEXPECTED_MULTIPLE_PAYLOADS);
}
return result;
}

return result.then((incrementalResult) => {
if ('initialResult' in incrementalResult) {
return {
errors: [new GraphQLError(UNEXPECTED_MULTIPLE_PAYLOADS)],
};
// This can happen if the operation contains @defer or @stream directives
// and is not validated prior to execution
throw new Error(UNEXPECTED_MULTIPLE_PAYLOADS);
}
return incrementalResult;
});
Expand Down

0 comments on commit 522f495

Please sign in to comment.