github.com/matiasanaya/gqlgen@v0.6.0/codegen/build.go (about) 1 package codegen 2 3 import ( 4 "fmt" 5 "go/build" 6 "go/types" 7 "os" 8 9 "github.com/pkg/errors" 10 "golang.org/x/tools/go/loader" 11 ) 12 13 type Build struct { 14 PackageName string 15 Objects Objects 16 Inputs Objects 17 Interfaces []*Interface 18 Imports []*Import 19 QueryRoot *Object 20 MutationRoot *Object 21 SubscriptionRoot *Object 22 SchemaRaw string 23 SchemaFilename string 24 Directives []*Directive 25 } 26 27 type ModelBuild struct { 28 PackageName string 29 Imports []*Import 30 Models []Model 31 Enums []Enum 32 } 33 34 type ResolverBuild struct { 35 PackageName string 36 Imports []*Import 37 ResolverType string 38 Objects Objects 39 ResolverFound bool 40 } 41 42 type ServerBuild struct { 43 PackageName string 44 Imports []*Import 45 ExecPackageName string 46 ResolverPackageName string 47 } 48 49 // Create a list of models that need to be generated 50 func (cfg *Config) models() (*ModelBuild, error) { 51 namedTypes := cfg.buildNamedTypes() 52 53 progLoader := newLoader(namedTypes, true) 54 prog, err := progLoader.Load() 55 if err != nil { 56 return nil, errors.Wrap(err, "loading failed") 57 } 58 imports := buildImports(namedTypes, cfg.Model.Dir()) 59 60 cfg.bindTypes(imports, namedTypes, cfg.Model.Dir(), prog) 61 62 models, err := cfg.buildModels(namedTypes, prog, imports) 63 if err != nil { 64 return nil, err 65 } 66 return &ModelBuild{ 67 PackageName: cfg.Model.Package, 68 Models: models, 69 Enums: cfg.buildEnums(namedTypes), 70 Imports: imports.finalize(), 71 }, nil 72 } 73 74 // bind a schema together with some code to generate a Build 75 func (cfg *Config) resolver() (*ResolverBuild, error) { 76 progLoader := newLoader(cfg.buildNamedTypes(), true) 77 progLoader.Import(cfg.Resolver.ImportPath()) 78 79 prog, err := progLoader.Load() 80 if err != nil { 81 return nil, err 82 } 83 84 destDir := cfg.Resolver.Dir() 85 86 namedTypes := cfg.buildNamedTypes() 87 imports := buildImports(namedTypes, destDir) 88 imports.add(cfg.Exec.ImportPath()) 89 imports.add("github.com/99designs/gqlgen/handler") // avoid import github.com/vektah/gqlgen/handler 90 91 cfg.bindTypes(imports, namedTypes, destDir, prog) 92 93 objects, err := cfg.buildObjects(namedTypes, prog, imports) 94 if err != nil { 95 return nil, err 96 } 97 98 def, _ := findGoType(prog, cfg.Resolver.ImportPath(), cfg.Resolver.Type) 99 resolverFound := def != nil 100 101 return &ResolverBuild{ 102 PackageName: cfg.Resolver.Package, 103 Imports: imports.finalize(), 104 Objects: objects, 105 ResolverType: cfg.Resolver.Type, 106 ResolverFound: resolverFound, 107 }, nil 108 } 109 110 func (cfg *Config) server(destDir string) *ServerBuild { 111 imports := buildImports(NamedTypes{}, destDir) 112 imports.add(cfg.Exec.ImportPath()) 113 imports.add(cfg.Resolver.ImportPath()) 114 115 // extra imports only used by the server template 116 imports.add("context") 117 imports.add("log") 118 imports.add("net/http") 119 imports.add("os") 120 imports.add("github.com/99designs/gqlgen/handler") 121 122 return &ServerBuild{ 123 PackageName: cfg.Resolver.Package, 124 Imports: imports.finalize(), 125 ExecPackageName: cfg.Exec.Package, 126 ResolverPackageName: cfg.Resolver.Package, 127 } 128 } 129 130 // bind a schema together with some code to generate a Build 131 func (cfg *Config) bind() (*Build, error) { 132 namedTypes := cfg.buildNamedTypes() 133 134 progLoader := newLoader(namedTypes, true) 135 prog, err := progLoader.Load() 136 if err != nil { 137 return nil, errors.Wrap(err, "loading failed") 138 } 139 140 imports := buildImports(namedTypes, cfg.Exec.Dir()) 141 cfg.bindTypes(imports, namedTypes, cfg.Exec.Dir(), prog) 142 143 objects, err := cfg.buildObjects(namedTypes, prog, imports) 144 if err != nil { 145 return nil, err 146 } 147 148 inputs, err := cfg.buildInputs(namedTypes, prog, imports) 149 if err != nil { 150 return nil, err 151 } 152 directives, err := cfg.buildDirectives(namedTypes) 153 if err != nil { 154 return nil, err 155 } 156 157 b := &Build{ 158 PackageName: cfg.Exec.Package, 159 Objects: objects, 160 Interfaces: cfg.buildInterfaces(namedTypes, prog), 161 Inputs: inputs, 162 Imports: imports.finalize(), 163 SchemaRaw: cfg.SchemaStr, 164 SchemaFilename: cfg.SchemaFilename, 165 Directives: directives, 166 } 167 168 if cfg.schema.Query != nil { 169 b.QueryRoot = b.Objects.ByName(cfg.schema.Query.Name) 170 } else { 171 return b, fmt.Errorf("query entry point missing") 172 } 173 174 if cfg.schema.Mutation != nil { 175 b.MutationRoot = b.Objects.ByName(cfg.schema.Mutation.Name) 176 } 177 178 if cfg.schema.Subscription != nil { 179 b.SubscriptionRoot = b.Objects.ByName(cfg.schema.Subscription.Name) 180 } 181 return b, nil 182 } 183 184 func (cfg *Config) validate() error { 185 progLoader := newLoader(cfg.buildNamedTypes(), false) 186 _, err := progLoader.Load() 187 return err 188 } 189 190 func newLoader(namedTypes NamedTypes, allowErrors bool) loader.Config { 191 conf := loader.Config{} 192 if allowErrors { 193 conf = loader.Config{ 194 AllowErrors: true, 195 TypeChecker: types.Config{ 196 Error: func(e error) {}, 197 }, 198 } 199 } 200 for _, imp := range ambientImports { 201 conf.Import(imp) 202 } 203 204 for _, imp := range namedTypes { 205 if imp.Package != "" { 206 conf.Import(imp.Package) 207 } 208 } 209 return conf 210 } 211 212 func resolvePkg(pkgName string) (string, error) { 213 cwd, _ := os.Getwd() 214 215 pkg, err := build.Default.Import(pkgName, cwd, build.FindOnly) 216 if err != nil { 217 return "", err 218 } 219 220 return pkg.ImportPath, nil 221 }