Skip to content

Commit 9dcbf57

Browse files
committed
Schema Materializer
Adds the schema materializer. This components takes a schema definition AST and produces a set of type definition objects corresponding to the schema definitions. This allows a user to specify schema in a far more literate fashion The next tool that I'm going to write is one that takes the schema definition DSL and outputs the result of the introspection query against that schema. This will be really useful for tests, etc.
1 parent c518e9a commit 9dcbf57

File tree

5 files changed

+565
-2
lines changed

5 files changed

+565
-2
lines changed

src/executor/values.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ function coerceValue(type: GraphQLInputType, value: any): any {
214214
* Given a type and a value AST node known to match this type, build a
215215
* runtime value.
216216
*/
217-
function coerceValueAST(
217+
export function coerceValueAST(
218218
type: GraphQLInputType,
219219
valueAST: any,
220220
variables?: ?{ [key: string]: any }
Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
/**
2+
* Copyright (c) 2015, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
import { expect } from 'chai';
11+
import { describe, it } from 'mocha';
12+
import { parseSchema } from '../parser';
13+
import { materializeSchema } from '../materializer';
14+
import { printSchema } from '../../../type/printer';
15+
import { introspectionQuery } from '../../../type/introspectionQuery';
16+
import { graphql } from '../../../';
17+
18+
// 80+ char lines are useful in describe/it, so ignore in this file.
19+
/*eslint-disable max-len */
20+
21+
function printForTest(result) {
22+
return '\n' + printSchema(result) + '\n';
23+
}
24+
25+
async function getOutput(body, queryType) {
26+
var doc = parseSchema(body);
27+
var schema = materializeSchema(doc, queryType);
28+
var result = await graphql(schema, introspectionQuery);
29+
return await printForTest(result);
30+
}
31+
32+
describe('Schema Materializer', () => {
33+
it('Simple type', async () => {
34+
var body = `
35+
type HelloScalars {
36+
str: String
37+
int: Int
38+
bool: Boolean
39+
}
40+
`;
41+
var output = await getOutput(body, 'HelloScalars');
42+
expect(output).to.equal(body);
43+
});
44+
45+
it('Type modifiers', async () => {
46+
var body = `
47+
type HelloScalars {
48+
nonNullStr: String!
49+
listOfStrs: [String]
50+
listOfNonNullStrs: [String!]
51+
nonNullListOfStrs: [String]!
52+
nonNullListOfNonNullStrs: [String!]!
53+
}
54+
`;
55+
var output = await getOutput(body, 'HelloScalars');
56+
expect(output).to.equal(body);
57+
});
58+
59+
60+
it('Recursive type', async () => {
61+
var body = `
62+
type Recurse {
63+
str: String
64+
recurse: Recurse
65+
}
66+
`;
67+
var output = await getOutput(body, 'Recurse');
68+
expect(output).to.equal(body);
69+
});
70+
71+
it('Two types circular', async () => {
72+
var body = `
73+
type TypeOne {
74+
str: String
75+
typeTwo: TypeTwo
76+
}
77+
78+
type TypeTwo {
79+
str: String
80+
typeOne: TypeOne
81+
}
82+
`;
83+
var output = await getOutput(body, 'TypeOne');
84+
expect(output).to.equal(body);
85+
});
86+
87+
it('Single argument field', async () => {
88+
var body = `
89+
type Hello {
90+
str(int: Int): String
91+
}
92+
`;
93+
var output = await getOutput(body, 'Hello');
94+
expect(output).to.equal(body);
95+
});
96+
97+
it('Simple type with multiple arguments', async () => {
98+
var body = `
99+
type Hello {
100+
str(int: Int, bool: Boolean): String
101+
}
102+
`;
103+
var output = await getOutput(body, 'Hello');
104+
expect(output).to.equal(body);
105+
});
106+
107+
it('Simple type with interface', async () => {
108+
var body = `
109+
type HelloInterface implements WorldInterface {
110+
str: String
111+
}
112+
113+
interface WorldInterface {
114+
str: String
115+
}
116+
`;
117+
var output = await getOutput(body, 'HelloInterface');
118+
expect(output).to.equal(body);
119+
});
120+
121+
it('Simple output enum', async () => {
122+
var body = `
123+
enum Hello {
124+
WORLD
125+
}
126+
127+
type OutputEnumRoot {
128+
hello: Hello
129+
}
130+
`;
131+
var output = await getOutput(body, 'OutputEnumRoot');
132+
expect(output).to.equal(body);
133+
});
134+
135+
it('Simple input enum', async () => {
136+
var body = `
137+
enum Hello {
138+
WORLD
139+
}
140+
141+
type InputEnumRoot {
142+
str(hello: Hello): String
143+
}
144+
`;
145+
var output = await getOutput(body, 'InputEnumRoot');
146+
expect(output).to.equal(body);
147+
});
148+
149+
it('Multiple value enum', async () => {
150+
var body = `
151+
enum Hello {
152+
WO
153+
RLD
154+
}
155+
156+
type OutputEnumRoot {
157+
hello: Hello
158+
}
159+
`;
160+
var output = await getOutput(body, 'OutputEnumRoot');
161+
expect(output).to.equal(body);
162+
});
163+
164+
it('Simple Union', async () => {
165+
var body = `
166+
union Hello = World
167+
168+
type Root {
169+
hello: Hello
170+
}
171+
172+
type World {
173+
str: String
174+
}
175+
`;
176+
var output = await getOutput(body, 'Root');
177+
expect(output).to.equal(body);
178+
});
179+
180+
it('Multiple Union', async () => {
181+
var body = `
182+
union Hello = WorldOne | WorldTwo
183+
184+
type Root {
185+
hello: Hello
186+
}
187+
188+
type WorldOne {
189+
str: String
190+
}
191+
192+
type WorldTwo {
193+
str: String
194+
}
195+
`;
196+
var output = await getOutput(body, 'Root');
197+
expect(output).to.equal(body);
198+
});
199+
200+
it('Simple Union', async () => {
201+
var body = `
202+
scalar CustomScalar
203+
204+
type Root {
205+
customScalar: CustomScalar
206+
}
207+
`;
208+
209+
var output = await getOutput(body, 'Root');
210+
expect(output).to.equal(body);
211+
});
212+
213+
it('Input Object', async() => {
214+
var body = `
215+
input Input {
216+
int: Int
217+
}
218+
219+
type Root {
220+
field(in: Input): String
221+
}
222+
`;
223+
224+
var output = await getOutput(body, 'Root');
225+
expect(output).to.equal(body);
226+
});
227+
228+
it('Simple argument field with default', async () => {
229+
var body = `
230+
type Hello {
231+
str(int: Int = 2): String
232+
}
233+
`;
234+
var output = await getOutput(body, 'Hello');
235+
expect(output).to.equal(body);
236+
});
237+
});
238+
239+
describe('Schema Parser Failures', () => {
240+
it('Unknown type referenced', () => {
241+
var body = `
242+
type Hello {
243+
bar: Bar
244+
}
245+
`;
246+
var doc = parseSchema(body);
247+
expect(() => materializeSchema(doc, 'Hello')).to.throw('Type Bar not found in document');
248+
});
249+
250+
it('Unknown type in interface list', () => {
251+
var body = `
252+
type Hello implements Bar { }
253+
`;
254+
var doc = parseSchema(body);
255+
expect(() => materializeSchema(doc, 'Hello')).to.throw('Type Bar not found in document');
256+
});
257+
258+
it('Unknown type in union list', () => {
259+
var body = `
260+
union TestUnion = Bar
261+
type Hello { testUnion: TestUnion }
262+
`;
263+
var doc = parseSchema(body);
264+
expect(() => materializeSchema(doc, 'Hello')).to.throw('Type Bar not found in document');
265+
});
266+
267+
268+
it('Unknown query type', () => {
269+
var body = `
270+
type Hello {
271+
str: String
272+
}
273+
`;
274+
var doc = parseSchema(body);
275+
expect(() => materializeSchema(doc, 'Wat')).to.throw('Type Wat not found in document');
276+
});
277+
});

src/language/schema/ast.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ export type SchemaDefinition =
3030
EnumDefinition |
3131
InputObjectDefinition
3232

33+
export type CompositeDefinition =
34+
TypeDefinition |
35+
InterfaceDefinition |
36+
UnionDefinition;
37+
3338
export type TypeDefinition = {
3439
kind: 'TypeDefinition';
3540
loc?: ?Location;

0 commit comments

Comments
 (0)