Skip to content

Commit

Permalink
Refactor config loading so we can get a single packages.Load call
Browse files Browse the repository at this point in the history
  • Loading branch information
vektah committed Jan 16, 2020
1 parent bbfacfa commit 9c87c28
Show file tree
Hide file tree
Showing 16 changed files with 234 additions and 193 deletions.
28 changes: 19 additions & 9 deletions api/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"github.com/99designs/gqlgen/plugin/federation"
"github.com/99designs/gqlgen/plugin/modelgen"
"github.com/99designs/gqlgen/plugin/resolvergen"
"github.com/99designs/gqlgen/plugin/schemaconfig"
"github.com/pkg/errors"
)

Expand All @@ -18,11 +17,8 @@ func Generate(cfg *config.Config, option ...Option) error {
if cfg.Model.IsDefined() {
_ = syscall.Unlink(cfg.Model.Filename)
}
if err := cfg.Check(); err != nil {
return errors.Wrap(err, "generating core failed")
}

plugins := []plugin.Plugin{schemaconfig.New()}
plugins := []plugin.Plugin{}
if cfg.Model.IsDefined() {
plugins = append(plugins, modelgen.New())
}
Expand All @@ -35,16 +31,30 @@ func Generate(cfg *config.Config, option ...Option) error {
o(cfg, &plugins)
}

schemaMutators := []codegen.SchemaMutator{}
for _, p := range plugins {
if inj, ok := p.(plugin.SourcesInjector); ok {
inj.InjectSources(cfg)
}
if mut, ok := p.(codegen.SchemaMutator); ok {
schemaMutators = append(schemaMutators, mut)
}

err := cfg.LoadSchema()
if err != nil {
return errors.Wrap(err, "failed to load schema")
}

for _, p := range plugins {
if mut, ok := p.(plugin.SchemaMutator); ok {
err := mut.MutateSchema(cfg.Schema)
if err != nil {
return errors.Wrap(err, p.Name())
}
}
}

if err := cfg.Init(); err != nil {
return errors.Wrap(err, "generating core failed")
}

for _, p := range plugins {
if mut, ok := p.(plugin.ConfigMutator); ok {
err := mut.MutateConfig(cfg)
Expand All @@ -54,7 +64,7 @@ func Generate(cfg *config.Config, option ...Option) error {
}
}
// Merge again now that the generated models have been injected into the typemap
data, err := codegen.BuildData(cfg, schemaMutators)
data, err := codegen.BuildData(cfg)
if err != nil {
return errors.Wrap(err, "merging type systems failed")
}
Expand Down
4 changes: 2 additions & 2 deletions codegen/config/binder.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ type Binder struct {
SawInvalid bool
}

func (c *Config) NewBinder(s *ast.Schema) *Binder {
func (c *Config) NewBinder() *Binder {
return &Binder{
pkgs: c.Packages,
schema: s,
schema: c.Schema,
cfg: c,
}
}
Expand Down
6 changes: 3 additions & 3 deletions codegen/config/binder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,15 @@ func createBinder(cfg Config) (*Binder, *ast.Schema) {
}
cfg.Packages = &code.Packages{}

s := gqlparser.MustLoadSchema(&ast.Source{Name: "TestAutobinding.schema", Input: `
cfg.Schema = gqlparser.MustLoadSchema(&ast.Source{Name: "TestAutobinding.schema", Input: `
type Message { id: ID }
type Query {
messages: [Message!]!
}
`})

b := cfg.NewBinder(s)
b := cfg.NewBinder()

return b, s
return b, cfg.Schema
}
145 changes: 132 additions & 13 deletions codegen/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type Config struct {
Federated bool `yaml:"federated,omitempty"`
AdditionalSources []*ast.Source `yaml:"-"`
Packages *code.Packages `yaml:"-"`
Schema *ast.Schema `yaml:"-"`
}

var cfgFilenames = []string{".gqlgen.yml", "gqlgen.yml", "gqlgen.yaml"}
Expand All @@ -42,6 +43,7 @@ func DefaultConfig() *Config {
Model: PackageConfig{Filename: "models_gen.go"},
Exec: PackageConfig{Filename: "generated.go"},
Directives: map[string]DirectiveConfig{},
Models: TypeMap{},
}
}

Expand Down Expand Up @@ -224,7 +226,114 @@ func (c *PackageConfig) IsDefined() bool {
return c.Filename != ""
}

func (c *Config) Check() error {
func (c *Config) Init() error {
if c.Packages == nil {
c.Packages = &code.Packages{}
}

if c.Schema == nil {
if err := c.LoadSchema(); err != nil {
return err
}
}

err := c.injectTypesFromSchema()
if err != nil {
return err
}

err = c.autobind()
if err != nil {
return err
}

c.injectBuiltins()

// prefetch all packages in one big packages.Load call
pkgs := []string{
"github.com/99designs/gqlgen/graphql",
"github.com/99designs/gqlgen/graphql/introspection",
}
pkgs = append(pkgs, c.Models.ReferencedPackages()...)
pkgs = append(pkgs, c.AutoBind...)
c.Packages.LoadAll(pkgs...)

// check everything is valid on the way out
err = c.check()
if err != nil {
return err
}

return nil
}

func (c *Config) injectTypesFromSchema() error {
c.Directives["goModel"] = DirectiveConfig{
SkipRuntime: true,
}

c.Directives["goField"] = DirectiveConfig{
SkipRuntime: true,
}

for _, schemaType := range c.Schema.Types {
if schemaType == c.Schema.Query || schemaType == c.Schema.Mutation || schemaType == c.Schema.Subscription {
continue
}

if bd := schemaType.Directives.ForName("goModel"); bd != nil {
if ma := bd.Arguments.ForName("model"); ma != nil {
if mv, err := ma.Value.Value(nil); err == nil {
c.Models.Add(schemaType.Name, mv.(string))
}
}
if ma := bd.Arguments.ForName("models"); ma != nil {
if mvs, err := ma.Value.Value(nil); err == nil {
for _, mv := range mvs.([]interface{}) {
c.Models.Add(schemaType.Name, mv.(string))
}
}
}
}

if schemaType.Kind == ast.Object || schemaType.Kind == ast.InputObject {
for _, field := range schemaType.Fields {
if fd := field.Directives.ForName("goField"); fd != nil {
forceResolver := c.Models[schemaType.Name].Fields[field.Name].Resolver
fieldName := c.Models[schemaType.Name].Fields[field.Name].FieldName

if ra := fd.Arguments.ForName("forceResolver"); ra != nil {
if fr, err := ra.Value.Value(nil); err == nil {
forceResolver = fr.(bool)
}
}

if na := fd.Arguments.ForName("name"); na != nil {
if fr, err := na.Value.Value(nil); err == nil {
fieldName = fr.(string)
}
}

if c.Models[schemaType.Name].Fields == nil {
c.Models[schemaType.Name] = TypeMapEntry{
Model: c.Models[schemaType.Name].Model,
Fields: map[string]TypeMapField{},
}
}

c.Models[schemaType.Name].Fields[field.Name] = TypeMapField{
FieldName: fieldName,
Resolver: forceResolver,
}
}
}
}
}

return nil
}

func (c *Config) check() error {
if err := c.Models.Check(); err != nil {
return errors.Wrap(err, "config.models")
}
Expand Down Expand Up @@ -272,8 +381,6 @@ func (c *Config) Check() error {
return err
}

c.Packages = &code.Packages{}
c.Packages.LoadAll(append(c.Models.ReferencedPackages(), c.AutoBind...)...)
return nil
}

Expand Down Expand Up @@ -305,7 +412,7 @@ func (tm TypeMap) Check() error {
}

func (tm TypeMap) ReferencedPackages() []string {
pkgs := []string{"github.com/99designs/gqlgen/graphql"}
pkgs := []string{}

for _, typ := range tm {
for _, model := range typ.Model {
Expand Down Expand Up @@ -402,14 +509,14 @@ func (c *Config) normalize() error {
return nil
}

func (c *Config) Autobind(s *ast.Schema) error {
func (c *Config) autobind() error {
if len(c.AutoBind) == 0 {
return nil
}

ps := c.Packages.LoadAll(c.AutoBind...)

for _, t := range s.Types {
for _, t := range c.Schema.Types {
if c.Models.UserDefined(t.Name) {
continue
}
Expand Down Expand Up @@ -446,7 +553,7 @@ func (c *Config) Autobind(s *ast.Schema) error {
return nil
}

func (c *Config) InjectBuiltins(s *ast.Schema) {
func (c *Config) injectBuiltins() {
builtins := TypeMap{
"__Directive": {Model: StringList{"github.com/99designs/gqlgen/graphql/introspection.Directive"}},
"__DirectiveLocation": {Model: StringList{"github.com/99designs/gqlgen/graphql.String"}},
Expand Down Expand Up @@ -487,13 +594,22 @@ func (c *Config) InjectBuiltins(s *ast.Schema) {
}

for typeName, entry := range extraBuiltins {
if t, ok := s.Types[typeName]; !c.Models.Exists(typeName) && ok && t.Kind == ast.Scalar {
if t, ok := c.Schema.Types[typeName]; !c.Models.Exists(typeName) && ok && t.Kind == ast.Scalar {
c.Models[typeName] = entry
}
}
}

func (c *Config) LoadSchema() (*ast.Schema, error) {
func (c *Config) LoadSchema() error {
if c.Packages == nil {
c.Packages = &code.Packages{}
}
// first check everything is valid on the way in
err := c.check()
if err != nil {
return err
}

sources := append([]*ast.Source{}, c.AdditionalSources...)
for _, filename := range c.SchemaFilename {
filename = filepath.ToSlash(filename)
Expand All @@ -507,11 +623,14 @@ func (c *Config) LoadSchema() (*ast.Schema, error) {
sources = append(sources, &ast.Source{Name: filename, Input: string(schemaRaw)})
}

schema, err := gqlparser.LoadSchema(sources...)
if err != nil {
return nil, err
schema, gerr := gqlparser.LoadSchema(sources...)
if gerr != nil {
return gerr
}
return schema, nil

c.Schema = schema

return nil
}

func abs(path string) string {
Expand Down
8 changes: 4 additions & 4 deletions codegen/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func TestReferencedPackages(t *testing.T) {

pkgs := tm.ReferencedPackages()

assert.Equal(t, []string{"github.com/test", "github.com/otherpkg", "github.com/99designs/gqlgen/graphql"}, pkgs)
assert.Equal(t, []string{"github.com/test", "github.com/otherpkg"}, pkgs)
})

}
Expand All @@ -115,7 +115,7 @@ func TestConfigCheck(t *testing.T) {
err = config.normalize()
require.NoError(t, err)

err = config.Check()
err = config.Init()
require.EqualError(t, err, "filenames exec.go and models.go are in the same directory but have different package definitions")
})
}
Expand All @@ -130,12 +130,12 @@ func TestAutobinding(t *testing.T) {
Packages: &code.Packages{},
}

s := gqlparser.MustLoadSchema(&ast.Source{Name: "TestAutobinding.schema", Input: `
cfg.Schema = gqlparser.MustLoadSchema(&ast.Source{Name: "TestAutobinding.schema", Input: `
scalar Banned
type Message { id: ID }
`})

require.NoError(t, cfg.Autobind(s))
require.NoError(t, cfg.autobind())

require.Equal(t, "github.com/99designs/gqlgen/example/scalars/model.Banned", cfg.Models["Banned"].Model[0])
require.Equal(t, "github.com/99designs/gqlgen/example/chat.Message", cfg.Models["Message"].Model[0])
Expand Down
35 changes: 4 additions & 31 deletions codegen/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,42 +37,15 @@ type builder struct {
Directives map[string]*Directive
}

type SchemaMutator interface {
MutateSchema(s *ast.Schema) error
}

func BuildData(cfg *config.Config, plugins []SchemaMutator) (*Data, error) {
func BuildData(cfg *config.Config) (*Data, error) {
b := builder{
Config: cfg,
Schema: cfg.Schema,
}

var err error
b.Schema, err = cfg.LoadSchema()
if err != nil {
return nil, err
}

err = cfg.Check()
if err != nil {
return nil, err
}

err = cfg.Autobind(b.Schema)
if err != nil {
return nil, err
}

cfg.InjectBuiltins(b.Schema)

for _, p := range plugins {
err = p.MutateSchema(b.Schema)
if err != nil {
return nil, fmt.Errorf("error running MutateSchema: %v", err)
}
}

b.Binder = b.Config.NewBinder(b.Schema)
b.Binder = b.Config.NewBinder()

var err error
b.Directives, err = b.buildDirectives()
if err != nil {
return nil, err
Expand Down
Loading

0 comments on commit 9c87c28

Please sign in to comment.