diff --git a/codegen/config/config.go b/codegen/config/config.go index 3e77074fce4..c7a7d4d8914 100644 --- a/codegen/config/config.go +++ b/codegen/config/config.go @@ -10,6 +10,8 @@ import ( "sort" "strings" + "golang.org/x/tools/go/packages" + "github.com/99designs/gqlgen/internal/code" "github.com/pkg/errors" "github.com/vektah/gqlparser" @@ -22,6 +24,7 @@ type Config struct { Exec PackageConfig `yaml:"exec"` Model PackageConfig `yaml:"model"` Resolver PackageConfig `yaml:"resolver,omitempty"` + AutoBind []string `yaml:"autobind"` Models TypeMap `yaml:"models,omitempty"` StructTag string `yaml:"struct_tag,omitempty"` Directives map[string]DirectiveConfig `yaml:"directives,omitempty"` @@ -379,6 +382,31 @@ func (c *Config) normalize() error { return nil } +func (c *Config) Autobind(s *ast.Schema) error { + if len(c.AutoBind) == 0 { + return nil + } + ps, err := packages.Load(&packages.Config{Mode: packages.LoadTypes}, c.AutoBind...) + if err != nil { + return err + } + + for _, t := range s.Types { + if c.Models.UserDefined(t.Name) { + continue + } + + for _, p := range ps { + if t := p.Types.Scope().Lookup(t.Name); t != nil { + c.Models.Add(t.Name(), t.Pkg().Path()+"."+t.Name()) + break + } + } + } + + return nil +} + func (c *Config) InjectBuiltins(s *ast.Schema) { builtins := TypeMap{ "__Directive": {Model: StringList{"github.com/99designs/gqlgen/graphql/introspection.Directive"}}, diff --git a/codegen/config/config_test.go b/codegen/config/config_test.go index 5408ecbcc0d..7551a11543a 100644 --- a/codegen/config/config_test.go +++ b/codegen/config/config_test.go @@ -6,6 +6,9 @@ import ( "runtime" "testing" + "github.com/vektah/gqlparser" + "github.com/vektah/gqlparser/ast" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -114,3 +117,23 @@ func TestConfigCheck(t *testing.T) { require.EqualError(t, err, "filenames exec.go and models.go are in the same directory but have different package definitions") }) } + +func TestAutobinding(t *testing.T) { + cfg := Config{ + Models: TypeMap{}, + AutoBind: []string{ + "github.com/99designs/gqlgen/example/chat", + "github.com/99designs/gqlgen/example/scalars/model", + }, + } + + s := gqlparser.MustLoadSchema(&ast.Source{Name: "TestAutobinding.schema", Input: ` + scalar Banned + type Message { id: ID } + `}) + + require.NoError(t, cfg.Autobind(s)) + + 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]) +} diff --git a/codegen/data.go b/codegen/data.go index 12c85921064..98d2ec8886a 100644 --- a/codegen/data.go +++ b/codegen/data.go @@ -51,6 +51,11 @@ func BuildData(cfg *config.Config) (*Data, error) { return nil, err } + err = cfg.Autobind(b.Schema) + if err != nil { + return nil, err + } + cfg.InjectBuiltins(b.Schema) b.Binder, err = b.Config.NewBinder(b.Schema) diff --git a/docs/content/config.md b/docs/content/config.md index a12f406a9e5..50d550514ab 100644 --- a/docs/content/config.md +++ b/docs/content/config.md @@ -44,6 +44,11 @@ resolver: # Optional, turns on binding to field names by tag provided struct_tag: json +# Instead of listing out every model like below, you can automatically bind to any matching types +# within the given path. EXPERIMENTAL in v0.9.1 +autobind: + - github.com/my/app/models + # Tell gqlgen about any existing models you want to reuse for # graphql. These normally come from the db or a remote api. models: diff --git a/example/starwars/.gqlgen.yml b/example/starwars/.gqlgen.yml index 42d07800ed9..f1b08bb5951 100644 --- a/example/starwars/.gqlgen.yml +++ b/example/starwars/.gqlgen.yml @@ -3,15 +3,10 @@ exec: model: filename: models/generated.go +autobind: + - github.com/99designs/gqlgen/example/starwars/models + models: - Droid: - model: github.com/99designs/gqlgen/example/starwars/models.Droid - FriendsConnection: - model: github.com/99designs/gqlgen/example/starwars/models.FriendsConnection - Human: - model: github.com/99designs/gqlgen/example/starwars/models.Human - Review: - model: github.com/99designs/gqlgen/example/starwars/models.Review ReviewInput: model: github.com/99designs/gqlgen/example/starwars/models.Review Starship: diff --git a/plugin/modelgen/models.go b/plugin/modelgen/models.go index bb400f1b766..376499ae218 100644 --- a/plugin/modelgen/models.go +++ b/plugin/modelgen/models.go @@ -72,6 +72,11 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error { return err } + err = cfg.Autobind(schema) + if err != nil { + return err + } + cfg.InjectBuiltins(schema) binder, err := cfg.NewBinder(schema)