1package schema
2
3import (
4 "fmt"
5 "strings"
6 "text/scanner"
7
8 "github.com/vektah/gqlgen/neelance/common"
9 "github.com/vektah/gqlgen/neelance/errors"
10)
11
12type Schema struct {
13 EntryPoints map[string]NamedType
14 Types map[string]NamedType
15 Directives map[string]*DirectiveDecl
16
17 entryPointNames map[string]string
18 objects []*Object
19 unions []*Union
20 enums []*Enum
21}
22
23var defaultEntrypoints = map[string]string{
24 "query": "Query",
25 "mutation": "Mutation",
26 "subscription": "Subscription",
27}
28
29func (s *Schema) Resolve(name string) common.Type {
30 return s.Types[name]
31}
32
33type NamedType interface {
34 common.Type
35 TypeName() string
36 Description() string
37}
38
39type Scalar struct {
40 Name string
41 Desc string
42}
43
44type Object struct {
45 Name string
46 Interfaces []*Interface
47 Fields FieldList
48 Desc string
49
50 interfaceNames []string
51}
52
53type Interface struct {
54 Name string
55 PossibleTypes []*Object
56 Fields FieldList
57 Desc string
58}
59
60type Union struct {
61 Name string
62 PossibleTypes []*Object
63 Desc string
64
65 typeNames []string
66}
67
68type Enum struct {
69 Name string
70 Values []*EnumValue
71 Desc string
72}
73
74type EnumValue struct {
75 Name string
76 Directives common.DirectiveList
77 Desc string
78}
79
80type InputObject struct {
81 Name string
82 Desc string
83 Values common.InputValueList
84}
85
86type FieldList []*Field
87
88func (l FieldList) Get(name string) *Field {
89 for _, f := range l {
90 if f.Name == name {
91 return f
92 }
93 }
94 return nil
95}
96
97func (l FieldList) Names() []string {
98 names := make([]string, len(l))
99 for i, f := range l {
100 names[i] = f.Name
101 }
102 return names
103}
104
105type DirectiveDecl struct {
106 Name string
107 Desc string
108 Locs []string
109 Args common.InputValueList
110}
111
112func (*Scalar) Kind() string { return "SCALAR" }
113func (*Object) Kind() string { return "OBJECT" }
114func (*Interface) Kind() string { return "INTERFACE" }
115func (*Union) Kind() string { return "UNION" }
116func (*Enum) Kind() string { return "ENUM" }
117func (*InputObject) Kind() string { return "INPUT_OBJECT" }
118
119func (t *Scalar) String() string { return t.Name }
120func (t *Object) String() string { return t.Name }
121func (t *Interface) String() string { return t.Name }
122func (t *Union) String() string { return t.Name }
123func (t *Enum) String() string { return t.Name }
124func (t *InputObject) String() string { return t.Name }
125
126func (t *Scalar) TypeName() string { return t.Name }
127func (t *Object) TypeName() string { return t.Name }
128func (t *Interface) TypeName() string { return t.Name }
129func (t *Union) TypeName() string { return t.Name }
130func (t *Enum) TypeName() string { return t.Name }
131func (t *InputObject) TypeName() string { return t.Name }
132
133func (t *Scalar) Description() string { return t.Desc }
134func (t *Object) Description() string { return t.Desc }
135func (t *Interface) Description() string { return t.Desc }
136func (t *Union) Description() string { return t.Desc }
137func (t *Enum) Description() string { return t.Desc }
138func (t *InputObject) Description() string { return t.Desc }
139
140type Field struct {
141 Name string
142 Args common.InputValueList
143 Type common.Type
144 Directives common.DirectiveList
145 Desc string
146}
147
148func MustParse(str string) *Schema {
149 s := New()
150 err := s.Parse(str)
151 if err != nil {
152 panic(err)
153 }
154 return s
155}
156
157func New() *Schema {
158 s := &Schema{
159 entryPointNames: make(map[string]string),
160 Types: make(map[string]NamedType),
161 Directives: make(map[string]*DirectiveDecl),
162 }
163 for n, t := range Meta.Types {
164 s.Types[n] = t
165 }
166 for n, d := range Meta.Directives {
167 s.Directives[n] = d
168 }
169 return s
170}
171
172func (s *Schema) Parse(schemaString string) error {
173 sc := &scanner.Scanner{
174 Mode: scanner.ScanIdents | scanner.ScanInts | scanner.ScanFloats | scanner.ScanStrings,
175 }
176 sc.Init(strings.NewReader(schemaString))
177
178 l := common.New(sc)
179 err := l.CatchSyntaxError(func() {
180 parseSchema(s, l)
181 })
182 if err != nil {
183 return err
184 }
185
186 for _, t := range s.Types {
187 if err := resolveNamedType(s, t); err != nil {
188 return err
189 }
190 }
191 for _, d := range s.Directives {
192 for _, arg := range d.Args {
193 t, err := common.ResolveType(arg.Type, s.Resolve)
194 if err != nil {
195 return err
196 }
197 arg.Type = t
198 }
199 }
200
201 s.EntryPoints = make(map[string]NamedType)
202 for key, name := range s.entryPointNames {
203 t, ok := s.Types[name]
204 if !ok {
205 if !ok {
206 return errors.Errorf("type %q not found", name)
207 }
208 }
209 s.EntryPoints[key] = t
210 }
211
212 for entrypointName, typeName := range defaultEntrypoints {
213 if _, ok := s.EntryPoints[entrypointName]; ok {
214 continue
215 }
216
217 if _, ok := s.Types[typeName]; !ok {
218 continue
219 }
220
221 s.EntryPoints[entrypointName] = s.Types[typeName]
222 }
223
224 for _, obj := range s.objects {
225 obj.Interfaces = make([]*Interface, len(obj.interfaceNames))
226 for i, intfName := range obj.interfaceNames {
227 t, ok := s.Types[intfName]
228 if !ok {
229 return errors.Errorf("interface %q not found", intfName)
230 }
231 intf, ok := t.(*Interface)
232 if !ok {
233 return errors.Errorf("type %q is not an interface", intfName)
234 }
235 obj.Interfaces[i] = intf
236 intf.PossibleTypes = append(intf.PossibleTypes, obj)
237 }
238 }
239
240 for _, union := range s.unions {
241 union.PossibleTypes = make([]*Object, len(union.typeNames))
242 for i, name := range union.typeNames {
243 t, ok := s.Types[name]
244 if !ok {
245 return errors.Errorf("object type %q not found", name)
246 }
247 obj, ok := t.(*Object)
248 if !ok {
249 return errors.Errorf("type %q is not an object", name)
250 }
251 union.PossibleTypes[i] = obj
252 }
253 }
254
255 for _, enum := range s.enums {
256 for _, value := range enum.Values {
257 if err := resolveDirectives(s, value.Directives); err != nil {
258 return err
259 }
260 }
261 }
262
263 return nil
264}
265
266func resolveNamedType(s *Schema, t NamedType) error {
267 switch t := t.(type) {
268 case *Object:
269 for _, f := range t.Fields {
270 if err := resolveField(s, f); err != nil {
271 return err
272 }
273 }
274 case *Interface:
275 for _, f := range t.Fields {
276 if err := resolveField(s, f); err != nil {
277 return err
278 }
279 }
280 case *InputObject:
281 if err := resolveInputObject(s, t.Values); err != nil {
282 return err
283 }
284 }
285 return nil
286}
287
288func resolveField(s *Schema, f *Field) error {
289 t, err := common.ResolveType(f.Type, s.Resolve)
290 if err != nil {
291 return err
292 }
293 f.Type = t
294 if err := resolveDirectives(s, f.Directives); err != nil {
295 return err
296 }
297 return resolveInputObject(s, f.Args)
298}
299
300func resolveDirectives(s *Schema, directives common.DirectiveList) error {
301 for _, d := range directives {
302 dirName := d.Name.Name
303 dd, ok := s.Directives[dirName]
304 if !ok {
305 return errors.Errorf("directive %q not found", dirName)
306 }
307 for _, arg := range d.Args {
308 if dd.Args.Get(arg.Name.Name) == nil {
309 return errors.Errorf("invalid argument %q for directive %q", arg.Name.Name, dirName)
310 }
311 }
312 for _, arg := range dd.Args {
313 if _, ok := d.Args.Get(arg.Name.Name); !ok {
314 d.Args = append(d.Args, common.Argument{Name: arg.Name, Value: arg.Default})
315 }
316 }
317 }
318 return nil
319}
320
321func resolveInputObject(s *Schema, values common.InputValueList) error {
322 for _, v := range values {
323 t, err := common.ResolveType(v.Type, s.Resolve)
324 if err != nil {
325 return err
326 }
327 v.Type = t
328 }
329 return nil
330}
331
332func parseSchema(s *Schema, l *common.Lexer) {
333 for l.Peek() != scanner.EOF {
334 desc := l.DescComment()
335 switch x := l.ConsumeIdent(); x {
336 case "schema":
337 l.ConsumeToken('{')
338 for l.Peek() != '}' {
339 name := l.ConsumeIdent()
340 l.ConsumeToken(':')
341 typ := l.ConsumeIdent()
342 s.entryPointNames[name] = typ
343 }
344 l.ConsumeToken('}')
345 case "type":
346 obj := parseObjectDecl(l)
347 obj.Desc = desc
348 s.Types[obj.Name] = obj
349 s.objects = append(s.objects, obj)
350 case "interface":
351 intf := parseInterfaceDecl(l)
352 intf.Desc = desc
353 s.Types[intf.Name] = intf
354 case "union":
355 union := parseUnionDecl(l)
356 union.Desc = desc
357 s.Types[union.Name] = union
358 s.unions = append(s.unions, union)
359 case "enum":
360 enum := parseEnumDecl(l)
361 enum.Desc = desc
362 s.Types[enum.Name] = enum
363 s.enums = append(s.enums, enum)
364 case "input":
365 input := parseInputDecl(l)
366 input.Desc = desc
367 s.Types[input.Name] = input
368 case "scalar":
369 name := l.ConsumeIdent()
370 s.Types[name] = &Scalar{Name: name, Desc: desc}
371 case "directive":
372 directive := parseDirectiveDecl(l)
373 directive.Desc = desc
374 s.Directives[directive.Name] = directive
375 default:
376 l.SyntaxError(fmt.Sprintf(`unexpected %q, expecting "schema", "type", "enum", "interface", "union", "input", "scalar" or "directive"`, x))
377 }
378 }
379}
380
381func parseObjectDecl(l *common.Lexer) *Object {
382 o := &Object{}
383 o.Name = l.ConsumeIdent()
384 if l.Peek() == scanner.Ident {
385 l.ConsumeKeyword("implements")
386 for {
387 o.interfaceNames = append(o.interfaceNames, l.ConsumeIdent())
388 if l.Peek() == '{' {
389 break
390 }
391 }
392 }
393 l.ConsumeToken('{')
394 o.Fields = parseFields(l)
395 l.ConsumeToken('}')
396 return o
397}
398
399func parseInterfaceDecl(l *common.Lexer) *Interface {
400 i := &Interface{}
401 i.Name = l.ConsumeIdent()
402 l.ConsumeToken('{')
403 i.Fields = parseFields(l)
404 l.ConsumeToken('}')
405 return i
406}
407
408func parseUnionDecl(l *common.Lexer) *Union {
409 union := &Union{}
410 union.Name = l.ConsumeIdent()
411 l.ConsumeToken('=')
412 union.typeNames = []string{l.ConsumeIdent()}
413 for l.Peek() == '|' {
414 l.ConsumeToken('|')
415 union.typeNames = append(union.typeNames, l.ConsumeIdent())
416 }
417 return union
418}
419
420func parseInputDecl(l *common.Lexer) *InputObject {
421 i := &InputObject{}
422 i.Name = l.ConsumeIdent()
423 l.ConsumeToken('{')
424 for l.Peek() != '}' {
425 i.Values = append(i.Values, common.ParseInputValue(l))
426 }
427 l.ConsumeToken('}')
428 return i
429}
430
431func parseEnumDecl(l *common.Lexer) *Enum {
432 enum := &Enum{}
433 enum.Name = l.ConsumeIdent()
434 l.ConsumeToken('{')
435 for l.Peek() != '}' {
436 v := &EnumValue{}
437 v.Desc = l.DescComment()
438 v.Name = l.ConsumeIdent()
439 v.Directives = common.ParseDirectives(l)
440 enum.Values = append(enum.Values, v)
441 }
442 l.ConsumeToken('}')
443 return enum
444}
445
446func parseDirectiveDecl(l *common.Lexer) *DirectiveDecl {
447 d := &DirectiveDecl{}
448 l.ConsumeToken('@')
449 d.Name = l.ConsumeIdent()
450 if l.Peek() == '(' {
451 l.ConsumeToken('(')
452 for l.Peek() != ')' {
453 v := common.ParseInputValue(l)
454 d.Args = append(d.Args, v)
455 }
456 l.ConsumeToken(')')
457 }
458 l.ConsumeKeyword("on")
459 for {
460 loc := l.ConsumeIdent()
461 d.Locs = append(d.Locs, loc)
462 if l.Peek() != '|' {
463 break
464 }
465 l.ConsumeToken('|')
466 }
467 return d
468}
469
470func parseFields(l *common.Lexer) FieldList {
471 var fields FieldList
472 for l.Peek() != '}' {
473 f := &Field{}
474 f.Desc = l.DescComment()
475 f.Name = l.ConsumeIdent()
476 if l.Peek() == '(' {
477 l.ConsumeToken('(')
478 for l.Peek() != ')' {
479 f.Args = append(f.Args, common.ParseInputValue(l))
480 }
481 l.ConsumeToken(')')
482 }
483 l.ConsumeToken(':')
484 f.Type = common.ParseType(l)
485 f.Directives = common.ParseDirectives(l)
486 fields = append(fields, f)
487 }
488 return fields
489}