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  }