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