Skip to content

Commit ef585e9

Browse files
authored
Merge pull request #1345 from graphql/get-operation
Expose getOperationRootType(schema, operationNode)
2 parents 2eccaad + 69cf8a8 commit ef585e9

File tree

6 files changed

+200
-42
lines changed

6 files changed

+200
-42
lines changed

src/execution/execute.js

Lines changed: 1 addition & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import promiseReduce from '../jsutils/promiseReduce';
1919
import type { ObjMap } from '../jsutils/ObjMap';
2020
import type { MaybePromise } from '../jsutils/MaybePromise';
2121

22+
import { getOperationRootType } from '../utilities/getOperationRootType';
2223
import { typeFromAST } from '../utilities/typeFromAST';
2324
import { Kind } from '../language/kinds';
2425
import {
@@ -415,47 +416,6 @@ function executeOperation(
415416
}
416417
}
417418

418-
/**
419-
* Extracts the root type of the operation from the schema.
420-
*/
421-
export function getOperationRootType(
422-
schema: GraphQLSchema,
423-
operation: OperationDefinitionNode,
424-
): GraphQLObjectType {
425-
switch (operation.operation) {
426-
case 'query':
427-
const queryType = schema.getQueryType();
428-
if (!queryType) {
429-
throw new GraphQLError(
430-
'Schema does not define the required query root type.',
431-
[operation],
432-
);
433-
}
434-
return queryType;
435-
case 'mutation':
436-
const mutationType = schema.getMutationType();
437-
if (!mutationType) {
438-
throw new GraphQLError('Schema is not configured for mutations.', [
439-
operation,
440-
]);
441-
}
442-
return mutationType;
443-
case 'subscription':
444-
const subscriptionType = schema.getSubscriptionType();
445-
if (!subscriptionType) {
446-
throw new GraphQLError('Schema is not configured for subscriptions.', [
447-
operation,
448-
]);
449-
}
450-
return subscriptionType;
451-
default:
452-
throw new GraphQLError(
453-
'Can only execute queries, mutations and subscriptions.',
454-
[operation],
455-
);
456-
}
457-
}
458-
459419
/**
460420
* Implements the "Evaluating selection sets" section of the spec
461421
* for "write" mode.

src/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,8 @@ export {
320320
introspectionQuery,
321321
// Gets the target Operation from a Document
322322
getOperationAST,
323+
// Gets the Type for the target Operation AST.
324+
getOperationRootType,
323325
// Convert a GraphQLSchema to an IntrospectionQuery
324326
introspectionFromSchema,
325327
// Build a GraphQLSchema from an introspection result.

src/subscription/subscribe.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import {
1818
collectFields,
1919
execute,
2020
getFieldDef,
21-
getOperationRootType,
2221
resolveFieldValueOrError,
2322
responsePathAsArray,
2423
} from '../execution/execute';
@@ -29,6 +28,7 @@ import type { ObjMap } from '../jsutils/ObjMap';
2928
import type { ExecutionResult } from '../execution/execute';
3029
import type { DocumentNode } from '../language/ast';
3130
import type { GraphQLFieldResolver } from '../type/definition';
31+
import { getOperationRootType } from '../utilities/getOperationRootType';
3232

3333
/**
3434
* Implements the "Subscribe" algorithm described in the GraphQL specification.
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
import { expect } from 'chai';
9+
import { describe, it } from 'mocha';
10+
import { getOperationRootType } from '../getOperationRootType';
11+
import { parse, GraphQLSchema, GraphQLObjectType, GraphQLString } from '../../';
12+
13+
const queryType = new GraphQLObjectType({
14+
name: 'FooQuery',
15+
fields: () => ({
16+
field: { type: GraphQLString },
17+
}),
18+
});
19+
20+
const mutationType = new GraphQLObjectType({
21+
name: 'FooMutation',
22+
fields: () => ({
23+
field: { type: GraphQLString },
24+
}),
25+
});
26+
27+
const subscriptionType = new GraphQLObjectType({
28+
name: 'FooSubscription',
29+
fields: () => ({
30+
field: { type: GraphQLString },
31+
}),
32+
});
33+
34+
describe('getOperationRootType', () => {
35+
it('Gets a Query type for an unnamed OperationDefinitionNode', () => {
36+
const testSchema = new GraphQLSchema({
37+
query: queryType,
38+
});
39+
const doc = parse('{ field }');
40+
expect(getOperationRootType(testSchema, doc.definitions[0])).to.equal(
41+
queryType,
42+
);
43+
});
44+
45+
it('Gets a Query type for an named OperationDefinitionNode', () => {
46+
const testSchema = new GraphQLSchema({
47+
query: queryType,
48+
});
49+
50+
const doc = parse('query Q { field }');
51+
expect(getOperationRootType(testSchema, doc.definitions[0])).to.equal(
52+
queryType,
53+
);
54+
});
55+
56+
it('Gets a type for OperationTypeDefinitionNodes', () => {
57+
const testSchema = new GraphQLSchema({
58+
query: queryType,
59+
mutation: mutationType,
60+
subscription: subscriptionType,
61+
});
62+
63+
const doc = parse(
64+
'schema { query: FooQuery mutation: FooMutation subscription: FooSubscription }',
65+
);
66+
const operationTypes = doc.definitions[0].operationTypes;
67+
expect(getOperationRootType(testSchema, operationTypes[0])).to.equal(
68+
queryType,
69+
);
70+
expect(getOperationRootType(testSchema, operationTypes[1])).to.equal(
71+
mutationType,
72+
);
73+
expect(getOperationRootType(testSchema, operationTypes[2])).to.equal(
74+
subscriptionType,
75+
);
76+
});
77+
78+
it('Gets a Mutation type for an OperationDefinitionNode', () => {
79+
const testSchema = new GraphQLSchema({
80+
mutation: mutationType,
81+
});
82+
83+
const doc = parse('mutation { field }');
84+
expect(getOperationRootType(testSchema, doc.definitions[0])).to.equal(
85+
mutationType,
86+
);
87+
});
88+
89+
it('Gets a Subscription type for an OperationDefinitionNode', () => {
90+
const testSchema = new GraphQLSchema({
91+
subscription: subscriptionType,
92+
});
93+
94+
const doc = parse('subscription { field }');
95+
expect(getOperationRootType(testSchema, doc.definitions[0])).to.equal(
96+
subscriptionType,
97+
);
98+
});
99+
100+
it('Throws when query type not defined in schema', () => {
101+
const testSchema = new GraphQLSchema({});
102+
103+
const doc = parse('query { field }');
104+
expect(() => getOperationRootType(testSchema, doc.definitions[0])).to.throw(
105+
'Schema does not define the required query root type.',
106+
);
107+
});
108+
109+
it('Throws when mutation type not defined in schema', () => {
110+
const testSchema = new GraphQLSchema({});
111+
112+
const doc = parse('mutation { field }');
113+
expect(() => getOperationRootType(testSchema, doc.definitions[0])).to.throw(
114+
'Schema is not configured for mutations.',
115+
);
116+
});
117+
118+
it('Throws when subscription type not defined in schema', () => {
119+
const testSchema = new GraphQLSchema({});
120+
121+
const doc = parse('subscription { field }');
122+
expect(() => getOperationRootType(testSchema, doc.definitions[0])).to.throw(
123+
'Schema is not configured for subscriptions.',
124+
);
125+
});
126+
127+
it('Throws when operation not a valid operation kind', () => {
128+
const testSchema = new GraphQLSchema({});
129+
130+
const doc = parse('{ field }');
131+
doc.definitions[0].operation = 'non_existent_operation';
132+
expect(() => getOperationRootType(testSchema, doc.definitions[0])).to.throw(
133+
'Can only have query, mutation and subscription operations.',
134+
);
135+
});
136+
});

src/utilities/getOperationRootType.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow strict
8+
*/
9+
10+
import { GraphQLError } from '../error/GraphQLError';
11+
import type {
12+
OperationDefinitionNode,
13+
OperationTypeDefinitionNode,
14+
} from '../language/ast';
15+
import { GraphQLSchema } from '../type/schema';
16+
import type { GraphQLObjectType } from '../type/definition';
17+
18+
/**
19+
* Extracts the root type of the operation from the schema.
20+
*/
21+
export function getOperationRootType(
22+
schema: GraphQLSchema,
23+
operation: OperationDefinitionNode | OperationTypeDefinitionNode,
24+
): GraphQLObjectType {
25+
switch (operation.operation) {
26+
case 'query':
27+
const queryType = schema.getQueryType();
28+
if (!queryType) {
29+
throw new GraphQLError(
30+
'Schema does not define the required query root type.',
31+
[operation],
32+
);
33+
}
34+
return queryType;
35+
case 'mutation':
36+
const mutationType = schema.getMutationType();
37+
if (!mutationType) {
38+
throw new GraphQLError('Schema is not configured for mutations.', [
39+
operation,
40+
]);
41+
}
42+
return mutationType;
43+
case 'subscription':
44+
const subscriptionType = schema.getSubscriptionType();
45+
if (!subscriptionType) {
46+
throw new GraphQLError('Schema is not configured for subscriptions.', [
47+
operation,
48+
]);
49+
}
50+
return subscriptionType;
51+
default:
52+
throw new GraphQLError(
53+
'Can only have query, mutation and subscription operations.',
54+
[operation],
55+
);
56+
}
57+
}

src/utilities/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ export type {
4141
// Gets the target Operation from a Document
4242
export { getOperationAST } from './getOperationAST';
4343

44+
// Gets the Type for the target Operation AST.
45+
export { getOperationRootType } from './getOperationRootType';
46+
4447
// Convert a GraphQLSchema to an IntrospectionQuery
4548
export { introspectionFromSchema } from './introspectionFromSchema';
4649

0 commit comments

Comments
 (0)