data.go

  1package codegen
  2
  3import (
  4	"fmt"
  5	"sort"
  6
  7	"github.com/99designs/gqlgen/codegen/config"
  8	"github.com/pkg/errors"
  9	"github.com/vektah/gqlparser/ast"
 10)
 11
 12// Data is a unified model of the code to be generated. Plugins may modify this structure to do things like implement
 13// resolvers or directives automatically (eg grpc, validation)
 14type Data struct {
 15	Config          *config.Config
 16	Schema          *ast.Schema
 17	SchemaStr       map[string]string
 18	Directives      DirectiveList
 19	Objects         Objects
 20	Inputs          Objects
 21	Interfaces      map[string]*Interface
 22	ReferencedTypes map[string]*config.TypeReference
 23	ComplexityRoots map[string]*Object
 24
 25	QueryRoot        *Object
 26	MutationRoot     *Object
 27	SubscriptionRoot *Object
 28}
 29
 30type builder struct {
 31	Config     *config.Config
 32	Schema     *ast.Schema
 33	SchemaStr  map[string]string
 34	Binder     *config.Binder
 35	Directives map[string]*Directive
 36}
 37
 38func BuildData(cfg *config.Config) (*Data, error) {
 39	b := builder{
 40		Config: cfg,
 41	}
 42
 43	var err error
 44	b.Schema, b.SchemaStr, err = cfg.LoadSchema()
 45	if err != nil {
 46		return nil, err
 47	}
 48
 49	err = cfg.Check()
 50	if err != nil {
 51		return nil, err
 52	}
 53
 54	err = cfg.Autobind(b.Schema)
 55	if err != nil {
 56		return nil, err
 57	}
 58
 59	cfg.InjectBuiltins(b.Schema)
 60
 61	b.Binder, err = b.Config.NewBinder(b.Schema)
 62	if err != nil {
 63		return nil, err
 64	}
 65
 66	b.Directives, err = b.buildDirectives()
 67	if err != nil {
 68		return nil, err
 69	}
 70
 71	dataDirectives := make(map[string]*Directive)
 72	for name, d := range b.Directives {
 73		if !d.Builtin {
 74			dataDirectives[name] = d
 75		}
 76	}
 77
 78	s := Data{
 79		Config:     cfg,
 80		Directives: dataDirectives,
 81		Schema:     b.Schema,
 82		SchemaStr:  b.SchemaStr,
 83		Interfaces: map[string]*Interface{},
 84	}
 85
 86	for _, schemaType := range b.Schema.Types {
 87		switch schemaType.Kind {
 88		case ast.Object:
 89			obj, err := b.buildObject(schemaType)
 90			if err != nil {
 91				return nil, errors.Wrap(err, "unable to build object definition")
 92			}
 93
 94			s.Objects = append(s.Objects, obj)
 95		case ast.InputObject:
 96			input, err := b.buildObject(schemaType)
 97			if err != nil {
 98				return nil, errors.Wrap(err, "unable to build input definition")
 99			}
100
101			s.Inputs = append(s.Inputs, input)
102
103		case ast.Union, ast.Interface:
104			s.Interfaces[schemaType.Name] = b.buildInterface(schemaType)
105		}
106	}
107
108	if s.Schema.Query != nil {
109		s.QueryRoot = s.Objects.ByName(s.Schema.Query.Name)
110	} else {
111		return nil, fmt.Errorf("query entry point missing")
112	}
113
114	if s.Schema.Mutation != nil {
115		s.MutationRoot = s.Objects.ByName(s.Schema.Mutation.Name)
116	}
117
118	if s.Schema.Subscription != nil {
119		s.SubscriptionRoot = s.Objects.ByName(s.Schema.Subscription.Name)
120	}
121
122	if err := b.injectIntrospectionRoots(&s); err != nil {
123		return nil, err
124	}
125
126	s.ReferencedTypes = b.buildTypes()
127
128	sort.Slice(s.Objects, func(i, j int) bool {
129		return s.Objects[i].Definition.Name < s.Objects[j].Definition.Name
130	})
131
132	sort.Slice(s.Inputs, func(i, j int) bool {
133		return s.Inputs[i].Definition.Name < s.Inputs[j].Definition.Name
134	})
135
136	return &s, nil
137}
138
139func (b *builder) injectIntrospectionRoots(s *Data) error {
140	obj := s.Objects.ByName(b.Schema.Query.Name)
141	if obj == nil {
142		return fmt.Errorf("root query type must be defined")
143	}
144
145	__type, err := b.buildField(obj, &ast.FieldDefinition{
146		Name: "__type",
147		Type: ast.NamedType("__Type", nil),
148		Arguments: []*ast.ArgumentDefinition{
149			{
150				Name: "name",
151				Type: ast.NonNullNamedType("String", nil),
152			},
153		},
154	})
155	if err != nil {
156		return err
157	}
158
159	__schema, err := b.buildField(obj, &ast.FieldDefinition{
160		Name: "__schema",
161		Type: ast.NamedType("__Schema", nil),
162	})
163	if err != nil {
164		return err
165	}
166
167	obj.Fields = append(obj.Fields, __type, __schema)
168
169	return nil
170}