schema.go

  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}