diff --git a/CHANGELOG.md b/CHANGELOG.md
index 662377f1b8..d977ea4063 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,10 +5,178 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-## [Unreleased](https://github.com/99designs/gqlgen/compare/v0.17.35...HEAD)
+## [Unreleased](https://github.com/99designs/gqlgen/compare/v0.17.37...HEAD)
+
+## [v0.17.37](https://github.com/99designs/gqlgen/compare/v0.17.36...v0.17.37) - 2023-09-08
+- ccae370e release v0.17.37
+
+- 6505f8be Update gqlparser (#2785)
+
+
153ec470 add uuid type (#2751) (closes #2749)
+
+* add uuid type
+
+* add uuid example
+
+* add uuid scalar doc
+
+* strconv.Quote
+
+* Apply suggestions from code review
+
+* fix
+
+
+
+---------
+
+
+
+fa471180 ForceGenerate parameter to [@goModel](https://github.com/goModel) added. (#2780)
+
+* forceGenerate to docs added
+
+---------
+
+
+
+11bb9b18 codegen: add support for `go_build_tags` option in gqlgen.yaml (#2784)
+
+* codegen: support go_build_tags option in gqlgen.yaml
+
+* chore: added test
+
+* docs/content: update config example
+
+* chore: more comment
+
+
+
+bee47dcf fix flaky test TestSubscriptions (#2779)
+
+* fix flaky test TestSubscriptions
+
+* update other copy of the test
+
+
+
+- a41f4daa docs: short-lived loader (#2778)
+
+- cc4e0ba2 ensure HasOperationContext checks for nil (#2776)
+
+a1ca2204 fix typo in TESTING.md server path (#2774)
+
+following TESTING.md instructions, I got an error:
+"stat ./server/server.go: no such file or directory"
+
+server.go path is: integration/server/cmd/integration/server.go
+
+
+
+1cde8c3f return internal types in schema introspection (#2773)
+
+according to graphql spec:
+```
+types: return the set of all named types contained within this schema.
+Any named type which can be found through a field of any introspection type must be included in this set.
+```
+source: https://github.com/graphql/graphql-spec/blob/main/spec/Section%204%20--%20Introspection.md#the-__schema-type
+
+some clients libs (like HotChocolate for C#) depends on this behavior.
+
+
+
+- 065aea3e Fix gqlgen truncates tag value with colon (#2759)
+
+- d6270e4f Update subsciptions documentation to correctly close channel (#2753)
+
+- 2d8673a6 Add Model references to Interface (#2738)
+
+- 790d7a75 Allow GraphiQL headers to be set when creating the playground handler (#2740) (closes #2739)
+
+- 0eb95dc4 v0.17.36 postrelease bump
+
+
+
+
+
+
+## [v0.17.36](https://github.com/99designs/gqlgen/compare/v0.17.35...v0.17.36) - 2023-07-27
+- bd6cfd31 release v0.17.36
+
+60ec0d86 Fix plugin template resolution (#2733) (closes #2262)
+
+- According to the documentation comment for [templates.Options], if the
+ `Template` and `TemplateFS` fields are empty, it `Render` should find
+ the `.gotpl` files from the calling plugin. However, it looks like
+ helper function. This results in broken behavior in consumers such as
+ [infiotinc/gqlgenc](https://github.com/infiotinc/gqlgenc) when they
+ use the latest version of `gqlgen` as instead of finding the template
+ from the plugin, the test template from this package is used which
+ outputs only: `this is my test package`.
+- The cause for this is that `runtime.Caller` was still only skipping
+ one stack level which means that it was finding the `Render` function
+ instead of its caller.
+
+
+
+- 76d444c1 Make models configurable via template (#2730)
+
+- abe3ffde Don't set the package variable for the new Resolver Template (#2725)
+
+febf9566 Make the resolver implementation configurable via a new template resolver.gotpl (#2720)
+
+* Make an optional resolver.gotpl ResolverTemplate to implement a custom resolver
+
+* Add test
+
+* Add documetation for the new resolver option
+
+* Change the tab to spaces
+
+* remove unecessary test assertion :/
+
+
+
+bda30260 Fixed Data Loader docs (#2723)
+
+Also updated to v7
+
+
+
+16c9eb64 Fix docs (#2722)
+
+* docs: fix variable names in dataloader sample
+
+* fix: request-scoped middleware
+
+
+
+b233a01b docs: update dataloader docs (#2719)
+
+* docs: update example
+
+* docs: update example
+
+* fix: import
+
+
+
+- cccc7389 Added go mod tidy to quick start guide (#2718) (closes #2717, #2651, #2641, #2614, #2576)
+
+- 9adc7b81 Update gqlparser to v2.5.8 (#2716)
+
+- b442fbf4 Post v0.17.35 changelog update
+
+- 57c12199 v0.17.35 postrelease bump
+
+
+
+
+
## [v0.17.35](https://github.com/99designs/gqlgen/compare/v0.17.34...v0.17.35) - 2023-07-15
- 05006bf1 release v0.17.35
diff --git a/README.md b/README.md
index e35db1c123..b11ab55392 100644
--- a/README.md
+++ b/README.md
@@ -30,6 +30,8 @@ Still not convinced enough to use **gqlgen**? Compare **gqlgen** with other Go g
go run github.com/99designs/gqlgen init
+ go mod tidy
+
4. Start the graphql server
go run server.go
diff --git a/TESTING.md b/TESTING.md
index b8adadd649..2677b33e48 100644
--- a/TESTING.md
+++ b/TESTING.md
@@ -25,7 +25,7 @@ Setting up the integration environment is a little tricky:
```bash
cd integration
go generate ./...
-go run ./server/server.go
+go run ./server/cmd/integration/server.go
```
in another terminal
```bash
diff --git a/_examples/chat/chat_test.go b/_examples/chat/chat_test.go
index 8a4081bdb8..c3dd59abee 100644
--- a/_examples/chat/chat_test.go
+++ b/_examples/chat/chat_test.go
@@ -6,10 +6,11 @@ import (
"sync"
"testing"
- "github.com/99designs/gqlgen/client"
- "github.com/99designs/gqlgen/graphql/handler"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+
+ "github.com/99designs/gqlgen/client"
+ "github.com/99designs/gqlgen/graphql/handler"
)
func TestChatSubscriptions(t *testing.T) {
diff --git a/_examples/chat/generated.go b/_examples/chat/generated.go
index 58f7545a7b..2ee09e11a2 100644
--- a/_examples/chat/generated.go
+++ b/_examples/chat/generated.go
@@ -25,6 +25,7 @@ import (
// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
return &executableSchema{
+ schema: cfg.Schema,
resolvers: cfg.Resolvers,
directives: cfg.Directives,
complexity: cfg.Complexity,
@@ -32,6 +33,7 @@ func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
}
type Config struct {
+ Schema *ast.Schema
Resolvers ResolverRoot
Directives DirectiveRoot
Complexity ComplexityRoot
@@ -84,12 +86,16 @@ type SubscriptionResolver interface {
}
type executableSchema struct {
+ schema *ast.Schema
resolvers ResolverRoot
directives DirectiveRoot
complexity ComplexityRoot
}
func (e *executableSchema) Schema() *ast.Schema {
+ if e.schema != nil {
+ return e.schema
+ }
return parsedSchema
}
@@ -288,14 +294,14 @@ func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapSchema(parsedSchema), nil
+ return introspection.WrapSchema(ec.Schema()), nil
}
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
+ return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil
}
//go:embed "schema.graphql"
diff --git a/_examples/chat/server/server.go b/_examples/chat/server/server.go
index 19e938f340..5627f4d2a0 100644
--- a/_examples/chat/server/server.go
+++ b/_examples/chat/server/server.go
@@ -6,11 +6,6 @@ import (
"net/url"
"time"
- "github.com/99designs/gqlgen/graphql/handler/extension"
- "github.com/99designs/gqlgen/graphql/handler/transport"
-
- "github.com/99designs/gqlgen/graphql/playground"
-
"github.com/gorilla/websocket"
"github.com/opentracing/opentracing-go"
"github.com/rs/cors"
@@ -20,6 +15,9 @@ import (
"github.com/99designs/gqlgen/_examples/chat"
"github.com/99designs/gqlgen/graphql/handler"
+ "github.com/99designs/gqlgen/graphql/handler/extension"
+ "github.com/99designs/gqlgen/graphql/handler/transport"
+ "github.com/99designs/gqlgen/graphql/playground"
)
func main() {
diff --git a/_examples/config/generated.go b/_examples/config/generated.go
index 9d2a01c55a..b377298385 100644
--- a/_examples/config/generated.go
+++ b/_examples/config/generated.go
@@ -23,6 +23,7 @@ import (
// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
return &executableSchema{
+ schema: cfg.Schema,
resolvers: cfg.Resolvers,
directives: cfg.Directives,
complexity: cfg.Complexity,
@@ -30,6 +31,7 @@ func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
}
type Config struct {
+ Schema *ast.Schema
Resolvers ResolverRoot
Directives DirectiveRoot
Complexity ComplexityRoot
@@ -87,12 +89,16 @@ type RoleResolver interface {
}
type executableSchema struct {
+ schema *ast.Schema
resolvers ResolverRoot
directives DirectiveRoot
complexity ComplexityRoot
}
func (e *executableSchema) Schema() *ast.Schema {
+ if e.schema != nil {
+ return e.schema
+ }
return parsedSchema
}
@@ -278,14 +284,14 @@ func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapSchema(parsedSchema), nil
+ return introspection.WrapSchema(ec.Schema()), nil
}
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
+ return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil
}
//go:embed "schema.graphql" "todo.graphql" "user.graphql"
diff --git a/_examples/config/schema.resolvers.go b/_examples/config/schema.resolvers.go
index 39649ff57f..c783ab751e 100644
--- a/_examples/config/schema.resolvers.go
+++ b/_examples/config/schema.resolvers.go
@@ -2,7 +2,7 @@ package config
// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.35-dev
+// Code generated by github.com/99designs/gqlgen version v0.17.40-dev
import (
"context"
diff --git a/_examples/config/todo.resolvers.go b/_examples/config/todo.resolvers.go
index 04fff1f298..57ca050c8e 100644
--- a/_examples/config/todo.resolvers.go
+++ b/_examples/config/todo.resolvers.go
@@ -2,7 +2,7 @@ package config
// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.35-dev
+// Code generated by github.com/99designs/gqlgen version v0.17.40-dev
import (
"context"
diff --git a/_examples/config/user.resolvers.go b/_examples/config/user.resolvers.go
index 06a9c54377..05a4deb48c 100644
--- a/_examples/config/user.resolvers.go
+++ b/_examples/config/user.resolvers.go
@@ -2,7 +2,7 @@ package config
// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.35-dev
+// Code generated by github.com/99designs/gqlgen version v0.17.40-dev
import (
"context"
diff --git a/_examples/dataloader/dataloader_test.go b/_examples/dataloader/dataloader_test.go
index c70b45b95a..34dc9e427d 100644
--- a/_examples/dataloader/dataloader_test.go
+++ b/_examples/dataloader/dataloader_test.go
@@ -3,10 +3,11 @@ package dataloader
import (
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/introspection"
- "github.com/stretchr/testify/require"
)
func TestTodo(t *testing.T) {
diff --git a/_examples/dataloader/generated.go b/_examples/dataloader/generated.go
index e205815208..b882fbc52c 100644
--- a/_examples/dataloader/generated.go
+++ b/_examples/dataloader/generated.go
@@ -24,6 +24,7 @@ import (
// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
return &executableSchema{
+ schema: cfg.Schema,
resolvers: cfg.Resolvers,
directives: cfg.Directives,
complexity: cfg.Complexity,
@@ -31,6 +32,7 @@ func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
}
type Config struct {
+ Schema *ast.Schema
Resolvers ResolverRoot
Directives DirectiveRoot
Complexity ComplexityRoot
@@ -91,12 +93,16 @@ type QueryResolver interface {
}
type executableSchema struct {
+ schema *ast.Schema
resolvers ResolverRoot
directives DirectiveRoot
complexity ComplexityRoot
}
func (e *executableSchema) Schema() *ast.Schema {
+ if e.schema != nil {
+ return e.schema
+ }
return parsedSchema
}
@@ -298,14 +304,14 @@ func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapSchema(parsedSchema), nil
+ return introspection.WrapSchema(ec.Schema()), nil
}
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
+ return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil
}
//go:embed "schema.graphql"
diff --git a/_examples/embedding/subdir/embedding_test.go b/_examples/embedding/subdir/embedding_test.go
index d779455236..3f2e97d24c 100644
--- a/_examples/embedding/subdir/embedding_test.go
+++ b/_examples/embedding/subdir/embedding_test.go
@@ -3,10 +3,11 @@ package subdir
import (
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/_examples/embedding/subdir/gendir"
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestEmbeddingWorks(t *testing.T) {
diff --git a/_examples/embedding/subdir/gendir/generated.go b/_examples/embedding/subdir/gendir/generated.go
index edb6ace6ba..eaf200d2dd 100644
--- a/_examples/embedding/subdir/gendir/generated.go
+++ b/_examples/embedding/subdir/gendir/generated.go
@@ -23,6 +23,7 @@ import (
// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
return &executableSchema{
+ schema: cfg.Schema,
resolvers: cfg.Resolvers,
directives: cfg.Directives,
complexity: cfg.Complexity,
@@ -30,6 +31,7 @@ func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
}
type Config struct {
+ Schema *ast.Schema
Resolvers ResolverRoot
Directives DirectiveRoot
Complexity ComplexityRoot
@@ -62,12 +64,16 @@ type QueryResolver interface {
}
type executableSchema struct {
+ schema *ast.Schema
resolvers ResolverRoot
directives DirectiveRoot
complexity ComplexityRoot
}
func (e *executableSchema) Schema() *ast.Schema {
+ if e.schema != nil {
+ return e.schema
+ }
return parsedSchema
}
@@ -189,14 +195,14 @@ func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapSchema(parsedSchema), nil
+ return introspection.WrapSchema(ec.Schema()), nil
}
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
+ return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil
}
var sources = []*ast.Source{
diff --git a/_examples/embedding/subdir/root_.generated.go b/_examples/embedding/subdir/root_.generated.go
index 03c8e18e5a..d2dc848a05 100644
--- a/_examples/embedding/subdir/root_.generated.go
+++ b/_examples/embedding/subdir/root_.generated.go
@@ -19,6 +19,7 @@ import (
// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
return &executableSchema{
+ schema: cfg.Schema,
resolvers: cfg.Resolvers,
directives: cfg.Directives,
complexity: cfg.Complexity,
@@ -26,6 +27,7 @@ func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
}
type Config struct {
+ Schema *ast.Schema
Resolvers ResolverRoot
Directives DirectiveRoot
Complexity ComplexityRoot
@@ -52,12 +54,16 @@ type ComplexityRoot struct {
}
type executableSchema struct {
+ schema *ast.Schema
resolvers ResolverRoot
directives DirectiveRoot
complexity ComplexityRoot
}
func (e *executableSchema) Schema() *ast.Schema {
+ if e.schema != nil {
+ return e.schema
+ }
return parsedSchema
}
@@ -179,14 +185,14 @@ func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapSchema(parsedSchema), nil
+ return introspection.WrapSchema(ec.Schema()), nil
}
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
+ return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil
}
//go:embed "schemadir/root.graphqls" "subdir.graphqls"
diff --git a/_examples/federation/accounts/graph/entity.resolvers.go b/_examples/federation/accounts/graph/entity.resolvers.go
index 6daa854284..31b2cad602 100644
--- a/_examples/federation/accounts/graph/entity.resolvers.go
+++ b/_examples/federation/accounts/graph/entity.resolvers.go
@@ -2,7 +2,7 @@ package graph
// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.35-dev
+// Code generated by github.com/99designs/gqlgen version v0.17.40-dev
import (
"context"
diff --git a/_examples/federation/accounts/graph/generated.go b/_examples/federation/accounts/graph/generated.go
index 398daeacd9..791d5fa047 100644
--- a/_examples/federation/accounts/graph/generated.go
+++ b/_examples/federation/accounts/graph/generated.go
@@ -25,6 +25,7 @@ import (
// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
return &executableSchema{
+ schema: cfg.Schema,
resolvers: cfg.Resolvers,
directives: cfg.Directives,
complexity: cfg.Complexity,
@@ -32,6 +33,7 @@ func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
}
type Config struct {
+ Schema *ast.Schema
Resolvers ResolverRoot
Directives DirectiveRoot
Complexity ComplexityRoot
@@ -83,12 +85,16 @@ type QueryResolver interface {
}
type executableSchema struct {
+ schema *ast.Schema
resolvers ResolverRoot
directives DirectiveRoot
complexity ComplexityRoot
}
func (e *executableSchema) Schema() *ast.Schema {
+ if e.schema != nil {
+ return e.schema
+ }
return parsedSchema
}
@@ -274,14 +280,14 @@ func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapSchema(parsedSchema), nil
+ return introspection.WrapSchema(ec.Schema()), nil
}
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
+ return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil
}
//go:embed "schema.graphqls"
diff --git a/_examples/federation/accounts/graph/schema.resolvers.go b/_examples/federation/accounts/graph/schema.resolvers.go
index acc71de4fc..a3364c1207 100644
--- a/_examples/federation/accounts/graph/schema.resolvers.go
+++ b/_examples/federation/accounts/graph/schema.resolvers.go
@@ -2,7 +2,7 @@ package graph
// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.35-dev
+// Code generated by github.com/99designs/gqlgen version v0.17.40-dev
import (
"context"
diff --git a/_examples/federation/products/graph/entity.resolvers.go b/_examples/federation/products/graph/entity.resolvers.go
index 2d66bf9e19..840d32321a 100644
--- a/_examples/federation/products/graph/entity.resolvers.go
+++ b/_examples/federation/products/graph/entity.resolvers.go
@@ -2,7 +2,7 @@ package graph
// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.35-dev
+// Code generated by github.com/99designs/gqlgen version v0.17.40-dev
import (
"context"
diff --git a/_examples/federation/products/graph/generated.go b/_examples/federation/products/graph/generated.go
index 15a66fb2cc..0f13b18d8f 100644
--- a/_examples/federation/products/graph/generated.go
+++ b/_examples/federation/products/graph/generated.go
@@ -25,6 +25,7 @@ import (
// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
return &executableSchema{
+ schema: cfg.Schema,
resolvers: cfg.Resolvers,
directives: cfg.Directives,
complexity: cfg.Complexity,
@@ -32,6 +33,7 @@ func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
}
type Config struct {
+ Schema *ast.Schema
Resolvers ResolverRoot
Directives DirectiveRoot
Complexity ComplexityRoot
@@ -86,12 +88,16 @@ type QueryResolver interface {
}
type executableSchema struct {
+ schema *ast.Schema
resolvers ResolverRoot
directives DirectiveRoot
complexity ComplexityRoot
}
func (e *executableSchema) Schema() *ast.Schema {
+ if e.schema != nil {
+ return e.schema
+ }
return parsedSchema
}
@@ -301,14 +307,14 @@ func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapSchema(parsedSchema), nil
+ return introspection.WrapSchema(ec.Schema()), nil
}
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
+ return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil
}
//go:embed "schema.graphqls"
diff --git a/_examples/federation/products/graph/schema.resolvers.go b/_examples/federation/products/graph/schema.resolvers.go
index 4255804608..87d62e225c 100644
--- a/_examples/federation/products/graph/schema.resolvers.go
+++ b/_examples/federation/products/graph/schema.resolvers.go
@@ -2,7 +2,7 @@ package graph
// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.35-dev
+// Code generated by github.com/99designs/gqlgen version v0.17.40-dev
import (
"context"
diff --git a/_examples/federation/reviews/graph/entity.resolvers.go b/_examples/federation/reviews/graph/entity.resolvers.go
index 265b2cdc8d..08102f8a30 100644
--- a/_examples/federation/reviews/graph/entity.resolvers.go
+++ b/_examples/federation/reviews/graph/entity.resolvers.go
@@ -2,7 +2,7 @@ package graph
// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.35-dev
+// Code generated by github.com/99designs/gqlgen version v0.17.40-dev
import (
"context"
diff --git a/_examples/federation/reviews/graph/generated.go b/_examples/federation/reviews/graph/generated.go
index ac7f09beab..79060f78c2 100644
--- a/_examples/federation/reviews/graph/generated.go
+++ b/_examples/federation/reviews/graph/generated.go
@@ -25,6 +25,7 @@ import (
// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
return &executableSchema{
+ schema: cfg.Schema,
resolvers: cfg.Resolvers,
directives: cfg.Directives,
complexity: cfg.Complexity,
@@ -32,6 +33,7 @@ func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
}
type Config struct {
+ Schema *ast.Schema
Resolvers ResolverRoot
Directives DirectiveRoot
Complexity ComplexityRoot
@@ -97,12 +99,16 @@ type UserResolver interface {
}
type executableSchema struct {
+ schema *ast.Schema
resolvers ResolverRoot
directives DirectiveRoot
complexity ComplexityRoot
}
func (e *executableSchema) Schema() *ast.Schema {
+ if e.schema != nil {
+ return e.schema
+ }
return parsedSchema
}
@@ -323,14 +329,14 @@ func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapSchema(parsedSchema), nil
+ return introspection.WrapSchema(ec.Schema()), nil
}
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
+ return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil
}
//go:embed "schema.graphqls"
diff --git a/_examples/federation/reviews/graph/schema.resolvers.go b/_examples/federation/reviews/graph/schema.resolvers.go
index 1df3e2f031..4900e4d8e2 100644
--- a/_examples/federation/reviews/graph/schema.resolvers.go
+++ b/_examples/federation/reviews/graph/schema.resolvers.go
@@ -2,7 +2,7 @@ package graph
// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.35-dev
+// Code generated by github.com/99designs/gqlgen version v0.17.40-dev
import (
"context"
diff --git a/_examples/fileupload/fileupload_test.go b/_examples/fileupload/fileupload_test.go
index 29ef9dc3fb..c4138c14c9 100644
--- a/_examples/fileupload/fileupload_test.go
+++ b/_examples/fileupload/fileupload_test.go
@@ -8,12 +8,13 @@ import (
"os"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/_examples/fileupload/model"
gqlclient "github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/handler/transport"
- "github.com/stretchr/testify/require"
)
func TestFileUpload(t *testing.T) {
diff --git a/_examples/fileupload/generated.go b/_examples/fileupload/generated.go
index f5730632e9..160ab84faa 100644
--- a/_examples/fileupload/generated.go
+++ b/_examples/fileupload/generated.go
@@ -24,6 +24,7 @@ import (
// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
return &executableSchema{
+ schema: cfg.Schema,
resolvers: cfg.Resolvers,
directives: cfg.Directives,
complexity: cfg.Complexity,
@@ -31,6 +32,7 @@ func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
}
type Config struct {
+ Schema *ast.Schema
Resolvers ResolverRoot
Directives DirectiveRoot
Complexity ComplexityRoot
@@ -75,12 +77,16 @@ type QueryResolver interface {
}
type executableSchema struct {
+ schema *ast.Schema
resolvers ResolverRoot
directives DirectiveRoot
complexity ComplexityRoot
}
func (e *executableSchema) Schema() *ast.Schema {
+ if e.schema != nil {
+ return e.schema
+ }
return parsedSchema
}
@@ -267,14 +273,14 @@ func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapSchema(parsedSchema), nil
+ return introspection.WrapSchema(ec.Schema()), nil
}
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
+ return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil
}
//go:embed "schema.graphql"
diff --git a/_examples/fileupload/server/server.go b/_examples/fileupload/server/server.go
index 75a47b73b6..55dc08d883 100644
--- a/_examples/fileupload/server/server.go
+++ b/_examples/fileupload/server/server.go
@@ -7,15 +7,13 @@ import (
"log"
"net/http"
- "github.com/99designs/gqlgen/graphql/handler/extension"
- "github.com/99designs/gqlgen/graphql/handler/transport"
-
- "github.com/99designs/gqlgen/graphql/playground"
-
"github.com/99designs/gqlgen/_examples/fileupload"
"github.com/99designs/gqlgen/_examples/fileupload/model"
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler"
+ "github.com/99designs/gqlgen/graphql/handler/extension"
+ "github.com/99designs/gqlgen/graphql/handler/transport"
+ "github.com/99designs/gqlgen/graphql/playground"
)
func main() {
diff --git a/_examples/go.mod b/_examples/go.mod
index 1da124d769..b6dfdaa00b 100644
--- a/_examples/go.mod
+++ b/_examples/go.mod
@@ -5,14 +5,15 @@ go 1.18
replace github.com/99designs/gqlgen => ../
require (
- github.com/99designs/gqlgen v0.17.32
+ github.com/99designs/gqlgen v0.17.36
+ github.com/google/uuid v1.3.0
github.com/gorilla/websocket v1.5.0
github.com/mitchellh/mapstructure v1.5.0
github.com/opentracing/opentracing-go v1.2.0
github.com/rs/cors v1.9.0
github.com/stretchr/testify v1.8.2
github.com/vektah/dataloaden v0.3.0
- github.com/vektah/gqlparser/v2 v2.5.7
+ github.com/vektah/gqlparser/v2 v2.5.10
sourcegraph.com/sourcegraph/appdash v0.0.0-20211028080628-e2786a622600
)
@@ -24,6 +25,7 @@ require (
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/sosodev/duration v1.1.0 // indirect
golang.org/x/mod v0.10.0 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/tools v0.9.3 // indirect
diff --git a/_examples/go.sum b/_examples/go.sum
index 5272749751..98f0ac96a2 100644
--- a/_examples/go.sum
+++ b/_examples/go.sum
@@ -1,7 +1,6 @@
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
-github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -12,6 +11,8 @@ github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
+github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
@@ -21,11 +22,6 @@ github.com/hashicorp/golang-lru/v2 v2.0.3/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyf
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/logrusorgru/aurora/v3 v3.0.0 h1:R6zcoZZbvVcGMvDCKo45A9U/lzYyzl5NfYIvznmDfE4=
github.com/logrusorgru/aurora/v3 v3.0.0/go.mod h1:vsR12bk5grlLvLXAYrBsb5Oc/N+LxAlxggSjiwMnCUc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
@@ -48,17 +44,17 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE=
github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
-github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 h1:bUGsEnyNbVPw06Bs80sCeARAlK8lhwqGyi6UT8ymuGk=
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 h1:pXY9qYc/MP5zdvqWEUH6SjNiu7VhSjuVFTFiTcphaLU=
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
+github.com/sosodev/duration v1.1.0 h1:kQcaiGbJaIsRqgQy7VGlZrVw1giWO+lDoX3MCPnpVO4=
+github.com/sosodev/duration v1.1.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
@@ -66,8 +62,8 @@ github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/vektah/dataloaden v0.3.0 h1:ZfVN2QD6swgvp+tDqdH/OIT/wu3Dhu0cus0k5gIZS84=
github.com/vektah/dataloaden v0.3.0/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U=
-github.com/vektah/gqlparser/v2 v2.5.7 h1:QnW4lWFSaycZ1jqvVaQ/tDXGGzQfqAuWdyC4S9g/KVM=
-github.com/vektah/gqlparser/v2 v2.5.7/go.mod h1:z8xXUff237NntSuH8mLFijZ+1tjV1swDbpDqjJmk6ME=
+github.com/vektah/gqlparser/v2 v2.5.10 h1:6zSM4azXC9u4Nxy5YmdmGu4uKamfwsdKTwp5zsEealU=
+github.com/vektah/gqlparser/v2 v2.5.10/go.mod h1:1rCcfwB2ekJofmluGWXMSEnPMZgbxzwj6FaZ/4OT8Cc=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -114,12 +110,10 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
-gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/_examples/scalars/generated.go b/_examples/scalars/generated.go
index 94e57c0fa9..549d3a4fa5 100644
--- a/_examples/scalars/generated.go
+++ b/_examples/scalars/generated.go
@@ -26,6 +26,7 @@ import (
// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
return &executableSchema{
+ schema: cfg.Schema,
resolvers: cfg.Resolvers,
directives: cfg.Directives,
complexity: cfg.Complexity,
@@ -33,6 +34,7 @@ func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
}
type Config struct {
+ Schema *ast.Schema
Resolvers ResolverRoot
Directives DirectiveRoot
Complexity ComplexityRoot
@@ -84,12 +86,16 @@ type UserResolver interface {
}
type executableSchema struct {
+ schema *ast.Schema
resolvers ResolverRoot
directives DirectiveRoot
complexity ComplexityRoot
}
func (e *executableSchema) Schema() *ast.Schema {
+ if e.schema != nil {
+ return e.schema
+ }
return parsedSchema
}
@@ -305,14 +311,14 @@ func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapSchema(parsedSchema), nil
+ return introspection.WrapSchema(ec.Schema()), nil
}
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
+ return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil
}
//go:embed "schema.graphql"
diff --git a/_examples/scalars/scalar_test.go b/_examples/scalars/scalar_test.go
index f9ca2b1dd1..0d3228b141 100644
--- a/_examples/scalars/scalar_test.go
+++ b/_examples/scalars/scalar_test.go
@@ -4,10 +4,11 @@ import (
"testing"
"time"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/introspection"
- "github.com/stretchr/testify/require"
)
type RawUser struct {
diff --git a/_examples/selection/generated.go b/_examples/selection/generated.go
index b0f567eefd..a583e9edab 100644
--- a/_examples/selection/generated.go
+++ b/_examples/selection/generated.go
@@ -24,6 +24,7 @@ import (
// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
return &executableSchema{
+ schema: cfg.Schema,
resolvers: cfg.Resolvers,
directives: cfg.Directives,
complexity: cfg.Complexity,
@@ -31,6 +32,7 @@ func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
}
type Config struct {
+ Schema *ast.Schema
Resolvers ResolverRoot
Directives DirectiveRoot
Complexity ComplexityRoot
@@ -68,12 +70,16 @@ type QueryResolver interface {
}
type executableSchema struct {
+ schema *ast.Schema
resolvers ResolverRoot
directives DirectiveRoot
complexity ComplexityRoot
}
func (e *executableSchema) Schema() *ast.Schema {
+ if e.schema != nil {
+ return e.schema
+ }
return parsedSchema
}
@@ -223,14 +229,14 @@ func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapSchema(parsedSchema), nil
+ return introspection.WrapSchema(ec.Schema()), nil
}
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
+ return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil
}
//go:embed "schema.graphql"
diff --git a/_examples/selection/selection.go b/_examples/selection/selection.go
index 5890d14ab9..6a6b0f9bec 100644
--- a/_examples/selection/selection.go
+++ b/_examples/selection/selection.go
@@ -7,8 +7,9 @@ import (
"fmt"
"time"
- "github.com/99designs/gqlgen/graphql"
"github.com/vektah/gqlparser/v2/ast"
+
+ "github.com/99designs/gqlgen/graphql"
)
type Resolver struct{}
diff --git a/_examples/selection/selection_test.go b/_examples/selection/selection_test.go
index c687403322..72495e927b 100644
--- a/_examples/selection/selection_test.go
+++ b/_examples/selection/selection_test.go
@@ -3,9 +3,10 @@ package selection
import (
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestSelection(t *testing.T) {
diff --git a/_examples/starwars/generated/exec.go b/_examples/starwars/generated/exec.go
index b7a934bdab..1465c2bb43 100644
--- a/_examples/starwars/generated/exec.go
+++ b/_examples/starwars/generated/exec.go
@@ -24,6 +24,7 @@ import (
// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
return &executableSchema{
+ schema: cfg.Schema,
resolvers: cfg.Resolvers,
directives: cfg.Directives,
complexity: cfg.Complexity,
@@ -31,6 +32,7 @@ func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
}
type Config struct {
+ Schema *ast.Schema
Resolvers ResolverRoot
Directives DirectiveRoot
Complexity ComplexityRoot
@@ -146,12 +148,16 @@ type StarshipResolver interface {
}
type executableSchema struct {
+ schema *ast.Schema
resolvers ResolverRoot
directives DirectiveRoot
complexity ComplexityRoot
}
func (e *executableSchema) Schema() *ast.Schema {
+ if e.schema != nil {
+ return e.schema
+ }
return parsedSchema
}
@@ -581,14 +587,14 @@ func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapSchema(parsedSchema), nil
+ return introspection.WrapSchema(ec.Schema()), nil
}
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
+ return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil
}
var sources = []*ast.Source{
diff --git a/_examples/starwars/resolvers.go b/_examples/starwars/resolvers.go
index e7b9629d12..6c94a2ea0f 100644
--- a/_examples/starwars/resolvers.go
+++ b/_examples/starwars/resolvers.go
@@ -12,7 +12,6 @@ import (
"time"
"github.com/99designs/gqlgen/_examples/starwars/generated"
-
"github.com/99designs/gqlgen/_examples/starwars/models"
)
diff --git a/_examples/starwars/starwars_test.go b/_examples/starwars/starwars_test.go
index 8cbe861b0c..a01f9fb7b5 100644
--- a/_examples/starwars/starwars_test.go
+++ b/_examples/starwars/starwars_test.go
@@ -3,11 +3,12 @@ package starwars
import (
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/_examples/starwars/generated"
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/introspection"
- "github.com/stretchr/testify/require"
)
func TestStarwars(t *testing.T) {
diff --git a/_examples/todo/generated.go b/_examples/todo/generated.go
index 8317645e00..0aa9e6c197 100644
--- a/_examples/todo/generated.go
+++ b/_examples/todo/generated.go
@@ -23,6 +23,7 @@ import (
// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
return &executableSchema{
+ schema: cfg.Schema,
resolvers: cfg.Resolvers,
directives: cfg.Directives,
complexity: cfg.Complexity,
@@ -30,6 +31,7 @@ func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
}
type Config struct {
+ Schema *ast.Schema
Resolvers ResolverRoot
Directives DirectiveRoot
Complexity ComplexityRoot
@@ -75,12 +77,16 @@ type MyQueryResolver interface {
}
type executableSchema struct {
+ schema *ast.Schema
resolvers ResolverRoot
directives DirectiveRoot
complexity ComplexityRoot
}
func (e *executableSchema) Schema() *ast.Schema {
+ if e.schema != nil {
+ return e.schema
+ }
return parsedSchema
}
@@ -259,14 +265,14 @@ func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapSchema(parsedSchema), nil
+ return introspection.WrapSchema(ec.Schema()), nil
}
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
+ return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil
}
//go:embed "schema.graphql"
diff --git a/_examples/todo/todo.go b/_examples/todo/todo.go
index ad3da2c392..f8a710722e 100644
--- a/_examples/todo/todo.go
+++ b/_examples/todo/todo.go
@@ -8,8 +8,9 @@ import (
"fmt"
"time"
- "github.com/99designs/gqlgen/graphql"
"github.com/mitchellh/mapstructure"
+
+ "github.com/99designs/gqlgen/graphql"
)
var (
diff --git a/_examples/todo/todo_test.go b/_examples/todo/todo_test.go
index a6cef4ac05..348ecc7023 100644
--- a/_examples/todo/todo_test.go
+++ b/_examples/todo/todo_test.go
@@ -3,10 +3,11 @@ package todo
import (
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/introspection"
- "github.com/stretchr/testify/require"
)
func TestTodo(t *testing.T) {
diff --git a/_examples/type-system-extension/generated.go b/_examples/type-system-extension/generated.go
index 1fa0b781b2..71fb282a51 100644
--- a/_examples/type-system-extension/generated.go
+++ b/_examples/type-system-extension/generated.go
@@ -23,6 +23,7 @@ import (
// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
return &executableSchema{
+ schema: cfg.Schema,
resolvers: cfg.Resolvers,
directives: cfg.Directives,
complexity: cfg.Complexity,
@@ -30,6 +31,7 @@ func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
}
type Config struct {
+ Schema *ast.Schema
Resolvers ResolverRoot
Directives DirectiveRoot
Complexity ComplexityRoot
@@ -77,12 +79,16 @@ type MyQueryResolver interface {
}
type executableSchema struct {
+ schema *ast.Schema
resolvers ResolverRoot
directives DirectiveRoot
complexity ComplexityRoot
}
func (e *executableSchema) Schema() *ast.Schema {
+ if e.schema != nil {
+ return e.schema
+ }
return parsedSchema
}
@@ -245,14 +251,14 @@ func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapSchema(parsedSchema), nil
+ return introspection.WrapSchema(ec.Schema()), nil
}
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
+ return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil
}
//go:embed "schemas/enum-extension.graphql" "schemas/input-object-extension.graphql" "schemas/interface-extension.graphql" "schemas/object-extension.graphql" "schemas/scalar-extension.graphql" "schemas/schema-extension.graphql" "schemas/schema.graphql" "schemas/type-extension.graphql" "schemas/union-extension.graphql"
diff --git a/_examples/type-system-extension/server/server.go b/_examples/type-system-extension/server/server.go
index 2ddca5f7b9..6fec1d2403 100644
--- a/_examples/type-system-extension/server/server.go
+++ b/_examples/type-system-extension/server/server.go
@@ -5,10 +5,9 @@ import (
"net/http"
"os"
- "github.com/99designs/gqlgen/graphql/playground"
-
extension "github.com/99designs/gqlgen/_examples/type-system-extension"
"github.com/99designs/gqlgen/graphql/handler"
+ "github.com/99designs/gqlgen/graphql/playground"
)
const defaultPort = "8080"
diff --git a/_examples/uuid/gqlgen.yml b/_examples/uuid/gqlgen.yml
new file mode 100644
index 0000000000..33c3d09ddd
--- /dev/null
+++ b/_examples/uuid/gqlgen.yml
@@ -0,0 +1,90 @@
+# Where are all the schema files located? globs are supported eg src/**/*.graphqls
+schema:
+ - graph/*.graphqls
+
+# Where should the generated server code go?
+exec:
+ filename: graph/generated.go
+ package: graph
+
+# Uncomment to enable federation
+# federation:
+# filename: graph/federation.go
+# package: graph
+
+# Where should any generated models go?
+model:
+ filename: graph/model/models_gen.go
+ package: model
+
+# Where should the resolver implementations go?
+resolver:
+ layout: follow-schema
+ dir: graph
+ package: graph
+ filename_template: "{name}.resolvers.go"
+ # Optional: turn on to not generate template comments above resolvers
+ # omit_template_comment: false
+
+# Optional: turn on use ` + "`" + `gqlgen:"fieldName"` + "`" + ` tags in your models
+# struct_tag: json
+
+# Optional: turn on to use []Thing instead of []*Thing
+# omit_slice_element_pointers: false
+
+# Optional: turn on to omit Is() methods to interface and unions
+# omit_interface_checks : true
+
+# Optional: turn on to skip generation of ComplexityRoot struct content and Complexity function
+# omit_complexity: false
+
+# Optional: turn on to not generate any file notice comments in generated files
+# omit_gqlgen_file_notice: false
+
+# Optional: turn on to exclude the gqlgen version in the generated file notice. No effect if `omit_gqlgen_file_notice` is true.
+# omit_gqlgen_version_in_file_notice: false
+
+# Optional: turn off to make struct-type struct fields not use pointers
+# e.g. type Thing struct { FieldA OtherThing } instead of { FieldA *OtherThing }
+# struct_fields_always_pointers: true
+
+# Optional: turn off to make resolvers return values instead of pointers for structs
+# resolvers_always_return_pointers: true
+
+# Optional: turn on to return pointers instead of values in unmarshalInput
+# return_pointers_in_unmarshalinput: false
+
+# Optional: wrap nullable input fields with Omittable
+# nullable_input_omittable: true
+
+# Optional: set to speed up generation time by not performing a final validation pass.
+# skip_validation: true
+
+# Optional: set to skip running `go mod tidy` when generating server code
+# skip_mod_tidy: true
+
+# gqlgen will search for any type names in the schema in these go packages
+# if they match it will use them, otherwise it will generate them.
+autobind:
+# - "github.com/99designs/gqlgen/_examples/uuid/graph/model"
+
+# This section declares type mapping between the GraphQL and go type systems
+#
+# The first line in each type will be used as defaults for resolver arguments and
+# modelgen, the others will be allowed when binding to fields. Configure them to
+# your liking
+models:
+ ID:
+ model:
+ - github.com/99designs/gqlgen/graphql.ID
+ - github.com/99designs/gqlgen/graphql.Int
+ - github.com/99designs/gqlgen/graphql.Int64
+ - github.com/99designs/gqlgen/graphql.Int32
+ Int:
+ model:
+ - github.com/99designs/gqlgen/graphql.Int
+ - github.com/99designs/gqlgen/graphql.Int64
+ - github.com/99designs/gqlgen/graphql.Int32
+ UUID:
+ model:
+ - github.com/99designs/gqlgen/graphql.UUID
diff --git a/_examples/uuid/graph/generated.go b/_examples/uuid/graph/generated.go
new file mode 100644
index 0000000000..57b2c363a8
--- /dev/null
+++ b/_examples/uuid/graph/generated.go
@@ -0,0 +1,3700 @@
+// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
+
+package graph
+
+import (
+ "bytes"
+ "context"
+ "embed"
+ "errors"
+ "fmt"
+ "strconv"
+ "sync"
+ "sync/atomic"
+
+ "github.com/99designs/gqlgen/_examples/uuid/graph/model"
+ "github.com/99designs/gqlgen/graphql"
+ "github.com/99designs/gqlgen/graphql/introspection"
+ "github.com/google/uuid"
+ gqlparser "github.com/vektah/gqlparser/v2"
+ "github.com/vektah/gqlparser/v2/ast"
+)
+
+// region ************************** generated!.gotpl **************************
+
+// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
+func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
+ return &executableSchema{
+ resolvers: cfg.Resolvers,
+ directives: cfg.Directives,
+ complexity: cfg.Complexity,
+ }
+}
+
+type Config struct {
+ Resolvers ResolverRoot
+ Directives DirectiveRoot
+ Complexity ComplexityRoot
+}
+
+type ResolverRoot interface {
+ Mutation() MutationResolver
+ Query() QueryResolver
+}
+
+type DirectiveRoot struct {
+}
+
+type ComplexityRoot struct {
+ Mutation struct {
+ CreateTodo func(childComplexity int, input model.NewTodo) int
+ }
+
+ Query struct {
+ Todos func(childComplexity int) int
+ }
+
+ Todo struct {
+ Done func(childComplexity int) int
+ ID func(childComplexity int) int
+ Text func(childComplexity int) int
+ UID func(childComplexity int) int
+ }
+}
+
+type MutationResolver interface {
+ CreateTodo(ctx context.Context, input model.NewTodo) (*model.Todo, error)
+}
+type QueryResolver interface {
+ Todos(ctx context.Context) ([]*model.Todo, error)
+}
+
+type executableSchema struct {
+ resolvers ResolverRoot
+ directives DirectiveRoot
+ complexity ComplexityRoot
+}
+
+func (e *executableSchema) Schema() *ast.Schema {
+ return parsedSchema
+}
+
+func (e *executableSchema) Complexity(typeName, field string, childComplexity int, rawArgs map[string]interface{}) (int, bool) {
+ ec := executionContext{nil, e, 0, 0, nil}
+ _ = ec
+ switch typeName + "." + field {
+
+ case "Mutation.createTodo":
+ if e.complexity.Mutation.CreateTodo == nil {
+ break
+ }
+
+ args, err := ec.field_Mutation_createTodo_args(context.TODO(), rawArgs)
+ if err != nil {
+ return 0, false
+ }
+
+ return e.complexity.Mutation.CreateTodo(childComplexity, args["input"].(model.NewTodo)), true
+
+ case "Query.todos":
+ if e.complexity.Query.Todos == nil {
+ break
+ }
+
+ return e.complexity.Query.Todos(childComplexity), true
+
+ case "Todo.done":
+ if e.complexity.Todo.Done == nil {
+ break
+ }
+
+ return e.complexity.Todo.Done(childComplexity), true
+
+ case "Todo.id":
+ if e.complexity.Todo.ID == nil {
+ break
+ }
+
+ return e.complexity.Todo.ID(childComplexity), true
+
+ case "Todo.text":
+ if e.complexity.Todo.Text == nil {
+ break
+ }
+
+ return e.complexity.Todo.Text(childComplexity), true
+
+ case "Todo.uid":
+ if e.complexity.Todo.UID == nil {
+ break
+ }
+
+ return e.complexity.Todo.UID(childComplexity), true
+
+ }
+ return 0, false
+}
+
+func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
+ rc := graphql.GetOperationContext(ctx)
+ ec := executionContext{rc, e, 0, 0, make(chan graphql.DeferredResult)}
+ inputUnmarshalMap := graphql.BuildUnmarshalerMap(
+ ec.unmarshalInputNewTodo,
+ )
+ first := true
+
+ switch rc.Operation.Operation {
+ case ast.Query:
+ return func(ctx context.Context) *graphql.Response {
+ var response graphql.Response
+ var data graphql.Marshaler
+ if first {
+ first = false
+ ctx = graphql.WithUnmarshalerMap(ctx, inputUnmarshalMap)
+ data = ec._Query(ctx, rc.Operation.SelectionSet)
+ } else {
+ if atomic.LoadInt32(&ec.pendingDeferred) > 0 {
+ result := <-ec.deferredResults
+ atomic.AddInt32(&ec.pendingDeferred, -1)
+ data = result.Result
+ response.Path = result.Path
+ response.Label = result.Label
+ response.Errors = result.Errors
+ } else {
+ return nil
+ }
+ }
+ var buf bytes.Buffer
+ data.MarshalGQL(&buf)
+ response.Data = buf.Bytes()
+ if atomic.LoadInt32(&ec.deferred) > 0 {
+ hasNext := atomic.LoadInt32(&ec.pendingDeferred) > 0
+ response.HasNext = &hasNext
+ }
+
+ return &response
+ }
+ case ast.Mutation:
+ return func(ctx context.Context) *graphql.Response {
+ if !first {
+ return nil
+ }
+ first = false
+ ctx = graphql.WithUnmarshalerMap(ctx, inputUnmarshalMap)
+ data := ec._Mutation(ctx, rc.Operation.SelectionSet)
+ var buf bytes.Buffer
+ data.MarshalGQL(&buf)
+
+ return &graphql.Response{
+ Data: buf.Bytes(),
+ }
+ }
+
+ default:
+ return graphql.OneShot(graphql.ErrorResponse(ctx, "unsupported GraphQL operation"))
+ }
+}
+
+type executionContext struct {
+ *graphql.OperationContext
+ *executableSchema
+ deferred int32
+ pendingDeferred int32
+ deferredResults chan graphql.DeferredResult
+}
+
+func (ec *executionContext) processDeferredGroup(dg graphql.DeferredGroup) {
+ atomic.AddInt32(&ec.pendingDeferred, 1)
+ go func() {
+ ctx := graphql.WithFreshResponseContext(dg.Context)
+ dg.FieldSet.Dispatch(ctx)
+ ds := graphql.DeferredResult{
+ Path: dg.Path,
+ Label: dg.Label,
+ Result: dg.FieldSet,
+ Errors: graphql.GetErrors(ctx),
+ }
+ // null fields should bubble up
+ if dg.FieldSet.Invalids > 0 {
+ ds.Result = graphql.Null
+ }
+ ec.deferredResults <- ds
+ }()
+}
+
+func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
+ if ec.DisableIntrospection {
+ return nil, errors.New("introspection disabled")
+ }
+ return introspection.WrapSchema(parsedSchema), nil
+}
+
+func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
+ if ec.DisableIntrospection {
+ return nil, errors.New("introspection disabled")
+ }
+ return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
+}
+
+//go:embed "schema.graphqls"
+var sourcesFS embed.FS
+
+func sourceData(filename string) string {
+ data, err := sourcesFS.ReadFile(filename)
+ if err != nil {
+ panic(fmt.Sprintf("codegen problem: %s not available", filename))
+ }
+ return string(data)
+}
+
+var sources = []*ast.Source{
+ {Name: "schema.graphqls", Input: sourceData("schema.graphqls"), BuiltIn: false},
+}
+var parsedSchema = gqlparser.MustLoadSchema(sources...)
+
+// endregion ************************** generated!.gotpl **************************
+
+// region ***************************** args.gotpl *****************************
+
+func (ec *executionContext) field_Mutation_createTodo_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
+ var err error
+ args := map[string]interface{}{}
+ var arg0 model.NewTodo
+ if tmp, ok := rawArgs["input"]; ok {
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("input"))
+ arg0, err = ec.unmarshalNNewTodo2githubᚗcomᚋ99designsᚋgqlgenᚋ_examplesᚋuuidᚋgraphᚋmodelᚐNewTodo(ctx, tmp)
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["input"] = arg0
+ return args, nil
+}
+
+func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
+ var err error
+ args := map[string]interface{}{}
+ var arg0 string
+ if tmp, ok := rawArgs["name"]; ok {
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name"))
+ arg0, err = ec.unmarshalNString2string(ctx, tmp)
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["name"] = arg0
+ return args, nil
+}
+
+func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
+ var err error
+ args := map[string]interface{}{}
+ var arg0 bool
+ if tmp, ok := rawArgs["includeDeprecated"]; ok {
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated"))
+ arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp)
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["includeDeprecated"] = arg0
+ return args, nil
+}
+
+func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
+ var err error
+ args := map[string]interface{}{}
+ var arg0 bool
+ if tmp, ok := rawArgs["includeDeprecated"]; ok {
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated"))
+ arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp)
+ if err != nil {
+ return nil, err
+ }
+ }
+ args["includeDeprecated"] = arg0
+ return args, nil
+}
+
+// endregion ***************************** args.gotpl *****************************
+
+// region ************************** directives.gotpl **************************
+
+// endregion ************************** directives.gotpl **************************
+
+// region **************************** field.gotpl *****************************
+
+func (ec *executionContext) _Mutation_createTodo(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Mutation_createTodo(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.resolvers.Mutation().CreateTodo(rctx, fc.Args["input"].(model.NewTodo))
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(*model.Todo)
+ fc.Result = res
+ return ec.marshalNTodo2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋ_examplesᚋuuidᚋgraphᚋmodelᚐTodo(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Mutation_createTodo(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Mutation",
+ Field: field,
+ IsMethod: true,
+ IsResolver: true,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "id":
+ return ec.fieldContext_Todo_id(ctx, field)
+ case "text":
+ return ec.fieldContext_Todo_text(ctx, field)
+ case "done":
+ return ec.fieldContext_Todo_done(ctx, field)
+ case "uid":
+ return ec.fieldContext_Todo_uid(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type Todo", field.Name)
+ },
+ }
+ defer func() {
+ if r := recover(); r != nil {
+ err = ec.Recover(ctx, r)
+ ec.Error(ctx, err)
+ }
+ }()
+ ctx = graphql.WithFieldContext(ctx, fc)
+ if fc.Args, err = ec.field_Mutation_createTodo_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
+ ec.Error(ctx, err)
+ return fc, err
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _Query_todos(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Query_todos(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.resolvers.Query().Todos(rctx)
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.([]*model.Todo)
+ fc.Result = res
+ return ec.marshalNTodo2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋ_examplesᚋuuidᚋgraphᚋmodelᚐTodoᚄ(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Query_todos(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Query",
+ Field: field,
+ IsMethod: true,
+ IsResolver: true,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "id":
+ return ec.fieldContext_Todo_id(ctx, field)
+ case "text":
+ return ec.fieldContext_Todo_text(ctx, field)
+ case "done":
+ return ec.fieldContext_Todo_done(ctx, field)
+ case "uid":
+ return ec.fieldContext_Todo_uid(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type Todo", field.Name)
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Query___type(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.introspectType(fc.Args["name"].(string))
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*introspection.Type)
+ fc.Result = res
+ return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Query___type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Query",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "kind":
+ return ec.fieldContext___Type_kind(ctx, field)
+ case "name":
+ return ec.fieldContext___Type_name(ctx, field)
+ case "description":
+ return ec.fieldContext___Type_description(ctx, field)
+ case "fields":
+ return ec.fieldContext___Type_fields(ctx, field)
+ case "interfaces":
+ return ec.fieldContext___Type_interfaces(ctx, field)
+ case "possibleTypes":
+ return ec.fieldContext___Type_possibleTypes(ctx, field)
+ case "enumValues":
+ return ec.fieldContext___Type_enumValues(ctx, field)
+ case "inputFields":
+ return ec.fieldContext___Type_inputFields(ctx, field)
+ case "ofType":
+ return ec.fieldContext___Type_ofType(ctx, field)
+ case "specifiedByURL":
+ return ec.fieldContext___Type_specifiedByURL(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name)
+ },
+ }
+ defer func() {
+ if r := recover(); r != nil {
+ err = ec.Recover(ctx, r)
+ ec.Error(ctx, err)
+ }
+ }()
+ ctx = graphql.WithFieldContext(ctx, fc)
+ if fc.Args, err = ec.field_Query___type_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
+ ec.Error(ctx, err)
+ return fc, err
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Query___schema(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return ec.introspectSchema()
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*introspection.Schema)
+ fc.Result = res
+ return ec.marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Query___schema(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Query",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "description":
+ return ec.fieldContext___Schema_description(ctx, field)
+ case "types":
+ return ec.fieldContext___Schema_types(ctx, field)
+ case "queryType":
+ return ec.fieldContext___Schema_queryType(ctx, field)
+ case "mutationType":
+ return ec.fieldContext___Schema_mutationType(ctx, field)
+ case "subscriptionType":
+ return ec.fieldContext___Schema_subscriptionType(ctx, field)
+ case "directives":
+ return ec.fieldContext___Schema_directives(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type __Schema", field.Name)
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _Todo_id(ctx context.Context, field graphql.CollectedField, obj *model.Todo) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Todo_id(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.ID, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(string)
+ fc.Result = res
+ return ec.marshalNID2string(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Todo_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Todo",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type ID does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _Todo_text(ctx context.Context, field graphql.CollectedField, obj *model.Todo) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Todo_text(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Text, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(string)
+ fc.Result = res
+ return ec.marshalNString2string(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Todo_text(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Todo",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type String does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _Todo_done(ctx context.Context, field graphql.CollectedField, obj *model.Todo) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Todo_done(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Done, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(bool)
+ fc.Result = res
+ return ec.marshalNBoolean2bool(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Todo_done(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Todo",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type Boolean does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _Todo_uid(ctx context.Context, field graphql.CollectedField, obj *model.Todo) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_Todo_uid(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.UID, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(uuid.UUID)
+ fc.Result = res
+ return ec.marshalNUUID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_Todo_uid(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "Todo",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type UUID does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Directive_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Directive_name(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Name, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(string)
+ fc.Result = res
+ return ec.marshalNString2string(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Directive_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Directive",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type String does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Directive_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Directive_description(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Description(), nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*string)
+ fc.Result = res
+ return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Directive_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Directive",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type String does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Directive_locations(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Directive_locations(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Locations, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.([]string)
+ fc.Result = res
+ return ec.marshalN__DirectiveLocation2ᚕstringᚄ(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Directive_locations(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Directive",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type __DirectiveLocation does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Directive_args(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Directive_args(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Args, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.([]introspection.InputValue)
+ fc.Result = res
+ return ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Directive_args(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Directive",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "name":
+ return ec.fieldContext___InputValue_name(ctx, field)
+ case "description":
+ return ec.fieldContext___InputValue_description(ctx, field)
+ case "type":
+ return ec.fieldContext___InputValue_type(ctx, field)
+ case "defaultValue":
+ return ec.fieldContext___InputValue_defaultValue(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name)
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Directive_isRepeatable(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Directive_isRepeatable(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.IsRepeatable, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(bool)
+ fc.Result = res
+ return ec.marshalNBoolean2bool(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Directive_isRepeatable(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Directive",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type Boolean does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___EnumValue_name(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___EnumValue_name(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Name, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(string)
+ fc.Result = res
+ return ec.marshalNString2string(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___EnumValue_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__EnumValue",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type String does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___EnumValue_description(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___EnumValue_description(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Description(), nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*string)
+ fc.Result = res
+ return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___EnumValue_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__EnumValue",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type String does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___EnumValue_isDeprecated(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___EnumValue_isDeprecated(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.IsDeprecated(), nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(bool)
+ fc.Result = res
+ return ec.marshalNBoolean2bool(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___EnumValue_isDeprecated(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__EnumValue",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type Boolean does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___EnumValue_deprecationReason(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___EnumValue_deprecationReason(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.DeprecationReason(), nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*string)
+ fc.Result = res
+ return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___EnumValue_deprecationReason(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__EnumValue",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type String does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Field_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Field_name(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Name, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(string)
+ fc.Result = res
+ return ec.marshalNString2string(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Field_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Field",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type String does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Field_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Field_description(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Description(), nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*string)
+ fc.Result = res
+ return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Field_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Field",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type String does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Field_args(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Field_args(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Args, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.([]introspection.InputValue)
+ fc.Result = res
+ return ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Field_args(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Field",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "name":
+ return ec.fieldContext___InputValue_name(ctx, field)
+ case "description":
+ return ec.fieldContext___InputValue_description(ctx, field)
+ case "type":
+ return ec.fieldContext___InputValue_type(ctx, field)
+ case "defaultValue":
+ return ec.fieldContext___InputValue_defaultValue(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name)
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Field_type(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Field_type(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Type, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(*introspection.Type)
+ fc.Result = res
+ return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Field_type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Field",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "kind":
+ return ec.fieldContext___Type_kind(ctx, field)
+ case "name":
+ return ec.fieldContext___Type_name(ctx, field)
+ case "description":
+ return ec.fieldContext___Type_description(ctx, field)
+ case "fields":
+ return ec.fieldContext___Type_fields(ctx, field)
+ case "interfaces":
+ return ec.fieldContext___Type_interfaces(ctx, field)
+ case "possibleTypes":
+ return ec.fieldContext___Type_possibleTypes(ctx, field)
+ case "enumValues":
+ return ec.fieldContext___Type_enumValues(ctx, field)
+ case "inputFields":
+ return ec.fieldContext___Type_inputFields(ctx, field)
+ case "ofType":
+ return ec.fieldContext___Type_ofType(ctx, field)
+ case "specifiedByURL":
+ return ec.fieldContext___Type_specifiedByURL(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name)
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Field_isDeprecated(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Field_isDeprecated(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.IsDeprecated(), nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(bool)
+ fc.Result = res
+ return ec.marshalNBoolean2bool(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Field_isDeprecated(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Field",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type Boolean does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Field_deprecationReason(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Field_deprecationReason(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.DeprecationReason(), nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*string)
+ fc.Result = res
+ return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Field_deprecationReason(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Field",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type String does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___InputValue_name(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___InputValue_name(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Name, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(string)
+ fc.Result = res
+ return ec.marshalNString2string(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___InputValue_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__InputValue",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type String does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___InputValue_description(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___InputValue_description(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Description(), nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*string)
+ fc.Result = res
+ return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___InputValue_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__InputValue",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type String does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___InputValue_type(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___InputValue_type(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Type, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(*introspection.Type)
+ fc.Result = res
+ return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___InputValue_type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__InputValue",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "kind":
+ return ec.fieldContext___Type_kind(ctx, field)
+ case "name":
+ return ec.fieldContext___Type_name(ctx, field)
+ case "description":
+ return ec.fieldContext___Type_description(ctx, field)
+ case "fields":
+ return ec.fieldContext___Type_fields(ctx, field)
+ case "interfaces":
+ return ec.fieldContext___Type_interfaces(ctx, field)
+ case "possibleTypes":
+ return ec.fieldContext___Type_possibleTypes(ctx, field)
+ case "enumValues":
+ return ec.fieldContext___Type_enumValues(ctx, field)
+ case "inputFields":
+ return ec.fieldContext___Type_inputFields(ctx, field)
+ case "ofType":
+ return ec.fieldContext___Type_ofType(ctx, field)
+ case "specifiedByURL":
+ return ec.fieldContext___Type_specifiedByURL(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name)
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___InputValue_defaultValue(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___InputValue_defaultValue(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.DefaultValue, nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*string)
+ fc.Result = res
+ return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___InputValue_defaultValue(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__InputValue",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type String does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Schema_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Schema_description(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Description(), nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*string)
+ fc.Result = res
+ return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Schema_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Schema",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type String does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Schema_types(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Schema_types(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Types(), nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.([]introspection.Type)
+ fc.Result = res
+ return ec.marshalN__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Schema_types(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Schema",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "kind":
+ return ec.fieldContext___Type_kind(ctx, field)
+ case "name":
+ return ec.fieldContext___Type_name(ctx, field)
+ case "description":
+ return ec.fieldContext___Type_description(ctx, field)
+ case "fields":
+ return ec.fieldContext___Type_fields(ctx, field)
+ case "interfaces":
+ return ec.fieldContext___Type_interfaces(ctx, field)
+ case "possibleTypes":
+ return ec.fieldContext___Type_possibleTypes(ctx, field)
+ case "enumValues":
+ return ec.fieldContext___Type_enumValues(ctx, field)
+ case "inputFields":
+ return ec.fieldContext___Type_inputFields(ctx, field)
+ case "ofType":
+ return ec.fieldContext___Type_ofType(ctx, field)
+ case "specifiedByURL":
+ return ec.fieldContext___Type_specifiedByURL(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name)
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Schema_queryType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Schema_queryType(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.QueryType(), nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(*introspection.Type)
+ fc.Result = res
+ return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Schema_queryType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Schema",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "kind":
+ return ec.fieldContext___Type_kind(ctx, field)
+ case "name":
+ return ec.fieldContext___Type_name(ctx, field)
+ case "description":
+ return ec.fieldContext___Type_description(ctx, field)
+ case "fields":
+ return ec.fieldContext___Type_fields(ctx, field)
+ case "interfaces":
+ return ec.fieldContext___Type_interfaces(ctx, field)
+ case "possibleTypes":
+ return ec.fieldContext___Type_possibleTypes(ctx, field)
+ case "enumValues":
+ return ec.fieldContext___Type_enumValues(ctx, field)
+ case "inputFields":
+ return ec.fieldContext___Type_inputFields(ctx, field)
+ case "ofType":
+ return ec.fieldContext___Type_ofType(ctx, field)
+ case "specifiedByURL":
+ return ec.fieldContext___Type_specifiedByURL(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name)
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Schema_mutationType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Schema_mutationType(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.MutationType(), nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*introspection.Type)
+ fc.Result = res
+ return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Schema_mutationType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Schema",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "kind":
+ return ec.fieldContext___Type_kind(ctx, field)
+ case "name":
+ return ec.fieldContext___Type_name(ctx, field)
+ case "description":
+ return ec.fieldContext___Type_description(ctx, field)
+ case "fields":
+ return ec.fieldContext___Type_fields(ctx, field)
+ case "interfaces":
+ return ec.fieldContext___Type_interfaces(ctx, field)
+ case "possibleTypes":
+ return ec.fieldContext___Type_possibleTypes(ctx, field)
+ case "enumValues":
+ return ec.fieldContext___Type_enumValues(ctx, field)
+ case "inputFields":
+ return ec.fieldContext___Type_inputFields(ctx, field)
+ case "ofType":
+ return ec.fieldContext___Type_ofType(ctx, field)
+ case "specifiedByURL":
+ return ec.fieldContext___Type_specifiedByURL(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name)
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Schema_subscriptionType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Schema_subscriptionType(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.SubscriptionType(), nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*introspection.Type)
+ fc.Result = res
+ return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Schema_subscriptionType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Schema",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "kind":
+ return ec.fieldContext___Type_kind(ctx, field)
+ case "name":
+ return ec.fieldContext___Type_name(ctx, field)
+ case "description":
+ return ec.fieldContext___Type_description(ctx, field)
+ case "fields":
+ return ec.fieldContext___Type_fields(ctx, field)
+ case "interfaces":
+ return ec.fieldContext___Type_interfaces(ctx, field)
+ case "possibleTypes":
+ return ec.fieldContext___Type_possibleTypes(ctx, field)
+ case "enumValues":
+ return ec.fieldContext___Type_enumValues(ctx, field)
+ case "inputFields":
+ return ec.fieldContext___Type_inputFields(ctx, field)
+ case "ofType":
+ return ec.fieldContext___Type_ofType(ctx, field)
+ case "specifiedByURL":
+ return ec.fieldContext___Type_specifiedByURL(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name)
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Schema_directives(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Schema_directives(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Directives(), nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.([]introspection.Directive)
+ fc.Result = res
+ return ec.marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirectiveᚄ(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Schema_directives(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Schema",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "name":
+ return ec.fieldContext___Directive_name(ctx, field)
+ case "description":
+ return ec.fieldContext___Directive_description(ctx, field)
+ case "locations":
+ return ec.fieldContext___Directive_locations(ctx, field)
+ case "args":
+ return ec.fieldContext___Directive_args(ctx, field)
+ case "isRepeatable":
+ return ec.fieldContext___Directive_isRepeatable(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type __Directive", field.Name)
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Type_kind(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Type_kind(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Kind(), nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(string)
+ fc.Result = res
+ return ec.marshalN__TypeKind2string(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Type_kind(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Type",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type __TypeKind does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Type_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Type_name(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Name(), nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*string)
+ fc.Result = res
+ return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Type_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Type",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type String does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Type_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Type_description(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Description(), nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*string)
+ fc.Result = res
+ return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Type_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Type",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type String does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Type_fields(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Type_fields(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Fields(fc.Args["includeDeprecated"].(bool)), nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.([]introspection.Field)
+ fc.Result = res
+ return ec.marshalO__Field2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐFieldᚄ(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Type_fields(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Type",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "name":
+ return ec.fieldContext___Field_name(ctx, field)
+ case "description":
+ return ec.fieldContext___Field_description(ctx, field)
+ case "args":
+ return ec.fieldContext___Field_args(ctx, field)
+ case "type":
+ return ec.fieldContext___Field_type(ctx, field)
+ case "isDeprecated":
+ return ec.fieldContext___Field_isDeprecated(ctx, field)
+ case "deprecationReason":
+ return ec.fieldContext___Field_deprecationReason(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type __Field", field.Name)
+ },
+ }
+ defer func() {
+ if r := recover(); r != nil {
+ err = ec.Recover(ctx, r)
+ ec.Error(ctx, err)
+ }
+ }()
+ ctx = graphql.WithFieldContext(ctx, fc)
+ if fc.Args, err = ec.field___Type_fields_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
+ ec.Error(ctx, err)
+ return fc, err
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Type_interfaces(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Type_interfaces(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Interfaces(), nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.([]introspection.Type)
+ fc.Result = res
+ return ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Type_interfaces(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Type",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "kind":
+ return ec.fieldContext___Type_kind(ctx, field)
+ case "name":
+ return ec.fieldContext___Type_name(ctx, field)
+ case "description":
+ return ec.fieldContext___Type_description(ctx, field)
+ case "fields":
+ return ec.fieldContext___Type_fields(ctx, field)
+ case "interfaces":
+ return ec.fieldContext___Type_interfaces(ctx, field)
+ case "possibleTypes":
+ return ec.fieldContext___Type_possibleTypes(ctx, field)
+ case "enumValues":
+ return ec.fieldContext___Type_enumValues(ctx, field)
+ case "inputFields":
+ return ec.fieldContext___Type_inputFields(ctx, field)
+ case "ofType":
+ return ec.fieldContext___Type_ofType(ctx, field)
+ case "specifiedByURL":
+ return ec.fieldContext___Type_specifiedByURL(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name)
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Type_possibleTypes(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Type_possibleTypes(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.PossibleTypes(), nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.([]introspection.Type)
+ fc.Result = res
+ return ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Type_possibleTypes(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Type",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "kind":
+ return ec.fieldContext___Type_kind(ctx, field)
+ case "name":
+ return ec.fieldContext___Type_name(ctx, field)
+ case "description":
+ return ec.fieldContext___Type_description(ctx, field)
+ case "fields":
+ return ec.fieldContext___Type_fields(ctx, field)
+ case "interfaces":
+ return ec.fieldContext___Type_interfaces(ctx, field)
+ case "possibleTypes":
+ return ec.fieldContext___Type_possibleTypes(ctx, field)
+ case "enumValues":
+ return ec.fieldContext___Type_enumValues(ctx, field)
+ case "inputFields":
+ return ec.fieldContext___Type_inputFields(ctx, field)
+ case "ofType":
+ return ec.fieldContext___Type_ofType(ctx, field)
+ case "specifiedByURL":
+ return ec.fieldContext___Type_specifiedByURL(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name)
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Type_enumValues(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Type_enumValues(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.EnumValues(fc.Args["includeDeprecated"].(bool)), nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.([]introspection.EnumValue)
+ fc.Result = res
+ return ec.marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Type_enumValues(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Type",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "name":
+ return ec.fieldContext___EnumValue_name(ctx, field)
+ case "description":
+ return ec.fieldContext___EnumValue_description(ctx, field)
+ case "isDeprecated":
+ return ec.fieldContext___EnumValue_isDeprecated(ctx, field)
+ case "deprecationReason":
+ return ec.fieldContext___EnumValue_deprecationReason(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type __EnumValue", field.Name)
+ },
+ }
+ defer func() {
+ if r := recover(); r != nil {
+ err = ec.Recover(ctx, r)
+ ec.Error(ctx, err)
+ }
+ }()
+ ctx = graphql.WithFieldContext(ctx, fc)
+ if fc.Args, err = ec.field___Type_enumValues_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
+ ec.Error(ctx, err)
+ return fc, err
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Type_inputFields(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Type_inputFields(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.InputFields(), nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.([]introspection.InputValue)
+ fc.Result = res
+ return ec.marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Type_inputFields(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Type",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "name":
+ return ec.fieldContext___InputValue_name(ctx, field)
+ case "description":
+ return ec.fieldContext___InputValue_description(ctx, field)
+ case "type":
+ return ec.fieldContext___InputValue_type(ctx, field)
+ case "defaultValue":
+ return ec.fieldContext___InputValue_defaultValue(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name)
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Type_ofType(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Type_ofType(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.OfType(), nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*introspection.Type)
+ fc.Result = res
+ return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Type_ofType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Type",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "kind":
+ return ec.fieldContext___Type_kind(ctx, field)
+ case "name":
+ return ec.fieldContext___Type_name(ctx, field)
+ case "description":
+ return ec.fieldContext___Type_description(ctx, field)
+ case "fields":
+ return ec.fieldContext___Type_fields(ctx, field)
+ case "interfaces":
+ return ec.fieldContext___Type_interfaces(ctx, field)
+ case "possibleTypes":
+ return ec.fieldContext___Type_possibleTypes(ctx, field)
+ case "enumValues":
+ return ec.fieldContext___Type_enumValues(ctx, field)
+ case "inputFields":
+ return ec.fieldContext___Type_inputFields(ctx, field)
+ case "ofType":
+ return ec.fieldContext___Type_ofType(ctx, field)
+ case "specifiedByURL":
+ return ec.fieldContext___Type_specifiedByURL(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name)
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) ___Type_specifiedByURL(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext___Type_specifiedByURL(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.SpecifiedByURL(), nil
+ })
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*string)
+ fc.Result = res
+ return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext___Type_specifiedByURL(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "__Type",
+ Field: field,
+ IsMethod: true,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type String does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+// endregion **************************** field.gotpl *****************************
+
+// region **************************** input.gotpl *****************************
+
+func (ec *executionContext) unmarshalInputNewTodo(ctx context.Context, obj interface{}) (model.NewTodo, error) {
+ var it model.NewTodo
+ asMap := map[string]interface{}{}
+ for k, v := range obj.(map[string]interface{}) {
+ asMap[k] = v
+ }
+
+ fieldsInOrder := [...]string{"text", "userId", "uid"}
+ for _, k := range fieldsInOrder {
+ v, ok := asMap[k]
+ if !ok {
+ continue
+ }
+ switch k {
+ case "text":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("text"))
+ data, err := ec.unmarshalNString2string(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it.Text = data
+ case "userId":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("userId"))
+ data, err := ec.unmarshalNString2string(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it.UserID = data
+ case "uid":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("uid"))
+ data, err := ec.unmarshalNUUID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it.UID = data
+ }
+ }
+
+ return it, nil
+}
+
+// endregion **************************** input.gotpl *****************************
+
+// region ************************** interface.gotpl ***************************
+
+// endregion ************************** interface.gotpl ***************************
+
+// region **************************** object.gotpl ****************************
+
+var mutationImplementors = []string{"Mutation"}
+
+func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler {
+ fields := graphql.CollectFields(ec.OperationContext, sel, mutationImplementors)
+ ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{
+ Object: "Mutation",
+ })
+
+ out := graphql.NewFieldSet(fields)
+ deferred := make(map[string]*graphql.FieldSet)
+ for i, field := range fields {
+ innerCtx := graphql.WithRootFieldContext(ctx, &graphql.RootFieldContext{
+ Object: field.Name,
+ Field: field,
+ })
+
+ switch field.Name {
+ case "__typename":
+ out.Values[i] = graphql.MarshalString("Mutation")
+ case "createTodo":
+ out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
+ return ec._Mutation_createTodo(ctx, field)
+ })
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ default:
+ panic("unknown field " + strconv.Quote(field.Name))
+ }
+ }
+ out.Dispatch(ctx)
+ if out.Invalids > 0 {
+ return graphql.Null
+ }
+
+ atomic.AddInt32(&ec.deferred, int32(len(deferred)))
+
+ for label, dfs := range deferred {
+ ec.processDeferredGroup(graphql.DeferredGroup{
+ Label: label,
+ Path: graphql.GetPath(ctx),
+ FieldSet: dfs,
+ Context: ctx,
+ })
+ }
+
+ return out
+}
+
+var queryImplementors = []string{"Query"}
+
+func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler {
+ fields := graphql.CollectFields(ec.OperationContext, sel, queryImplementors)
+ ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{
+ Object: "Query",
+ })
+
+ out := graphql.NewFieldSet(fields)
+ deferred := make(map[string]*graphql.FieldSet)
+ for i, field := range fields {
+ innerCtx := graphql.WithRootFieldContext(ctx, &graphql.RootFieldContext{
+ Object: field.Name,
+ Field: field,
+ })
+
+ switch field.Name {
+ case "__typename":
+ out.Values[i] = graphql.MarshalString("Query")
+ case "todos":
+ field := field
+
+ innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ }
+ }()
+ res = ec._Query_todos(ctx, field)
+ if res == graphql.Null {
+ atomic.AddUint32(&fs.Invalids, 1)
+ }
+ return res
+ }
+
+ rrm := func(ctx context.Context) graphql.Marshaler {
+ return ec.OperationContext.RootResolverMiddleware(ctx,
+ func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
+ }
+
+ out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) })
+ case "__type":
+ out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
+ return ec._Query___type(ctx, field)
+ })
+ case "__schema":
+ out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
+ return ec._Query___schema(ctx, field)
+ })
+ default:
+ panic("unknown field " + strconv.Quote(field.Name))
+ }
+ }
+ out.Dispatch(ctx)
+ if out.Invalids > 0 {
+ return graphql.Null
+ }
+
+ atomic.AddInt32(&ec.deferred, int32(len(deferred)))
+
+ for label, dfs := range deferred {
+ ec.processDeferredGroup(graphql.DeferredGroup{
+ Label: label,
+ Path: graphql.GetPath(ctx),
+ FieldSet: dfs,
+ Context: ctx,
+ })
+ }
+
+ return out
+}
+
+var todoImplementors = []string{"Todo"}
+
+func (ec *executionContext) _Todo(ctx context.Context, sel ast.SelectionSet, obj *model.Todo) graphql.Marshaler {
+ fields := graphql.CollectFields(ec.OperationContext, sel, todoImplementors)
+
+ out := graphql.NewFieldSet(fields)
+ deferred := make(map[string]*graphql.FieldSet)
+ for i, field := range fields {
+ switch field.Name {
+ case "__typename":
+ out.Values[i] = graphql.MarshalString("Todo")
+ case "id":
+ out.Values[i] = ec._Todo_id(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "text":
+ out.Values[i] = ec._Todo_text(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "done":
+ out.Values[i] = ec._Todo_done(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "uid":
+ out.Values[i] = ec._Todo_uid(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ default:
+ panic("unknown field " + strconv.Quote(field.Name))
+ }
+ }
+ out.Dispatch(ctx)
+ if out.Invalids > 0 {
+ return graphql.Null
+ }
+
+ atomic.AddInt32(&ec.deferred, int32(len(deferred)))
+
+ for label, dfs := range deferred {
+ ec.processDeferredGroup(graphql.DeferredGroup{
+ Label: label,
+ Path: graphql.GetPath(ctx),
+ FieldSet: dfs,
+ Context: ctx,
+ })
+ }
+
+ return out
+}
+
+var __DirectiveImplementors = []string{"__Directive"}
+
+func (ec *executionContext) ___Directive(ctx context.Context, sel ast.SelectionSet, obj *introspection.Directive) graphql.Marshaler {
+ fields := graphql.CollectFields(ec.OperationContext, sel, __DirectiveImplementors)
+
+ out := graphql.NewFieldSet(fields)
+ deferred := make(map[string]*graphql.FieldSet)
+ for i, field := range fields {
+ switch field.Name {
+ case "__typename":
+ out.Values[i] = graphql.MarshalString("__Directive")
+ case "name":
+ out.Values[i] = ec.___Directive_name(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "description":
+ out.Values[i] = ec.___Directive_description(ctx, field, obj)
+ case "locations":
+ out.Values[i] = ec.___Directive_locations(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "args":
+ out.Values[i] = ec.___Directive_args(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "isRepeatable":
+ out.Values[i] = ec.___Directive_isRepeatable(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ default:
+ panic("unknown field " + strconv.Quote(field.Name))
+ }
+ }
+ out.Dispatch(ctx)
+ if out.Invalids > 0 {
+ return graphql.Null
+ }
+
+ atomic.AddInt32(&ec.deferred, int32(len(deferred)))
+
+ for label, dfs := range deferred {
+ ec.processDeferredGroup(graphql.DeferredGroup{
+ Label: label,
+ Path: graphql.GetPath(ctx),
+ FieldSet: dfs,
+ Context: ctx,
+ })
+ }
+
+ return out
+}
+
+var __EnumValueImplementors = []string{"__EnumValue"}
+
+func (ec *executionContext) ___EnumValue(ctx context.Context, sel ast.SelectionSet, obj *introspection.EnumValue) graphql.Marshaler {
+ fields := graphql.CollectFields(ec.OperationContext, sel, __EnumValueImplementors)
+
+ out := graphql.NewFieldSet(fields)
+ deferred := make(map[string]*graphql.FieldSet)
+ for i, field := range fields {
+ switch field.Name {
+ case "__typename":
+ out.Values[i] = graphql.MarshalString("__EnumValue")
+ case "name":
+ out.Values[i] = ec.___EnumValue_name(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "description":
+ out.Values[i] = ec.___EnumValue_description(ctx, field, obj)
+ case "isDeprecated":
+ out.Values[i] = ec.___EnumValue_isDeprecated(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "deprecationReason":
+ out.Values[i] = ec.___EnumValue_deprecationReason(ctx, field, obj)
+ default:
+ panic("unknown field " + strconv.Quote(field.Name))
+ }
+ }
+ out.Dispatch(ctx)
+ if out.Invalids > 0 {
+ return graphql.Null
+ }
+
+ atomic.AddInt32(&ec.deferred, int32(len(deferred)))
+
+ for label, dfs := range deferred {
+ ec.processDeferredGroup(graphql.DeferredGroup{
+ Label: label,
+ Path: graphql.GetPath(ctx),
+ FieldSet: dfs,
+ Context: ctx,
+ })
+ }
+
+ return out
+}
+
+var __FieldImplementors = []string{"__Field"}
+
+func (ec *executionContext) ___Field(ctx context.Context, sel ast.SelectionSet, obj *introspection.Field) graphql.Marshaler {
+ fields := graphql.CollectFields(ec.OperationContext, sel, __FieldImplementors)
+
+ out := graphql.NewFieldSet(fields)
+ deferred := make(map[string]*graphql.FieldSet)
+ for i, field := range fields {
+ switch field.Name {
+ case "__typename":
+ out.Values[i] = graphql.MarshalString("__Field")
+ case "name":
+ out.Values[i] = ec.___Field_name(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "description":
+ out.Values[i] = ec.___Field_description(ctx, field, obj)
+ case "args":
+ out.Values[i] = ec.___Field_args(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "type":
+ out.Values[i] = ec.___Field_type(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "isDeprecated":
+ out.Values[i] = ec.___Field_isDeprecated(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "deprecationReason":
+ out.Values[i] = ec.___Field_deprecationReason(ctx, field, obj)
+ default:
+ panic("unknown field " + strconv.Quote(field.Name))
+ }
+ }
+ out.Dispatch(ctx)
+ if out.Invalids > 0 {
+ return graphql.Null
+ }
+
+ atomic.AddInt32(&ec.deferred, int32(len(deferred)))
+
+ for label, dfs := range deferred {
+ ec.processDeferredGroup(graphql.DeferredGroup{
+ Label: label,
+ Path: graphql.GetPath(ctx),
+ FieldSet: dfs,
+ Context: ctx,
+ })
+ }
+
+ return out
+}
+
+var __InputValueImplementors = []string{"__InputValue"}
+
+func (ec *executionContext) ___InputValue(ctx context.Context, sel ast.SelectionSet, obj *introspection.InputValue) graphql.Marshaler {
+ fields := graphql.CollectFields(ec.OperationContext, sel, __InputValueImplementors)
+
+ out := graphql.NewFieldSet(fields)
+ deferred := make(map[string]*graphql.FieldSet)
+ for i, field := range fields {
+ switch field.Name {
+ case "__typename":
+ out.Values[i] = graphql.MarshalString("__InputValue")
+ case "name":
+ out.Values[i] = ec.___InputValue_name(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "description":
+ out.Values[i] = ec.___InputValue_description(ctx, field, obj)
+ case "type":
+ out.Values[i] = ec.___InputValue_type(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "defaultValue":
+ out.Values[i] = ec.___InputValue_defaultValue(ctx, field, obj)
+ default:
+ panic("unknown field " + strconv.Quote(field.Name))
+ }
+ }
+ out.Dispatch(ctx)
+ if out.Invalids > 0 {
+ return graphql.Null
+ }
+
+ atomic.AddInt32(&ec.deferred, int32(len(deferred)))
+
+ for label, dfs := range deferred {
+ ec.processDeferredGroup(graphql.DeferredGroup{
+ Label: label,
+ Path: graphql.GetPath(ctx),
+ FieldSet: dfs,
+ Context: ctx,
+ })
+ }
+
+ return out
+}
+
+var __SchemaImplementors = []string{"__Schema"}
+
+func (ec *executionContext) ___Schema(ctx context.Context, sel ast.SelectionSet, obj *introspection.Schema) graphql.Marshaler {
+ fields := graphql.CollectFields(ec.OperationContext, sel, __SchemaImplementors)
+
+ out := graphql.NewFieldSet(fields)
+ deferred := make(map[string]*graphql.FieldSet)
+ for i, field := range fields {
+ switch field.Name {
+ case "__typename":
+ out.Values[i] = graphql.MarshalString("__Schema")
+ case "description":
+ out.Values[i] = ec.___Schema_description(ctx, field, obj)
+ case "types":
+ out.Values[i] = ec.___Schema_types(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "queryType":
+ out.Values[i] = ec.___Schema_queryType(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "mutationType":
+ out.Values[i] = ec.___Schema_mutationType(ctx, field, obj)
+ case "subscriptionType":
+ out.Values[i] = ec.___Schema_subscriptionType(ctx, field, obj)
+ case "directives":
+ out.Values[i] = ec.___Schema_directives(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ default:
+ panic("unknown field " + strconv.Quote(field.Name))
+ }
+ }
+ out.Dispatch(ctx)
+ if out.Invalids > 0 {
+ return graphql.Null
+ }
+
+ atomic.AddInt32(&ec.deferred, int32(len(deferred)))
+
+ for label, dfs := range deferred {
+ ec.processDeferredGroup(graphql.DeferredGroup{
+ Label: label,
+ Path: graphql.GetPath(ctx),
+ FieldSet: dfs,
+ Context: ctx,
+ })
+ }
+
+ return out
+}
+
+var __TypeImplementors = []string{"__Type"}
+
+func (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, obj *introspection.Type) graphql.Marshaler {
+ fields := graphql.CollectFields(ec.OperationContext, sel, __TypeImplementors)
+
+ out := graphql.NewFieldSet(fields)
+ deferred := make(map[string]*graphql.FieldSet)
+ for i, field := range fields {
+ switch field.Name {
+ case "__typename":
+ out.Values[i] = graphql.MarshalString("__Type")
+ case "kind":
+ out.Values[i] = ec.___Type_kind(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ case "name":
+ out.Values[i] = ec.___Type_name(ctx, field, obj)
+ case "description":
+ out.Values[i] = ec.___Type_description(ctx, field, obj)
+ case "fields":
+ out.Values[i] = ec.___Type_fields(ctx, field, obj)
+ case "interfaces":
+ out.Values[i] = ec.___Type_interfaces(ctx, field, obj)
+ case "possibleTypes":
+ out.Values[i] = ec.___Type_possibleTypes(ctx, field, obj)
+ case "enumValues":
+ out.Values[i] = ec.___Type_enumValues(ctx, field, obj)
+ case "inputFields":
+ out.Values[i] = ec.___Type_inputFields(ctx, field, obj)
+ case "ofType":
+ out.Values[i] = ec.___Type_ofType(ctx, field, obj)
+ case "specifiedByURL":
+ out.Values[i] = ec.___Type_specifiedByURL(ctx, field, obj)
+ default:
+ panic("unknown field " + strconv.Quote(field.Name))
+ }
+ }
+ out.Dispatch(ctx)
+ if out.Invalids > 0 {
+ return graphql.Null
+ }
+
+ atomic.AddInt32(&ec.deferred, int32(len(deferred)))
+
+ for label, dfs := range deferred {
+ ec.processDeferredGroup(graphql.DeferredGroup{
+ Label: label,
+ Path: graphql.GetPath(ctx),
+ FieldSet: dfs,
+ Context: ctx,
+ })
+ }
+
+ return out
+}
+
+// endregion **************************** object.gotpl ****************************
+
+// region ***************************** type.gotpl *****************************
+
+func (ec *executionContext) unmarshalNBoolean2bool(ctx context.Context, v interface{}) (bool, error) {
+ res, err := graphql.UnmarshalBoolean(v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler {
+ res := graphql.MarshalBoolean(v)
+ if res == graphql.Null {
+ if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
+ ec.Errorf(ctx, "the requested element is null which the schema does not allow")
+ }
+ }
+ return res
+}
+
+func (ec *executionContext) unmarshalNID2string(ctx context.Context, v interface{}) (string, error) {
+ res, err := graphql.UnmarshalID(v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) marshalNID2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler {
+ res := graphql.MarshalID(v)
+ if res == graphql.Null {
+ if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
+ ec.Errorf(ctx, "the requested element is null which the schema does not allow")
+ }
+ }
+ return res
+}
+
+func (ec *executionContext) unmarshalNNewTodo2githubᚗcomᚋ99designsᚋgqlgenᚋ_examplesᚋuuidᚋgraphᚋmodelᚐNewTodo(ctx context.Context, v interface{}) (model.NewTodo, error) {
+ res, err := ec.unmarshalInputNewTodo(ctx, v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) unmarshalNString2string(ctx context.Context, v interface{}) (string, error) {
+ res, err := graphql.UnmarshalString(v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) marshalNString2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler {
+ res := graphql.MarshalString(v)
+ if res == graphql.Null {
+ if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
+ ec.Errorf(ctx, "the requested element is null which the schema does not allow")
+ }
+ }
+ return res
+}
+
+func (ec *executionContext) marshalNTodo2githubᚗcomᚋ99designsᚋgqlgenᚋ_examplesᚋuuidᚋgraphᚋmodelᚐTodo(ctx context.Context, sel ast.SelectionSet, v model.Todo) graphql.Marshaler {
+ return ec._Todo(ctx, sel, &v)
+}
+
+func (ec *executionContext) marshalNTodo2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋ_examplesᚋuuidᚋgraphᚋmodelᚐTodoᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.Todo) graphql.Marshaler {
+ ret := make(graphql.Array, len(v))
+ var wg sync.WaitGroup
+ isLen1 := len(v) == 1
+ if !isLen1 {
+ wg.Add(len(v))
+ }
+ for i := range v {
+ i := i
+ fc := &graphql.FieldContext{
+ Index: &i,
+ Result: &v[i],
+ }
+ ctx := graphql.WithFieldContext(ctx, fc)
+ f := func(i int) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = nil
+ }
+ }()
+ if !isLen1 {
+ defer wg.Done()
+ }
+ ret[i] = ec.marshalNTodo2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋ_examplesᚋuuidᚋgraphᚋmodelᚐTodo(ctx, sel, v[i])
+ }
+ if isLen1 {
+ f(i)
+ } else {
+ go f(i)
+ }
+
+ }
+ wg.Wait()
+
+ for _, e := range ret {
+ if e == graphql.Null {
+ return graphql.Null
+ }
+ }
+
+ return ret
+}
+
+func (ec *executionContext) marshalNTodo2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋ_examplesᚋuuidᚋgraphᚋmodelᚐTodo(ctx context.Context, sel ast.SelectionSet, v *model.Todo) graphql.Marshaler {
+ if v == nil {
+ if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
+ ec.Errorf(ctx, "the requested element is null which the schema does not allow")
+ }
+ return graphql.Null
+ }
+ return ec._Todo(ctx, sel, v)
+}
+
+func (ec *executionContext) unmarshalNUUID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx context.Context, v interface{}) (uuid.UUID, error) {
+ res, err := graphql.UnmarshalUUID(v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) marshalNUUID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx context.Context, sel ast.SelectionSet, v uuid.UUID) graphql.Marshaler {
+ res := graphql.MarshalUUID(v)
+ if res == graphql.Null {
+ if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
+ ec.Errorf(ctx, "the requested element is null which the schema does not allow")
+ }
+ }
+ return res
+}
+
+func (ec *executionContext) marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx context.Context, sel ast.SelectionSet, v introspection.Directive) graphql.Marshaler {
+ return ec.___Directive(ctx, sel, &v)
+}
+
+func (ec *executionContext) marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirectiveᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Directive) graphql.Marshaler {
+ ret := make(graphql.Array, len(v))
+ var wg sync.WaitGroup
+ isLen1 := len(v) == 1
+ if !isLen1 {
+ wg.Add(len(v))
+ }
+ for i := range v {
+ i := i
+ fc := &graphql.FieldContext{
+ Index: &i,
+ Result: &v[i],
+ }
+ ctx := graphql.WithFieldContext(ctx, fc)
+ f := func(i int) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = nil
+ }
+ }()
+ if !isLen1 {
+ defer wg.Done()
+ }
+ ret[i] = ec.marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx, sel, v[i])
+ }
+ if isLen1 {
+ f(i)
+ } else {
+ go f(i)
+ }
+
+ }
+ wg.Wait()
+
+ for _, e := range ret {
+ if e == graphql.Null {
+ return graphql.Null
+ }
+ }
+
+ return ret
+}
+
+func (ec *executionContext) unmarshalN__DirectiveLocation2string(ctx context.Context, v interface{}) (string, error) {
+ res, err := graphql.UnmarshalString(v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) marshalN__DirectiveLocation2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler {
+ res := graphql.MarshalString(v)
+ if res == graphql.Null {
+ if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
+ ec.Errorf(ctx, "the requested element is null which the schema does not allow")
+ }
+ }
+ return res
+}
+
+func (ec *executionContext) unmarshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) {
+ var vSlice []interface{}
+ if v != nil {
+ vSlice = graphql.CoerceList(v)
+ }
+ var err error
+ res := make([]string, len(vSlice))
+ for i := range vSlice {
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i))
+ res[i], err = ec.unmarshalN__DirectiveLocation2string(ctx, vSlice[i])
+ if err != nil {
+ return nil, err
+ }
+ }
+ return res, nil
+}
+
+func (ec *executionContext) marshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, sel ast.SelectionSet, v []string) graphql.Marshaler {
+ ret := make(graphql.Array, len(v))
+ var wg sync.WaitGroup
+ isLen1 := len(v) == 1
+ if !isLen1 {
+ wg.Add(len(v))
+ }
+ for i := range v {
+ i := i
+ fc := &graphql.FieldContext{
+ Index: &i,
+ Result: &v[i],
+ }
+ ctx := graphql.WithFieldContext(ctx, fc)
+ f := func(i int) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = nil
+ }
+ }()
+ if !isLen1 {
+ defer wg.Done()
+ }
+ ret[i] = ec.marshalN__DirectiveLocation2string(ctx, sel, v[i])
+ }
+ if isLen1 {
+ f(i)
+ } else {
+ go f(i)
+ }
+
+ }
+ wg.Wait()
+
+ for _, e := range ret {
+ if e == graphql.Null {
+ return graphql.Null
+ }
+ }
+
+ return ret
+}
+
+func (ec *executionContext) marshalN__EnumValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValue(ctx context.Context, sel ast.SelectionSet, v introspection.EnumValue) graphql.Marshaler {
+ return ec.___EnumValue(ctx, sel, &v)
+}
+
+func (ec *executionContext) marshalN__Field2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐField(ctx context.Context, sel ast.SelectionSet, v introspection.Field) graphql.Marshaler {
+ return ec.___Field(ctx, sel, &v)
+}
+
+func (ec *executionContext) marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx context.Context, sel ast.SelectionSet, v introspection.InputValue) graphql.Marshaler {
+ return ec.___InputValue(ctx, sel, &v)
+}
+
+func (ec *executionContext) marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.InputValue) graphql.Marshaler {
+ ret := make(graphql.Array, len(v))
+ var wg sync.WaitGroup
+ isLen1 := len(v) == 1
+ if !isLen1 {
+ wg.Add(len(v))
+ }
+ for i := range v {
+ i := i
+ fc := &graphql.FieldContext{
+ Index: &i,
+ Result: &v[i],
+ }
+ ctx := graphql.WithFieldContext(ctx, fc)
+ f := func(i int) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = nil
+ }
+ }()
+ if !isLen1 {
+ defer wg.Done()
+ }
+ ret[i] = ec.marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx, sel, v[i])
+ }
+ if isLen1 {
+ f(i)
+ } else {
+ go f(i)
+ }
+
+ }
+ wg.Wait()
+
+ for _, e := range ret {
+ if e == graphql.Null {
+ return graphql.Null
+ }
+ }
+
+ return ret
+}
+
+func (ec *executionContext) marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v introspection.Type) graphql.Marshaler {
+ return ec.___Type(ctx, sel, &v)
+}
+
+func (ec *executionContext) marshalN__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Type) graphql.Marshaler {
+ ret := make(graphql.Array, len(v))
+ var wg sync.WaitGroup
+ isLen1 := len(v) == 1
+ if !isLen1 {
+ wg.Add(len(v))
+ }
+ for i := range v {
+ i := i
+ fc := &graphql.FieldContext{
+ Index: &i,
+ Result: &v[i],
+ }
+ ctx := graphql.WithFieldContext(ctx, fc)
+ f := func(i int) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = nil
+ }
+ }()
+ if !isLen1 {
+ defer wg.Done()
+ }
+ ret[i] = ec.marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, sel, v[i])
+ }
+ if isLen1 {
+ f(i)
+ } else {
+ go f(i)
+ }
+
+ }
+ wg.Wait()
+
+ for _, e := range ret {
+ if e == graphql.Null {
+ return graphql.Null
+ }
+ }
+
+ return ret
+}
+
+func (ec *executionContext) marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v *introspection.Type) graphql.Marshaler {
+ if v == nil {
+ if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
+ ec.Errorf(ctx, "the requested element is null which the schema does not allow")
+ }
+ return graphql.Null
+ }
+ return ec.___Type(ctx, sel, v)
+}
+
+func (ec *executionContext) unmarshalN__TypeKind2string(ctx context.Context, v interface{}) (string, error) {
+ res, err := graphql.UnmarshalString(v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler {
+ res := graphql.MarshalString(v)
+ if res == graphql.Null {
+ if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
+ ec.Errorf(ctx, "the requested element is null which the schema does not allow")
+ }
+ }
+ return res
+}
+
+func (ec *executionContext) unmarshalOBoolean2bool(ctx context.Context, v interface{}) (bool, error) {
+ res, err := graphql.UnmarshalBoolean(v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) marshalOBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler {
+ res := graphql.MarshalBoolean(v)
+ return res
+}
+
+func (ec *executionContext) unmarshalOBoolean2ᚖbool(ctx context.Context, v interface{}) (*bool, error) {
+ if v == nil {
+ return nil, nil
+ }
+ res, err := graphql.UnmarshalBoolean(v)
+ return &res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast.SelectionSet, v *bool) graphql.Marshaler {
+ if v == nil {
+ return graphql.Null
+ }
+ res := graphql.MarshalBoolean(*v)
+ return res
+}
+
+func (ec *executionContext) unmarshalOString2ᚖstring(ctx context.Context, v interface{}) (*string, error) {
+ if v == nil {
+ return nil, nil
+ }
+ res, err := graphql.UnmarshalString(v)
+ return &res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) marshalOString2ᚖstring(ctx context.Context, sel ast.SelectionSet, v *string) graphql.Marshaler {
+ if v == nil {
+ return graphql.Null
+ }
+ res := graphql.MarshalString(*v)
+ return res
+}
+
+func (ec *executionContext) marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.EnumValue) graphql.Marshaler {
+ if v == nil {
+ return graphql.Null
+ }
+ ret := make(graphql.Array, len(v))
+ var wg sync.WaitGroup
+ isLen1 := len(v) == 1
+ if !isLen1 {
+ wg.Add(len(v))
+ }
+ for i := range v {
+ i := i
+ fc := &graphql.FieldContext{
+ Index: &i,
+ Result: &v[i],
+ }
+ ctx := graphql.WithFieldContext(ctx, fc)
+ f := func(i int) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = nil
+ }
+ }()
+ if !isLen1 {
+ defer wg.Done()
+ }
+ ret[i] = ec.marshalN__EnumValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValue(ctx, sel, v[i])
+ }
+ if isLen1 {
+ f(i)
+ } else {
+ go f(i)
+ }
+
+ }
+ wg.Wait()
+
+ for _, e := range ret {
+ if e == graphql.Null {
+ return graphql.Null
+ }
+ }
+
+ return ret
+}
+
+func (ec *executionContext) marshalO__Field2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐFieldᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Field) graphql.Marshaler {
+ if v == nil {
+ return graphql.Null
+ }
+ ret := make(graphql.Array, len(v))
+ var wg sync.WaitGroup
+ isLen1 := len(v) == 1
+ if !isLen1 {
+ wg.Add(len(v))
+ }
+ for i := range v {
+ i := i
+ fc := &graphql.FieldContext{
+ Index: &i,
+ Result: &v[i],
+ }
+ ctx := graphql.WithFieldContext(ctx, fc)
+ f := func(i int) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = nil
+ }
+ }()
+ if !isLen1 {
+ defer wg.Done()
+ }
+ ret[i] = ec.marshalN__Field2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐField(ctx, sel, v[i])
+ }
+ if isLen1 {
+ f(i)
+ } else {
+ go f(i)
+ }
+
+ }
+ wg.Wait()
+
+ for _, e := range ret {
+ if e == graphql.Null {
+ return graphql.Null
+ }
+ }
+
+ return ret
+}
+
+func (ec *executionContext) marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.InputValue) graphql.Marshaler {
+ if v == nil {
+ return graphql.Null
+ }
+ ret := make(graphql.Array, len(v))
+ var wg sync.WaitGroup
+ isLen1 := len(v) == 1
+ if !isLen1 {
+ wg.Add(len(v))
+ }
+ for i := range v {
+ i := i
+ fc := &graphql.FieldContext{
+ Index: &i,
+ Result: &v[i],
+ }
+ ctx := graphql.WithFieldContext(ctx, fc)
+ f := func(i int) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = nil
+ }
+ }()
+ if !isLen1 {
+ defer wg.Done()
+ }
+ ret[i] = ec.marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx, sel, v[i])
+ }
+ if isLen1 {
+ f(i)
+ } else {
+ go f(i)
+ }
+
+ }
+ wg.Wait()
+
+ for _, e := range ret {
+ if e == graphql.Null {
+ return graphql.Null
+ }
+ }
+
+ return ret
+}
+
+func (ec *executionContext) marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx context.Context, sel ast.SelectionSet, v *introspection.Schema) graphql.Marshaler {
+ if v == nil {
+ return graphql.Null
+ }
+ return ec.___Schema(ctx, sel, v)
+}
+
+func (ec *executionContext) marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Type) graphql.Marshaler {
+ if v == nil {
+ return graphql.Null
+ }
+ ret := make(graphql.Array, len(v))
+ var wg sync.WaitGroup
+ isLen1 := len(v) == 1
+ if !isLen1 {
+ wg.Add(len(v))
+ }
+ for i := range v {
+ i := i
+ fc := &graphql.FieldContext{
+ Index: &i,
+ Result: &v[i],
+ }
+ ctx := graphql.WithFieldContext(ctx, fc)
+ f := func(i int) {
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = nil
+ }
+ }()
+ if !isLen1 {
+ defer wg.Done()
+ }
+ ret[i] = ec.marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, sel, v[i])
+ }
+ if isLen1 {
+ f(i)
+ } else {
+ go f(i)
+ }
+
+ }
+ wg.Wait()
+
+ for _, e := range ret {
+ if e == graphql.Null {
+ return graphql.Null
+ }
+ }
+
+ return ret
+}
+
+func (ec *executionContext) marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v *introspection.Type) graphql.Marshaler {
+ if v == nil {
+ return graphql.Null
+ }
+ return ec.___Type(ctx, sel, v)
+}
+
+// endregion ***************************** type.gotpl *****************************
diff --git a/_examples/uuid/graph/model/models_gen.go b/_examples/uuid/graph/model/models_gen.go
new file mode 100644
index 0000000000..a4dc0a3239
--- /dev/null
+++ b/_examples/uuid/graph/model/models_gen.go
@@ -0,0 +1,20 @@
+// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
+
+package model
+
+import (
+ "github.com/google/uuid"
+)
+
+type NewTodo struct {
+ Text string `json:"text"`
+ UserID string `json:"userId"`
+ UID uuid.UUID `json:"uid"`
+}
+
+type Todo struct {
+ ID string `json:"id"`
+ Text string `json:"text"`
+ Done bool `json:"done"`
+ UID uuid.UUID `json:"uid"`
+}
diff --git a/_examples/uuid/graph/resolver.go b/_examples/uuid/graph/resolver.go
new file mode 100644
index 0000000000..a25c09c619
--- /dev/null
+++ b/_examples/uuid/graph/resolver.go
@@ -0,0 +1,7 @@
+package graph
+
+// This file will not be regenerated automatically.
+//
+// It serves as dependency injection for your app, add any dependencies you require here.
+
+type Resolver struct{}
diff --git a/_examples/uuid/graph/schema.graphqls b/_examples/uuid/graph/schema.graphqls
new file mode 100644
index 0000000000..074282574f
--- /dev/null
+++ b/_examples/uuid/graph/schema.graphqls
@@ -0,0 +1,27 @@
+# GraphQL schema example
+#
+# https://gqlgen.com/getting-started/
+
+type Todo {
+ id: ID!
+ text: String!
+ done: Boolean!
+ uid: UUID!
+}
+
+
+type Query {
+ todos: [Todo!]!
+}
+
+input NewTodo {
+ text: String!
+ userId: String!
+ uid: UUID!
+}
+
+type Mutation {
+ createTodo(input: NewTodo!): Todo!
+}
+
+scalar UUID
diff --git a/_examples/uuid/graph/schema.resolvers.go b/_examples/uuid/graph/schema.resolvers.go
new file mode 100644
index 0000000000..1fd92e5290
--- /dev/null
+++ b/_examples/uuid/graph/schema.resolvers.go
@@ -0,0 +1,39 @@
+package graph
+
+// This file will be automatically regenerated based on the schema, any resolver implementations
+// will be copied through when generating and any unknown code will be moved to the end.
+// Code generated by github.com/99designs/gqlgen version v0.17.36
+
+import (
+ "context"
+
+ "github.com/99designs/gqlgen/_examples/uuid/graph/model"
+ "github.com/google/uuid"
+)
+
+// CreateTodo is the resolver for the createTodo field.
+func (r *mutationResolver) CreateTodo(ctx context.Context, input model.NewTodo) (*model.Todo, error) {
+ return &model.Todo{
+ ID: input.UserID,
+ Text: input.Text,
+ Done: true,
+ UID: input.UID,
+ }, nil
+}
+
+// Todos is the resolver for the todos field.
+func (r *queryResolver) Todos(ctx context.Context) ([]*model.Todo, error) {
+ return []*model.Todo{
+ {ID: "1", Text: "hello", Done: true, UID: uuid.New()},
+ {ID: "2", Text: "world", Done: false, UID: uuid.New()},
+ }, nil
+}
+
+// Mutation returns MutationResolver implementation.
+func (r *Resolver) Mutation() MutationResolver { return &mutationResolver{r} }
+
+// Query returns QueryResolver implementation.
+func (r *Resolver) Query() QueryResolver { return &queryResolver{r} }
+
+type mutationResolver struct{ *Resolver }
+type queryResolver struct{ *Resolver }
diff --git a/_examples/uuid/server.go b/_examples/uuid/server.go
new file mode 100644
index 0000000000..cb10a9dfa8
--- /dev/null
+++ b/_examples/uuid/server.go
@@ -0,0 +1,28 @@
+package main
+
+import (
+ "log"
+ "net/http"
+ "os"
+
+ "github.com/99designs/gqlgen/_examples/uuid/graph"
+ "github.com/99designs/gqlgen/graphql/handler"
+ "github.com/99designs/gqlgen/graphql/playground"
+)
+
+const defaultPort = "8080"
+
+func main() {
+ port := os.Getenv("PORT")
+ if port == "" {
+ port = defaultPort
+ }
+
+ srv := handler.NewDefaultServer(graph.NewExecutableSchema(graph.Config{Resolvers: &graph.Resolver{}}))
+
+ http.Handle("/", playground.Handler("GraphQL playground", "/query"))
+ http.Handle("/query", srv)
+
+ log.Printf("connect to http://localhost:%s/ for GraphQL playground", port)
+ log.Fatal(http.ListenAndServe(":"+port, nil))
+}
diff --git a/_examples/websocket-initfunc/server/go.mod b/_examples/websocket-initfunc/server/go.mod
index 494e3cbf33..20722874ba 100644
--- a/_examples/websocket-initfunc/server/go.mod
+++ b/_examples/websocket-initfunc/server/go.mod
@@ -7,7 +7,7 @@ require (
github.com/go-chi/chi v1.5.4
github.com/gorilla/websocket v1.5.0
github.com/rs/cors v1.9.0
- github.com/vektah/gqlparser/v2 v2.5.7
+ github.com/vektah/gqlparser/v2 v2.5.10
)
require (
diff --git a/_examples/websocket-initfunc/server/go.sum b/_examples/websocket-initfunc/server/go.sum
index 6be6085a3d..352a0a6587 100644
--- a/_examples/websocket-initfunc/server/go.sum
+++ b/_examples/websocket-initfunc/server/go.sum
@@ -3,12 +3,9 @@ github.com/99designs/gqlgen v0.17.34/go.mod h1:Axcd3jIFHBVcqzixujJQr1wGqE+lGTpz6
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
-github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g=
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
github.com/go-chi/chi v1.5.4 h1:QHdzF2szwjqVV4wmByUnTcsbIg7UGaQ0tPF2t5GcAIs=
@@ -17,25 +14,14 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/golang-lru/v2 v2.0.3 h1:kmRrRLlInXvng0SmLxmQpQkpbYAvcXm7NPDrgxJa9mE=
github.com/hashicorp/golang-lru/v2 v2.0.3/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE=
github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
-github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
-github.com/vektah/gqlparser/v2 v2.5.7 h1:QnW4lWFSaycZ1jqvVaQ/tDXGGzQfqAuWdyC4S9g/KVM=
-github.com/vektah/gqlparser/v2 v2.5.7/go.mod h1:z8xXUff237NntSuH8mLFijZ+1tjV1swDbpDqjJmk6ME=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+github.com/vektah/gqlparser/v2 v2.5.10 h1:6zSM4azXC9u4Nxy5YmdmGu4uKamfwsdKTwp5zsEealU=
+github.com/vektah/gqlparser/v2 v2.5.10/go.mod h1:1rCcfwB2ekJofmluGWXMSEnPMZgbxzwj6FaZ/4OT8Cc=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
-gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
diff --git a/_examples/websocket-initfunc/server/server.go b/_examples/websocket-initfunc/server/server.go
index 4704708dab..7027e9728e 100644
--- a/_examples/websocket-initfunc/server/server.go
+++ b/_examples/websocket-initfunc/server/server.go
@@ -8,22 +8,23 @@ import (
"os"
"time"
- "github.com/99designs/gqlgen/graphql/handler"
- "github.com/99designs/gqlgen/graphql/handler/extension"
- "github.com/99designs/gqlgen/graphql/handler/transport"
- "github.com/99designs/gqlgen/graphql/playground"
"github.com/go-chi/chi"
"github.com/gorilla/websocket"
"github.com/gqlgen/_examples/websocket-initfunc/server/graph"
"github.com/rs/cors"
+
+ "github.com/99designs/gqlgen/graphql/handler"
+ "github.com/99designs/gqlgen/graphql/handler/extension"
+ "github.com/99designs/gqlgen/graphql/handler/transport"
+ "github.com/99designs/gqlgen/graphql/playground"
)
-func webSocketInit(ctx context.Context, initPayload transport.InitPayload) (context.Context, error) {
+func webSocketInit(ctx context.Context, initPayload transport.InitPayload) (context.Context, *transport.InitPayload, error) {
// Get the token from payload
payload := initPayload["authToken"]
token, ok := payload.(string)
if !ok || token == "" {
- return nil, errors.New("authToken not found in transport payload")
+ return nil, nil, errors.New("authToken not found in transport payload")
}
// Perform token verification and authentication...
@@ -32,7 +33,7 @@ func webSocketInit(ctx context.Context, initPayload transport.InitPayload) (cont
// put it in context
ctxNew := context.WithValue(ctx, "username", userId)
- return ctxNew, nil
+ return ctxNew, nil, nil
}
const defaultPort = "8080"
@@ -62,7 +63,7 @@ func main() {
return true
},
},
- InitFunc: func(ctx context.Context, initPayload transport.InitPayload) (context.Context, error) {
+ InitFunc: func(ctx context.Context, initPayload transport.InitPayload) (*transport.InitPayload, context.Context, error) {
return webSocketInit(ctx, initPayload)
},
})
diff --git a/api/generate_test.go b/api/generate_test.go
index 417e6f3060..7778f95343 100644
--- a/api/generate_test.go
+++ b/api/generate_test.go
@@ -5,8 +5,9 @@ import (
"path"
"testing"
- "github.com/99designs/gqlgen/codegen/config"
"github.com/stretchr/testify/require"
+
+ "github.com/99designs/gqlgen/codegen/config"
)
func cleanup(workDir string) {
diff --git a/api/option_test.go b/api/option_test.go
index 5819c4bdd0..d84da902fd 100644
--- a/api/option_test.go
+++ b/api/option_test.go
@@ -3,12 +3,13 @@ package api
import (
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/codegen/config"
"github.com/99designs/gqlgen/plugin"
"github.com/99designs/gqlgen/plugin/federation"
"github.com/99designs/gqlgen/plugin/modelgen"
"github.com/99designs/gqlgen/plugin/resolvergen"
- "github.com/stretchr/testify/require"
)
type testPlugin struct{}
diff --git a/api/testdata/default/graph/generated.go b/api/testdata/default/graph/generated.go
index 386e78e65b..143fa7da3c 100644
--- a/api/testdata/default/graph/generated.go
+++ b/api/testdata/default/graph/generated.go
@@ -24,6 +24,7 @@ import (
// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
return &executableSchema{
+ schema: cfg.Schema,
resolvers: cfg.Resolvers,
directives: cfg.Directives,
complexity: cfg.Complexity,
@@ -31,6 +32,7 @@ func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
}
type Config struct {
+ Schema *ast.Schema
Resolvers ResolverRoot
Directives DirectiveRoot
Complexity ComplexityRoot
@@ -74,12 +76,16 @@ type QueryResolver interface {
}
type executableSchema struct {
+ schema *ast.Schema
resolvers ResolverRoot
directives DirectiveRoot
complexity ComplexityRoot
}
func (e *executableSchema) Schema() *ast.Schema {
+ if e.schema != nil {
+ return e.schema
+ }
return parsedSchema
}
@@ -244,14 +250,14 @@ func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapSchema(parsedSchema), nil
+ return introspection.WrapSchema(ec.Schema()), nil
}
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
+ return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil
}
//go:embed "schema.graphqls"
diff --git a/api/testdata/federation2/graph/generated.go b/api/testdata/federation2/graph/generated.go
index cc5924b8b1..4e6932e824 100644
--- a/api/testdata/federation2/graph/generated.go
+++ b/api/testdata/federation2/graph/generated.go
@@ -25,6 +25,7 @@ import (
// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
return &executableSchema{
+ schema: cfg.Schema,
resolvers: cfg.Resolvers,
directives: cfg.Directives,
complexity: cfg.Complexity,
@@ -32,6 +33,7 @@ func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
}
type Config struct {
+ Schema *ast.Schema
Resolvers ResolverRoot
Directives DirectiveRoot
Complexity ComplexityRoot
@@ -43,8 +45,6 @@ type ResolverRoot interface {
}
type DirectiveRoot struct {
- ComposeDirective func(ctx context.Context, obj interface{}, next graphql.Resolver, name string) (res interface{}, err error)
- InterfaceObject func(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error)
}
type ComplexityRoot struct {
@@ -82,12 +82,16 @@ type QueryResolver interface {
}
type executableSchema struct {
+ schema *ast.Schema
resolvers ResolverRoot
directives DirectiveRoot
complexity ComplexityRoot
}
func (e *executableSchema) Schema() *ast.Schema {
+ if e.schema != nil {
+ return e.schema
+ }
return parsedSchema
}
@@ -266,14 +270,14 @@ func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapSchema(parsedSchema), nil
+ return introspection.WrapSchema(ec.Schema()), nil
}
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
+ return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil
}
//go:embed "schema.graphqls"
@@ -290,6 +294,7 @@ func sourceData(filename string) string {
var sources = []*ast.Source{
{Name: "schema.graphqls", Input: sourceData("schema.graphqls"), BuiltIn: false},
{Name: "../federation/directives.graphql", Input: `
+ directive @authenticated on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM
directive @composeDirective(name: String!) repeatable on SCHEMA
directive @extends on OBJECT | INTERFACE
directive @external on OBJECT | FIELD_DEFINITION
@@ -310,6 +315,12 @@ var sources = []*ast.Source{
directive @override(from: String!) on FIELD_DEFINITION
directive @provides(fields: FieldSet!) on FIELD_DEFINITION
directive @requires(fields: FieldSet!) on FIELD_DEFINITION
+ directive @requiresScopes(scopes: [[federation__Scope!]!]!) on
+ | FIELD_DEFINITION
+ | OBJECT
+ | INTERFACE
+ | SCALAR
+ | ENUM
directive @shareable repeatable on FIELD_DEFINITION | OBJECT
directive @tag(name: String!) repeatable on
| ARGUMENT_DEFINITION
@@ -324,6 +335,7 @@ var sources = []*ast.Source{
| UNION
scalar _Any
scalar FieldSet
+ scalar federation__Scope
`, BuiltIn: true},
{Name: "../federation/entity.graphql", Input: `
type _Service {
@@ -341,21 +353,6 @@ var parsedSchema = gqlparser.MustLoadSchema(sources...)
// region ***************************** args.gotpl *****************************
-func (ec *executionContext) dir_composeDirective_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
- var err error
- args := map[string]interface{}{}
- var arg0 string
- if tmp, ok := rawArgs["name"]; ok {
- ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name"))
- arg0, err = ec.unmarshalNString2string(ctx, tmp)
- if err != nil {
- return nil, err
- }
- }
- args["name"] = arg0
- return args, nil
-}
-
func (ec *executionContext) field_Mutation_createTodo_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
@@ -3843,6 +3840,85 @@ func (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel a
return res
}
+func (ec *executionContext) unmarshalNfederation__Scope2string(ctx context.Context, v interface{}) (string, error) {
+ res, err := graphql.UnmarshalString(v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) marshalNfederation__Scope2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler {
+ res := graphql.MarshalString(v)
+ if res == graphql.Null {
+ if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
+ ec.Errorf(ctx, "the requested element is null which the schema does not allow")
+ }
+ }
+ return res
+}
+
+func (ec *executionContext) unmarshalNfederation__Scope2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) {
+ var vSlice []interface{}
+ if v != nil {
+ vSlice = graphql.CoerceList(v)
+ }
+ var err error
+ res := make([]string, len(vSlice))
+ for i := range vSlice {
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i))
+ res[i], err = ec.unmarshalNfederation__Scope2string(ctx, vSlice[i])
+ if err != nil {
+ return nil, err
+ }
+ }
+ return res, nil
+}
+
+func (ec *executionContext) marshalNfederation__Scope2ᚕstringᚄ(ctx context.Context, sel ast.SelectionSet, v []string) graphql.Marshaler {
+ ret := make(graphql.Array, len(v))
+ for i := range v {
+ ret[i] = ec.marshalNfederation__Scope2string(ctx, sel, v[i])
+ }
+
+ for _, e := range ret {
+ if e == graphql.Null {
+ return graphql.Null
+ }
+ }
+
+ return ret
+}
+
+func (ec *executionContext) unmarshalNfederation__Scope2ᚕᚕstringᚄ(ctx context.Context, v interface{}) ([][]string, error) {
+ var vSlice []interface{}
+ if v != nil {
+ vSlice = graphql.CoerceList(v)
+ }
+ var err error
+ res := make([][]string, len(vSlice))
+ for i := range vSlice {
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i))
+ res[i], err = ec.unmarshalNfederation__Scope2ᚕstringᚄ(ctx, vSlice[i])
+ if err != nil {
+ return nil, err
+ }
+ }
+ return res, nil
+}
+
+func (ec *executionContext) marshalNfederation__Scope2ᚕᚕstringᚄ(ctx context.Context, sel ast.SelectionSet, v [][]string) graphql.Marshaler {
+ ret := make(graphql.Array, len(v))
+ for i := range v {
+ ret[i] = ec.marshalNfederation__Scope2ᚕstringᚄ(ctx, sel, v[i])
+ }
+
+ for _, e := range ret {
+ if e == graphql.Null {
+ return graphql.Null
+ }
+ }
+
+ return ret
+}
+
func (ec *executionContext) unmarshalOBoolean2bool(ctx context.Context, v interface{}) (bool, error) {
res, err := graphql.UnmarshalBoolean(v)
return res, graphql.ErrorOnPath(ctx, err)
diff --git a/client/client_test.go b/client/client_test.go
index 4755ca5fa8..d7b95dcae2 100644
--- a/client/client_test.go
+++ b/client/client_test.go
@@ -12,9 +12,10 @@ import (
"testing"
"time"
- "github.com/99designs/gqlgen/client"
"github.com/mitchellh/mapstructure"
"github.com/stretchr/testify/require"
+
+ "github.com/99designs/gqlgen/client"
)
func TestClient(t *testing.T) {
diff --git a/client/withfilesoption_test.go b/client/withfilesoption_test.go
index dbb7756cd7..054c3622fe 100644
--- a/client/withfilesoption_test.go
+++ b/client/withfilesoption_test.go
@@ -10,8 +10,9 @@ import (
"strings"
"testing"
- "github.com/99designs/gqlgen/client"
"github.com/stretchr/testify/require"
+
+ "github.com/99designs/gqlgen/client"
)
func TestWithFiles(t *testing.T) {
diff --git a/codegen/args.go b/codegen/args.go
index c4cecea932..2f174332c7 100644
--- a/codegen/args.go
+++ b/codegen/args.go
@@ -5,9 +5,10 @@ import (
"go/types"
"strings"
+ "github.com/vektah/gqlparser/v2/ast"
+
"github.com/99designs/gqlgen/codegen/config"
"github.com/99designs/gqlgen/codegen/templates"
- "github.com/vektah/gqlparser/v2/ast"
)
type ArgSet struct {
diff --git a/codegen/config/binder.go b/codegen/config/binder.go
index 0483afdbdf..dd25d6f5e6 100644
--- a/codegen/config/binder.go
+++ b/codegen/config/binder.go
@@ -5,12 +5,12 @@ import (
"fmt"
"go/token"
"go/types"
- "strings"
+ "github.com/vektah/gqlparser/v2/ast"
"golang.org/x/tools/go/packages"
+ "github.com/99designs/gqlgen/codegen/templates"
"github.com/99designs/gqlgen/internal/code"
- "github.com/vektah/gqlparser/v2/ast"
)
var ErrTypeNotFound = errors.New("unable to find type")
@@ -274,6 +274,10 @@ func (ref *TypeReference) IsScalar() bool {
return ref.Definition.Kind == ast.Scalar
}
+func (ref *TypeReference) IsMap() bool {
+ return ref.GO == MapType
+}
+
func (ref *TypeReference) UniquenessKey() string {
nullability := "O"
if ref.GQL.NonNull {
@@ -285,7 +289,7 @@ func (ref *TypeReference) UniquenessKey() string {
// Fix for #896
elemNullability = "ᚄ"
}
- return nullability + ref.Definition.Name + "2" + TypeIdentifier(ref.GO) + elemNullability
+ return nullability + ref.Definition.Name + "2" + templates.TypeIdentifier(ref.GO) + elemNullability
}
func (ref *TypeReference) MarshalFunc() string {
@@ -540,41 +544,3 @@ func basicUnderlying(it types.Type) *types.Basic {
return nil
}
-
-var pkgReplacer = strings.NewReplacer(
- "/", "ᚋ",
- ".", "ᚗ",
- "-", "ᚑ",
- "~", "א",
-)
-
-func TypeIdentifier(t types.Type) string {
- res := ""
- for {
- switch it := t.(type) {
- case *types.Pointer:
- t.Underlying()
- res += "ᚖ"
- t = it.Elem()
- case *types.Slice:
- res += "ᚕ"
- t = it.Elem()
- case *types.Named:
- res += pkgReplacer.Replace(it.Obj().Pkg().Path())
- res += "ᚐ"
- res += it.Obj().Name()
- return res
- case *types.Basic:
- res += it.Name()
- return res
- case *types.Map:
- res += "map"
- return res
- case *types.Interface:
- res += "interface"
- return res
- default:
- panic(fmt.Errorf("unexpected type %T", it))
- }
- }
-}
diff --git a/codegen/config/binder_test.go b/codegen/config/binder_test.go
index fed3913adb..f436a8efe3 100644
--- a/codegen/config/binder_test.go
+++ b/codegen/config/binder_test.go
@@ -4,11 +4,11 @@ import (
"go/types"
"testing"
- "github.com/99designs/gqlgen/internal/code"
-
"github.com/stretchr/testify/require"
"github.com/vektah/gqlparser/v2"
"github.com/vektah/gqlparser/v2/ast"
+
+ "github.com/99designs/gqlgen/internal/code"
)
func TestBindingToInvalid(t *testing.T) {
@@ -187,7 +187,7 @@ func createBinder(cfg Config) (*Binder, *ast.Schema) {
Model: []string{"github.com/99designs/gqlgen/graphql.String"},
},
}
- cfg.Packages = &code.Packages{}
+ cfg.Packages = code.NewPackages()
cfg.Schema = gqlparser.MustLoadSchema(&ast.Source{Name: "TestAutobinding.schema", Input: `
type Message { id: ID }
diff --git a/codegen/config/config.go b/codegen/config/config.go
index 8a7205f06b..50ccaeffda 100644
--- a/codegen/config/config.go
+++ b/codegen/config/config.go
@@ -3,6 +3,7 @@ package config
import (
"bytes"
"fmt"
+ "go/types"
"io"
"os"
"path/filepath"
@@ -10,10 +11,13 @@ import (
"sort"
"strings"
- "github.com/99designs/gqlgen/internal/code"
"github.com/vektah/gqlparser/v2"
"github.com/vektah/gqlparser/v2/ast"
+ "golang.org/x/tools/go/packages"
"gopkg.in/yaml.v3"
+
+ "github.com/99designs/gqlgen/codegen/templates"
+ "github.com/99designs/gqlgen/internal/code"
)
type Config struct {
@@ -26,6 +30,7 @@ type Config struct {
Models TypeMap `yaml:"models,omitempty"`
StructTag string `yaml:"struct_tag,omitempty"`
Directives map[string]DirectiveConfig `yaml:"directives,omitempty"`
+ GoBuildTags StringList `yaml:"go_build_tags,omitempty"`
GoInitialisms GoInitialismsConfig `yaml:"go_initialisms,omitempty"`
OmitSliceElementPointers bool `yaml:"omit_slice_element_pointers,omitempty"`
OmitGetters bool `yaml:"omit_getters,omitempty"`
@@ -211,7 +216,9 @@ func CompleteConfig(config *Config) error {
func (c *Config) Init() error {
if c.Packages == nil {
- c.Packages = &code.Packages{}
+ c.Packages = code.NewPackages(
+ code.WithBuildTags(c.GoBuildTags...),
+ )
}
if c.Schema == nil {
@@ -281,6 +288,7 @@ func (c *Config) injectTypesFromSchema() error {
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{}) {
@@ -288,6 +296,12 @@ func (c *Config) injectTypesFromSchema() error {
}
}
}
+
+ if fg := bd.Arguments.ForName("forceGenerate"); fg != nil {
+ if mv, err := fg.Value.Value(nil); err == nil {
+ c.Models.ForceGenerate(schemaType.Name, mv.(bool))
+ }
+ }
}
if schemaType.Kind == ast.Object || schemaType.Kind == ast.InputObject {
@@ -329,8 +343,9 @@ func (c *Config) injectTypesFromSchema() error {
}
type TypeMapEntry struct {
- Model StringList `yaml:"model"`
- Fields map[string]TypeMapField `yaml:"fields,omitempty"`
+ Model StringList `yaml:"model,omitempty"`
+ ForceGenerate bool `yaml:"forceGenerate,omitempty"`
+ Fields map[string]TypeMapField `yaml:"fields,omitempty"`
// Key is the Go name of the field.
ExtraFields map[string]ModelExtraField `yaml:"extraFields,omitempty"`
@@ -529,6 +544,12 @@ func (tm TypeMap) Add(name string, goType string) {
tm[name] = modelCfg
}
+func (tm TypeMap) ForceGenerate(name string, forceGenerate bool) {
+ modelCfg := tm[name]
+ modelCfg.ForceGenerate = forceGenerate
+ tm[name] = modelCfg
+}
+
type DirectiveConfig struct {
SkipRuntime bool `yaml:"skip_runtime"`
}
@@ -583,7 +604,7 @@ func (c *Config) autobind() error {
ps := c.Packages.LoadAll(c.AutoBind...)
for _, t := range c.Schema.Types {
- if c.Models.UserDefined(t.Name) {
+ if c.Models.UserDefined(t.Name) || c.Models[t.Name].ForceGenerate {
continue
}
@@ -591,14 +612,20 @@ func (c *Config) autobind() error {
if p == nil || p.Module == nil {
return fmt.Errorf("unable to load %s - make sure you're using an import path to a package that exists", c.AutoBind[i])
}
- if t := p.Types.Scope().Lookup(t.Name); t != nil {
- c.Models.Add(t.Name(), t.Pkg().Path()+"."+t.Name())
+
+ autobindType := c.lookupAutobindType(p, t)
+ if autobindType != nil {
+ c.Models.Add(t.Name, autobindType.Pkg().Path()+"."+autobindType.Name())
break
}
}
}
for i, t := range c.Models {
+ if t.ForceGenerate {
+ continue
+ }
+
for j, m := range t.Model {
pkg, typename := code.PkgAndType(m)
@@ -622,6 +649,17 @@ func (c *Config) autobind() error {
return nil
}
+func (c *Config) lookupAutobindType(p *packages.Package, schemaType *ast.Definition) types.Object {
+ // Try binding to either the original schema type name, or the normalized go type name
+ for _, lookupName := range []string{schemaType.Name, templates.ToGo(schemaType.Name)} {
+ if t := p.Types.Scope().Lookup(lookupName); t != nil {
+ return t
+ }
+ }
+
+ return nil
+}
+
func (c *Config) injectBuiltins() {
builtins := TypeMap{
"__Directive": {Model: StringList{"github.com/99designs/gqlgen/graphql/introspection.Directive"}},
@@ -671,7 +709,9 @@ func (c *Config) injectBuiltins() {
func (c *Config) LoadSchema() error {
if c.Packages != nil {
- c.Packages = &code.Packages{}
+ c.Packages = code.NewPackages(
+ code.WithBuildTags(c.GoBuildTags...),
+ )
}
if err := c.check(); err != nil {
diff --git a/codegen/config/config_test.go b/codegen/config/config_test.go
index 2ed5d5ac86..c8cb42ea3a 100644
--- a/codegen/config/config_test.go
+++ b/codegen/config/config_test.go
@@ -192,7 +192,7 @@ func TestAutobinding(t *testing.T) {
"github.com/99designs/gqlgen/codegen/config/testdata/autobinding/chat",
"github.com/99designs/gqlgen/codegen/config/testdata/autobinding/scalars/model",
},
- Packages: &code.Packages{},
+ Packages: code.NewPackages(),
}
cfg.Schema = gqlparser.MustLoadSchema(&ast.Source{Name: "TestAutobinding.schema", Input: `
@@ -206,13 +206,38 @@ func TestAutobinding(t *testing.T) {
require.Equal(t, "github.com/99designs/gqlgen/codegen/config/testdata/autobinding/chat.Message", cfg.Models["Message"].Model[0])
})
+ t.Run("normalized type names", func(t *testing.T) {
+ cfg := Config{
+ Models: TypeMap{},
+ AutoBind: []string{
+ "github.com/99designs/gqlgen/codegen/config/testdata/autobinding/chat",
+ "github.com/99designs/gqlgen/codegen/config/testdata/autobinding/scalars/model",
+ },
+ Packages: code.NewPackages(),
+ }
+
+ cfg.Schema = gqlparser.MustLoadSchema(&ast.Source{Name: "TestAutobinding.schema", Input: `
+ scalar Banned
+ type Message { id: ID }
+ enum ProductSKU { ProductSkuTrial }
+ type ChatAPI { id: ID }
+ `})
+
+ require.NoError(t, cfg.autobind())
+
+ require.Equal(t, "github.com/99designs/gqlgen/codegen/config/testdata/autobinding/scalars/model.Banned", cfg.Models["Banned"].Model[0])
+ require.Equal(t, "github.com/99designs/gqlgen/codegen/config/testdata/autobinding/chat.Message", cfg.Models["Message"].Model[0])
+ require.Equal(t, "github.com/99designs/gqlgen/codegen/config/testdata/autobinding/chat.ProductSku", cfg.Models["ProductSKU"].Model[0])
+ require.Equal(t, "github.com/99designs/gqlgen/codegen/config/testdata/autobinding/chat.ChatAPI", cfg.Models["ChatAPI"].Model[0])
+ })
+
t.Run("with file path", func(t *testing.T) {
cfg := Config{
Models: TypeMap{},
AutoBind: []string{
"../chat",
},
- Packages: &code.Packages{},
+ Packages: code.NewPackages(),
}
cfg.Schema = gqlparser.MustLoadSchema(&ast.Source{Name: "TestAutobinding.schema", Input: `
diff --git a/codegen/config/initialisms.go b/codegen/config/initialisms.go
index 5c169c8900..25e7331f8a 100644
--- a/codegen/config/initialisms.go
+++ b/codegen/config/initialisms.go
@@ -1,62 +1,10 @@
package config
-import "strings"
+import (
+ "strings"
-// commonInitialisms is a set of common initialisms.
-// Only add entries that are highly unlikely to be non-initialisms.
-// For instance, "ID" is fine (Freudian code is rare), but "AND" is not.
-var commonInitialisms = map[string]bool{
- "ACL": true,
- "API": true,
- "ASCII": true,
- "CPU": true,
- "CSS": true,
- "CSV": true,
- "DNS": true,
- "EOF": true,
- "GUID": true,
- "HTML": true,
- "HTTP": true,
- "HTTPS": true,
- "ICMP": true,
- "ID": true,
- "IP": true,
- "JSON": true,
- "KVK": true,
- "LHS": true,
- "PDF": true,
- "PGP": true,
- "QPS": true,
- "QR": true,
- "RAM": true,
- "RHS": true,
- "RPC": true,
- "SLA": true,
- "SMTP": true,
- "SQL": true,
- "SSH": true,
- "SVG": true,
- "TCP": true,
- "TLS": true,
- "TTL": true,
- "UDP": true,
- "UI": true,
- "UID": true,
- "URI": true,
- "URL": true,
- "UTF8": true,
- "UUID": true,
- "VM": true,
- "XML": true,
- "XMPP": true,
- "XSRF": true,
- "XSS": true,
-}
-
-// GetInitialisms returns the initialisms to capitalize in Go names. If unchanged, default initialisms will be returned
-var GetInitialisms = func() map[string]bool {
- return commonInitialisms
-}
+ "github.com/99designs/gqlgen/codegen/templates"
+)
// GoInitialismsConfig allows to modify the default behavior of naming Go methods, types and properties
type GoInitialismsConfig struct {
@@ -69,7 +17,7 @@ type GoInitialismsConfig struct {
// setInitialisms adjustes GetInitialisms based on its settings.
func (i GoInitialismsConfig) setInitialisms() {
toUse := i.determineGoInitialisms()
- GetInitialisms = func() map[string]bool {
+ templates.GetInitialisms = func() map[string]bool {
return toUse
}
}
@@ -82,8 +30,8 @@ func (i GoInitialismsConfig) determineGoInitialisms() (initialismsToUse map[stri
initialismsToUse[strings.ToUpper(initialism)] = true
}
} else {
- initialismsToUse = make(map[string]bool, len(commonInitialisms)+len(i.Initialisms))
- for initialism, value := range commonInitialisms {
+ initialismsToUse = make(map[string]bool, len(templates.CommonInitialisms)+len(i.Initialisms))
+ for initialism, value := range templates.CommonInitialisms {
initialismsToUse[strings.ToUpper(initialism)] = value
}
for _, initialism := range i.Initialisms {
diff --git a/codegen/config/initialisms_test.go b/codegen/config/initialisms_test.go
index 5bea561a3a..13c0da2465 100644
--- a/codegen/config/initialisms_test.go
+++ b/codegen/config/initialisms_test.go
@@ -5,6 +5,8 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+
+ "github.com/99designs/gqlgen/codegen/templates"
)
func TestGoInitialismsConfig(t *testing.T) {
@@ -17,12 +19,12 @@ func TestGoInitialismsConfig(t *testing.T) {
t.Run("empty initialism config doesn't change anything", func(t *testing.T) {
tt := GoInitialismsConfig{}
result := tt.determineGoInitialisms()
- assert.Equal(t, len(commonInitialisms), len(result))
+ assert.Equal(t, len(templates.CommonInitialisms), len(result))
})
t.Run("initialism config appends if desired", func(t *testing.T) {
tt := GoInitialismsConfig{ReplaceDefaults: false, Initialisms: []string{"ASDF"}}
result := tt.determineGoInitialisms()
- assert.Equal(t, len(commonInitialisms)+1, len(result))
+ assert.Equal(t, len(templates.CommonInitialisms)+1, len(result))
assert.True(t, result["ASDF"])
})
t.Run("initialism config replaces if desired", func(t *testing.T) {
diff --git a/codegen/config/package.go b/codegen/config/package.go
index faacd1496f..37692ece7e 100644
--- a/codegen/config/package.go
+++ b/codegen/config/package.go
@@ -10,9 +10,10 @@ import (
)
type PackageConfig struct {
- Filename string `yaml:"filename,omitempty"`
- Package string `yaml:"package,omitempty"`
- Version int `yaml:"version,omitempty"`
+ Filename string `yaml:"filename,omitempty"`
+ Package string `yaml:"package,omitempty"`
+ Version int `yaml:"version,omitempty"`
+ ModelTemplate string `yaml:"model_template,omitempty"`
}
func (c *PackageConfig) ImportPath() string {
diff --git a/codegen/config/resolver.go b/codegen/config/resolver.go
index a3ec38f8e2..cb5fb72b36 100644
--- a/codegen/config/resolver.go
+++ b/codegen/config/resolver.go
@@ -17,6 +17,7 @@ type ResolverConfig struct {
Layout ResolverLayout `yaml:"layout,omitempty"`
DirName string `yaml:"dir"`
OmitTemplateComment bool `yaml:"omit_template_comment,omitempty"`
+ ResolverTemplate string `yaml:"resolver_template,omitempty"`
}
type ResolverLayout string
diff --git a/codegen/config/testdata/autobinding/chat/message.go b/codegen/config/testdata/autobinding/chat/model.go
similarity index 62%
rename from codegen/config/testdata/autobinding/chat/message.go
rename to codegen/config/testdata/autobinding/chat/model.go
index b35be48c93..fa621ee90a 100644
--- a/codegen/config/testdata/autobinding/chat/message.go
+++ b/codegen/config/testdata/autobinding/chat/model.go
@@ -10,3 +10,13 @@ type Message struct {
CreatedBy string `json:"createdBy"`
CreatedAt time.Time `json:"createdAt"`
}
+
+type ProductSku string
+
+const (
+ ProductSkuTrial ProductSku = "Trial"
+)
+
+type ChatAPI struct {
+ ID string `json:"id"`
+}
diff --git a/codegen/data_test.go b/codegen/data_test.go
index a1ac4d3df9..64ca8c621f 100644
--- a/codegen/data_test.go
+++ b/codegen/data_test.go
@@ -3,10 +3,10 @@ package codegen
import (
"testing"
- "github.com/99designs/gqlgen/codegen/config"
+ "github.com/stretchr/testify/assert"
"github.com/vektah/gqlparser/v2/ast"
- "github.com/stretchr/testify/assert"
+ "github.com/99designs/gqlgen/codegen/config"
)
func TestData_Directives(t *testing.T) {
diff --git a/codegen/directive.go b/codegen/directive.go
index 973061129a..f955665be8 100644
--- a/codegen/directive.go
+++ b/codegen/directive.go
@@ -5,8 +5,9 @@ import (
"strconv"
"strings"
- "github.com/99designs/gqlgen/codegen/templates"
"github.com/vektah/gqlparser/v2/ast"
+
+ "github.com/99designs/gqlgen/codegen/templates"
)
type DirectiveList map[string]*Directive
diff --git a/codegen/field.go b/codegen/field.go
index a7e1fb2ba6..6d11538a02 100644
--- a/codegen/field.go
+++ b/codegen/field.go
@@ -10,11 +10,12 @@ import (
"strconv"
"strings"
- "github.com/99designs/gqlgen/codegen/config"
- "github.com/99designs/gqlgen/codegen/templates"
"github.com/vektah/gqlparser/v2/ast"
"golang.org/x/text/cases"
"golang.org/x/text/language"
+
+ "github.com/99designs/gqlgen/codegen/config"
+ "github.com/99designs/gqlgen/codegen/templates"
)
type Field struct {
diff --git a/codegen/field_test.go b/codegen/field_test.go
index 642d2d3f5c..0d5eb16216 100644
--- a/codegen/field_test.go
+++ b/codegen/field_test.go
@@ -8,9 +8,10 @@ import (
"go/types"
"testing"
- "github.com/99designs/gqlgen/codegen/config"
"github.com/stretchr/testify/require"
ast2 "github.com/vektah/gqlparser/v2/ast"
+
+ "github.com/99designs/gqlgen/codegen/config"
)
func TestFindField(t *testing.T) {
diff --git a/codegen/generate.go b/codegen/generate.go
index 1ce8c329dc..d63758abf1 100644
--- a/codegen/generate.go
+++ b/codegen/generate.go
@@ -9,9 +9,10 @@ import (
"runtime"
"strings"
+ "github.com/vektah/gqlparser/v2/ast"
+
"github.com/99designs/gqlgen/codegen/config"
"github.com/99designs/gqlgen/codegen/templates"
- "github.com/vektah/gqlparser/v2/ast"
)
//go:embed *.gotpl
diff --git a/codegen/generated!.gotpl b/codegen/generated!.gotpl
index ae1da002e8..eb3baf7054 100644
--- a/codegen/generated!.gotpl
+++ b/codegen/generated!.gotpl
@@ -18,6 +18,7 @@
// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
return &executableSchema{
+ schema: cfg.Schema,
resolvers: cfg.Resolvers,
directives: cfg.Directives,
complexity: cfg.Complexity,
@@ -25,6 +26,7 @@
}
type Config struct {
+ Schema *ast.Schema
Resolvers ResolverRoot
Directives DirectiveRoot
Complexity ComplexityRoot
@@ -93,6 +95,7 @@
{{ if eq .Config.Exec.Layout "single-file" }}
type executableSchema struct {
+ schema *ast.Schema
resolvers ResolverRoot
directives DirectiveRoot
complexity ComplexityRoot
@@ -112,6 +115,10 @@
func (e *executableSchema) Schema() *ast.Schema {
return gqlparser.MustLoadSchema(e.sources...)
+ // if e.schema != nil {
+ // return e.schema
+ // }
+ // return parsedSchema
}
func (e *executableSchema) Complexity(typeName, field string, childComplexity int, rawArgs map[string]interface{}) (int, bool) {
@@ -280,14 +287,14 @@
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapSchema(parsedSchema), nil
+ return introspection.WrapSchema(ec.Schema()), nil
}
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
+ return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil
}
{{if .HasEmbeddableSources }}
diff --git a/codegen/input.gotpl b/codegen/input.gotpl
index dcd125399a..a30c28d9a0 100644
--- a/codegen/input.gotpl
+++ b/codegen/input.gotpl
@@ -5,7 +5,11 @@
{{- $it = "&it" }}
{{- end }}
func (ec *executionContext) unmarshalInput{{ .Name }}(ctx context.Context, obj interface{}) ({{ if .PointersInUmarshalInput }}*{{ end }}{{.Type | ref}}, error) {
- var it {{.Type | ref}}
+ {{- if $input.IsMap }}
+ it := make(map[string]interface{}, len(obj.(map[string]interface{})))
+ {{- else }}
+ var it {{.Type | ref}}
+ {{- end }}
asMap := map[string]interface{}{}
for k, v := range obj.(map[string]interface{}) {
asMap[k] = v
@@ -29,6 +33,11 @@
case {{$field.Name|quote}}:
var err error
+ {{- $lhs := (printf "it.%s" $field.GoFieldName) }}
+ {{- if $input.IsMap }}
+ {{- $lhs = (printf "it[%q]" $field.Name) }}
+ {{- end }}
+
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField({{$field.Name|quote}}))
{{- if $field.ImplDirectives }}
directive0 := func(ctx context.Context) (interface{}, error) { return ec.{{ $field.TypeReference.UnmarshalFunc }}(ctx, v) }
@@ -44,18 +53,18 @@
}
{{- else }}
{{- if $field.TypeReference.IsOmittable }}
- it.{{$field.GoFieldName}} = graphql.OmittableOf(data)
+ {{ $lhs }} = graphql.OmittableOf(data)
{{- else }}
- it.{{$field.GoFieldName}} = data
+ {{ $lhs }} = data
{{- end }}
{{- end }}
{{- if $field.TypeReference.IsNilable }}
{{- if not $field.IsResolver }}
} else if tmp == nil {
{{- if $field.TypeReference.IsOmittable }}
- it.{{$field.GoFieldName}} = graphql.OmittableOf[{{ $field.TypeReference.GO | ref }}](nil)
+ {{ $lhs }} = graphql.OmittableOf[{{ $field.TypeReference.GO | ref }}](nil)
{{- else }}
- it.{{$field.GoFieldName}} = nil
+ {{ $lhs }} = nil
{{- end }}
{{- end }}
{{- end }}
@@ -78,9 +87,9 @@
return {{$it}}, err
}
{{- if $field.TypeReference.IsOmittable }}
- it.{{$field.GoFieldName}} = graphql.OmittableOf(data)
+ {{ $lhs }} = graphql.OmittableOf(data)
{{- else }}
- it.{{$field.GoFieldName}} = data
+ {{ $lhs }} = data
{{- end }}
{{- end }}
{{- end }}
diff --git a/codegen/object.go b/codegen/object.go
index 8609232719..97575f30a8 100644
--- a/codegen/object.go
+++ b/codegen/object.go
@@ -7,10 +7,11 @@ import (
"strings"
"unicode"
- "github.com/99designs/gqlgen/codegen/config"
"github.com/vektah/gqlparser/v2/ast"
"golang.org/x/text/cases"
"golang.org/x/text/language"
+
+ "github.com/99designs/gqlgen/codegen/config"
)
type GoFieldType int
@@ -112,8 +113,8 @@ func (o *Object) HasResolvers() bool {
}
func (o *Object) HasUnmarshal() bool {
- if o.Type == config.MapType {
- return true
+ if o.IsMap() {
+ return false
}
for i := 0; i < o.Type.(*types.Named).NumMethods(); i++ {
if o.Type.(*types.Named).Method(i).Name() == "UnmarshalGQL" {
@@ -149,6 +150,10 @@ func (o *Object) IsReserved() bool {
return strings.HasPrefix(o.Definition.Name, "__")
}
+func (o *Object) IsMap() bool {
+ return o.Type == config.MapType
+}
+
func (o *Object) Description() string {
return o.Definition.Description
}
diff --git a/codegen/root_.gotpl b/codegen/root_.gotpl
index e1cfa1cf0a..6429e97d80 100644
--- a/codegen/root_.gotpl
+++ b/codegen/root_.gotpl
@@ -17,6 +17,7 @@
// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
return &executableSchema{
+ schema: cfg.Schema,
resolvers: cfg.Resolvers,
directives: cfg.Directives,
complexity: cfg.Complexity,
@@ -25,6 +26,7 @@ func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
}
type Config struct {
+ Schema *ast.Schema
Resolvers ResolverRoot
Directives DirectiveRoot
Complexity ComplexityRoot
@@ -67,6 +69,7 @@ type ComplexityRoot struct {
}
type executableSchema struct {
+ schema *ast.Schema
resolvers ResolverRoot
directives DirectiveRoot
complexity ComplexityRoot
@@ -84,6 +87,10 @@ func (es *executableSchema) afterUnmarshalInput(ctx context.Context, obj interfa
}
func (e *executableSchema) Schema() *ast.Schema {
return gqlparser.MustLoadSchema(e.sources...)
+ // if e.schema != nil {
+ // return e.schema
+ // }
+ // return parsedSchema
}
func (e *executableSchema) Complexity(typeName, field string, childComplexity int, rawArgs map[string]interface{}) (int, bool) {
@@ -252,14 +259,14 @@ func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapSchema(parsedSchema), nil
+ return introspection.WrapSchema(ec.Schema()), nil
}
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
+ return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil
}
diff --git a/codegen/templates/import_test.go b/codegen/templates/import_test.go
index baf88b50ab..d709f72cc9 100644
--- a/codegen/templates/import_test.go
+++ b/codegen/templates/import_test.go
@@ -6,9 +6,9 @@ import (
"os"
"testing"
- "github.com/99designs/gqlgen/internal/code"
-
"github.com/stretchr/testify/require"
+
+ "github.com/99designs/gqlgen/internal/code"
)
func TestImports(t *testing.T) {
@@ -20,14 +20,14 @@ func TestImports(t *testing.T) {
mismatch := "github.com/99designs/gqlgen/codegen/templates/testdata/pkg_mismatch"
t.Run("multiple lookups is ok", func(t *testing.T) {
- a := Imports{destDir: wd, packages: &code.Packages{}}
+ a := Imports{destDir: wd, packages: code.NewPackages()}
require.Equal(t, "bar", a.Lookup(aBar))
require.Equal(t, "bar", a.Lookup(aBar))
})
t.Run("lookup by type", func(t *testing.T) {
- a := Imports{destDir: wd, packages: &code.Packages{}}
+ a := Imports{destDir: wd, packages: code.NewPackages()}
pkg := types.NewPackage("github.com/99designs/gqlgen/codegen/templates/testdata/b/bar", "bar")
typ := types.NewNamed(types.NewTypeName(0, pkg, "Boolean", types.Typ[types.Bool]), types.Typ[types.Bool], nil)
@@ -36,7 +36,7 @@ func TestImports(t *testing.T) {
})
t.Run("duplicates are decollisioned", func(t *testing.T) {
- a := Imports{destDir: wd, packages: &code.Packages{}}
+ a := Imports{destDir: wd, packages: code.NewPackages()}
require.Equal(t, "bar", a.Lookup(aBar))
require.Equal(t, "bar1", a.Lookup(bBar))
@@ -47,7 +47,7 @@ func TestImports(t *testing.T) {
})
t.Run("duplicates above 10 are decollisioned", func(t *testing.T) {
- a := Imports{destDir: wd, packages: &code.Packages{}}
+ a := Imports{destDir: wd, packages: code.NewPackages()}
for i := 0; i < 100; i++ {
cBar := fmt.Sprintf("github.com/99designs/gqlgen/codegen/templates/testdata/%d/bar", i)
if i > 0 {
@@ -59,13 +59,13 @@ func TestImports(t *testing.T) {
})
t.Run("package name defined in code will be used", func(t *testing.T) {
- a := Imports{destDir: wd, packages: &code.Packages{}}
+ a := Imports{destDir: wd, packages: code.NewPackages()}
require.Equal(t, "turtles", a.Lookup(mismatch))
})
t.Run("string printing for import block", func(t *testing.T) {
- a := Imports{destDir: wd, packages: &code.Packages{}}
+ a := Imports{destDir: wd, packages: code.NewPackages()}
a.Lookup(aBar)
a.Lookup(bBar)
a.Lookup(mismatch)
@@ -80,7 +80,7 @@ turtles "github.com/99designs/gqlgen/codegen/templates/testdata/pkg_mismatch"`,
})
t.Run("aliased imports will not collide", func(t *testing.T) {
- a := Imports{destDir: wd, packages: &code.Packages{}}
+ a := Imports{destDir: wd, packages: code.NewPackages()}
_, _ = a.Reserve(aBar, "abar")
_, _ = a.Reserve(bBar, "bbar")
diff --git a/codegen/templates/templates.go b/codegen/templates/templates.go
index 332498f878..4a4e91594e 100644
--- a/codegen/templates/templates.go
+++ b/codegen/templates/templates.go
@@ -17,7 +17,6 @@ import (
"text/template"
"unicode"
- "github.com/99designs/gqlgen/codegen/config"
"github.com/99designs/gqlgen/internal/code"
"github.com/99designs/gqlgen/internal/imports"
)
@@ -172,7 +171,7 @@ func parseTemplates(cfg Options, t *template.Template) (*template.Template, erro
fileSystem = cfg.TemplateFS
} else {
// load path relative to calling source file
- _, callerFile, _, _ := runtime.Caller(1)
+ _, callerFile, _, _ := runtime.Caller(2)
rootDir := filepath.Dir(callerFile)
fileSystem = os.DirFS(rootDir)
}
@@ -202,7 +201,7 @@ func Funcs() template.FuncMap {
"rawQuote": rawQuote,
"dump": Dump,
"ref": ref,
- "ts": config.TypeIdentifier,
+ "ts": TypeIdentifier,
"call": Call,
"prefixLines": prefixLines,
"notNil": notNil,
@@ -465,7 +464,7 @@ func wordWalker(str string, f func(*wordInfo)) {
}
i++
- initialisms := config.GetInitialisms()
+ initialisms := GetInitialisms()
// [w,i) is a word.
word := string(runes[w:i])
if !eow && initialisms[word] && !unicode.IsLower(runes[i]) {
@@ -668,3 +667,97 @@ func write(filename string, b []byte, packages *code.Packages) error {
return nil
}
+
+var pkgReplacer = strings.NewReplacer(
+ "/", "ᚋ",
+ ".", "ᚗ",
+ "-", "ᚑ",
+ "~", "א",
+)
+
+func TypeIdentifier(t types.Type) string {
+ res := ""
+ for {
+ switch it := t.(type) {
+ case *types.Pointer:
+ t.Underlying()
+ res += "ᚖ"
+ t = it.Elem()
+ case *types.Slice:
+ res += "ᚕ"
+ t = it.Elem()
+ case *types.Named:
+ res += pkgReplacer.Replace(it.Obj().Pkg().Path())
+ res += "ᚐ"
+ res += it.Obj().Name()
+ return res
+ case *types.Basic:
+ res += it.Name()
+ return res
+ case *types.Map:
+ res += "map"
+ return res
+ case *types.Interface:
+ res += "interface"
+ return res
+ default:
+ panic(fmt.Errorf("unexpected type %T", it))
+ }
+ }
+}
+
+// CommonInitialisms is a set of common initialisms.
+// Only add entries that are highly unlikely to be non-initialisms.
+// For instance, "ID" is fine (Freudian code is rare), but "AND" is not.
+var CommonInitialisms = map[string]bool{
+ "ACL": true,
+ "API": true,
+ "ASCII": true,
+ "CPU": true,
+ "CSS": true,
+ "CSV": true,
+ "DNS": true,
+ "EOF": true,
+ "GUID": true,
+ "HTML": true,
+ "HTTP": true,
+ "HTTPS": true,
+ "ICMP": true,
+ "ID": true,
+ "IP": true,
+ "JSON": true,
+ "KVK": true,
+ "LHS": true,
+ "PDF": true,
+ "PGP": true,
+ "QPS": true,
+ "QR": true,
+ "RAM": true,
+ "RHS": true,
+ "RPC": true,
+ "SLA": true,
+ "SMTP": true,
+ "SQL": true,
+ "SSH": true,
+ "SVG": true,
+ "TCP": true,
+ "TLS": true,
+ "TTL": true,
+ "UDP": true,
+ "UI": true,
+ "UID": true,
+ "URI": true,
+ "URL": true,
+ "UTF8": true,
+ "UUID": true,
+ "VM": true,
+ "XML": true,
+ "XMPP": true,
+ "XSRF": true,
+ "XSS": true,
+}
+
+// GetInitialisms returns the initialisms to capitalize in Go names. If unchanged, default initialisms will be returned
+var GetInitialisms = func() map[string]bool {
+ return CommonInitialisms
+}
diff --git a/codegen/templates/templates_test.go b/codegen/templates/templates_test.go
index 2f57fc9ca1..277a979cdb 100644
--- a/codegen/templates/templates_test.go
+++ b/codegen/templates/templates_test.go
@@ -7,10 +7,10 @@ import (
"path/filepath"
"testing"
- "github.com/99designs/gqlgen/internal/code"
-
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+
+ "github.com/99designs/gqlgen/internal/code"
)
//go:embed *.gotpl
@@ -326,7 +326,7 @@ func TestTemplateOverride(t *testing.T) {
}
defer f.Close()
defer os.RemoveAll(f.Name())
- err = Render(Options{Template: "hello", Filename: f.Name(), Packages: &code.Packages{}})
+ err = Render(Options{Template: "hello", Filename: f.Name(), Packages: code.NewPackages()})
if err != nil {
t.Fatal(err)
}
@@ -346,7 +346,7 @@ func TestRenderFS(t *testing.T) {
}
defer f.Close()
defer os.RemoveAll(f.Name())
- err = Render(Options{TemplateFS: templateFS, Filename: f.Name(), Packages: &code.Packages{}})
+ err = Render(Options{TemplateFS: templateFS, Filename: f.Name(), Packages: code.NewPackages()})
if err != nil {
t.Fatal(err)
}
diff --git a/codegen/testserver/followschema/complexity_test.go b/codegen/testserver/followschema/complexity_test.go
index 6a91e0f000..fd69a79c5e 100644
--- a/codegen/testserver/followschema/complexity_test.go
+++ b/codegen/testserver/followschema/complexity_test.go
@@ -4,10 +4,11 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/handler/extension"
- "github.com/stretchr/testify/require"
)
func TestComplexityCollisions(t *testing.T) {
diff --git a/codegen/testserver/followschema/defaults_test.go b/codegen/testserver/followschema/defaults_test.go
index e5708a72e3..26adaa1373 100644
--- a/codegen/testserver/followschema/defaults_test.go
+++ b/codegen/testserver/followschema/defaults_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func assertDefaults(t *testing.T, ret *DefaultParametersMirror) {
diff --git a/codegen/testserver/followschema/directive_test.go b/codegen/testserver/followschema/directive_test.go
index e995b2721c..b6d84d6932 100644
--- a/codegen/testserver/followschema/directive_test.go
+++ b/codegen/testserver/followschema/directive_test.go
@@ -5,10 +5,11 @@ import (
"fmt"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
type ckey string
diff --git a/codegen/testserver/followschema/embedded_test.go b/codegen/testserver/followschema/embedded_test.go
index b5e1575bac..207ea88182 100644
--- a/codegen/testserver/followschema/embedded_test.go
+++ b/codegen/testserver/followschema/embedded_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
type fakeUnexportedEmbeddedInterface struct{}
diff --git a/codegen/testserver/followschema/enums_test.go b/codegen/testserver/followschema/enums_test.go
index e7c80c29d2..c72293f169 100644
--- a/codegen/testserver/followschema/enums_test.go
+++ b/codegen/testserver/followschema/enums_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestEnumsResolver(t *testing.T) {
diff --git a/codegen/testserver/followschema/fields_order_test.go b/codegen/testserver/followschema/fields_order_test.go
index d521c8fc99..2be70d9da5 100644
--- a/codegen/testserver/followschema/fields_order_test.go
+++ b/codegen/testserver/followschema/fields_order_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
type FieldsOrderPayloadResults struct {
diff --git a/codegen/testserver/followschema/generated_test.go b/codegen/testserver/followschema/generated_test.go
index 9d10cde2c3..1792b0b4e4 100644
--- a/codegen/testserver/followschema/generated_test.go
+++ b/codegen/testserver/followschema/generated_test.go
@@ -8,9 +8,10 @@ import (
"reflect"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestForcedResolverFieldIsPointer(t *testing.T) {
diff --git a/codegen/testserver/followschema/input_test.go b/codegen/testserver/followschema/input_test.go
index 9a13f2d17f..27f6ada77a 100644
--- a/codegen/testserver/followschema/input_test.go
+++ b/codegen/testserver/followschema/input_test.go
@@ -6,9 +6,10 @@ import (
"testing"
"time"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestInput(t *testing.T) {
diff --git a/codegen/testserver/followschema/interfaces_test.go b/codegen/testserver/followschema/interfaces_test.go
index 3a7820fe52..2ef7312841 100644
--- a/codegen/testserver/followschema/interfaces_test.go
+++ b/codegen/testserver/followschema/interfaces_test.go
@@ -6,10 +6,11 @@ import (
"reflect"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestInterfaces(t *testing.T) {
diff --git a/codegen/testserver/followschema/introspection_test.go b/codegen/testserver/followschema/introspection_test.go
index ef2bfafb53..2f3fbc30cb 100644
--- a/codegen/testserver/followschema/introspection_test.go
+++ b/codegen/testserver/followschema/introspection_test.go
@@ -4,12 +4,13 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/handler/transport"
"github.com/99designs/gqlgen/graphql/introspection"
- "github.com/stretchr/testify/require"
)
func TestIntrospection(t *testing.T) {
diff --git a/codegen/testserver/followschema/maps.generated.go b/codegen/testserver/followschema/maps.generated.go
index 7fcd91fc1f..d2c4e1b885 100644
--- a/codegen/testserver/followschema/maps.generated.go
+++ b/codegen/testserver/followschema/maps.generated.go
@@ -27,6 +27,47 @@ import (
// region **************************** field.gotpl *****************************
+func (ec *executionContext) _MapNested_value(ctx context.Context, field graphql.CollectedField, obj *MapNested) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_MapNested_value(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Value, nil
+ })
+
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(CustomScalar)
+ fc.Result = res
+ return ec.marshalNCustomScalar2githubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋfollowschemaᚐCustomScalar(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_MapNested_value(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "MapNested",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type CustomScalar does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
func (ec *executionContext) _MapStringInterfaceType_a(ctx context.Context, field graphql.CollectedField, obj map[string]interface{}) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_MapStringInterfaceType_a(ctx, field)
if err != nil {
@@ -121,10 +162,193 @@ func (ec *executionContext) fieldContext_MapStringInterfaceType_b(ctx context.Co
return fc, nil
}
+func (ec *executionContext) _MapStringInterfaceType_c(ctx context.Context, field graphql.CollectedField, obj map[string]interface{}) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_MapStringInterfaceType_c(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ switch v := obj["c"].(type) {
+ case *CustomScalar:
+ return v, nil
+ case CustomScalar:
+ return &v, nil
+ case nil:
+ return (*CustomScalar)(nil), nil
+ default:
+ return nil, fmt.Errorf("unexpected type %T for field %s", v, "c")
+ }
+ })
+
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*CustomScalar)
+ fc.Result = res
+ return ec.marshalOCustomScalar2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋfollowschemaᚐCustomScalar(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_MapStringInterfaceType_c(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "MapStringInterfaceType",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type CustomScalar does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _MapStringInterfaceType_nested(ctx context.Context, field graphql.CollectedField, obj map[string]interface{}) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_MapStringInterfaceType_nested(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ switch v := obj["nested"].(type) {
+ case *MapNested:
+ return v, nil
+ case MapNested:
+ return &v, nil
+ case nil:
+ return (*MapNested)(nil), nil
+ default:
+ return nil, fmt.Errorf("unexpected type %T for field %s", v, "nested")
+ }
+ })
+
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*MapNested)
+ fc.Result = res
+ return ec.marshalOMapNested2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋfollowschemaᚐMapNested(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_MapStringInterfaceType_nested(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "MapStringInterfaceType",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "value":
+ return ec.fieldContext_MapNested_value(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type MapNested", field.Name)
+ },
+ }
+ return fc, nil
+}
+
// endregion **************************** field.gotpl *****************************
// region **************************** input.gotpl *****************************
+func (ec *executionContext) unmarshalInputMapNestedInput(ctx context.Context, obj interface{}) (MapNested, error) {
+ var it MapNested
+ asMap := map[string]interface{}{}
+ for k, v := range obj.(map[string]interface{}) {
+ asMap[k] = v
+ }
+
+ fieldsInOrder := [...]string{"value"}
+ for _, k := range fieldsInOrder {
+ v, ok := asMap[k]
+ if !ok {
+ continue
+ }
+ switch k {
+ case "value":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("value"))
+ data, err := ec.unmarshalNCustomScalar2githubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋfollowschemaᚐCustomScalar(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it.Value = data
+ }
+ }
+
+ return it, nil
+}
+
+func (ec *executionContext) unmarshalInputMapStringInterfaceInput(ctx context.Context, obj interface{}) (map[string]interface{}, error) {
+ it := make(map[string]interface{}, len(obj.(map[string]interface{})))
+ asMap := map[string]interface{}{}
+ for k, v := range obj.(map[string]interface{}) {
+ asMap[k] = v
+ }
+
+ fieldsInOrder := [...]string{"a", "b", "c", "nested"}
+ for _, k := range fieldsInOrder {
+ v, ok := asMap[k]
+ if !ok {
+ continue
+ }
+ switch k {
+ case "a":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("a"))
+ data, err := ec.unmarshalNString2string(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it["a"] = data
+ case "b":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("b"))
+ data, err := ec.unmarshalOInt2ᚖint(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it["b"] = data
+ case "c":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("c"))
+ data, err := ec.unmarshalOCustomScalar2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋfollowschemaᚐCustomScalar(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it["c"] = data
+ case "nested":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("nested"))
+ data, err := ec.unmarshalOMapNestedInput2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋfollowschemaᚐMapNested(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it["nested"] = data
+ }
+ }
+
+ return it, nil
+}
+
func (ec *executionContext) unmarshalInputNestedMapInput(ctx context.Context, obj interface{}) (NestedMapInput, error) {
var it NestedMapInput
asMap := map[string]interface{}{}
@@ -162,6 +386,45 @@ func (ec *executionContext) unmarshalInputNestedMapInput(ctx context.Context, ob
// region **************************** object.gotpl ****************************
+var mapNestedImplementors = []string{"MapNested"}
+
+func (ec *executionContext) _MapNested(ctx context.Context, sel ast.SelectionSet, obj *MapNested) graphql.Marshaler {
+ fields := graphql.CollectFields(ec.OperationContext, sel, mapNestedImplementors)
+
+ out := graphql.NewFieldSet(fields)
+ deferred := make(map[string]*graphql.FieldSet)
+ for i, field := range fields {
+ switch field.Name {
+ case "__typename":
+ out.Values[i] = graphql.MarshalString("MapNested")
+ case "value":
+ out.Values[i] = ec._MapNested_value(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ default:
+ panic("unknown field " + strconv.Quote(field.Name))
+ }
+ }
+ out.Dispatch(ctx)
+ if out.Invalids > 0 {
+ return graphql.Null
+ }
+
+ atomic.AddInt32(&ec.deferred, int32(len(deferred)))
+
+ for label, dfs := range deferred {
+ ec.processDeferredGroup(graphql.DeferredGroup{
+ Label: label,
+ Path: graphql.GetPath(ctx),
+ FieldSet: dfs,
+ Context: ctx,
+ })
+ }
+
+ return out
+}
+
var mapStringInterfaceTypeImplementors = []string{"MapStringInterfaceType"}
func (ec *executionContext) _MapStringInterfaceType(ctx context.Context, sel ast.SelectionSet, obj map[string]interface{}) graphql.Marshaler {
@@ -177,6 +440,10 @@ func (ec *executionContext) _MapStringInterfaceType(ctx context.Context, sel ast
out.Values[i] = ec._MapStringInterfaceType_a(ctx, field, obj)
case "b":
out.Values[i] = ec._MapStringInterfaceType_b(ctx, field, obj)
+ case "c":
+ out.Values[i] = ec._MapStringInterfaceType_c(ctx, field, obj)
+ case "nested":
+ out.Values[i] = ec._MapStringInterfaceType_nested(ctx, field, obj)
default:
panic("unknown field " + strconv.Quote(field.Name))
}
@@ -204,11 +471,53 @@ func (ec *executionContext) _MapStringInterfaceType(ctx context.Context, sel ast
// region ***************************** type.gotpl *****************************
+func (ec *executionContext) unmarshalNCustomScalar2githubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋfollowschemaᚐCustomScalar(ctx context.Context, v interface{}) (CustomScalar, error) {
+ var res CustomScalar
+ err := res.UnmarshalGQL(v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) marshalNCustomScalar2githubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋfollowschemaᚐCustomScalar(ctx context.Context, sel ast.SelectionSet, v CustomScalar) graphql.Marshaler {
+ return v
+}
+
+func (ec *executionContext) unmarshalOCustomScalar2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋfollowschemaᚐCustomScalar(ctx context.Context, v interface{}) (*CustomScalar, error) {
+ if v == nil {
+ return nil, nil
+ }
+ var res = new(CustomScalar)
+ err := res.UnmarshalGQL(v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) marshalOCustomScalar2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋfollowschemaᚐCustomScalar(ctx context.Context, sel ast.SelectionSet, v *CustomScalar) graphql.Marshaler {
+ if v == nil {
+ return graphql.Null
+ }
+ return v
+}
+
+func (ec *executionContext) marshalOMapNested2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋfollowschemaᚐMapNested(ctx context.Context, sel ast.SelectionSet, v *MapNested) graphql.Marshaler {
+ if v == nil {
+ return graphql.Null
+ }
+ return ec._MapNested(ctx, sel, v)
+}
+
+func (ec *executionContext) unmarshalOMapNestedInput2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋfollowschemaᚐMapNested(ctx context.Context, v interface{}) (*MapNested, error) {
+ if v == nil {
+ return nil, nil
+ }
+ res, err := ec.unmarshalInputMapNestedInput(ctx, v)
+ return &res, graphql.ErrorOnPath(ctx, err)
+}
+
func (ec *executionContext) unmarshalOMapStringInterfaceInput2map(ctx context.Context, v interface{}) (map[string]interface{}, error) {
if v == nil {
return nil, nil
}
- return v.(map[string]interface{}), nil
+ res, err := ec.unmarshalInputMapStringInterfaceInput(ctx, v)
+ return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalOMapStringInterfaceType2map(ctx context.Context, sel ast.SelectionSet, v map[string]interface{}) graphql.Marshaler {
diff --git a/codegen/testserver/followschema/maps.go b/codegen/testserver/followschema/maps.go
new file mode 100644
index 0000000000..871aabf3e6
--- /dev/null
+++ b/codegen/testserver/followschema/maps.go
@@ -0,0 +1,28 @@
+package followschema
+
+import (
+ "io"
+ "strconv"
+)
+
+type MapNested struct {
+ Value CustomScalar
+}
+
+type CustomScalar struct {
+ value int64
+}
+
+func (s *CustomScalar) UnmarshalGQL(v interface{}) (err error) {
+ switch v := v.(type) {
+ case string:
+ s.value, err = strconv.ParseInt(v, 10, 64)
+ case int64:
+ s.value = v
+ }
+ return
+}
+
+func (s CustomScalar) MarshalGQL(w io.Writer) {
+ _, _ = w.Write([]byte(strconv.Quote(strconv.FormatInt(s.value, 10))))
+}
diff --git a/codegen/testserver/followschema/maps.graphql b/codegen/testserver/followschema/maps.graphql
index 0fd639b0c4..51eac074ab 100644
--- a/codegen/testserver/followschema/maps.graphql
+++ b/codegen/testserver/followschema/maps.graphql
@@ -6,13 +6,27 @@ extend type Query {
type MapStringInterfaceType @goModel(model: "map[string]interface{}") {
a: String
b: Int
+ c: CustomScalar
+ nested: MapNested
+}
+
+type MapNested @goModel(model: "followschema.MapNested") {
+ value: CustomScalar!
}
input MapStringInterfaceInput @goModel(model: "map[string]interface{}") {
- a: String
+ a: String!
b: Int
+ c: CustomScalar
+ nested: MapNestedInput
}
+input MapNestedInput @goModel(model: "followschema.MapNested") {
+ value: CustomScalar!
+}
+
+scalar CustomScalar @goModel(model: "followschema.CustomScalar")
+
input NestedMapInput {
map: MapStringInterfaceInput
}
diff --git a/codegen/testserver/followschema/maps_test.go b/codegen/testserver/followschema/maps_test.go
index fe9750450f..58b559c16a 100644
--- a/codegen/testserver/followschema/maps_test.go
+++ b/codegen/testserver/followschema/maps_test.go
@@ -4,20 +4,23 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestMaps(t *testing.T) {
resolver := &Stub{}
resolver.QueryResolver.MapStringInterface = func(ctx context.Context, in map[string]interface{}) (i map[string]interface{}, e error) {
+ validateMapItemsType(t, in)
return in, nil
}
resolver.QueryResolver.MapNestedStringInterface = func(ctx context.Context, in *NestedMapInput) (i map[string]interface{}, e error) {
if in == nil {
return nil, nil
}
+ validateMapItemsType(t, in.Map)
return in.Map, nil
}
@@ -28,7 +31,7 @@ func TestMaps(t *testing.T) {
var resp struct {
MapStringInterface map[string]interface{}
}
- err := c.Post(`query { mapStringInterface { a, b } }`, &resp)
+ err := c.Post(`query { mapStringInterface { a, b, c, nested { value } } }`, &resp)
require.NoError(t, err)
require.Nil(t, resp.MapStringInterface)
})
@@ -37,7 +40,7 @@ func TestMaps(t *testing.T) {
var resp struct {
MapStringInterface map[string]interface{}
}
- err := c.Post(`query { mapStringInterface(in: null) { a, b } }`, &resp)
+ err := c.Post(`query { mapStringInterface(in: null) { a, b, c, nested { value } } }`, &resp)
require.NoError(t, err)
require.Nil(t, resp.MapStringInterface)
})
@@ -46,28 +49,53 @@ func TestMaps(t *testing.T) {
var resp struct {
MapStringInterface map[string]interface{}
}
- err := c.Post(`query { mapStringInterface(in: { a: "a", b: null }) { a, b } }`, &resp)
+ err := c.Post(`query($value: CustomScalar!) { mapStringInterface(in: { a: "a", b: null, c: 42, nested: { value: $value } }) { a, b, c, nested { value } } }`, &resp, client.Var("value", "17"))
require.NoError(t, err)
require.Equal(t, "a", resp.MapStringInterface["a"])
require.Nil(t, resp.MapStringInterface["b"])
+ require.Equal(t, "42", resp.MapStringInterface["c"])
+ require.NotNil(t, resp.MapStringInterface["nested"])
+ require.IsType(t, map[string]interface{}{}, resp.MapStringInterface["nested"])
+ require.Equal(t, "17", (resp.MapStringInterface["nested"].(map[string]interface{}))["value"])
})
t.Run("nested", func(t *testing.T) {
var resp struct {
MapNestedStringInterface map[string]interface{}
}
- err := c.Post(`query { mapNestedStringInterface(in: { map: { a: "a", b: null } }) { a, b } }`, &resp)
+ err := c.Post(`query { mapNestedStringInterface(in: { map: { a: "a", c: "42", nested: { value: 31 } } }) { a, b, c, nested { value } } }`, &resp)
require.NoError(t, err)
require.Equal(t, "a", resp.MapNestedStringInterface["a"])
require.Nil(t, resp.MapNestedStringInterface["b"])
+ require.Equal(t, "42", resp.MapNestedStringInterface["c"])
+ require.NotNil(t, resp.MapNestedStringInterface["nested"])
+ require.IsType(t, map[string]interface{}{}, resp.MapNestedStringInterface["nested"])
+ require.Equal(t, "31", (resp.MapNestedStringInterface["nested"].(map[string]interface{}))["value"])
})
t.Run("nested nil", func(t *testing.T) {
var resp struct {
MapNestedStringInterface map[string]interface{}
}
- err := c.Post(`query { mapNestedStringInterface(in: { map: null }) { a, b } }`, &resp)
+ err := c.Post(`query { mapNestedStringInterface(in: { map: null }) { a, b, c, nested { value } } }`, &resp)
require.NoError(t, err)
require.Nil(t, resp.MapNestedStringInterface)
})
}
+
+func validateMapItemsType(t *testing.T, in map[string]interface{}) {
+ for k, v := range in {
+ switch k {
+ case "a":
+ require.IsType(t, "", v)
+ case "b":
+ require.IsType(t, new(int), v)
+ case "c":
+ require.IsType(t, new(CustomScalar), v)
+ case "nested":
+ require.IsType(t, new(MapNested), v)
+ default:
+ require.Failf(t, "unexpected key in map", "key %q was not expected in map", k)
+ }
+ }
+}
diff --git a/codegen/testserver/followschema/middleware_test.go b/codegen/testserver/followschema/middleware_test.go
index 16fe10e612..3d214dc05b 100644
--- a/codegen/testserver/followschema/middleware_test.go
+++ b/codegen/testserver/followschema/middleware_test.go
@@ -5,12 +5,12 @@ import (
"sync"
"testing"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
)
func TestMiddleware(t *testing.T) {
diff --git a/codegen/testserver/followschema/modelmethod_test.go b/codegen/testserver/followschema/modelmethod_test.go
index 4cf1803729..3fda4b2a39 100644
--- a/codegen/testserver/followschema/modelmethod_test.go
+++ b/codegen/testserver/followschema/modelmethod_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestModelMethods(t *testing.T) {
diff --git a/codegen/testserver/followschema/mutation_with_custom_scalar_test.go b/codegen/testserver/followschema/mutation_with_custom_scalar_test.go
index 2f46c3ad4d..67f14ef31a 100644
--- a/codegen/testserver/followschema/mutation_with_custom_scalar_test.go
+++ b/codegen/testserver/followschema/mutation_with_custom_scalar_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestErrorInsideMutationArgument(t *testing.T) {
diff --git a/codegen/testserver/followschema/nulls_test.go b/codegen/testserver/followschema/nulls_test.go
index 6049a7ca6e..e738ffecf5 100644
--- a/codegen/testserver/followschema/nulls_test.go
+++ b/codegen/testserver/followschema/nulls_test.go
@@ -5,9 +5,10 @@ import (
"errors"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestNullBubbling(t *testing.T) {
diff --git a/codegen/testserver/followschema/panics_test.go b/codegen/testserver/followschema/panics_test.go
index 4433aad01a..e22fc144b1 100644
--- a/codegen/testserver/followschema/panics_test.go
+++ b/codegen/testserver/followschema/panics_test.go
@@ -5,12 +5,12 @@ import (
"fmt"
"testing"
- "github.com/99designs/gqlgen/graphql"
+ "github.com/stretchr/testify/require"
+ "github.com/vektah/gqlparser/v2/gqlerror"
"github.com/99designs/gqlgen/client"
+ "github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
- "github.com/vektah/gqlparser/v2/gqlerror"
)
func TestPanics(t *testing.T) {
diff --git a/codegen/testserver/followschema/primitive_objects_test.go b/codegen/testserver/followschema/primitive_objects_test.go
index 87de88bb45..106518cacc 100644
--- a/codegen/testserver/followschema/primitive_objects_test.go
+++ b/codegen/testserver/followschema/primitive_objects_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/assert"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/assert"
)
func TestPrimitiveObjects(t *testing.T) {
diff --git a/codegen/testserver/followschema/ptr_to_any_test.go b/codegen/testserver/followschema/ptr_to_any_test.go
index c1e78b8d80..3af48a89ed 100644
--- a/codegen/testserver/followschema/ptr_to_any_test.go
+++ b/codegen/testserver/followschema/ptr_to_any_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestPtrToAny(t *testing.T) {
diff --git a/codegen/testserver/followschema/ptr_to_ptr_input_test.go b/codegen/testserver/followschema/ptr_to_ptr_input_test.go
index ab40d1d68d..785b3bceb7 100644
--- a/codegen/testserver/followschema/ptr_to_ptr_input_test.go
+++ b/codegen/testserver/followschema/ptr_to_ptr_input_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
type UpdatePtrToPtrResults struct {
diff --git a/codegen/testserver/followschema/ptr_to_slice_test.go b/codegen/testserver/followschema/ptr_to_slice_test.go
index 20818cc4d1..a95b6b46c9 100644
--- a/codegen/testserver/followschema/ptr_to_slice_test.go
+++ b/codegen/testserver/followschema/ptr_to_slice_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestPtrToSlice(t *testing.T) {
diff --git a/codegen/testserver/followschema/response_extension_test.go b/codegen/testserver/followschema/response_extension_test.go
index 4ee1b5749f..92d1ade4af 100644
--- a/codegen/testserver/followschema/response_extension_test.go
+++ b/codegen/testserver/followschema/response_extension_test.go
@@ -4,10 +4,11 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestResponseExtension(t *testing.T) {
diff --git a/codegen/testserver/followschema/root_.generated.go b/codegen/testserver/followschema/root_.generated.go
index 1d1d0ff5e8..8463011b31 100644
--- a/codegen/testserver/followschema/root_.generated.go
+++ b/codegen/testserver/followschema/root_.generated.go
@@ -19,6 +19,7 @@ import (
// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
return &executableSchema{
+ schema: cfg.Schema,
resolvers: cfg.Resolvers,
directives: cfg.Directives,
complexity: cfg.Complexity,
@@ -26,6 +27,7 @@ func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
}
type Config struct {
+ Schema *ast.Schema
Resolvers ResolverRoot
Directives DirectiveRoot
Complexity ComplexityRoot
@@ -224,9 +226,15 @@ type ComplexityRoot struct {
ID func(childComplexity int) int
}
+ MapNested struct {
+ Value func(childComplexity int) int
+ }
+
MapStringInterfaceType struct {
- A func(childComplexity int) int
- B func(childComplexity int) int
+ A func(childComplexity int) int
+ B func(childComplexity int) int
+ C func(childComplexity int) int
+ Nested func(childComplexity int) int
}
ModelMethods struct {
@@ -466,12 +474,16 @@ type ComplexityRoot struct {
}
type executableSchema struct {
+ schema *ast.Schema
resolvers ResolverRoot
directives DirectiveRoot
complexity ComplexityRoot
}
func (e *executableSchema) Schema() *ast.Schema {
+ if e.schema != nil {
+ return e.schema
+ }
return parsedSchema
}
@@ -893,6 +905,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Map.ID(childComplexity), true
+ case "MapNested.value":
+ if e.complexity.MapNested.Value == nil {
+ break
+ }
+
+ return e.complexity.MapNested.Value(childComplexity), true
+
case "MapStringInterfaceType.a":
if e.complexity.MapStringInterfaceType.A == nil {
break
@@ -907,6 +926,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.MapStringInterfaceType.B(childComplexity), true
+ case "MapStringInterfaceType.c":
+ if e.complexity.MapStringInterfaceType.C == nil {
+ break
+ }
+
+ return e.complexity.MapStringInterfaceType.C(childComplexity), true
+
+ case "MapStringInterfaceType.nested":
+ if e.complexity.MapStringInterfaceType.Nested == nil {
+ break
+ }
+
+ return e.complexity.MapStringInterfaceType.Nested(childComplexity), true
+
case "ModelMethods.noContext":
if e.complexity.ModelMethods.NoContext == nil {
break
@@ -2084,12 +2117,15 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
rc := graphql.GetOperationContext(ctx)
ec := executionContext{rc, e, 0, 0, make(chan graphql.DeferredResult)}
inputUnmarshalMap := graphql.BuildUnmarshalerMap(
+ ec.unmarshalInputChanges,
ec.unmarshalInputDefaultInput,
ec.unmarshalInputFieldsOrderInput,
ec.unmarshalInputInnerDirectives,
ec.unmarshalInputInnerInput,
ec.unmarshalInputInputDirectives,
ec.unmarshalInputInputWithEnumValue,
+ ec.unmarshalInputMapNestedInput,
+ ec.unmarshalInputMapStringInterfaceInput,
ec.unmarshalInputNestedInput,
ec.unmarshalInputNestedMapInput,
ec.unmarshalInputOmittableInput,
@@ -2202,14 +2238,14 @@ func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapSchema(parsedSchema), nil
+ return introspection.WrapSchema(ec.Schema()), nil
}
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
+ return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil
}
//go:embed "builtinscalar.graphql" "complexity.graphql" "defaults.graphql" "defer.graphql" "directive.graphql" "embedded.graphql" "enum.graphql" "fields_order.graphql" "interfaces.graphql" "issue896.graphql" "loops.graphql" "maps.graphql" "mutation_with_custom_scalar.graphql" "nulls.graphql" "panics.graphql" "primitive_objects.graphql" "ptr_to_any.graphql" "ptr_to_ptr_input.graphql" "ptr_to_slice.graphql" "scalar_context.graphql" "scalar_default.graphql" "schema.graphql" "slices.graphql" "typefallback.graphql" "useptr.graphql" "v-ok.graphql" "validtypes.graphql" "variadic.graphql" "weird_type_cases.graphql" "wrapped_type.graphql"
diff --git a/codegen/testserver/followschema/scalar_context_test.go b/codegen/testserver/followschema/scalar_context_test.go
index 2e2a0dc361..2d4bf1c8ba 100644
--- a/codegen/testserver/followschema/scalar_context_test.go
+++ b/codegen/testserver/followschema/scalar_context_test.go
@@ -5,9 +5,10 @@ import (
"math"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestFloatInfAndNaN(t *testing.T) {
diff --git a/codegen/testserver/followschema/scalar_default_test.go b/codegen/testserver/followschema/scalar_default_test.go
index f6fc05cb09..f0faa0139e 100644
--- a/codegen/testserver/followschema/scalar_default_test.go
+++ b/codegen/testserver/followschema/scalar_default_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestDefaultScalarImplementation(t *testing.T) {
diff --git a/codegen/testserver/followschema/schema.generated.go b/codegen/testserver/followschema/schema.generated.go
index 0af031ea71..01387a495d 100644
--- a/codegen/testserver/followschema/schema.generated.go
+++ b/codegen/testserver/followschema/schema.generated.go
@@ -3610,6 +3610,10 @@ func (ec *executionContext) fieldContext_Query_mapStringInterface(ctx context.Co
return ec.fieldContext_MapStringInterfaceType_a(ctx, field)
case "b":
return ec.fieldContext_MapStringInterfaceType_b(ctx, field)
+ case "c":
+ return ec.fieldContext_MapStringInterfaceType_c(ctx, field)
+ case "nested":
+ return ec.fieldContext_MapStringInterfaceType_nested(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type MapStringInterfaceType", field.Name)
},
@@ -3665,6 +3669,10 @@ func (ec *executionContext) fieldContext_Query_mapNestedStringInterface(ctx cont
return ec.fieldContext_MapStringInterfaceType_a(ctx, field)
case "b":
return ec.fieldContext_MapStringInterfaceType_b(ctx, field)
+ case "c":
+ return ec.fieldContext_MapStringInterfaceType_c(ctx, field)
+ case "nested":
+ return ec.fieldContext_MapStringInterfaceType_nested(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type MapStringInterfaceType", field.Name)
},
@@ -5761,6 +5769,44 @@ func (ec *executionContext) fieldContext_User_pets(ctx context.Context, field gr
// region **************************** input.gotpl *****************************
+func (ec *executionContext) unmarshalInputChanges(ctx context.Context, obj interface{}) (map[string]interface{}, error) {
+ it := make(map[string]interface{}, len(obj.(map[string]interface{})))
+ asMap := map[string]interface{}{}
+ for k, v := range obj.(map[string]interface{}) {
+ asMap[k] = v
+ }
+
+ fieldsInOrder := [...]string{"a", "b"}
+ for _, k := range fieldsInOrder {
+ v, ok := asMap[k]
+ if !ok {
+ continue
+ }
+ switch k {
+ case "a":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("a"))
+ data, err := ec.unmarshalOInt2ᚖint(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it["a"] = data
+ case "b":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("b"))
+ data, err := ec.unmarshalOInt2ᚖint(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it["b"] = data
+ }
+ }
+
+ return it, nil
+}
+
func (ec *executionContext) unmarshalInputInnerInput(ctx context.Context, obj interface{}) (InnerInput, error) {
var it InnerInput
asMap := map[string]interface{}{}
@@ -8220,7 +8266,8 @@ func (ec *executionContext) unmarshalOChanges2map(ctx context.Context, v interfa
if v == nil {
return nil, nil
}
- return v.(map[string]interface{}), nil
+ res, err := ec.unmarshalInputChanges(ctx, v)
+ return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalOInvalidIdentifier2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋfollowschemaᚋinvalidᚑpackagenameᚐInvalidIdentifier(ctx context.Context, sel ast.SelectionSet, v *invalid_packagename.InvalidIdentifier) graphql.Marshaler {
diff --git a/codegen/testserver/followschema/slices_test.go b/codegen/testserver/followschema/slices_test.go
index 19df15816b..de29686186 100644
--- a/codegen/testserver/followschema/slices_test.go
+++ b/codegen/testserver/followschema/slices_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestSlices(t *testing.T) {
diff --git a/codegen/testserver/followschema/subscription_test.go b/codegen/testserver/followschema/subscription_test.go
index 6126db99ce..b25fb53bd6 100644
--- a/codegen/testserver/followschema/subscription_test.go
+++ b/codegen/testserver/followschema/subscription_test.go
@@ -8,12 +8,12 @@ import (
"testing"
"time"
- "github.com/99designs/gqlgen/graphql/handler/transport"
+ "github.com/stretchr/testify/require"
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
+ "github.com/99designs/gqlgen/graphql/handler/transport"
)
func TestSubscriptions(t *testing.T) {
@@ -130,6 +130,9 @@ func TestSubscriptions(t *testing.T) {
})
t.Run("will parse init payload", func(t *testing.T) {
+ runtime.GC() // ensure no go-routines left from preceding tests
+ initialGoroutineCount := runtime.NumGoroutine()
+
sub := c.WebsocketWithPayload(`subscription { initPayload }`, map[string]interface{}{
"Authorization": "Bearer of the curse",
"number": 32,
@@ -155,6 +158,14 @@ func TestSubscriptions(t *testing.T) {
require.NoError(t, err)
require.Equal(t, "strings = []interface {}{\"hello\", \"world\"}", msg.resp.InitPayload)
sub.Close()
+
+ // need a little bit of time for goroutines to settle
+ start := time.Now()
+ for time.Since(start).Seconds() < 2 && initialGoroutineCount != runtime.NumGoroutine() {
+ time.Sleep(5 * time.Millisecond)
+ }
+
+ require.Equal(t, initialGoroutineCount, runtime.NumGoroutine())
})
t.Run("websocket gets errors", func(t *testing.T) {
diff --git a/codegen/testserver/followschema/time_test.go b/codegen/testserver/followschema/time_test.go
index 60a098750a..947c1cc293 100644
--- a/codegen/testserver/followschema/time_test.go
+++ b/codegen/testserver/followschema/time_test.go
@@ -5,9 +5,10 @@ import (
"testing"
"time"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestTime(t *testing.T) {
diff --git a/codegen/testserver/followschema/typefallback_test.go b/codegen/testserver/followschema/typefallback_test.go
index 764661f84b..013ac1b7f8 100644
--- a/codegen/testserver/followschema/typefallback_test.go
+++ b/codegen/testserver/followschema/typefallback_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestTypeFallback(t *testing.T) {
diff --git a/codegen/testserver/followschema/validtypes_test.go b/codegen/testserver/followschema/validtypes_test.go
index 2c0e67942a..026ebe029c 100644
--- a/codegen/testserver/followschema/validtypes_test.go
+++ b/codegen/testserver/followschema/validtypes_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestValidType(t *testing.T) {
diff --git a/codegen/testserver/followschema/wrapped_type_test.go b/codegen/testserver/followschema/wrapped_type_test.go
index 95280b3d95..d28db51c3d 100644
--- a/codegen/testserver/followschema/wrapped_type_test.go
+++ b/codegen/testserver/followschema/wrapped_type_test.go
@@ -4,10 +4,11 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/codegen/testserver/followschema/otherpkg"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestWrappedTypes(t *testing.T) {
diff --git a/codegen/testserver/singlefile/complexity_test.go b/codegen/testserver/singlefile/complexity_test.go
index ac8e05a8c3..4dfbdffe7d 100644
--- a/codegen/testserver/singlefile/complexity_test.go
+++ b/codegen/testserver/singlefile/complexity_test.go
@@ -4,10 +4,11 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/handler/extension"
- "github.com/stretchr/testify/require"
)
func TestComplexityCollisions(t *testing.T) {
diff --git a/codegen/testserver/singlefile/defaults_test.go b/codegen/testserver/singlefile/defaults_test.go
index 4b403ad151..f69efcf49a 100644
--- a/codegen/testserver/singlefile/defaults_test.go
+++ b/codegen/testserver/singlefile/defaults_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func assertDefaults(t *testing.T, ret *DefaultParametersMirror) {
diff --git a/codegen/testserver/singlefile/defer_test.go b/codegen/testserver/singlefile/defer_test.go
index 876123401f..a5a1628da1 100644
--- a/codegen/testserver/singlefile/defer_test.go
+++ b/codegen/testserver/singlefile/defer_test.go
@@ -9,11 +9,12 @@ import (
"testing"
"time"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/handler/transport"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
)
func TestDefer(t *testing.T) {
diff --git a/codegen/testserver/singlefile/directive_test.go b/codegen/testserver/singlefile/directive_test.go
index 0b7cb97df8..e5df58d2e5 100644
--- a/codegen/testserver/singlefile/directive_test.go
+++ b/codegen/testserver/singlefile/directive_test.go
@@ -5,10 +5,11 @@ import (
"fmt"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
type ckey string
diff --git a/codegen/testserver/singlefile/embedded_test.go b/codegen/testserver/singlefile/embedded_test.go
index dd9ededd14..d3dc9a1a71 100644
--- a/codegen/testserver/singlefile/embedded_test.go
+++ b/codegen/testserver/singlefile/embedded_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
type fakeUnexportedEmbeddedInterface struct{}
diff --git a/codegen/testserver/singlefile/enums_test.go b/codegen/testserver/singlefile/enums_test.go
index 11ac0d1fbf..9a12bd3fb5 100644
--- a/codegen/testserver/singlefile/enums_test.go
+++ b/codegen/testserver/singlefile/enums_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestEnumsResolver(t *testing.T) {
diff --git a/codegen/testserver/singlefile/fields_order_test.go b/codegen/testserver/singlefile/fields_order_test.go
index eac294187f..daff5b6a38 100644
--- a/codegen/testserver/singlefile/fields_order_test.go
+++ b/codegen/testserver/singlefile/fields_order_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
type FieldsOrderPayloadResults struct {
diff --git a/codegen/testserver/singlefile/generated.go b/codegen/testserver/singlefile/generated.go
index 369cbf70d1..f260711bfb 100644
--- a/codegen/testserver/singlefile/generated.go
+++ b/codegen/testserver/singlefile/generated.go
@@ -28,6 +28,7 @@ import (
// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
return &executableSchema{
+ schema: cfg.Schema,
resolvers: cfg.Resolvers,
directives: cfg.Directives,
complexity: cfg.Complexity,
@@ -35,6 +36,7 @@ func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
}
type Config struct {
+ Schema *ast.Schema
Resolvers ResolverRoot
Directives DirectiveRoot
Complexity ComplexityRoot
@@ -233,9 +235,15 @@ type ComplexityRoot struct {
ID func(childComplexity int) int
}
+ MapNested struct {
+ Value func(childComplexity int) int
+ }
+
MapStringInterfaceType struct {
- A func(childComplexity int) int
- B func(childComplexity int) int
+ A func(childComplexity int) int
+ B func(childComplexity int) int
+ C func(childComplexity int) int
+ Nested func(childComplexity int) int
}
ModelMethods struct {
@@ -618,12 +626,16 @@ type FieldsOrderInputResolver interface {
}
type executableSchema struct {
+ schema *ast.Schema
resolvers ResolverRoot
directives DirectiveRoot
complexity ComplexityRoot
}
func (e *executableSchema) Schema() *ast.Schema {
+ if e.schema != nil {
+ return e.schema
+ }
return parsedSchema
}
@@ -1045,6 +1057,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Map.ID(childComplexity), true
+ case "MapNested.value":
+ if e.complexity.MapNested.Value == nil {
+ break
+ }
+
+ return e.complexity.MapNested.Value(childComplexity), true
+
case "MapStringInterfaceType.a":
if e.complexity.MapStringInterfaceType.A == nil {
break
@@ -1059,6 +1078,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.MapStringInterfaceType.B(childComplexity), true
+ case "MapStringInterfaceType.c":
+ if e.complexity.MapStringInterfaceType.C == nil {
+ break
+ }
+
+ return e.complexity.MapStringInterfaceType.C(childComplexity), true
+
+ case "MapStringInterfaceType.nested":
+ if e.complexity.MapStringInterfaceType.Nested == nil {
+ break
+ }
+
+ return e.complexity.MapStringInterfaceType.Nested(childComplexity), true
+
case "ModelMethods.noContext":
if e.complexity.ModelMethods.NoContext == nil {
break
@@ -2236,12 +2269,15 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
rc := graphql.GetOperationContext(ctx)
ec := executionContext{rc, e, 0, 0, make(chan graphql.DeferredResult)}
inputUnmarshalMap := graphql.BuildUnmarshalerMap(
+ ec.unmarshalInputChanges,
ec.unmarshalInputDefaultInput,
ec.unmarshalInputFieldsOrderInput,
ec.unmarshalInputInnerDirectives,
ec.unmarshalInputInnerInput,
ec.unmarshalInputInputDirectives,
ec.unmarshalInputInputWithEnumValue,
+ ec.unmarshalInputMapNestedInput,
+ ec.unmarshalInputMapStringInterfaceInput,
ec.unmarshalInputNestedInput,
ec.unmarshalInputNestedMapInput,
ec.unmarshalInputOmittableInput,
@@ -2354,14 +2390,14 @@ func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapSchema(parsedSchema), nil
+ return introspection.WrapSchema(ec.Schema()), nil
}
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
+ return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil
}
//go:embed "builtinscalar.graphql" "complexity.graphql" "defaults.graphql" "defer.graphql" "directive.graphql" "embedded.graphql" "enum.graphql" "fields_order.graphql" "interfaces.graphql" "issue896.graphql" "loops.graphql" "maps.graphql" "mutation_with_custom_scalar.graphql" "nulls.graphql" "panics.graphql" "primitive_objects.graphql" "ptr_to_any.graphql" "ptr_to_ptr_input.graphql" "ptr_to_slice.graphql" "scalar_context.graphql" "scalar_default.graphql" "schema.graphql" "slices.graphql" "typefallback.graphql" "useptr.graphql" "v-ok.graphql" "validtypes.graphql" "variadic.graphql" "weird_type_cases.graphql" "wrapped_type.graphql"
@@ -6047,6 +6083,47 @@ func (ec *executionContext) fieldContext_Map_id(ctx context.Context, field graph
return fc, nil
}
+func (ec *executionContext) _MapNested_value(ctx context.Context, field graphql.CollectedField, obj *MapNested) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_MapNested_value(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ return obj.Value, nil
+ })
+
+ if resTmp == nil {
+ if !graphql.HasFieldError(ctx, fc) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ return graphql.Null
+ }
+ res := resTmp.(CustomScalar)
+ fc.Result = res
+ return ec.marshalNCustomScalar2githubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋsinglefileᚐCustomScalar(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_MapNested_value(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "MapNested",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type CustomScalar does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
func (ec *executionContext) _MapStringInterfaceType_a(ctx context.Context, field graphql.CollectedField, obj map[string]interface{}) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_MapStringInterfaceType_a(ctx, field)
if err != nil {
@@ -6141,6 +6218,104 @@ func (ec *executionContext) fieldContext_MapStringInterfaceType_b(ctx context.Co
return fc, nil
}
+func (ec *executionContext) _MapStringInterfaceType_c(ctx context.Context, field graphql.CollectedField, obj map[string]interface{}) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_MapStringInterfaceType_c(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ switch v := obj["c"].(type) {
+ case *CustomScalar:
+ return v, nil
+ case CustomScalar:
+ return &v, nil
+ case nil:
+ return (*CustomScalar)(nil), nil
+ default:
+ return nil, fmt.Errorf("unexpected type %T for field %s", v, "c")
+ }
+ })
+
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*CustomScalar)
+ fc.Result = res
+ return ec.marshalOCustomScalar2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋsinglefileᚐCustomScalar(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_MapStringInterfaceType_c(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "MapStringInterfaceType",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ return nil, errors.New("field of type CustomScalar does not have child fields")
+ },
+ }
+ return fc, nil
+}
+
+func (ec *executionContext) _MapStringInterfaceType_nested(ctx context.Context, field graphql.CollectedField, obj map[string]interface{}) (ret graphql.Marshaler) {
+ fc, err := ec.fieldContext_MapStringInterfaceType_nested(ctx, field)
+ if err != nil {
+ return graphql.Null
+ }
+ ctx = graphql.WithFieldContext(ctx, fc)
+ defer func() {
+ if r := recover(); r != nil {
+ ec.Error(ctx, ec.Recover(ctx, r))
+ ret = graphql.Null
+ }
+ }()
+ resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) {
+ ctx = rctx // use context from middleware stack in children
+ switch v := obj["nested"].(type) {
+ case *MapNested:
+ return v, nil
+ case MapNested:
+ return &v, nil
+ case nil:
+ return (*MapNested)(nil), nil
+ default:
+ return nil, fmt.Errorf("unexpected type %T for field %s", v, "nested")
+ }
+ })
+
+ if resTmp == nil {
+ return graphql.Null
+ }
+ res := resTmp.(*MapNested)
+ fc.Result = res
+ return ec.marshalOMapNested2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋsinglefileᚐMapNested(ctx, field.Selections, res)
+}
+
+func (ec *executionContext) fieldContext_MapStringInterfaceType_nested(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
+ fc = &graphql.FieldContext{
+ Object: "MapStringInterfaceType",
+ Field: field,
+ IsMethod: false,
+ IsResolver: false,
+ Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
+ switch field.Name {
+ case "value":
+ return ec.fieldContext_MapNested_value(ctx, field)
+ }
+ return nil, fmt.Errorf("no field named %q was found under type MapNested", field.Name)
+ },
+ }
+ return fc, nil
+}
+
func (ec *executionContext) _ModelMethods_resolverField(ctx context.Context, field graphql.CollectedField, obj *ModelMethods) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_ModelMethods_resolverField(ctx, field)
if err != nil {
@@ -9890,6 +10065,10 @@ func (ec *executionContext) fieldContext_Query_mapStringInterface(ctx context.Co
return ec.fieldContext_MapStringInterfaceType_a(ctx, field)
case "b":
return ec.fieldContext_MapStringInterfaceType_b(ctx, field)
+ case "c":
+ return ec.fieldContext_MapStringInterfaceType_c(ctx, field)
+ case "nested":
+ return ec.fieldContext_MapStringInterfaceType_nested(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type MapStringInterfaceType", field.Name)
},
@@ -9945,6 +10124,10 @@ func (ec *executionContext) fieldContext_Query_mapNestedStringInterface(ctx cont
return ec.fieldContext_MapStringInterfaceType_a(ctx, field)
case "b":
return ec.fieldContext_MapStringInterfaceType_b(ctx, field)
+ case "c":
+ return ec.fieldContext_MapStringInterfaceType_c(ctx, field)
+ case "nested":
+ return ec.fieldContext_MapStringInterfaceType_nested(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type MapStringInterfaceType", field.Name)
},
@@ -14769,6 +14952,44 @@ func (ec *executionContext) fieldContext_iIt_id(ctx context.Context, field graph
// region **************************** input.gotpl *****************************
+func (ec *executionContext) unmarshalInputChanges(ctx context.Context, obj interface{}) (map[string]interface{}, error) {
+ it := make(map[string]interface{}, len(obj.(map[string]interface{})))
+ asMap := map[string]interface{}{}
+ for k, v := range obj.(map[string]interface{}) {
+ asMap[k] = v
+ }
+
+ fieldsInOrder := [...]string{"a", "b"}
+ for _, k := range fieldsInOrder {
+ v, ok := asMap[k]
+ if !ok {
+ continue
+ }
+ switch k {
+ case "a":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("a"))
+ data, err := ec.unmarshalOInt2ᚖint(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it["a"] = data
+ case "b":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("b"))
+ data, err := ec.unmarshalOInt2ᚖint(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it["b"] = data
+ }
+ }
+
+ return it, nil
+}
+
func (ec *executionContext) unmarshalInputDefaultInput(ctx context.Context, obj interface{}) (DefaultInput, error) {
var it DefaultInput
asMap := map[string]interface{}{}
@@ -15144,6 +15365,91 @@ func (ec *executionContext) unmarshalInputInputWithEnumValue(ctx context.Context
return it, nil
}
+func (ec *executionContext) unmarshalInputMapNestedInput(ctx context.Context, obj interface{}) (MapNested, error) {
+ var it MapNested
+ asMap := map[string]interface{}{}
+ for k, v := range obj.(map[string]interface{}) {
+ asMap[k] = v
+ }
+
+ fieldsInOrder := [...]string{"value"}
+ for _, k := range fieldsInOrder {
+ v, ok := asMap[k]
+ if !ok {
+ continue
+ }
+ switch k {
+ case "value":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("value"))
+ data, err := ec.unmarshalNCustomScalar2githubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋsinglefileᚐCustomScalar(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it.Value = data
+ }
+ }
+
+ return it, nil
+}
+
+func (ec *executionContext) unmarshalInputMapStringInterfaceInput(ctx context.Context, obj interface{}) (map[string]interface{}, error) {
+ it := make(map[string]interface{}, len(obj.(map[string]interface{})))
+ asMap := map[string]interface{}{}
+ for k, v := range obj.(map[string]interface{}) {
+ asMap[k] = v
+ }
+
+ fieldsInOrder := [...]string{"a", "b", "c", "nested"}
+ for _, k := range fieldsInOrder {
+ v, ok := asMap[k]
+ if !ok {
+ continue
+ }
+ switch k {
+ case "a":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("a"))
+ data, err := ec.unmarshalNString2string(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it["a"] = data
+ case "b":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("b"))
+ data, err := ec.unmarshalOInt2ᚖint(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it["b"] = data
+ case "c":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("c"))
+ data, err := ec.unmarshalOCustomScalar2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋsinglefileᚐCustomScalar(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it["c"] = data
+ case "nested":
+ var err error
+
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("nested"))
+ data, err := ec.unmarshalOMapNestedInput2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋsinglefileᚐMapNested(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it["nested"] = data
+ }
+ }
+
+ return it, nil
+}
+
func (ec *executionContext) unmarshalInputNestedInput(ctx context.Context, obj interface{}) (NestedInput, error) {
var it NestedInput
asMap := map[string]interface{}{}
@@ -17443,6 +17749,45 @@ func (ec *executionContext) _Map(ctx context.Context, sel ast.SelectionSet, obj
return out
}
+var mapNestedImplementors = []string{"MapNested"}
+
+func (ec *executionContext) _MapNested(ctx context.Context, sel ast.SelectionSet, obj *MapNested) graphql.Marshaler {
+ fields := graphql.CollectFields(ec.OperationContext, sel, mapNestedImplementors)
+
+ out := graphql.NewFieldSet(fields)
+ deferred := make(map[string]*graphql.FieldSet)
+ for i, field := range fields {
+ switch field.Name {
+ case "__typename":
+ out.Values[i] = graphql.MarshalString("MapNested")
+ case "value":
+ out.Values[i] = ec._MapNested_value(ctx, field, obj)
+ if out.Values[i] == graphql.Null {
+ out.Invalids++
+ }
+ default:
+ panic("unknown field " + strconv.Quote(field.Name))
+ }
+ }
+ out.Dispatch(ctx)
+ if out.Invalids > 0 {
+ return graphql.Null
+ }
+
+ atomic.AddInt32(&ec.deferred, int32(len(deferred)))
+
+ for label, dfs := range deferred {
+ ec.processDeferredGroup(graphql.DeferredGroup{
+ Label: label,
+ Path: graphql.GetPath(ctx),
+ FieldSet: dfs,
+ Context: ctx,
+ })
+ }
+
+ return out
+}
+
var mapStringInterfaceTypeImplementors = []string{"MapStringInterfaceType"}
func (ec *executionContext) _MapStringInterfaceType(ctx context.Context, sel ast.SelectionSet, obj map[string]interface{}) graphql.Marshaler {
@@ -17458,6 +17803,10 @@ func (ec *executionContext) _MapStringInterfaceType(ctx context.Context, sel ast
out.Values[i] = ec._MapStringInterfaceType_a(ctx, field, obj)
case "b":
out.Values[i] = ec._MapStringInterfaceType_b(ctx, field, obj)
+ case "c":
+ out.Values[i] = ec._MapStringInterfaceType_c(ctx, field, obj)
+ case "nested":
+ out.Values[i] = ec._MapStringInterfaceType_nested(ctx, field, obj)
default:
panic("unknown field " + strconv.Quote(field.Name))
}
@@ -21096,6 +21445,16 @@ func (ec *executionContext) marshalNCheckIssue8962ᚖgithubᚗcomᚋ99designsᚋ
return ec._CheckIssue896(ctx, sel, v)
}
+func (ec *executionContext) unmarshalNCustomScalar2githubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋsinglefileᚐCustomScalar(ctx context.Context, v interface{}) (CustomScalar, error) {
+ var res CustomScalar
+ err := res.UnmarshalGQL(v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) marshalNCustomScalar2githubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋsinglefileᚐCustomScalar(ctx context.Context, sel ast.SelectionSet, v CustomScalar) graphql.Marshaler {
+ return v
+}
+
func (ec *executionContext) unmarshalNDefaultInput2githubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋsinglefileᚐDefaultInput(ctx context.Context, v interface{}) (DefaultInput, error) {
res, err := ec.unmarshalInputDefaultInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err)
@@ -22199,7 +22558,8 @@ func (ec *executionContext) unmarshalOChanges2map(ctx context.Context, v interfa
if v == nil {
return nil, nil
}
- return v.(map[string]interface{}), nil
+ res, err := ec.unmarshalInputChanges(ctx, v)
+ return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalOCheckIssue8962ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋsinglefileᚐCheckIssue896(ctx context.Context, sel ast.SelectionSet, v []*CheckIssue896) graphql.Marshaler {
@@ -22308,6 +22668,22 @@ func (ec *executionContext) marshalOCoordinates2githubᚗcomᚋ99designsᚋgqlge
return ec._Coordinates(ctx, sel, &v)
}
+func (ec *executionContext) unmarshalOCustomScalar2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋsinglefileᚐCustomScalar(ctx context.Context, v interface{}) (*CustomScalar, error) {
+ if v == nil {
+ return nil, nil
+ }
+ var res = new(CustomScalar)
+ err := res.UnmarshalGQL(v)
+ return res, graphql.ErrorOnPath(ctx, err)
+}
+
+func (ec *executionContext) marshalOCustomScalar2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋsinglefileᚐCustomScalar(ctx context.Context, sel ast.SelectionSet, v *CustomScalar) graphql.Marshaler {
+ if v == nil {
+ return graphql.Null
+ }
+ return v
+}
+
func (ec *executionContext) unmarshalODefaultScalarImplementation2ᚖstring(ctx context.Context, v interface{}) (*string, error) {
if v == nil {
return nil, nil
@@ -22588,11 +22964,27 @@ func (ec *executionContext) marshalOIt2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋco
return ec._It(ctx, sel, v)
}
+func (ec *executionContext) marshalOMapNested2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋsinglefileᚐMapNested(ctx context.Context, sel ast.SelectionSet, v *MapNested) graphql.Marshaler {
+ if v == nil {
+ return graphql.Null
+ }
+ return ec._MapNested(ctx, sel, v)
+}
+
+func (ec *executionContext) unmarshalOMapNestedInput2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋsinglefileᚐMapNested(ctx context.Context, v interface{}) (*MapNested, error) {
+ if v == nil {
+ return nil, nil
+ }
+ res, err := ec.unmarshalInputMapNestedInput(ctx, v)
+ return &res, graphql.ErrorOnPath(ctx, err)
+}
+
func (ec *executionContext) unmarshalOMapStringInterfaceInput2map(ctx context.Context, v interface{}) (map[string]interface{}, error) {
if v == nil {
return nil, nil
}
- return v.(map[string]interface{}), nil
+ res, err := ec.unmarshalInputMapStringInterfaceInput(ctx, v)
+ return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalOMapStringInterfaceType2map(ctx context.Context, sel ast.SelectionSet, v map[string]interface{}) graphql.Marshaler {
diff --git a/codegen/testserver/singlefile/generated_test.go b/codegen/testserver/singlefile/generated_test.go
index 6d1dfa7e3c..63a6a4f2a1 100644
--- a/codegen/testserver/singlefile/generated_test.go
+++ b/codegen/testserver/singlefile/generated_test.go
@@ -8,9 +8,10 @@ import (
"reflect"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestForcedResolverFieldIsPointer(t *testing.T) {
diff --git a/codegen/testserver/singlefile/input_test.go b/codegen/testserver/singlefile/input_test.go
index d33081b26c..ea05b2edfb 100644
--- a/codegen/testserver/singlefile/input_test.go
+++ b/codegen/testserver/singlefile/input_test.go
@@ -6,9 +6,10 @@ import (
"testing"
"time"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestInput(t *testing.T) {
diff --git a/codegen/testserver/singlefile/interfaces_test.go b/codegen/testserver/singlefile/interfaces_test.go
index 23b3fb0206..9a38a3f942 100644
--- a/codegen/testserver/singlefile/interfaces_test.go
+++ b/codegen/testserver/singlefile/interfaces_test.go
@@ -6,10 +6,11 @@ import (
"reflect"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestInterfaces(t *testing.T) {
diff --git a/codegen/testserver/singlefile/introspection_test.go b/codegen/testserver/singlefile/introspection_test.go
index f78a8202c1..64958e7e79 100644
--- a/codegen/testserver/singlefile/introspection_test.go
+++ b/codegen/testserver/singlefile/introspection_test.go
@@ -4,12 +4,13 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/handler/transport"
"github.com/99designs/gqlgen/graphql/introspection"
- "github.com/stretchr/testify/require"
)
func TestIntrospection(t *testing.T) {
diff --git a/codegen/testserver/singlefile/maps.go b/codegen/testserver/singlefile/maps.go
new file mode 100644
index 0000000000..58366271b9
--- /dev/null
+++ b/codegen/testserver/singlefile/maps.go
@@ -0,0 +1,28 @@
+package singlefile
+
+import (
+ "io"
+ "strconv"
+)
+
+type MapNested struct {
+ Value CustomScalar
+}
+
+type CustomScalar struct {
+ value int64
+}
+
+func (s *CustomScalar) UnmarshalGQL(v interface{}) (err error) {
+ switch v := v.(type) {
+ case string:
+ s.value, err = strconv.ParseInt(v, 10, 64)
+ case int64:
+ s.value = v
+ }
+ return
+}
+
+func (s CustomScalar) MarshalGQL(w io.Writer) {
+ _, _ = w.Write([]byte(strconv.Quote(strconv.FormatInt(s.value, 10))))
+}
diff --git a/codegen/testserver/singlefile/maps.graphql b/codegen/testserver/singlefile/maps.graphql
index 0fd639b0c4..38205ad2ac 100644
--- a/codegen/testserver/singlefile/maps.graphql
+++ b/codegen/testserver/singlefile/maps.graphql
@@ -6,13 +6,27 @@ extend type Query {
type MapStringInterfaceType @goModel(model: "map[string]interface{}") {
a: String
b: Int
+ c: CustomScalar
+ nested: MapNested
+}
+
+type MapNested @goModel(model: "singlefile.MapNested") {
+ value: CustomScalar!
}
input MapStringInterfaceInput @goModel(model: "map[string]interface{}") {
- a: String
+ a: String!
b: Int
+ c: CustomScalar
+ nested: MapNestedInput
}
+input MapNestedInput @goModel(model: "singlefile.MapNested") {
+ value: CustomScalar!
+}
+
+scalar CustomScalar @goModel(model: "singlefile.CustomScalar")
+
input NestedMapInput {
map: MapStringInterfaceInput
}
diff --git a/codegen/testserver/singlefile/maps_test.go b/codegen/testserver/singlefile/maps_test.go
index 0c7129ae61..1b532909fb 100644
--- a/codegen/testserver/singlefile/maps_test.go
+++ b/codegen/testserver/singlefile/maps_test.go
@@ -4,20 +4,23 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestMaps(t *testing.T) {
resolver := &Stub{}
resolver.QueryResolver.MapStringInterface = func(ctx context.Context, in map[string]interface{}) (i map[string]interface{}, e error) {
+ validateMapItemsType(t, in)
return in, nil
}
resolver.QueryResolver.MapNestedStringInterface = func(ctx context.Context, in *NestedMapInput) (i map[string]interface{}, e error) {
if in == nil {
return nil, nil
}
+ validateMapItemsType(t, in.Map)
return in.Map, nil
}
@@ -28,7 +31,7 @@ func TestMaps(t *testing.T) {
var resp struct {
MapStringInterface map[string]interface{}
}
- err := c.Post(`query { mapStringInterface { a, b } }`, &resp)
+ err := c.Post(`query { mapStringInterface { a, b, c, nested { value } } }`, &resp)
require.NoError(t, err)
require.Nil(t, resp.MapStringInterface)
})
@@ -37,7 +40,7 @@ func TestMaps(t *testing.T) {
var resp struct {
MapStringInterface map[string]interface{}
}
- err := c.Post(`query { mapStringInterface(in: null) { a, b } }`, &resp)
+ err := c.Post(`query { mapStringInterface(in: null) { a, b, c, nested { value } } }`, &resp)
require.NoError(t, err)
require.Nil(t, resp.MapStringInterface)
})
@@ -46,28 +49,53 @@ func TestMaps(t *testing.T) {
var resp struct {
MapStringInterface map[string]interface{}
}
- err := c.Post(`query { mapStringInterface(in: { a: "a", b: null }) { a, b } }`, &resp)
+ err := c.Post(`query($value: CustomScalar!) { mapStringInterface(in: { a: "a", b: null, c: 42, nested: { value: $value } }) { a, b, c, nested { value } } }`, &resp, client.Var("value", "17"))
require.NoError(t, err)
require.Equal(t, "a", resp.MapStringInterface["a"])
require.Nil(t, resp.MapStringInterface["b"])
+ require.Equal(t, "42", resp.MapStringInterface["c"])
+ require.NotNil(t, resp.MapStringInterface["nested"])
+ require.IsType(t, map[string]interface{}{}, resp.MapStringInterface["nested"])
+ require.Equal(t, "17", (resp.MapStringInterface["nested"].(map[string]interface{}))["value"])
})
t.Run("nested", func(t *testing.T) {
var resp struct {
MapNestedStringInterface map[string]interface{}
}
- err := c.Post(`query { mapNestedStringInterface(in: { map: { a: "a", b: null } }) { a, b } }`, &resp)
+ err := c.Post(`query { mapNestedStringInterface(in: { map: { a: "a", c: "42", nested: { value: 31 } } }) { a, b, c, nested { value } } }`, &resp)
require.NoError(t, err)
require.Equal(t, "a", resp.MapNestedStringInterface["a"])
require.Nil(t, resp.MapNestedStringInterface["b"])
+ require.Equal(t, "42", resp.MapNestedStringInterface["c"])
+ require.NotNil(t, resp.MapNestedStringInterface["nested"])
+ require.IsType(t, map[string]interface{}{}, resp.MapNestedStringInterface["nested"])
+ require.Equal(t, "31", (resp.MapNestedStringInterface["nested"].(map[string]interface{}))["value"])
})
t.Run("nested nil", func(t *testing.T) {
var resp struct {
MapNestedStringInterface map[string]interface{}
}
- err := c.Post(`query { mapNestedStringInterface(in: { map: null }) { a, b } }`, &resp)
+ err := c.Post(`query { mapNestedStringInterface(in: { map: null }) { a, b, c, nested { value } } }`, &resp)
require.NoError(t, err)
require.Nil(t, resp.MapNestedStringInterface)
})
}
+
+func validateMapItemsType(t *testing.T, in map[string]interface{}) {
+ for k, v := range in {
+ switch k {
+ case "a":
+ require.IsType(t, "", v)
+ case "b":
+ require.IsType(t, new(int), v)
+ case "c":
+ require.IsType(t, new(CustomScalar), v)
+ case "nested":
+ require.IsType(t, new(MapNested), v)
+ default:
+ require.Failf(t, "unexpected key in map", "key %q was not expected in map", k)
+ }
+ }
+}
diff --git a/codegen/testserver/singlefile/middleware_test.go b/codegen/testserver/singlefile/middleware_test.go
index 5a840d0751..7b404d41ea 100644
--- a/codegen/testserver/singlefile/middleware_test.go
+++ b/codegen/testserver/singlefile/middleware_test.go
@@ -5,12 +5,12 @@ import (
"sync"
"testing"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
)
func TestMiddleware(t *testing.T) {
diff --git a/codegen/testserver/singlefile/modelmethod_test.go b/codegen/testserver/singlefile/modelmethod_test.go
index aefb14aa7b..a584b35b78 100644
--- a/codegen/testserver/singlefile/modelmethod_test.go
+++ b/codegen/testserver/singlefile/modelmethod_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestModelMethods(t *testing.T) {
diff --git a/codegen/testserver/singlefile/mutation_with_custom_scalar_test.go b/codegen/testserver/singlefile/mutation_with_custom_scalar_test.go
index 3290b373e2..5237e99f2f 100644
--- a/codegen/testserver/singlefile/mutation_with_custom_scalar_test.go
+++ b/codegen/testserver/singlefile/mutation_with_custom_scalar_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestErrorInsideMutationArgument(t *testing.T) {
diff --git a/codegen/testserver/singlefile/nulls_test.go b/codegen/testserver/singlefile/nulls_test.go
index 853428f485..c2609676fc 100644
--- a/codegen/testserver/singlefile/nulls_test.go
+++ b/codegen/testserver/singlefile/nulls_test.go
@@ -5,9 +5,10 @@ import (
"errors"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestNullBubbling(t *testing.T) {
diff --git a/codegen/testserver/singlefile/panics_test.go b/codegen/testserver/singlefile/panics_test.go
index 209344d79d..a426130618 100644
--- a/codegen/testserver/singlefile/panics_test.go
+++ b/codegen/testserver/singlefile/panics_test.go
@@ -5,12 +5,12 @@ import (
"fmt"
"testing"
- "github.com/99designs/gqlgen/graphql"
+ "github.com/stretchr/testify/require"
+ "github.com/vektah/gqlparser/v2/gqlerror"
"github.com/99designs/gqlgen/client"
+ "github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
- "github.com/vektah/gqlparser/v2/gqlerror"
)
func TestPanics(t *testing.T) {
diff --git a/codegen/testserver/singlefile/primitive_objects_test.go b/codegen/testserver/singlefile/primitive_objects_test.go
index 80e7a96d7a..c16e305565 100644
--- a/codegen/testserver/singlefile/primitive_objects_test.go
+++ b/codegen/testserver/singlefile/primitive_objects_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/assert"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/assert"
)
func TestPrimitiveObjects(t *testing.T) {
diff --git a/codegen/testserver/singlefile/ptr_to_any_test.go b/codegen/testserver/singlefile/ptr_to_any_test.go
index 88feadecc7..7ad1dcb408 100644
--- a/codegen/testserver/singlefile/ptr_to_any_test.go
+++ b/codegen/testserver/singlefile/ptr_to_any_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestPtrToAny(t *testing.T) {
diff --git a/codegen/testserver/singlefile/ptr_to_ptr_input_test.go b/codegen/testserver/singlefile/ptr_to_ptr_input_test.go
index 1e46e7e33c..f5f1f381bd 100644
--- a/codegen/testserver/singlefile/ptr_to_ptr_input_test.go
+++ b/codegen/testserver/singlefile/ptr_to_ptr_input_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
type UpdatePtrToPtrResults struct {
diff --git a/codegen/testserver/singlefile/ptr_to_slice_test.go b/codegen/testserver/singlefile/ptr_to_slice_test.go
index 0eee0bb873..5549ec68ab 100644
--- a/codegen/testserver/singlefile/ptr_to_slice_test.go
+++ b/codegen/testserver/singlefile/ptr_to_slice_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestPtrToSlice(t *testing.T) {
diff --git a/codegen/testserver/singlefile/response_extension_test.go b/codegen/testserver/singlefile/response_extension_test.go
index 9e570dbda0..8fca678027 100644
--- a/codegen/testserver/singlefile/response_extension_test.go
+++ b/codegen/testserver/singlefile/response_extension_test.go
@@ -4,10 +4,11 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestResponseExtension(t *testing.T) {
diff --git a/codegen/testserver/singlefile/scalar_context_test.go b/codegen/testserver/singlefile/scalar_context_test.go
index 2070b0996b..63d2ad32fb 100644
--- a/codegen/testserver/singlefile/scalar_context_test.go
+++ b/codegen/testserver/singlefile/scalar_context_test.go
@@ -5,9 +5,10 @@ import (
"math"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestFloatInfAndNaN(t *testing.T) {
diff --git a/codegen/testserver/singlefile/scalar_default_test.go b/codegen/testserver/singlefile/scalar_default_test.go
index 556a3eccb4..f23f6c2e82 100644
--- a/codegen/testserver/singlefile/scalar_default_test.go
+++ b/codegen/testserver/singlefile/scalar_default_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestDefaultScalarImplementation(t *testing.T) {
diff --git a/codegen/testserver/singlefile/slices_test.go b/codegen/testserver/singlefile/slices_test.go
index b6c3e37b9a..596e332528 100644
--- a/codegen/testserver/singlefile/slices_test.go
+++ b/codegen/testserver/singlefile/slices_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestSlices(t *testing.T) {
diff --git a/codegen/testserver/singlefile/subscription_test.go b/codegen/testserver/singlefile/subscription_test.go
index 24186e5ebe..6199bab6d5 100644
--- a/codegen/testserver/singlefile/subscription_test.go
+++ b/codegen/testserver/singlefile/subscription_test.go
@@ -8,12 +8,12 @@ import (
"testing"
"time"
- "github.com/99designs/gqlgen/graphql/handler/transport"
+ "github.com/stretchr/testify/require"
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
+ "github.com/99designs/gqlgen/graphql/handler/transport"
)
func TestSubscriptions(t *testing.T) {
@@ -130,6 +130,9 @@ func TestSubscriptions(t *testing.T) {
})
t.Run("will parse init payload", func(t *testing.T) {
+ runtime.GC() // ensure no go-routines left from preceding tests
+ initialGoroutineCount := runtime.NumGoroutine()
+
sub := c.WebsocketWithPayload(`subscription { initPayload }`, map[string]interface{}{
"Authorization": "Bearer of the curse",
"number": 32,
@@ -155,6 +158,14 @@ func TestSubscriptions(t *testing.T) {
require.NoError(t, err)
require.Equal(t, "strings = []interface {}{\"hello\", \"world\"}", msg.resp.InitPayload)
sub.Close()
+
+ // need a little bit of time for goroutines to settle
+ start := time.Now()
+ for time.Since(start).Seconds() < 2 && initialGoroutineCount != runtime.NumGoroutine() {
+ time.Sleep(5 * time.Millisecond)
+ }
+
+ require.Equal(t, initialGoroutineCount, runtime.NumGoroutine())
})
t.Run("websocket gets errors", func(t *testing.T) {
diff --git a/codegen/testserver/singlefile/time_test.go b/codegen/testserver/singlefile/time_test.go
index 90c8a0c539..1a7c9f9ac3 100644
--- a/codegen/testserver/singlefile/time_test.go
+++ b/codegen/testserver/singlefile/time_test.go
@@ -5,9 +5,10 @@ import (
"testing"
"time"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestTime(t *testing.T) {
diff --git a/codegen/testserver/singlefile/typefallback_test.go b/codegen/testserver/singlefile/typefallback_test.go
index 13ba74449c..55f49282ed 100644
--- a/codegen/testserver/singlefile/typefallback_test.go
+++ b/codegen/testserver/singlefile/typefallback_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestTypeFallback(t *testing.T) {
diff --git a/codegen/testserver/singlefile/validtypes_test.go b/codegen/testserver/singlefile/validtypes_test.go
index 28c5f07974..6b27a4a399 100644
--- a/codegen/testserver/singlefile/validtypes_test.go
+++ b/codegen/testserver/singlefile/validtypes_test.go
@@ -4,9 +4,10 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestValidType(t *testing.T) {
diff --git a/codegen/testserver/singlefile/wrapped_type_test.go b/codegen/testserver/singlefile/wrapped_type_test.go
index 13a9ccab84..98ffaa3a7c 100644
--- a/codegen/testserver/singlefile/wrapped_type_test.go
+++ b/codegen/testserver/singlefile/wrapped_type_test.go
@@ -4,10 +4,11 @@ import (
"context"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/client"
"github.com/99designs/gqlgen/codegen/testserver/singlefile/otherpkg"
"github.com/99designs/gqlgen/graphql/handler"
- "github.com/stretchr/testify/require"
)
func TestWrappedTypes(t *testing.T) {
diff --git a/codegen/type.gotpl b/codegen/type.gotpl
index 5cbd737c77..99ad9e0006 100644
--- a/codegen/type.gotpl
+++ b/codegen/type.gotpl
@@ -59,8 +59,6 @@
{{- else}}
return res, graphql.ErrorOnPath(ctx, err)
{{- end }}
- {{- else if eq ($type.GO | ref) "map[string]interface{}" }}
- return v.(map[string]interface{}), nil
{{- else if $type.IsMarshaler }}
{{- if and $type.IsNilable $type.Elem }}
var res = new({{ $type.Elem.GO | ref }})
@@ -75,7 +73,7 @@
return res, graphql.ErrorOnPath(ctx, err)
{{- else }}
res, err := ec.unmarshalInput{{ $type.GQL.Name }}(ctx, v)
- {{- if and $type.IsNilable (not $type.PointersInUmarshalInput) }}
+ {{- if and $type.IsNilable (not $type.IsMap) (not $type.PointersInUmarshalInput) }}
return &res, graphql.ErrorOnPath(ctx, err)
{{- else if and (not $type.IsNilable) $type.PointersInUmarshalInput }}
return *res, graphql.ErrorOnPath(ctx, err)
diff --git a/complexity/complexity.go b/complexity/complexity.go
index e3ecf7612d..aa0f86432e 100644
--- a/complexity/complexity.go
+++ b/complexity/complexity.go
@@ -1,8 +1,9 @@
package complexity
import (
- "github.com/99designs/gqlgen/graphql"
"github.com/vektah/gqlparser/v2/ast"
+
+ "github.com/99designs/gqlgen/graphql"
)
func Calculate(es graphql.ExecutableSchema, op *ast.OperationDefinition, vars map[string]interface{}) int {
diff --git a/complexity/complexity_test.go b/complexity/complexity_test.go
index 0c4be24e1c..e99acf0efb 100644
--- a/complexity/complexity_test.go
+++ b/complexity/complexity_test.go
@@ -4,10 +4,11 @@ import (
"math"
"testing"
- "github.com/99designs/gqlgen/graphql"
"github.com/stretchr/testify/require"
"github.com/vektah/gqlparser/v2"
"github.com/vektah/gqlparser/v2/ast"
+
+ "github.com/99designs/gqlgen/graphql"
)
var schema = gqlparser.MustLoadSchema(
diff --git a/docs/content/config.md b/docs/content/config.md
index 7233055346..f464359aca 100644
--- a/docs/content/config.md
+++ b/docs/content/config.md
@@ -30,6 +30,8 @@ federation:
model:
filename: graph/model/models_gen.go
package: model
+ # Optional: Pass in a path to a new gotpl template to use for generating the models
+ # model_template: [your/path/model.gotpl]
# Where should the resolver implementations go?
resolver:
@@ -39,6 +41,8 @@ resolver:
filename_template: "{name}.resolvers.go"
# Optional: turn on to not generate template comments above resolvers
# omit_template_comment: false
+ # Optional: Pass in a path to a new gotpl template to use for generating resolvers
+ # resolver_template: [your/path/resolver.gotpl]
# Optional: turn on use ` + "`" + `gqlgen:"fieldName"` + "`" + ` tags in your models
# struct_tag: json
@@ -80,6 +84,11 @@ resolver:
# Optional: set to skip running `go mod tidy` when generating server code
# skip_mod_tidy: true
+# Optional: set build tags that will be used to load packages
+# go_build_tags:
+# - private
+# - enterprise
+
# Optional: set to modify the initialisms regarded for Go names
# go_initialisms:
# replace_defaults: false # if true, the default initialisms will get dropped in favor of the new ones instead of being added
@@ -109,6 +118,9 @@ models:
- github.com/99designs/gqlgen/graphql.Int
- github.com/99designs/gqlgen/graphql.Int64
- github.com/99designs/gqlgen/graphql.Int32
+ UUID:
+ model:
+ - github.com/99designs/gqlgen/graphql.UUID
```
Everything has defaults, so add things as you need.
@@ -123,12 +135,13 @@ To start using them you first need to define them:
directive @goModel(
model: String
models: [String!]
+ forceGenerate: Boolean
) on OBJECT | INPUT_OBJECT | SCALAR | ENUM | INTERFACE | UNION
directive @goField(
forceResolver: Boolean
name: String
- omittable: Boolean
+ omittable: Boolean
) on INPUT_FIELD_DEFINITION | FIELD_DEFINITION
directive @goTag(
@@ -152,6 +165,12 @@ type User @goModel(model: "github.com/my/app/models.User") {
@goTag(key: "xorm", value: "-")
@goTag(key: "yaml")
}
+
+# This make sense when autobind activated.
+type Person @goModel(forceGenerate: true) {
+ id: ID!
+ name: String!
+}
```
The builtin directives `goField`, `goModel` and `goTag` are automatically registered to `skip_runtime`. Any directives registered as `skip_runtime` will not exposed during introspection and are used during code generation only.
diff --git a/docs/content/getting-started.md b/docs/content/getting-started.md
index 42fee8eb9a..ba3c442406 100644
--- a/docs/content/getting-started.md
+++ b/docs/content/getting-started.md
@@ -135,14 +135,14 @@ type Resolver struct{
}
```
-Returning to `graph/schema.resolvers.go`, let's implement the bodies of those automatically generated resolver functions. For `CreateTodo`, we'll use the [`math.rand` package](https://pkg.go.dev/math/rand#Rand.Int) to simply return a todo with a randomly generated ID and store that in the in-memory todos list --- in a real app, you're likely to use a database or some other backend service.
+Returning to `graph/schema.resolvers.go`, let's implement the bodies of those automatically generated resolver functions. For `CreateTodo`, we'll use the [`crypto.rand` package](https://pkg.go.dev/crypto/rand#Int) to simply return a todo with a randomly generated ID and store that in the in-memory todos list --- in a real app, you're likely to use a database or some other backend service.
```go
func (r *mutationResolver) CreateTodo(ctx context.Context, input model.NewTodo) (*model.Todo, error) {
- rand, _ := rand.Int(rand.Reader, big.NewInt(100))
+ randNumber, _ := rand.Int(rand.Reader, big.NewInt(100))
todo := &model.Todo{
Text: input.Text,
- ID: fmt.Sprintf("T%d", rand),
+ ID: fmt.Sprintf("T%d", randNumber),
User: &model.User{ID: input.UserID, Name: "user " + input.UserID},
}
r.todos = append(r.todos, todo)
@@ -250,10 +250,10 @@ And run `go run github.com/99designs/gqlgen generate`.
Now if we look in `graph/schema.resolvers.go` we can see a new resolver, lets implement it and fix `CreateTodo`.
```go
func (r *mutationResolver) CreateTodo(ctx context.Context, input model.NewTodo) (*model.Todo, error) {
+ randNumber, _ := rand.Int(rand.Reader, big.NewInt(100))
todo := &model.Todo{
Text: input.Text,
- ID: fmt.Sprintf("T%d", rand.Int()),
- User: &model.User{ID: input.UserID, Name: "user " + input.UserID},
+ ID: fmt.Sprintf("T%d", randNumber),
UserID: input.UserID,
}
r.todos = append(r.todos, todo)
diff --git a/docs/content/recipes/subscriptions.md b/docs/content/recipes/subscriptions.md
index 5845bb724c..4cf72204e4 100644
--- a/docs/content/recipes/subscriptions.md
+++ b/docs/content/recipes/subscriptions.md
@@ -121,6 +121,9 @@ func (r *subscriptionResolver) CurrentTime(ctx context.Context) (<-chan *model.T
// You can (and probably should) handle your channels in a central place outside of `schema.resolvers.go`.
// For this example we'll simply use a Goroutine with a simple loop.
go func() {
+ // Handle deregistration of the channel here. Note the `defer`
+ defer close(ch)
+
for {
// In our example we'll send the current time every second.
time.Sleep(1 * time.Second)
@@ -294,6 +297,8 @@ func (r *subscriptionResolver) CurrentTime(ctx context.Context) (<-chan *model.T
ch := make(chan *model.Time)
go func() {
+ defer close(ch)
+
for {
time.Sleep(1 * time.Second)
fmt.Println("Tick")
diff --git a/docs/content/reference/changesets.md b/docs/content/reference/changesets.md
index 329206ba5e..513eb67817 100644
--- a/docs/content/reference/changesets.md
+++ b/docs/content/reference/changesets.md
@@ -13,7 +13,7 @@ type Mutation {
updateUser(id: ID!, changes: UserChanges!): User
}
-type UserChanges {
+input UserChanges {
name: String
email: String
}
@@ -36,6 +36,9 @@ func (r *mutationResolver) UpdateUser(ctx context.Context, id int, changes map[s
}
```
+Please note that map values are automatically coerced to the types defined in the schema.
+This means that optional, nested inputs or scalars will conform to their expected types.
+
We often use the mapstructure library to directly apply these changesets directly to the object using reflection:
```go
diff --git a/docs/content/reference/dataloaders.md b/docs/content/reference/dataloaders.md
index 15cfda3e3e..d28be2a8fe 100644
--- a/docs/content/reference/dataloaders.md
+++ b/docs/content/reference/dataloaders.md
@@ -18,22 +18,30 @@ query { todos { user { name } } }
and the `todo.user` resolver reads the `User` from a database...
```go
func (r *todoResolver) User(ctx context.Context, obj *model.Todo) (*model.User, error) {
- res := db.LogAndQuery(
- r.Conn,
- "SELECT id, name FROM users WHERE id = ?",
- obj.UserID,
- )
- defer res.Close()
-
- if !res.Next() {
- return nil, nil
+ stmt, err := r.db.PrepareContext(ctx, "SELECT id, name FROM users WHERE id = ?")
+ if err != nil {
+ return nil, err
+ }
+ defer stmt.Close()
+
+ rows, err := stmt.QueryContext(ctx, obj.UserID)
+ if err != nil {
+ return nil, err
+ }
+ defer rows.Close()
+
+ if !rows.Next() {
+ return nil, rows.Err()
}
+
var user model.User
- if err := res.Scan(&user.ID, &user.Name); err != nil {
- panic(err)
+ if err := rows.Scan(&user.ID, &user.Name); err != nil {
+ return nil, err
}
return &user, nil
}
+
+
```
The query executor will call the `Query.Todos` resolver which does a `select * from todo` and returns `N` todos. If the nested `User` is selected, the above `UserRaw` resolver will run a separate query for each user, resulting in `N+1` database queries.
@@ -58,17 +66,23 @@ Dataloaders allow us to consolidate the fetching of `todo.user` across all resol
We're going to use [graph-gophers/dataloader](https://github.com/graph-gophers/dataloader) to implement a dataloader for bulk-fetching users.
```bash
-go get -u github.com/graph-gophers/dataloader
+go get -u github.com/graph-gophers/dataloader/v7
```
Next, we implement a data loader and a middleware for injecting the data loader on a request context.
```go
-package storage
+package loaders
// import graph gophers with your other imports
import (
- "github.com/graph-gophers/dataloader"
+ "context"
+ "database/sql"
+ "net/http"
+ "strings"
+ "time"
+
+ "github.com/graph-gophers/dataloader/v7"
)
type ctxKey string
@@ -77,71 +91,67 @@ const (
loadersKey = ctxKey("dataloaders")
)
-// UserReader reads Users from a database
-type UserReader struct {
- conn *sql.DB
+// userReader reads Users from a database
+type userReader struct {
+ db *sql.DB
}
-// GetUsers implements a batch function that can retrieve many users by ID,
+// getUsers implements a batch function that can retrieve many users by ID,
// for use in a dataloader
-func (u *UserReader) GetUsers(ctx context.Context, keys dataloader.Keys) []*dataloader.Result {
- // read all requested users in a single query
- userIDs := make([]string, len(keys))
- for ix, key := range keys {
- userIDs[ix] = key.String()
+func (u *userReader) getUsers(ctx context.Context, userIds []string) []*dataloader.Result[*model.User] {
+ stmt, err := u.db.PrepareContext(ctx, `SELECT id, name FROM users WHERE id IN (?`+strings.Repeat(",?", len(userIds)-1)+`)`)
+ if err != nil {
+ return handleError[*model.User](len(userIds), err)
}
- res := u.db.Exec(
- r.Conn,
- "SELECT id, name
- FROM users
- WHERE id IN (?" + strings.Repeat(",?", len(userIDs-1)) + ")",
- userIDs...,
- )
- defer res.Close()
- // return User records into a map by ID
- userById := map[string]*model.User{}
- for res.Next() {
- user := model.User{}
- if err := res.Scan(&user.ID, &user.Name); err != nil {
- panic(err)
- }
- userById[user.ID] = &user
+ defer stmt.Close()
+
+ rows, err := stmt.QueryContext(ctx, userIds)
+ if err != nil {
+ return handleError[*model.User](len(userIds), err)
}
- // return users in the same order requested
- output := make([]*dataloader.Result, len(keys))
- for index, userKey := range keys {
- user, ok := userById[userKey.String()]
- if ok {
- output[index] = &dataloader.Result{Data: user, Error: nil}
- } else {
- err := fmt.Errorf("user not found %s", userKey.String())
- output[index] = &dataloader.Result{Data: nil, Error: err}
+ defer rows.Close()
+
+ result := make([]*dataloader.Result[*model.User], 0, len(userIds))
+ for rows.Next() {
+ var user model.User
+ if err := rows.Scan(&user.ID, &user.Name); err != nil {
+ result = append(result, &dataloader.Result[*model.User]{Error: err})
+ continue
}
+ result = append(result, &dataloader.Result[*model.User]{Data: &user})
}
- return output
+ return result
+}
+
+// handleError creates array of result with the same error repeated for as many items requested
+func handleError[T any](itemsLength int, err error) []*dataloader.Result[T] {
+ result := make([]*dataloader.Result[T], itemsLength)
+ for i := 0; i < itemsLength; i++ {
+ result[i] = &dataloader.Result[T]{Error: err}
+ }
+ return result
}
// Loaders wrap your data loaders to inject via middleware
type Loaders struct {
- UserLoader *dataloader.Loader
+ UserLoader *dataloader.Loader[string, *model.User]
}
// NewLoaders instantiates data loaders for the middleware
func NewLoaders(conn *sql.DB) *Loaders {
// define the data loader
- userReader := &UserReader{conn: conn}
- loaders := &Loaders{
- UserLoader: dataloader.NewBatchedLoader(userReader.GetUsers),
+ ur := &userReader{db: conn}
+ return &Loaders{
+ UserLoader: dataloader.NewBatchedLoader(ur.getUsers, dataloader.WithWait[string, *model.User](time.Millisecond)),
}
- return loaders
}
// Middleware injects data loaders into the context
-func Middleware(loaders *Loaders, next http.Handler) http.Handler {
+func Middleware(conn *sql.DB, next http.Handler) http.Handler {
// return a middleware that injects the loader to the request context
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- nextCtx := context.WithValue(r.Context(), loadersKey, loaders)
- r = r.WithContext(nextCtx)
+ loader := NewLoaders(conn)
+ r = r.WithContext(context.WithValue(r.Context(), loadersKey, loader))
next.ServeHTTP(w, r)
})
}
@@ -151,23 +161,35 @@ func For(ctx context.Context) *Loaders {
return ctx.Value(loadersKey).(*Loaders)
}
-// GetUser wraps the User dataloader for efficient retrieval by user ID
+// GetUser returns single user by id efficiently
func GetUser(ctx context.Context, userID string) (*model.User, error) {
loaders := For(ctx)
- thunk := loaders.UserLoader.Load(ctx, dataloader.StringKey(userID))
- result, err := thunk()
- if err != nil {
- return nil, err
- }
- return result.(*model.User), nil
+ return loaders.UserLoader.Load(ctx, userID)()
+}
+
+// GetUsers returns many users by ids efficiently
+func GetUsers(ctx context.Context, userIDs []string) ([]*model.User, []error) {
+ loaders := For(ctx)
+ return loaders.UserLoader.LoadMany(ctx, userIDs)()
}
```
+Add the dataloader middleware to your server...
+```go
+// create the query handler
+var srv http.Handler = handler.NewDefaultServer(generated.NewExecutableSchema(...))
+// wrap the query handler with middleware to inject dataloader in requests.
+// pass in your dataloader dependencies, in this case the db connection.
+srv = loaders.Middleware(db, srv)
+// register the wrapped handler
+http.Handle("/query", srv)
+```
+
Now lets update our resolver to call the dataloader:
```go
func (r *todoResolver) User(ctx context.Context, obj *model.Todo) (*model.User, error) {
- return storage.GetUser(ctx, obj.UserID)
+ return loaders.GetUser(ctx, obj.UserID)
}
```
diff --git a/docs/content/reference/scalars.md b/docs/content/reference/scalars.md
index 8241090b6a..137d3db8f6 100644
--- a/docs/content/reference/scalars.md
+++ b/docs/content/reference/scalars.md
@@ -7,7 +7,8 @@ menu: { main: { parent: "reference", weight: 10 } }
## Built-in helpers
-gqlgen ships with some built-in helpers for common custom scalar use-cases, `Time`, `Any`, `Upload` and `Map`. Adding any of these to a schema will automatically add the marshalling behaviour to Go types.
+gqlgen ships with some built-in helpers for common custom scalar use-cases, `Time`, `Any`, `Upload` and `Map`.
+Adding any of these to a schema will automatically add the marshalling behaviour to Go types.
### Time
@@ -15,7 +16,27 @@ gqlgen ships with some built-in helpers for common custom scalar use-cases, `Tim
scalar Time
```
-Maps a `Time` GraphQL scalar to a Go `time.Time` struct. This scalar adheres to the [time.RFC3339Nano](https://pkg.go.dev/time#pkg-constants) format.
+Maps a `Time` GraphQL scalar to a Go `time.Time` struct.
+This scalar adheres to the [time.RFC3339Nano](https://pkg.go.dev/time#pkg-constants) format.
+
+### Universally Unique Identifier (UUID)
+
+```graphql
+scalar UUID
+```
+This maps a `UUID` scalar value to a `uuid.UUID` type.
+
+If you add to gqlgen.yml:
+```yaml
+models:
+ UUID:
+ model:
+ - github.com/99designs/gqlgen/graphql.UUID
+```
+
+And then add `scalar UUID` to `schema.graphql`
+
+See the _examples/uuid package for more examples.
### Map
@@ -50,6 +71,23 @@ scalar Any
Maps an arbitrary GraphQL value to a `interface{}` Go type.
+### Duration
+
+```graphql
+scalar Duration
+```
+This maps a `Duration` scalar value conforming to the `ISO8601` standard (ex.: `P1Y2D`) to a `time.Duration` type.
+
+If you add to gqlgen.yml:
+```yaml
+models:
+ Duration:
+ model:
+ - github.com/99designs/gqlgen/graphql.Duration
+```
+
+And then add `scalar Duration` to `schema.graphql`
+
## Custom scalars with user defined types
For user defined types you can implement the [graphql.Marshaler](https://pkg.go.dev/github.com/99designs/gqlgen/graphql#Marshaler) and [graphql.Unmarshaler](https://pkg.go.dev/github.com/99designs/gqlgen/graphql#Unmarshaler) or implement the [graphql.ContextMarshaler](https://pkg.go.dev/github.com/99designs/gqlgen/graphql#ContextMarshaler) and [graphql.ContextUnmarshaler](https://pkg.go.dev/github.com/99designs/gqlgen/graphql#ContextUnmarshaler) interfaces and they will be called.
@@ -131,7 +169,7 @@ func ParseLength(string) (Length, error)
func (l Length) FormatContext(ctx context.Context) (string, error)
```
-and then wire up the type in .gqlgen.yml or via directives like normal:
+and then wire up the type in `.gqlgen.yml` or via directives like normal:
```yaml
models:
@@ -141,8 +179,8 @@ models:
## Custom scalars with third party types
-Sometimes you are unable to add add methods to a type - perhaps you don't own the type, or it is part of the standard
-library (eg string or time.Time). To support this we can build an external marshaler:
+Sometimes you are unable to add add methods to a type — perhaps you don't own the type, or it is part of the standard
+library (eg `string` or `time.Time`). To support this we can build an external marshaler:
```go
package mypkg
@@ -180,7 +218,7 @@ func UnmarshalMyCustomBooleanScalar(v interface{}) (bool, error) {
}
```
-Then in .gqlgen.yml point to the name without the Marshal|Unmarshal in front:
+Then in `.gqlgen.yml` point to the name without the Marshal|Unmarshal in front:
```yaml
models:
@@ -188,10 +226,10 @@ models:
model: github.com/me/mypkg.MyCustomBooleanScalar
```
-**Note:** you also can un/marshal to pointer types via this approach, simply accept a pointer in your
+**Note:** You also can (un)marshal to pointer types via this approach, simply accept a pointer in your
`Marshal...` func and return one in your `Unmarshal...` func.
-**Note:** you can also un/marshal with a context by having your custom marshal function return a
+**Note:** You can also (un)marshal with a context by having your custom marshal function return a
`graphql.ContextMarshaler` _and_ your unmarshal function take a `context.Context` as the first argument.
See the [_examples/scalars](https://github.com/99designs/gqlgen/tree/master/_examples/scalars) package for more examples.
@@ -199,7 +237,7 @@ See the [_examples/scalars](https://github.com/99designs/gqlgen/tree/master/_exa
## Marshaling/Unmarshaling Errors
The errors that occur as part of custom scalar marshaling/unmarshaling will return a full path to the field.
-For example, given the following schema ...
+For example, given the following schema:
```graphql
extend type Mutation{
@@ -213,6 +251,7 @@ input UserInput {
}
scalar Email
+
input ContactDetailsInput {
email: Email!
}
@@ -221,7 +260,6 @@ input ContactDetailsInput {
... and the following variables:
```json
-
{
"userInput": {
"name": "George",
@@ -235,7 +273,9 @@ input ContactDetailsInput {
}
```
-... and an unmarshal function that returns an error if the email is invalid. The mutation will return an error containing the full path:
+... and an unmarshal function that returns an error if the email is invalid.
+The mutation will return an error containing the full path:
+
```json
{
"message": "email invalid",
diff --git a/go.mod b/go.mod
index 62fd40b813..b2bbd184b1 100644
--- a/go.mod
+++ b/go.mod
@@ -3,6 +3,7 @@ module github.com/99designs/gqlgen
go 1.18
require (
+ github.com/google/uuid v1.3.0
github.com/gorilla/websocket v1.5.0
github.com/hashicorp/golang-lru/v2 v2.0.3
github.com/kevinmbeaulieu/eq-go v1.0.0
@@ -11,9 +12,10 @@ require (
github.com/mattn/go-colorable v0.1.13
github.com/mattn/go-isatty v0.0.19
github.com/mitchellh/mapstructure v1.5.0
+ github.com/sosodev/duration v1.1.0
github.com/stretchr/testify v1.8.2
github.com/urfave/cli/v2 v2.25.5
- github.com/vektah/gqlparser/v2 v2.5.7
+ github.com/vektah/gqlparser/v2 v2.5.10
golang.org/x/text v0.9.0
golang.org/x/tools v0.9.3
google.golang.org/protobuf v1.30.0
diff --git a/go.sum b/go.sum
index 309f798936..46bd6ffb74 100644
--- a/go.sum
+++ b/go.sum
@@ -1,7 +1,6 @@
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
-github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
@@ -14,17 +13,14 @@ github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
+github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/golang-lru/v2 v2.0.3 h1:kmRrRLlInXvng0SmLxmQpQkpbYAvcXm7NPDrgxJa9mE=
github.com/hashicorp/golang-lru/v2 v2.0.3/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/kevinmbeaulieu/eq-go v1.0.0 h1:AQgYHURDOmnVJ62jnEk0W/7yFKEn+Lv8RHN6t7mB0Zo=
github.com/kevinmbeaulieu/eq-go v1.0.0/go.mod h1:G3S8ajA56gKBZm4UB9AOyoOS37JO3roToPzKNM8dtdM=
-github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/logrusorgru/aurora/v3 v3.0.0 h1:R6zcoZZbvVcGMvDCKo45A9U/lzYyzl5NfYIvznmDfE4=
github.com/logrusorgru/aurora/v3 v3.0.0/go.mod h1:vsR12bk5grlLvLXAYrBsb5Oc/N+LxAlxggSjiwMnCUc=
github.com/matryer/moq v0.2.7 h1:RtpiPUM8L7ZSCbSwK+QcZH/E9tgqAkFjKQxsRs25b4w=
@@ -41,19 +37,19 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
-github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
+github.com/sosodev/duration v1.1.0 h1:kQcaiGbJaIsRqgQy7VGlZrVw1giWO+lDoX3MCPnpVO4=
+github.com/sosodev/duration v1.1.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/urfave/cli/v2 v2.25.5 h1:d0NIAyhh5shGscroL7ek/Ya9QYQE0KNabJgiUinIQkc=
github.com/urfave/cli/v2 v2.25.5/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
-github.com/vektah/gqlparser/v2 v2.5.7 h1:QnW4lWFSaycZ1jqvVaQ/tDXGGzQfqAuWdyC4S9g/KVM=
-github.com/vektah/gqlparser/v2 v2.5.7/go.mod h1:z8xXUff237NntSuH8mLFijZ+1tjV1swDbpDqjJmk6ME=
+github.com/vektah/gqlparser/v2 v2.5.10 h1:6zSM4azXC9u4Nxy5YmdmGu4uKamfwsdKTwp5zsEealU=
+github.com/vektah/gqlparser/v2 v2.5.10/go.mod h1:1rCcfwB2ekJofmluGWXMSEnPMZgbxzwj6FaZ/4OT8Cc=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
@@ -97,12 +93,9 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
-gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/graphql/context_operation.go b/graphql/context_operation.go
index 77a42b84b7..3e6a221b0b 100644
--- a/graphql/context_operation.go
+++ b/graphql/context_operation.go
@@ -73,8 +73,8 @@ func WithOperationContext(ctx context.Context, rc *OperationContext) context.Con
//
// Some errors can happen outside of an operation, eg json unmarshal errors.
func HasOperationContext(ctx context.Context) bool {
- _, ok := ctx.Value(operationCtx).(*OperationContext)
- return ok
+ val, ok := ctx.Value(operationCtx).(*OperationContext)
+ return ok && val != nil
}
// This is just a convenient wrapper method for CollectFields
diff --git a/graphql/context_operation_test.go b/graphql/context_operation_test.go
index 4ce374601f..cd4e61e716 100644
--- a/graphql/context_operation_test.go
+++ b/graphql/context_operation_test.go
@@ -3,11 +3,33 @@ package graphql
import (
"context"
"testing"
+ "time"
"github.com/stretchr/testify/require"
"github.com/vektah/gqlparser/v2/ast"
)
+// implement context.Context interface
+type testGraphRequestContext struct {
+ opContext *OperationContext
+}
+
+func (t *testGraphRequestContext) Deadline() (deadline time.Time, ok bool) {
+ return time.Time{}, false
+}
+
+func (t *testGraphRequestContext) Done() <-chan struct{} {
+ return nil
+}
+
+func (t *testGraphRequestContext) Err() error {
+ return nil
+}
+
+func (t *testGraphRequestContext) Value(key interface{}) interface{} {
+ return t.opContext
+}
+
func TestGetOperationContext(t *testing.T) {
rc := &OperationContext{}
@@ -26,6 +48,15 @@ func TestGetOperationContext(t *testing.T) {
GetOperationContext(ctx)
})
})
+
+ t.Run("with nil operation context", func(t *testing.T) {
+ ctx := &testGraphRequestContext{opContext: nil}
+
+ require.False(t, HasOperationContext(ctx))
+ require.Panics(t, func() {
+ GetOperationContext(ctx)
+ })
+ })
}
func TestCollectAllFields(t *testing.T) {
diff --git a/graphql/duration.go b/graphql/duration.go
new file mode 100644
index 0000000000..3eb392db87
--- /dev/null
+++ b/graphql/duration.go
@@ -0,0 +1,27 @@
+package graphql
+
+import (
+ "fmt"
+ "time"
+
+ dur "github.com/sosodev/duration"
+)
+
+// UnmarshalDuration returns the duration from a string in ISO8601 format
+func UnmarshalDuration(v interface{}) (time.Duration, error) {
+ input, ok := v.(string)
+ if !ok {
+ return 0, fmt.Errorf("input must be a string")
+ }
+
+ d2, err := dur.Parse(input)
+ if err != nil {
+ return 0, err
+ }
+ return d2.ToTimeDuration(), nil
+}
+
+// MarshalDuration returns the duration on ISO8601 format
+func MarshalDuration(d time.Duration) Marshaler {
+ return MarshalString(dur.Format(d))
+}
diff --git a/graphql/duration_test.go b/graphql/duration_test.go
new file mode 100644
index 0000000000..56b6031f71
--- /dev/null
+++ b/graphql/duration_test.go
@@ -0,0 +1,26 @@
+package graphql
+
+import (
+ "bytes"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestDurationMarshaling(t *testing.T) {
+ t.Run("UnmarshalDuration", func(t *testing.T) {
+ d, err := UnmarshalDuration("P2Y")
+ assert.NoError(t, err)
+
+ assert.Equal(t, float64(365*24*2), d.Hours())
+ })
+ t.Run("MarshalDuration", func(t *testing.T) {
+ m := MarshalDuration(time.Hour * 365 * 24 * 2)
+
+ buf := new(bytes.Buffer)
+ m.MarshalGQL(buf)
+
+ assert.Equal(t, "\"P2Y\"", buf.String())
+ })
+}
diff --git a/graphql/executor/executor.go b/graphql/executor/executor.go
index c46a007b99..ef0603eaa0 100644
--- a/graphql/executor/executor.go
+++ b/graphql/executor/executor.go
@@ -3,12 +3,13 @@ package executor
import (
"context"
- "github.com/99designs/gqlgen/graphql"
- "github.com/99designs/gqlgen/graphql/errcode"
"github.com/vektah/gqlparser/v2/ast"
"github.com/vektah/gqlparser/v2/gqlerror"
"github.com/vektah/gqlparser/v2/parser"
"github.com/vektah/gqlparser/v2/validator"
+
+ "github.com/99designs/gqlgen/graphql"
+ "github.com/99designs/gqlgen/graphql/errcode"
)
// Executor executes graphql queries against a schema.
diff --git a/graphql/executor/executor_test.go b/graphql/executor/executor_test.go
index cf1944bd9d..79530c1fc7 100644
--- a/graphql/executor/executor_test.go
+++ b/graphql/executor/executor_test.go
@@ -4,14 +4,15 @@ import (
"context"
"testing"
- "github.com/99designs/gqlgen/graphql"
- "github.com/99designs/gqlgen/graphql/errcode"
- "github.com/99designs/gqlgen/graphql/executor/testexecutor"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/vektah/gqlparser/v2/ast"
"github.com/vektah/gqlparser/v2/gqlerror"
"github.com/vektah/gqlparser/v2/parser"
+
+ "github.com/99designs/gqlgen/graphql"
+ "github.com/99designs/gqlgen/graphql/errcode"
+ "github.com/99designs/gqlgen/graphql/executor/testexecutor"
)
func TestExecutor(t *testing.T) {
diff --git a/graphql/executor/testexecutor/testexecutor.go b/graphql/executor/testexecutor/testexecutor.go
index bf8fd9850f..a3e0a300dc 100644
--- a/graphql/executor/testexecutor/testexecutor.go
+++ b/graphql/executor/testexecutor/testexecutor.go
@@ -8,10 +8,11 @@ import (
"io"
"time"
- "github.com/99designs/gqlgen/graphql"
- "github.com/99designs/gqlgen/graphql/executor"
"github.com/vektah/gqlparser/v2"
"github.com/vektah/gqlparser/v2/ast"
+
+ "github.com/99designs/gqlgen/graphql"
+ "github.com/99designs/gqlgen/graphql/executor"
)
type MockResponse struct {
diff --git a/graphql/handler/apollofederatedtracingv1/tracing.go b/graphql/handler/apollofederatedtracingv1/tracing.go
index b186201beb..1c969b4f64 100644
--- a/graphql/handler/apollofederatedtracingv1/tracing.go
+++ b/graphql/handler/apollofederatedtracingv1/tracing.go
@@ -5,8 +5,9 @@ import (
"encoding/base64"
"fmt"
- "github.com/99designs/gqlgen/graphql"
"google.golang.org/protobuf/proto"
+
+ "github.com/99designs/gqlgen/graphql"
)
type (
diff --git a/graphql/handler/apollofederatedtracingv1/tracing_test.go b/graphql/handler/apollofederatedtracingv1/tracing_test.go
index 7217217ed6..aa05de7127 100644
--- a/graphql/handler/apollofederatedtracingv1/tracing_test.go
+++ b/graphql/handler/apollofederatedtracingv1/tracing_test.go
@@ -12,6 +12,11 @@ import (
"testing"
"time"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "github.com/vektah/gqlparser/v2/gqlerror"
+ "google.golang.org/protobuf/proto"
+
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler/apollofederatedtracingv1"
"github.com/99designs/gqlgen/graphql/handler/apollofederatedtracingv1/generated"
@@ -19,10 +24,6 @@ import (
"github.com/99designs/gqlgen/graphql/handler/lru"
"github.com/99designs/gqlgen/graphql/handler/testserver"
"github.com/99designs/gqlgen/graphql/handler/transport"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- "github.com/vektah/gqlparser/v2/gqlerror"
- "google.golang.org/protobuf/proto"
)
type alwaysError struct{}
diff --git a/graphql/handler/apollofederatedtracingv1/tree_builder.go b/graphql/handler/apollofederatedtracingv1/tree_builder.go
index a54b12db58..e211e626c0 100644
--- a/graphql/handler/apollofederatedtracingv1/tree_builder.go
+++ b/graphql/handler/apollofederatedtracingv1/tree_builder.go
@@ -6,9 +6,10 @@ import (
"sync"
"time"
+ "google.golang.org/protobuf/types/known/timestamppb"
+
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler/apollofederatedtracingv1/generated"
- "google.golang.org/protobuf/types/known/timestamppb"
)
type TreeBuilder struct {
diff --git a/graphql/handler/apollotracing/tracer.go b/graphql/handler/apollotracing/tracer.go
index d1e92bbfdc..0d5fc597c0 100644
--- a/graphql/handler/apollotracing/tracer.go
+++ b/graphql/handler/apollotracing/tracer.go
@@ -5,8 +5,9 @@ import (
"sync"
"time"
- "github.com/99designs/gqlgen/graphql"
"github.com/vektah/gqlparser/v2/ast"
+
+ "github.com/99designs/gqlgen/graphql"
)
type (
diff --git a/graphql/handler/apollotracing/tracer_test.go b/graphql/handler/apollotracing/tracer_test.go
index 789448cae9..74e4e6e127 100644
--- a/graphql/handler/apollotracing/tracer_test.go
+++ b/graphql/handler/apollotracing/tracer_test.go
@@ -9,16 +9,17 @@ import (
"testing"
"time"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "github.com/vektah/gqlparser/v2/ast"
+ "github.com/vektah/gqlparser/v2/gqlerror"
+
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler/apollotracing"
"github.com/99designs/gqlgen/graphql/handler/extension"
"github.com/99designs/gqlgen/graphql/handler/lru"
"github.com/99designs/gqlgen/graphql/handler/testserver"
"github.com/99designs/gqlgen/graphql/handler/transport"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- "github.com/vektah/gqlparser/v2/ast"
- "github.com/vektah/gqlparser/v2/gqlerror"
)
type alwaysError struct{}
diff --git a/graphql/handler/extension/apq.go b/graphql/handler/extension/apq.go
index 866276eed9..465c2ada61 100644
--- a/graphql/handler/extension/apq.go
+++ b/graphql/handler/extension/apq.go
@@ -6,12 +6,11 @@ import (
"encoding/hex"
"fmt"
- "github.com/99designs/gqlgen/graphql/errcode"
-
+ "github.com/mitchellh/mapstructure"
"github.com/vektah/gqlparser/v2/gqlerror"
"github.com/99designs/gqlgen/graphql"
- "github.com/mitchellh/mapstructure"
+ "github.com/99designs/gqlgen/graphql/errcode"
)
const (
diff --git a/graphql/handler/extension/apq_test.go b/graphql/handler/extension/apq_test.go
index 66970c62e9..92b06a5133 100644
--- a/graphql/handler/extension/apq_test.go
+++ b/graphql/handler/extension/apq_test.go
@@ -5,11 +5,12 @@ import (
"net/http"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler/extension"
"github.com/99designs/gqlgen/graphql/handler/testserver"
"github.com/99designs/gqlgen/graphql/handler/transport"
- "github.com/stretchr/testify/require"
)
func TestAPQIntegration(t *testing.T) {
diff --git a/graphql/handler/extension/complexity.go b/graphql/handler/extension/complexity.go
index e88848d18c..a5b6a60409 100644
--- a/graphql/handler/extension/complexity.go
+++ b/graphql/handler/extension/complexity.go
@@ -4,10 +4,11 @@ import (
"context"
"fmt"
+ "github.com/vektah/gqlparser/v2/gqlerror"
+
"github.com/99designs/gqlgen/complexity"
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/errcode"
- "github.com/vektah/gqlparser/v2/gqlerror"
)
const errComplexityLimit = "COMPLEXITY_LIMIT_EXCEEDED"
diff --git a/graphql/handler/extension/complexity_test.go b/graphql/handler/extension/complexity_test.go
index e533403e1a..5141f43ee4 100644
--- a/graphql/handler/extension/complexity_test.go
+++ b/graphql/handler/extension/complexity_test.go
@@ -7,11 +7,12 @@ import (
"strings"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler/extension"
"github.com/99designs/gqlgen/graphql/handler/testserver"
"github.com/99designs/gqlgen/graphql/handler/transport"
- "github.com/stretchr/testify/require"
)
func TestHandlerComplexity(t *testing.T) {
diff --git a/graphql/handler/extension/introspection.go b/graphql/handler/extension/introspection.go
index acc5db2fbc..8e3912651d 100644
--- a/graphql/handler/extension/introspection.go
+++ b/graphql/handler/extension/introspection.go
@@ -3,8 +3,9 @@ package extension
import (
"context"
- "github.com/99designs/gqlgen/graphql"
"github.com/vektah/gqlparser/v2/gqlerror"
+
+ "github.com/99designs/gqlgen/graphql"
)
// EnableIntrospection enables clients to reflect all of the types available on the graph.
diff --git a/graphql/handler/extension/introspection_test.go b/graphql/handler/extension/introspection_test.go
index e001eb529f..f719c262a6 100644
--- a/graphql/handler/extension/introspection_test.go
+++ b/graphql/handler/extension/introspection_test.go
@@ -4,8 +4,9 @@ import (
"context"
"testing"
- "github.com/99designs/gqlgen/graphql"
"github.com/stretchr/testify/require"
+
+ "github.com/99designs/gqlgen/graphql"
)
func TestIntrospection(t *testing.T) {
diff --git a/graphql/handler/lru/lru.go b/graphql/handler/lru/lru.go
index 68241ababf..6ae8a38e64 100644
--- a/graphql/handler/lru/lru.go
+++ b/graphql/handler/lru/lru.go
@@ -3,8 +3,9 @@ package lru
import (
"context"
- "github.com/99designs/gqlgen/graphql"
lru "github.com/hashicorp/golang-lru/v2"
+
+ "github.com/99designs/gqlgen/graphql"
)
type LRU struct {
diff --git a/graphql/handler/server.go b/graphql/handler/server.go
index b6524d8da1..fd365ccbbf 100644
--- a/graphql/handler/server.go
+++ b/graphql/handler/server.go
@@ -7,12 +7,13 @@ import (
"net/http"
"time"
+ "github.com/vektah/gqlparser/v2/gqlerror"
+
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/executor"
"github.com/99designs/gqlgen/graphql/handler/extension"
"github.com/99designs/gqlgen/graphql/handler/lru"
"github.com/99designs/gqlgen/graphql/handler/transport"
- "github.com/vektah/gqlparser/v2/gqlerror"
)
type (
diff --git a/graphql/handler/server_test.go b/graphql/handler/server_test.go
index b1ac60fb49..4b31c09ac4 100644
--- a/graphql/handler/server_test.go
+++ b/graphql/handler/server_test.go
@@ -8,14 +8,15 @@ import (
"net/url"
"testing"
- "github.com/99designs/gqlgen/graphql"
- "github.com/99designs/gqlgen/graphql/handler/testserver"
- "github.com/99designs/gqlgen/graphql/handler/transport"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/vektah/gqlparser/v2/ast"
"github.com/vektah/gqlparser/v2/gqlerror"
"github.com/vektah/gqlparser/v2/parser"
+
+ "github.com/99designs/gqlgen/graphql"
+ "github.com/99designs/gqlgen/graphql/handler/testserver"
+ "github.com/99designs/gqlgen/graphql/handler/transport"
)
func TestServer(t *testing.T) {
diff --git a/graphql/handler/testserver/testserver.go b/graphql/handler/testserver/testserver.go
index 9556d6828a..85dc7d2899 100644
--- a/graphql/handler/testserver/testserver.go
+++ b/graphql/handler/testserver/testserver.go
@@ -5,10 +5,11 @@ import (
"fmt"
"time"
- "github.com/99designs/gqlgen/graphql"
- "github.com/99designs/gqlgen/graphql/handler"
"github.com/vektah/gqlparser/v2"
"github.com/vektah/gqlparser/v2/ast"
+
+ "github.com/99designs/gqlgen/graphql"
+ "github.com/99designs/gqlgen/graphql/handler"
)
// New provides a server for use in tests that isn't relying on generated code. It isnt a perfect reproduction of
diff --git a/graphql/handler/transport/error.go b/graphql/handler/transport/error.go
index b1aeaf144d..18f09f5567 100644
--- a/graphql/handler/transport/error.go
+++ b/graphql/handler/transport/error.go
@@ -5,8 +5,9 @@ import (
"fmt"
"net/http"
- "github.com/99designs/gqlgen/graphql"
"github.com/vektah/gqlparser/v2/gqlerror"
+
+ "github.com/99designs/gqlgen/graphql"
)
// SendError sends a best effort error to a raw response writer. It assumes the client can understand the standard
diff --git a/graphql/handler/transport/headers_test.go b/graphql/handler/transport/headers_test.go
index 4673522de7..93fa4bf6b6 100644
--- a/graphql/handler/transport/headers_test.go
+++ b/graphql/handler/transport/headers_test.go
@@ -6,14 +6,15 @@ import (
"net/http/httptest"
"testing"
- "github.com/99designs/gqlgen/graphql"
- "github.com/99designs/gqlgen/graphql/handler"
- "github.com/99designs/gqlgen/graphql/handler/testserver"
- "github.com/99designs/gqlgen/graphql/handler/transport"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/vektah/gqlparser/v2"
"github.com/vektah/gqlparser/v2/ast"
+
+ "github.com/99designs/gqlgen/graphql"
+ "github.com/99designs/gqlgen/graphql/handler"
+ "github.com/99designs/gqlgen/graphql/handler/testserver"
+ "github.com/99designs/gqlgen/graphql/handler/transport"
)
func TestHeadersWithPOST(t *testing.T) {
diff --git a/graphql/handler/transport/http_form_multipart_test.go b/graphql/handler/transport/http_form_multipart_test.go
index 4eb636378b..6d7c327933 100644
--- a/graphql/handler/transport/http_form_multipart_test.go
+++ b/graphql/handler/transport/http_form_multipart_test.go
@@ -11,12 +11,13 @@ import (
"net/textproto"
"testing"
- "github.com/99designs/gqlgen/graphql"
- "github.com/99designs/gqlgen/graphql/handler"
- "github.com/99designs/gqlgen/graphql/handler/transport"
"github.com/stretchr/testify/require"
"github.com/vektah/gqlparser/v2"
"github.com/vektah/gqlparser/v2/ast"
+
+ "github.com/99designs/gqlgen/graphql"
+ "github.com/99designs/gqlgen/graphql/handler"
+ "github.com/99designs/gqlgen/graphql/handler/transport"
)
func TestFileUpload(t *testing.T) {
diff --git a/graphql/handler/transport/http_form_urlencode_test.go b/graphql/handler/transport/http_form_urlencode_test.go
index 8eecf449e1..fb984167a0 100644
--- a/graphql/handler/transport/http_form_urlencode_test.go
+++ b/graphql/handler/transport/http_form_urlencode_test.go
@@ -7,9 +7,10 @@ import (
"strings"
"testing"
+ "github.com/stretchr/testify/assert"
+
"github.com/99designs/gqlgen/graphql/handler/testserver"
"github.com/99designs/gqlgen/graphql/handler/transport"
- "github.com/stretchr/testify/assert"
)
func TestUrlEncodedForm(t *testing.T) {
diff --git a/graphql/handler/transport/http_get.go b/graphql/handler/transport/http_get.go
index 324fd98683..9a47bfbef8 100644
--- a/graphql/handler/transport/http_get.go
+++ b/graphql/handler/transport/http_get.go
@@ -7,10 +7,11 @@ import (
"net/url"
"strings"
- "github.com/99designs/gqlgen/graphql"
- "github.com/99designs/gqlgen/graphql/errcode"
"github.com/vektah/gqlparser/v2/ast"
"github.com/vektah/gqlparser/v2/gqlerror"
+
+ "github.com/99designs/gqlgen/graphql"
+ "github.com/99designs/gqlgen/graphql/errcode"
)
// GET implements the GET side of the default HTTP transport
diff --git a/graphql/handler/transport/http_get_test.go b/graphql/handler/transport/http_get_test.go
index 5e46d23185..6e0dde07f5 100644
--- a/graphql/handler/transport/http_get_test.go
+++ b/graphql/handler/transport/http_get_test.go
@@ -4,9 +4,10 @@ import (
"net/http"
"testing"
+ "github.com/stretchr/testify/assert"
+
"github.com/99designs/gqlgen/graphql/handler/testserver"
"github.com/99designs/gqlgen/graphql/handler/transport"
- "github.com/stretchr/testify/assert"
)
func TestGET(t *testing.T) {
diff --git a/graphql/handler/transport/http_graphql_test.go b/graphql/handler/transport/http_graphql_test.go
index e1add4a498..53fb891f00 100644
--- a/graphql/handler/transport/http_graphql_test.go
+++ b/graphql/handler/transport/http_graphql_test.go
@@ -7,9 +7,10 @@ import (
"strings"
"testing"
+ "github.com/stretchr/testify/assert"
+
"github.com/99designs/gqlgen/graphql/handler/testserver"
"github.com/99designs/gqlgen/graphql/handler/transport"
- "github.com/stretchr/testify/assert"
)
func TestGRAPHQL(t *testing.T) {
diff --git a/graphql/handler/transport/http_post_test.go b/graphql/handler/transport/http_post_test.go
index a26ba12912..a7ecd7d5eb 100644
--- a/graphql/handler/transport/http_post_test.go
+++ b/graphql/handler/transport/http_post_test.go
@@ -7,9 +7,10 @@ import (
"strings"
"testing"
+ "github.com/stretchr/testify/assert"
+
"github.com/99designs/gqlgen/graphql/handler/testserver"
"github.com/99designs/gqlgen/graphql/handler/transport"
- "github.com/stretchr/testify/assert"
)
func TestPOST(t *testing.T) {
diff --git a/graphql/handler/transport/util.go b/graphql/handler/transport/util.go
index ce845c1964..19b7521c08 100644
--- a/graphql/handler/transport/util.go
+++ b/graphql/handler/transport/util.go
@@ -5,8 +5,9 @@ import (
"fmt"
"io"
- "github.com/99designs/gqlgen/graphql"
"github.com/vektah/gqlparser/v2/gqlerror"
+
+ "github.com/99designs/gqlgen/graphql"
)
func writeJson(w io.Writer, response *graphql.Response) {
diff --git a/graphql/handler/transport/websocket.go b/graphql/handler/transport/websocket.go
index acd124fe8e..e1334b9290 100644
--- a/graphql/handler/transport/websocket.go
+++ b/graphql/handler/transport/websocket.go
@@ -12,10 +12,11 @@ import (
"sync"
"time"
- "github.com/99designs/gqlgen/graphql"
- "github.com/99designs/gqlgen/graphql/errcode"
"github.com/gorilla/websocket"
"github.com/vektah/gqlparser/v2/gqlerror"
+
+ "github.com/99designs/gqlgen/graphql"
+ "github.com/99designs/gqlgen/graphql/errcode"
)
type (
@@ -26,7 +27,17 @@ type (
ErrorFunc WebsocketErrorFunc
CloseFunc WebsocketCloseFunc
KeepAlivePingInterval time.Duration
+ PongOnlyInterval time.Duration
PingPongInterval time.Duration
+ /* If PingPongInterval has a non-0 duration, then when the server sends a ping
+ * it sets a ReadDeadline of PingPongInterval*2 and if the client doesn't respond
+ * with pong before that deadline is reached then the connection will die with a
+ * 1006 error code.
+ *
+ * MissingPongOk if true, tells the server to not use a ReadDeadline such that a
+ * missing/slow pong response from the client doesn't kill the connection.
+ */
+ MissingPongOk bool
didInjectSubprotocols bool
}
@@ -38,13 +49,16 @@ type (
active map[string]context.CancelFunc
mu sync.Mutex
keepAliveTicker *time.Ticker
+ pongOnlyTicker *time.Ticker
pingPongTicker *time.Ticker
+ receivedPong bool
exec graphql.GraphExecutor
+ closed bool
initPayload InitPayload
}
- WebsocketInitFunc func(ctx context.Context, initPayload InitPayload) (context.Context, error)
+ WebsocketInitFunc func(ctx context.Context, initPayload InitPayload) (context.Context, *InitPayload, error)
WebsocketErrorFunc func(ctx context.Context, err error)
// Callback called when websocket is closed.
@@ -179,8 +193,10 @@ func (c *wsConnection) init() bool {
}
}
+ var initAckPayload *InitPayload = nil
if c.InitFunc != nil {
- ctx, err := c.InitFunc(c.ctx, c.initPayload)
+ var ctx context.Context
+ ctx, initAckPayload, err = c.InitFunc(c.ctx, c.initPayload)
if err != nil {
c.sendConnectionError(err.Error())
c.close(websocket.CloseNormalClosure, "terminated")
@@ -189,7 +205,15 @@ func (c *wsConnection) init() bool {
c.ctx = ctx
}
- c.write(&message{t: connectionAckMessageType})
+ if initAckPayload != nil {
+ initJsonAckPayload, err := json.Marshal(*initAckPayload)
+ if err != nil {
+ panic(err)
+ }
+ c.write(&message{t: connectionAckMessageType, payload: initJsonAckPayload})
+ } else {
+ c.write(&message{t: connectionAckMessageType})
+ }
c.write(&message{t: keepAliveMessageType})
case connectionCloseMessageType:
c.close(websocket.CloseNormalClosure, "terminated")
@@ -228,16 +252,28 @@ func (c *wsConnection) run() {
go c.keepAlive(ctx)
}
+ // If we're running in graphql-transport-ws mode, create a timer that will trigger a
+ // just a pong message every interval
+ if c.conn.Subprotocol() == graphqltransportwsSubprotocol && c.PongOnlyInterval != 0 {
+ c.mu.Lock()
+ c.pongOnlyTicker = time.NewTicker(c.PongOnlyInterval)
+ c.mu.Unlock()
+
+ go c.keepAlivePongOnly(ctx)
+ }
+
// If we're running in graphql-transport-ws mode, create a timer that will
- // trigger a ping message every interval
+ // trigger a ping message every interval and expect a pong!
if c.conn.Subprotocol() == graphqltransportwsSubprotocol && c.PingPongInterval != 0 {
c.mu.Lock()
c.pingPongTicker = time.NewTicker(c.PingPongInterval)
c.mu.Unlock()
- // Note: when the connection is closed by this deadline, the client
- // will receive an "invalid close code"
- c.conn.SetReadDeadline(time.Now().UTC().Add(2 * c.PingPongInterval))
+ if !c.MissingPongOk {
+ // Note: when the connection is closed by this deadline, the client
+ // will receive an "invalid close code"
+ c.conn.SetReadDeadline(time.Now().UTC().Add(2 * c.PingPongInterval))
+ }
go c.ping(ctx)
}
@@ -272,7 +308,11 @@ func (c *wsConnection) run() {
case pingMessageType:
c.write(&message{t: pongMessageType, payload: m.payload})
case pongMessageType:
- c.conn.SetReadDeadline(time.Now().UTC().Add(2 * c.PingPongInterval))
+ c.mu.Lock()
+ c.receivedPong = true
+ c.mu.Unlock()
+ // Clear ReadTimeout -- 0 time val clears.
+ c.conn.SetReadDeadline(time.Time{})
default:
c.sendConnectionError("unexpected message %s", m.t)
c.close(websocket.CloseProtocolError, "unexpected message")
@@ -281,6 +321,18 @@ func (c *wsConnection) run() {
}
}
+func (c *wsConnection) keepAlivePongOnly(ctx context.Context) {
+ for {
+ select {
+ case <-ctx.Done():
+ c.pongOnlyTicker.Stop()
+ return
+ case <-c.pongOnlyTicker.C:
+ c.write(&message{t: pongMessageType, payload: json.RawMessage{}})
+ }
+ }
+}
+
func (c *wsConnection) keepAlive(ctx context.Context) {
for {
select {
@@ -301,6 +353,14 @@ func (c *wsConnection) ping(ctx context.Context) {
return
case <-c.pingPongTicker.C:
c.write(&message{t: pingMessageType, payload: json.RawMessage{}})
+ // The initial deadline for this method is set in run()
+ // if we have not yet received a pong, don't reset the deadline.
+ c.mu.Lock()
+ if !c.MissingPongOk && c.receivedPong {
+ c.conn.SetReadDeadline(time.Now().UTC().Add(2 * c.PingPongInterval))
+ }
+ c.receivedPong = false
+ c.mu.Unlock()
}
}
}
@@ -431,10 +491,15 @@ func (c *wsConnection) sendConnectionError(format string, args ...interface{}) {
func (c *wsConnection) close(closeCode int, message string) {
c.mu.Lock()
+ if c.closed {
+ c.mu.Unlock()
+ return
+ }
_ = c.conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(closeCode, message))
for _, closer := range c.active {
closer()
}
+ c.closed = true
c.mu.Unlock()
_ = c.conn.Close()
diff --git a/graphql/handler/transport/websocket_test.go b/graphql/handler/transport/websocket_test.go
index 9ac8ad65cc..e933677248 100644
--- a/graphql/handler/transport/websocket_test.go
+++ b/graphql/handler/transport/websocket_test.go
@@ -10,16 +10,17 @@ import (
"testing"
"time"
- "github.com/99designs/gqlgen/client"
- "github.com/99designs/gqlgen/graphql"
- "github.com/99designs/gqlgen/graphql/handler"
- "github.com/99designs/gqlgen/graphql/handler/testserver"
- "github.com/99designs/gqlgen/graphql/handler/transport"
"github.com/gorilla/websocket"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/vektah/gqlparser/v2"
"github.com/vektah/gqlparser/v2/ast"
+
+ "github.com/99designs/gqlgen/client"
+ "github.com/99designs/gqlgen/graphql"
+ "github.com/99designs/gqlgen/graphql/handler"
+ "github.com/99designs/gqlgen/graphql/handler/testserver"
+ "github.com/99designs/gqlgen/graphql/handler/transport"
)
type ckey string
@@ -207,8 +208,8 @@ func TestWebsocketInitFunc(t *testing.T) {
t.Run("accept connection if WebsocketInitFunc is provided and is accepting connection", func(t *testing.T) {
h := testserver.New()
h.AddTransport(transport.Websocket{
- InitFunc: func(ctx context.Context, initPayload transport.InitPayload) (context.Context, error) {
- return context.WithValue(ctx, ckey("newkey"), "newvalue"), nil
+ InitFunc: func(ctx context.Context, initPayload transport.InitPayload) (context.Context, *transport.InitPayload, error) {
+ return context.WithValue(ctx, ckey("newkey"), "newvalue"), nil, nil
},
})
srv := httptest.NewServer(h)
@@ -226,8 +227,8 @@ func TestWebsocketInitFunc(t *testing.T) {
t.Run("reject connection if WebsocketInitFunc is provided and is accepting connection", func(t *testing.T) {
h := testserver.New()
h.AddTransport(transport.Websocket{
- InitFunc: func(ctx context.Context, initPayload transport.InitPayload) (context.Context, error) {
- return ctx, errors.New("invalid init payload")
+ InitFunc: func(ctx context.Context, initPayload transport.InitPayload) (context.Context, *transport.InitPayload, error) {
+ return ctx, nil, errors.New("invalid init payload")
},
})
srv := httptest.NewServer(h)
@@ -261,8 +262,8 @@ func TestWebsocketInitFunc(t *testing.T) {
h := handler.New(es)
h.AddTransport(transport.Websocket{
- InitFunc: func(ctx context.Context, initPayload transport.InitPayload) (context.Context, error) {
- return context.WithValue(ctx, ckey("newkey"), "newvalue"), nil
+ InitFunc: func(ctx context.Context, initPayload transport.InitPayload) (context.Context, *transport.InitPayload, error) {
+ return context.WithValue(ctx, ckey("newkey"), "newvalue"), nil, nil
},
})
@@ -282,7 +283,7 @@ func TestWebsocketInitFunc(t *testing.T) {
h := testserver.New()
var cancel func()
h.AddTransport(transport.Websocket{
- InitFunc: func(ctx context.Context, _ transport.InitPayload) (newCtx context.Context, _ error) {
+ InitFunc: func(ctx context.Context, _ transport.InitPayload) (newCtx context.Context, _ *transport.InitPayload, _ error) {
newCtx, cancel = context.WithTimeout(transport.AppendCloseReason(ctx, "beep boop"), time.Millisecond*5)
return
},
@@ -303,6 +304,33 @@ func TestWebsocketInitFunc(t *testing.T) {
assert.Equal(t, m.Type, connectionErrorMsg)
assert.Equal(t, string(m.Payload), `{"message":"beep boop"}`)
})
+ t.Run("accept connection if WebsocketInitFunc is provided and is accepting connection", func(t *testing.T) {
+ h := testserver.New()
+ h.AddTransport(transport.Websocket{
+ InitFunc: func(ctx context.Context, initPayload transport.InitPayload) (context.Context, *transport.InitPayload, error) {
+ initResponsePayload := transport.InitPayload{"trackingId": "123-456"}
+ return context.WithValue(ctx, ckey("newkey"), "newvalue"), &initResponsePayload, nil
+ },
+ })
+ srv := httptest.NewServer(h)
+ defer srv.Close()
+
+ c := wsConnect(srv.URL)
+ defer c.Close()
+
+ require.NoError(t, c.WriteJSON(&operationMessage{Type: connectionInitMsg}))
+
+ connAck := readOp(c)
+ assert.Equal(t, connectionAckMsg, connAck.Type)
+
+ var payload map[string]interface{}
+ err := json.Unmarshal(connAck.Payload, &payload)
+ if err != nil {
+ t.Fatal("Unexpected Error", err)
+ }
+ assert.EqualValues(t, "123-456", payload["trackingId"])
+ assert.Equal(t, connectionKeepAliveMsg, readOp(c).Type)
+ })
}
func TestWebSocketInitTimeout(t *testing.T) {
@@ -382,8 +410,8 @@ func TestWebSocketErrorFunc(t *testing.T) {
t.Run("init func errors do not call the error handler", func(t *testing.T) {
h := testserver.New()
h.AddTransport(transport.Websocket{
- InitFunc: func(ctx context.Context, _ transport.InitPayload) (context.Context, error) {
- return ctx, errors.New("this is not what we agreed upon")
+ InitFunc: func(ctx context.Context, _ transport.InitPayload) (context.Context, *transport.InitPayload, error) {
+ return ctx, nil, errors.New("this is not what we agreed upon")
},
ErrorFunc: func(_ context.Context, err error) {
assert.Fail(t, "the error handler got called when it shouldn't have", "error: "+err.Error())
@@ -400,10 +428,10 @@ func TestWebSocketErrorFunc(t *testing.T) {
t.Run("init func context closes do not call the error handler", func(t *testing.T) {
h := testserver.New()
h.AddTransport(transport.Websocket{
- InitFunc: func(ctx context.Context, _ transport.InitPayload) (context.Context, error) {
+ InitFunc: func(ctx context.Context, _ transport.InitPayload) (context.Context, *transport.InitPayload, error) {
newCtx, cancel := context.WithCancel(ctx)
time.AfterFunc(time.Millisecond*5, cancel)
- return newCtx, nil
+ return newCtx, nil, nil
},
ErrorFunc: func(_ context.Context, err error) {
assert.Fail(t, "the error handler got called when it shouldn't have", "error: "+err.Error())
@@ -423,9 +451,9 @@ func TestWebSocketErrorFunc(t *testing.T) {
h := testserver.New()
var cancel func()
h.AddTransport(transport.Websocket{
- InitFunc: func(ctx context.Context, _ transport.InitPayload) (newCtx context.Context, _ error) {
+ InitFunc: func(ctx context.Context, _ transport.InitPayload) (newCtx context.Context, _ *transport.InitPayload, _ error) {
newCtx, cancel = context.WithDeadline(ctx, time.Now().Add(time.Millisecond*5))
- return newCtx, nil
+ return newCtx, nil, nil
},
ErrorFunc: func(_ context.Context, err error) {
assert.Fail(t, "the error handler got called when it shouldn't have", "error: "+err.Error())
@@ -473,12 +501,45 @@ func TestWebSocketCloseFunc(t *testing.T) {
}
})
+ t.Run("the on close handler gets called only once when the websocket is closed", func(t *testing.T) {
+ closeFuncCalled := make(chan bool, 1)
+ h := testserver.New()
+ h.AddTransport(transport.Websocket{
+ CloseFunc: func(_ context.Context, _closeCode int) {
+ closeFuncCalled <- true
+ },
+ })
+
+ srv := httptest.NewServer(h)
+ defer srv.Close()
+
+ c := wsConnect(srv.URL)
+ require.NoError(t, c.WriteJSON(&operationMessage{Type: connectionInitMsg}))
+ assert.Equal(t, connectionAckMsg, readOp(c).Type)
+ assert.Equal(t, connectionKeepAliveMsg, readOp(c).Type)
+ require.NoError(t, c.WriteJSON(&operationMessage{Type: connectionTerminateMsg}))
+
+ select {
+ case res := <-closeFuncCalled:
+ assert.True(t, res)
+ case <-time.NewTimer(time.Millisecond * 20).C:
+ assert.Fail(t, "The close handler was not called in time")
+ }
+
+ select {
+ case <-closeFuncCalled:
+ assert.Fail(t, "The close handler was called more than once")
+ case <-time.NewTimer(time.Millisecond * 20).C:
+ // ok
+ }
+ })
+
t.Run("init func errors call the close handler", func(t *testing.T) {
h := testserver.New()
closeFuncCalled := make(chan bool, 1)
h.AddTransport(transport.Websocket{
- InitFunc: func(ctx context.Context, _ transport.InitPayload) (context.Context, error) {
- return ctx, errors.New("error during init")
+ InitFunc: func(ctx context.Context, _ transport.InitPayload) (context.Context, *transport.InitPayload, error) {
+ return ctx, nil, errors.New("error during init")
},
CloseFunc: func(_ context.Context, _closeCode int) {
closeFuncCalled <- true
@@ -578,7 +639,7 @@ func TestWebsocketWithPingPongInterval(t *testing.T) {
}
t.Run("client receives ping and responds with pong", func(t *testing.T) {
- _, srv := initialize(transport.Websocket{PingPongInterval: 10 * time.Millisecond})
+ _, srv := initialize(transport.Websocket{PingPongInterval: 20 * time.Millisecond})
defer srv.Close()
c := wsConnectWithSubprocotol(srv.URL, graphqltransportwsSubprotocol)
@@ -592,6 +653,11 @@ func TestWebsocketWithPingPongInterval(t *testing.T) {
assert.Equal(t, graphqltransportwsPingMsg, readOp(c).Type)
})
+ t.Run("client sends ping and expects pong", func(t *testing.T) {
+ _, srv := initialize(transport.Websocket{PingPongInterval: 10 * time.Millisecond})
+ defer srv.Close()
+ })
+
t.Run("client sends ping and expects pong", func(t *testing.T) {
_, srv := initialize(transport.Websocket{PingPongInterval: 10 * time.Millisecond})
defer srv.Close()
@@ -606,6 +672,67 @@ func TestWebsocketWithPingPongInterval(t *testing.T) {
assert.Equal(t, graphqltransportwsPongMsg, readOp(c).Type)
})
+ t.Run("server closes with error if client does not pong and !MissingPongOk", func(t *testing.T) {
+ h := testserver.New()
+ closeFuncCalled := make(chan bool, 1)
+ h.AddTransport(transport.Websocket{
+ MissingPongOk: false, // default value but beign explicit for test clarity.
+ PingPongInterval: 5 * time.Millisecond,
+ CloseFunc: func(_ context.Context, _closeCode int) {
+ closeFuncCalled <- true
+ },
+ })
+
+ srv := httptest.NewServer(h)
+ defer srv.Close()
+
+ c := wsConnectWithSubprocotol(srv.URL, graphqltransportwsSubprotocol)
+ defer c.Close()
+
+ require.NoError(t, c.WriteJSON(&operationMessage{Type: graphqltransportwsConnectionInitMsg}))
+ assert.Equal(t, graphqltransportwsConnectionAckMsg, readOp(c).Type)
+
+ assert.Equal(t, graphqltransportwsPingMsg, readOp(c).Type)
+
+ select {
+ case res := <-closeFuncCalled:
+ assert.True(t, res)
+ case <-time.NewTimer(time.Millisecond * 20).C:
+ // with a 5ms interval 10ms should be the timeout, double that to make the test less likely to flake under load
+ assert.Fail(t, "The close handler was not called in time")
+ }
+ })
+
+ t.Run("server does not close with error if client does not pong and MissingPongOk", func(t *testing.T) {
+ h := testserver.New()
+ closeFuncCalled := make(chan bool, 1)
+ h.AddTransport(transport.Websocket{
+ MissingPongOk: true,
+ PingPongInterval: 10 * time.Millisecond,
+ CloseFunc: func(_ context.Context, _closeCode int) {
+ closeFuncCalled <- true
+ },
+ })
+
+ srv := httptest.NewServer(h)
+ defer srv.Close()
+
+ c := wsConnectWithSubprocotol(srv.URL, graphqltransportwsSubprotocol)
+ defer c.Close()
+
+ require.NoError(t, c.WriteJSON(&operationMessage{Type: graphqltransportwsConnectionInitMsg}))
+ assert.Equal(t, graphqltransportwsConnectionAckMsg, readOp(c).Type)
+
+ assert.Equal(t, graphqltransportwsPingMsg, readOp(c).Type)
+
+ select {
+ case <-closeFuncCalled:
+ assert.Fail(t, "The close handler was called even with MissingPongOk = true")
+ case _, ok := <-time.NewTimer(time.Millisecond * 20).C:
+ assert.True(t, ok)
+ }
+ })
+
t.Run("ping-pongs are not sent when the graphql-ws sub protocol is used", func(t *testing.T) {
// Regression test
// ---
@@ -632,6 +759,41 @@ func TestWebsocketWithPingPongInterval(t *testing.T) {
assert.Equal(t, connectionKeepAliveMsg, readOp(c).Type)
assert.Equal(t, connectionKeepAliveMsg, readOp(c).Type)
})
+ t.Run("pong only messages are sent when configured with graphql-transport-ws", func(t *testing.T) {
+
+ h, srv := initialize(transport.Websocket{PongOnlyInterval: 10 * time.Millisecond})
+ defer srv.Close()
+
+ c := wsConnectWithSubprocotol(srv.URL, graphqltransportwsSubprotocol)
+ defer c.Close()
+
+ require.NoError(t, c.WriteJSON(&operationMessage{Type: graphqltransportwsConnectionInitMsg}))
+ assert.Equal(t, graphqltransportwsConnectionAckMsg, readOp(c).Type)
+
+ assert.Equal(t, graphqltransportwsPongMsg, readOp(c).Type)
+
+ require.NoError(t, c.WriteJSON(&operationMessage{
+ Type: graphqltransportwsSubscribeMsg,
+ ID: "test_1",
+ Payload: json.RawMessage(`{"query": "subscription { name }"}`),
+ }))
+
+ // pong
+ msg := readOp(c)
+ assert.Equal(t, graphqltransportwsPongMsg, msg.Type)
+
+ // server message
+ h.SendNextSubscriptionMessage()
+ msg = readOp(c)
+ require.Equal(t, graphqltransportwsNextMsg, msg.Type, string(msg.Payload))
+ require.Equal(t, "test_1", msg.ID, string(msg.Payload))
+ require.Equal(t, `{"data":{"name":"test"}}`, string(msg.Payload))
+
+ // keepalive
+ msg = readOp(c)
+ assert.Equal(t, graphqltransportwsPongMsg, msg.Type)
+ })
+
}
func wsConnect(url string) *websocket.Conn {
diff --git a/graphql/introspection/schema.go b/graphql/introspection/schema.go
index b7b0ad94e0..897b1a098f 100644
--- a/graphql/introspection/schema.go
+++ b/graphql/introspection/schema.go
@@ -2,7 +2,6 @@ package introspection
import (
"sort"
- "strings"
"github.com/vektah/gqlparser/v2/ast"
)
@@ -22,9 +21,6 @@ func (s *Schema) Types() []Type {
typeIndex := map[string]Type{}
typeNames := make([]string, 0, len(s.schema.Types))
for _, typ := range s.schema.Types {
- if strings.HasPrefix(typ.Name, "__") {
- continue
- }
typeNames = append(typeNames, typ.Name)
typeIndex[typ.Name] = *WrapTypeFromDef(s.schema, typ)
}
diff --git a/graphql/introspection/schema_test.go b/graphql/introspection/schema_test.go
new file mode 100644
index 0000000000..92022b1179
--- /dev/null
+++ b/graphql/introspection/schema_test.go
@@ -0,0 +1,68 @@
+package introspection
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+ "github.com/vektah/gqlparser/v2/ast"
+)
+
+func TestSchema(t *testing.T) {
+ query := &ast.Definition{
+ Name: "Query",
+ Kind: ast.Object,
+ }
+
+ mutation := &ast.Definition{
+ Name: "Mutation",
+ Kind: ast.Object,
+ }
+
+ subscription := &ast.Definition{
+ Name: "Subscription",
+ Kind: ast.Object,
+ }
+
+ directive := &ast.Definition{
+ Name: "__Directive",
+ Kind: ast.Object,
+ }
+
+ schema := &Schema{
+ schema: &ast.Schema{
+ Query: query,
+ Mutation: mutation,
+ Subscription: subscription,
+ Types: map[string]*ast.Definition{
+ "Query": query,
+ "Mutation": mutation,
+ "__Directive": directive,
+ },
+ Description: "test description",
+ },
+ }
+
+ t.Run("description", func(t *testing.T) {
+ require.EqualValues(t, "test description", *schema.Description())
+ })
+
+ t.Run("query type", func(t *testing.T) {
+ require.Equal(t, "Query", *schema.QueryType().Name())
+ })
+
+ t.Run("mutation type", func(t *testing.T) {
+ require.Equal(t, "Mutation", *schema.MutationType().Name())
+ })
+
+ t.Run("subscription type", func(t *testing.T) {
+ require.Equal(t, "Subscription", *schema.SubscriptionType().Name())
+ })
+
+ t.Run("types", func(t *testing.T) {
+ types := schema.Types()
+ require.Len(t, types, 3)
+ require.Equal(t, "Mutation", *types[0].Name())
+ require.Equal(t, "Query", *types[1].Name())
+ require.Equal(t, "__Directive", *types[2].Name())
+ })
+}
diff --git a/graphql/playground/playground.go b/graphql/playground/playground.go
index da17ca6201..1719cd7388 100644
--- a/graphql/playground/playground.go
+++ b/graphql/playground/playground.go
@@ -58,13 +58,24 @@ var page = template.Must(template.New("graphiql").Parse(`
const wsProto = location.protocol == 'https:' ? 'wss:' : 'ws:';
const subscriptionUrl = wsProto + '//' + location.host + {{.endpoint}};
{{- end}}
+{{- if .fetcherHeaders}}
+ const fetcherHeaders = {{.fetcherHeaders}};
+{{- else}}
+ const fetcherHeaders = undefined;
+{{- end}}
+{{- if .uiHeaders}}
+ const uiHeaders = {{.uiHeaders}};
+{{- else}}
+ const uiHeaders = undefined;
+{{- end}}
- const fetcher = GraphiQL.createFetcher({ url, subscriptionUrl });
+ const fetcher = GraphiQL.createFetcher({ url, subscriptionUrl, headers: fetcherHeaders });
ReactDOM.render(
React.createElement(GraphiQL, {
fetcher: fetcher,
isHeadersEditorEnabled: true,
- shouldPersistHeaders: true
+ shouldPersistHeaders: true,
+ headers: JSON.stringify(uiHeaders, null, 2)
}),
document.getElementById('graphiql'),
);
@@ -75,11 +86,20 @@ var page = template.Must(template.New("graphiql").Parse(`
// Handler responsible for setting up the playground
func Handler(title string, endpoint string) http.HandlerFunc {
+ return HandlerWithHeaders(title, endpoint, nil, nil)
+}
+
+// HandlerWithHeaders sets up the playground.
+// fetcherHeaders are used by the playground's fetcher instance and will not be visible in the UI.
+// uiHeaders are default headers that will show up in the UI headers editor.
+func HandlerWithHeaders(title string, endpoint string, fetcherHeaders map[string]string, uiHeaders map[string]string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Type", "text/html; charset=UTF-8")
err := page.Execute(w, map[string]interface{}{
"title": title,
"endpoint": endpoint,
+ "fetcherHeaders": fetcherHeaders,
+ "uiHeaders": uiHeaders,
"endpointIsAbsolute": endpointHasScheme(endpoint),
"subscriptionEndpoint": getSubscriptionEndpoint(endpoint),
"version": "3.0.1",
diff --git a/graphql/uuid.go b/graphql/uuid.go
new file mode 100644
index 0000000000..e9f22dccdb
--- /dev/null
+++ b/graphql/uuid.go
@@ -0,0 +1,25 @@
+package graphql
+
+import (
+ "fmt"
+
+ "github.com/google/uuid"
+)
+
+func MarshalUUID(id uuid.UUID) Marshaler {
+ if id == uuid.Nil {
+ return Null
+ }
+ return MarshalString(id.String())
+}
+
+func UnmarshalUUID(v any) (uuid.UUID, error) {
+ switch v := v.(type) {
+ case string:
+ return uuid.Parse(v)
+ case []byte:
+ return uuid.ParseBytes(v)
+ default:
+ return uuid.Nil, fmt.Errorf("%T is not a uuid", v)
+ }
+}
diff --git a/graphql/uuid_test.go b/graphql/uuid_test.go
new file mode 100644
index 0000000000..1d20996449
--- /dev/null
+++ b/graphql/uuid_test.go
@@ -0,0 +1,56 @@
+package graphql
+
+import (
+ "testing"
+
+ "github.com/google/uuid"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestMarshalUUID(t *testing.T) {
+ t.Run("Null Values", func(t *testing.T) {
+ assert.Equal(t, "null", m2s(MarshalUUID(uuid.Nil)))
+ })
+
+ t.Run("Valid Values", func(t *testing.T) {
+
+ var values = []struct {
+ input uuid.UUID
+ expected string
+ }{
+ {uuid.MustParse("fd5343a9-0372-11ee-9fb2-0242ac160014"), "\"fd5343a9-0372-11ee-9fb2-0242ac160014\""},
+ }
+ for _, v := range values {
+ assert.Equal(t, v.expected, m2s(MarshalUUID(v.input)))
+ }
+ })
+}
+
+func TestUnmarshalUUID(t *testing.T) {
+ t.Run("Invalid Non-String Values", func(t *testing.T) {
+ var values = []interface{}{123, 1.2345678901, 1.2e+20, 1.2e-20, true, false, nil}
+ for _, v := range values {
+ result, err := UnmarshalUUID(v)
+ assert.Equal(t, uuid.Nil, result)
+ assert.ErrorContains(t, err, "is not a uuid")
+ }
+ })
+
+ t.Run("Invalid String Values", func(t *testing.T) {
+ var values = []struct {
+ input string
+ expected string
+ }{
+ {"X50e8400-e29b-41d4-a716-446655440000", "invalid UUID format"},
+ {"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "invalid UUID format"},
+ {"F50e8400-e29b-41d4-a716-44665544000", "invalid UUID length: 35"},
+ {"aaa", "invalid UUID length: 3"},
+ {"", "invalid UUID length: 0"},
+ }
+ for _, v := range values {
+ result, err := UnmarshalUUID(v.input)
+ assert.Equal(t, uuid.Nil, result)
+ assert.ErrorContains(t, err, v.expected)
+ }
+ })
+}
diff --git a/graphql/version.go b/graphql/version.go
index 8c16fdb5b9..92812f7acc 100644
--- a/graphql/version.go
+++ b/graphql/version.go
@@ -1,3 +1,3 @@
package graphql
-const Version = "v0.17.35-dev"
+const Version = "v0.17.40-dev"
diff --git a/handler/handler.go b/handler/handler.go
index 19491020de..08e6a4c0e1 100644
--- a/handler/handler.go
+++ b/handler/handler.go
@@ -5,13 +5,14 @@ import (
"net/http"
"time"
+ "github.com/gorilla/websocket"
+
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/handler/extension"
"github.com/99designs/gqlgen/graphql/handler/lru"
"github.com/99designs/gqlgen/graphql/handler/transport"
"github.com/99designs/gqlgen/graphql/playground"
- "github.com/gorilla/websocket"
)
// Deprecated: switch to graphql/handler.New
diff --git a/integration/package-lock.json b/integration/package-lock.json
index 195a333e0c..21e629b5f7 100644
--- a/integration/package-lock.json
+++ b/integration/package-lock.json
@@ -202,17 +202,80 @@
}
},
"node_modules/@babel/code-frame": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz",
- "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==",
+ "version": "7.22.13",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
+ "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
"dev": true,
"dependencies": {
- "@babel/highlight": "^7.22.5"
+ "@babel/highlight": "^7.22.13",
+ "chalk": "^2.4.2"
},
"engines": {
"node": ">=6.9.0"
}
},
+ "node_modules/@babel/code-frame/node_modules/ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/code-frame/node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/code-frame/node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/@babel/code-frame/node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "dev": true
+ },
+ "node_modules/@babel/code-frame/node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/code-frame/node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/@babel/compat-data": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.5.tgz",
@@ -253,12 +316,12 @@
}
},
"node_modules/@babel/generator": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.5.tgz",
- "integrity": "sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
+ "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.22.5",
+ "@babel/types": "^7.23.0",
"@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17",
"jsesc": "^2.5.1"
@@ -322,22 +385,22 @@
}
},
"node_modules/@babel/helper-environment-visitor": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz",
- "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
+ "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-function-name": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz",
- "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
+ "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
"dev": true,
"dependencies": {
- "@babel/template": "^7.22.5",
- "@babel/types": "^7.22.5"
+ "@babel/template": "^7.22.15",
+ "@babel/types": "^7.23.0"
},
"engines": {
"node": ">=6.9.0"
@@ -461,9 +524,9 @@
}
},
"node_modules/@babel/helper-split-export-declaration": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz",
- "integrity": "sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==",
+ "version": "7.22.6",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
+ "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
"dev": true,
"dependencies": {
"@babel/types": "^7.22.5"
@@ -482,9 +545,9 @@
}
},
"node_modules/@babel/helper-validator-identifier": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz",
- "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
+ "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
"dev": true,
"engines": {
"node": ">=6.9.0"
@@ -514,13 +577,13 @@
}
},
"node_modules/@babel/highlight": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz",
- "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
+ "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
"dev": true,
"dependencies": {
- "@babel/helper-validator-identifier": "^7.22.5",
- "chalk": "^2.0.0",
+ "@babel/helper-validator-identifier": "^7.22.20",
+ "chalk": "^2.4.2",
"js-tokens": "^4.0.0"
},
"engines": {
@@ -590,9 +653,9 @@
}
},
"node_modules/@babel/parser": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.5.tgz",
- "integrity": "sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
+ "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
"dev": true,
"bin": {
"parser": "bin/babel-parser.js"
@@ -1038,33 +1101,33 @@
}
},
"node_modules/@babel/template": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz",
- "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
+ "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
"dev": true,
"dependencies": {
- "@babel/code-frame": "^7.22.5",
- "@babel/parser": "^7.22.5",
- "@babel/types": "^7.22.5"
+ "@babel/code-frame": "^7.22.13",
+ "@babel/parser": "^7.22.15",
+ "@babel/types": "^7.22.15"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.5.tgz",
- "integrity": "sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==",
+ "version": "7.23.2",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
+ "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
"dev": true,
"dependencies": {
- "@babel/code-frame": "^7.22.5",
- "@babel/generator": "^7.22.5",
- "@babel/helper-environment-visitor": "^7.22.5",
- "@babel/helper-function-name": "^7.22.5",
+ "@babel/code-frame": "^7.22.13",
+ "@babel/generator": "^7.23.0",
+ "@babel/helper-environment-visitor": "^7.22.20",
+ "@babel/helper-function-name": "^7.23.0",
"@babel/helper-hoist-variables": "^7.22.5",
- "@babel/helper-split-export-declaration": "^7.22.5",
- "@babel/parser": "^7.22.5",
- "@babel/types": "^7.22.5",
+ "@babel/helper-split-export-declaration": "^7.22.6",
+ "@babel/parser": "^7.23.0",
+ "@babel/types": "^7.23.0",
"debug": "^4.1.0",
"globals": "^11.1.0"
},
@@ -1073,13 +1136,13 @@
}
},
"node_modules/@babel/types": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz",
- "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
+ "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
"dev": true,
"dependencies": {
"@babel/helper-string-parser": "^7.22.5",
- "@babel/helper-validator-identifier": "^7.22.5",
+ "@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
},
"engines": {
@@ -5835,9 +5898,9 @@
}
},
"node_modules/postcss": {
- "version": "8.4.24",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz",
- "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==",
+ "version": "8.4.31",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
+ "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"dev": true,
"funding": [
{
diff --git a/integration/server/cmd/integration/server.go b/integration/server/cmd/integration/server.go
index fec1c4827a..df542a4045 100644
--- a/integration/server/cmd/integration/server.go
+++ b/integration/server/cmd/integration/server.go
@@ -8,6 +8,8 @@ import (
"os"
"time"
+ "github.com/vektah/gqlparser/v2/gqlerror"
+
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/handler/extension"
@@ -15,7 +17,6 @@ import (
"github.com/99designs/gqlgen/graphql/handler/transport"
"github.com/99designs/gqlgen/graphql/playground"
"github.com/99designs/gqlgen/integration/server"
- "github.com/vektah/gqlparser/v2/gqlerror"
)
const defaultPort = "8080"
diff --git a/integration/server/generated.go b/integration/server/generated.go
index 6928d3f2d5..7b2c5c3ee1 100644
--- a/integration/server/generated.go
+++ b/integration/server/generated.go
@@ -26,6 +26,7 @@ import (
// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
return &executableSchema{
+ schema: cfg.Schema,
resolvers: cfg.Resolvers,
directives: cfg.Directives,
complexity: cfg.Complexity,
@@ -33,6 +34,7 @@ func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
}
type Config struct {
+ Schema *ast.Schema
Resolvers ResolverRoot
Directives DirectiveRoot
Complexity ComplexityRoot
@@ -99,12 +101,16 @@ type UserResolver interface {
}
type executableSchema struct {
+ schema *ast.Schema
resolvers ResolverRoot
directives DirectiveRoot
complexity ComplexityRoot
}
func (e *executableSchema) Schema() *ast.Schema {
+ if e.schema != nil {
+ return e.schema
+ }
return parsedSchema
}
@@ -319,14 +325,14 @@ func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapSchema(parsedSchema), nil
+ return introspection.WrapSchema(ec.Schema()), nil
}
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
+ return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil
}
//go:embed "schema/schema.graphql" "schema/testomitempty.graphql" "schema/user.graphql"
diff --git a/internal/code/packages.go b/internal/code/packages.go
index 6cb6ef2323..e7f8655aa0 100644
--- a/internal/code/packages.go
+++ b/internal/code/packages.go
@@ -28,15 +28,37 @@ var mode = packages.NeedName |
packages.NeedModule |
packages.NeedDeps
-// Packages is a wrapper around x/tools/go/packages that maintains a (hopefully prewarmed) cache of packages
-// that can be invalidated as writes are made and packages are known to change.
-type Packages struct {
- packages map[string]*packages.Package
- importToName map[string]string
- loadErrors []error
-
- numLoadCalls int // stupid test steam. ignore.
- numNameCalls int // stupid test steam. ignore.
+type (
+ // Packages is a wrapper around x/tools/go/packages that maintains a (hopefully prewarmed) cache of packages
+ // that can be invalidated as writes are made and packages are known to change.
+ Packages struct {
+ packages map[string]*packages.Package
+ importToName map[string]string
+ loadErrors []error
+ buildFlags []string
+
+ numLoadCalls int // stupid test steam. ignore.
+ numNameCalls int // stupid test steam. ignore.
+ }
+ // Option is a function that can be passed to NewPackages to configure the package loader
+ Option func(p *Packages)
+)
+
+// WithBuildTags adds build tags to the packages.Load call
+func WithBuildTags(tags ...string) func(p *Packages) {
+ return func(p *Packages) {
+ p.buildFlags = append(p.buildFlags, "-tags", strings.Join(tags, ","))
+ }
+}
+
+// NewPackages creates a new packages cache
+// It will load all packages in the current module, and any packages that are passed to Load or LoadAll
+func NewPackages(opts ...Option) *Packages {
+ p := &Packages{}
+ for _, opt := range opts {
+ opt(p)
+ }
+ return p
}
func (p *Packages) CleanupUserPackages() {
@@ -47,8 +69,8 @@ func (p *Packages) CleanupUserPackages() {
modInfo = nil
}
})
-
- // Don't cleanup github.com/99designs/gqlgen prefixed packages, they haven't changed and do not need to be reloaded
+ // Don't cleanup github.com/99designs/gqlgen prefixed packages,
+ // they haven't changed and do not need to be reloaded
if modInfo != nil {
var toRemove []string
for k := range p.packages {
@@ -56,7 +78,6 @@ func (p *Packages) CleanupUserPackages() {
toRemove = append(toRemove, k)
}
}
-
for _, k := range toRemove {
delete(p.packages, k)
}
@@ -91,7 +112,10 @@ func (p *Packages) LoadAll(importPaths ...string) []*packages.Package {
if len(missing) > 0 {
p.numLoadCalls++
- pkgs, err := packages.Load(&packages.Config{Mode: mode}, missing...)
+ pkgs, err := packages.Load(&packages.Config{
+ Mode: mode,
+ BuildFlags: p.buildFlags,
+ }, missing...)
if err != nil {
p.loadErrors = append(p.loadErrors, err)
}
@@ -140,7 +164,10 @@ func (p *Packages) LoadWithTypes(importPath string) *packages.Package {
pkg := p.Load(importPath)
if pkg == nil || pkg.TypesInfo == nil {
p.numLoadCalls++
- pkgs, err := packages.Load(&packages.Config{Mode: mode}, importPath)
+ pkgs, err := packages.Load(&packages.Config{
+ Mode: mode,
+ BuildFlags: p.buildFlags,
+ }, importPath)
if err != nil {
p.loadErrors = append(p.loadErrors, err)
return nil
@@ -173,7 +200,10 @@ func (p *Packages) NameForPackage(importPath string) string {
if pkg == nil {
// otherwise do a name only lookup for it but don't put it in the package cache.
p.numNameCalls++
- pkgs, err := packages.Load(&packages.Config{Mode: packages.NeedName}, importPath)
+ pkgs, err := packages.Load(&packages.Config{
+ Mode: packages.NeedName,
+ BuildFlags: p.buildFlags,
+ }, importPath)
if err != nil {
p.loadErrors = append(p.loadErrors, err)
} else {
diff --git a/internal/code/packages_test.go b/internal/code/packages_test.go
index 2fbf780c55..1d67419eae 100644
--- a/internal/code/packages_test.go
+++ b/internal/code/packages_test.go
@@ -38,6 +38,14 @@ func TestPackages(t *testing.T) {
require.Equal(t, "b", p.Load("github.com/99designs/gqlgen/internal/code/testdata/b").Name)
require.Equal(t, 3, p.numLoadCalls)
})
+ t.Run("able to load private package with build tags", func(t *testing.T) {
+ p := initialState(t, WithBuildTags("private"))
+ p.Evict("github.com/99designs/gqlgen/internal/code/testdata/a")
+ require.Equal(t, "a", p.Load("github.com/99designs/gqlgen/internal/code/testdata/a").Name)
+ require.Equal(t, 2, p.numLoadCalls)
+ require.Equal(t, "p", p.Load("github.com/99designs/gqlgen/internal/code/testdata/p").Name)
+ require.Equal(t, 3, p.numLoadCalls)
+ })
}
func TestNameForPackage(t *testing.T) {
@@ -50,8 +58,8 @@ func TestNameForPackage(t *testing.T) {
assert.Equal(t, "github_com", p.NameForPackage("github.com"))
}
-func initialState(t *testing.T) *Packages {
- p := &Packages{}
+func initialState(t *testing.T, opts ...Option) *Packages {
+ p := NewPackages(opts...)
pkgs := p.LoadAll(
"github.com/99designs/gqlgen/internal/code/testdata/a",
"github.com/99designs/gqlgen/internal/code/testdata/b",
diff --git a/internal/code/testdata/p/p.go b/internal/code/testdata/p/p.go
new file mode 100644
index 0000000000..bf516e9813
--- /dev/null
+++ b/internal/code/testdata/p/p.go
@@ -0,0 +1,13 @@
+//go:build private
+// +build private
+
+// This file is excluded from the build unless the "private" build tag is set.
+// This is used to test loading private packages.
+// See internal/code/packages_test.go for more details.
+package p
+
+import (
+ "github.com/99designs/gqlgen/internal/code/testdata/b"
+)
+
+var P = b.C + " P"
diff --git a/internal/imports/prune.go b/internal/imports/prune.go
index d42a415791..f5fc71c697 100644
--- a/internal/imports/prune.go
+++ b/internal/imports/prune.go
@@ -10,10 +10,10 @@ import (
"go/token"
"strings"
- "github.com/99designs/gqlgen/internal/code"
-
"golang.org/x/tools/go/ast/astutil"
"golang.org/x/tools/imports"
+
+ "github.com/99designs/gqlgen/internal/code"
)
type visitFn func(node ast.Node)
diff --git a/internal/imports/prune_test.go b/internal/imports/prune_test.go
index 15af13dcd2..d312aff6bc 100644
--- a/internal/imports/prune_test.go
+++ b/internal/imports/prune_test.go
@@ -5,14 +5,15 @@ import (
"strings"
"testing"
- "github.com/99designs/gqlgen/internal/code"
"github.com/stretchr/testify/require"
+
+ "github.com/99designs/gqlgen/internal/code"
)
func TestPrune(t *testing.T) {
// prime the packages cache so that it's not considered uninitialized
- b, err := Prune("testdata/unused.go", mustReadFile("testdata/unused.go"), &code.Packages{})
+ b, err := Prune("testdata/unused.go", mustReadFile("testdata/unused.go"), code.NewPackages())
require.NoError(t, err)
require.Equal(t, strings.ReplaceAll(string(mustReadFile("testdata/unused.expected.go")), "\r\n", "\n"), string(b))
}
diff --git a/internal/imports/testdata/unused.expected.go b/internal/imports/testdata/unused.expected.go
index 95cbe2d00f..f9d393d7ee 100644
--- a/internal/imports/testdata/unused.expected.go
+++ b/internal/imports/testdata/unused.expected.go
@@ -3,6 +3,7 @@ package testdata
import (
a "fmt"
"time"
+
_ "underscore"
)
diff --git a/internal/imports/testdata/unused.go b/internal/imports/testdata/unused.go
index 95cbe2d00f..f9d393d7ee 100644
--- a/internal/imports/testdata/unused.go
+++ b/internal/imports/testdata/unused.go
@@ -3,6 +3,7 @@ package testdata
import (
a "fmt"
"time"
+
_ "underscore"
)
diff --git a/internal/rewrite/rewriter.go b/internal/rewrite/rewriter.go
index 1ca722dcfd..7e68e55de9 100644
--- a/internal/rewrite/rewriter.go
+++ b/internal/rewrite/rewriter.go
@@ -10,8 +10,9 @@ import (
"strconv"
"strings"
- "github.com/99designs/gqlgen/internal/code"
"golang.org/x/tools/go/packages"
+
+ "github.com/99designs/gqlgen/internal/code"
)
type Rewriter struct {
diff --git a/internal/rewrite/rewriter_test.go b/internal/rewrite/rewriter_test.go
index fae86668fb..9ac5ffb0e7 100644
--- a/internal/rewrite/rewriter_test.go
+++ b/internal/rewrite/rewriter_test.go
@@ -26,14 +26,14 @@ func TestRewriter(t *testing.T) {
imps := r.ExistingImports("testdata/example.go")
require.Len(t, imps, 2)
assert.Equal(t, []Import{
- {
- Alias: "",
- ImportPath: "fmt",
- },
{
Alias: "lol",
ImportPath: "bytes",
},
+ {
+ Alias: "",
+ ImportPath: "fmt",
+ },
}, imps)
})
diff --git a/internal/rewrite/testdata/example.go b/internal/rewrite/testdata/example.go
index 949bbe8235..6a3297ad2b 100644
--- a/internal/rewrite/testdata/example.go
+++ b/internal/rewrite/testdata/example.go
@@ -1,9 +1,8 @@
package testdata
import (
- "fmt"
-
lol "bytes"
+ "fmt"
)
type Foo struct {
diff --git a/main.go b/main.go
index af365bfeb9..e0420d1502 100644
--- a/main.go
+++ b/main.go
@@ -12,12 +12,13 @@ import (
"os"
"path/filepath"
+ "github.com/urfave/cli/v2"
+
"github.com/99designs/gqlgen/api"
"github.com/99designs/gqlgen/codegen/config"
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/internal/code"
"github.com/99designs/gqlgen/plugin/servergen"
- "github.com/urfave/cli/v2"
)
//go:embed init-templates/schema.graphqls
diff --git a/plugin/federation/entity.go b/plugin/federation/entity.go
index 04a3c033b0..042dd59ad7 100644
--- a/plugin/federation/entity.go
+++ b/plugin/federation/entity.go
@@ -3,10 +3,11 @@ package federation
import (
"go/types"
+ "github.com/vektah/gqlparser/v2/ast"
+
"github.com/99designs/gqlgen/codegen/config"
"github.com/99designs/gqlgen/codegen/templates"
"github.com/99designs/gqlgen/plugin/federation/fieldset"
- "github.com/vektah/gqlparser/v2/ast"
)
// Entity represents a federated type
diff --git a/plugin/federation/federation.go b/plugin/federation/federation.go
index d0ee8435e1..7d98850315 100644
--- a/plugin/federation/federation.go
+++ b/plugin/federation/federation.go
@@ -59,6 +59,9 @@ func (f *federation) MutateConfig(cfg *config.Config) error {
"_Any": {
Model: config.StringList{"github.com/99designs/gqlgen/graphql.Map"},
},
+ "federation__Scope": {
+ Model: config.StringList{"github.com/99designs/gqlgen/graphql.String"},
+ },
}
for typeName, entry := range builtins {
@@ -80,6 +83,10 @@ func (f *federation) MutateConfig(cfg *config.Config) error {
cfg.Directives["tag"] = config.DirectiveConfig{SkipRuntime: true}
cfg.Directives["override"] = config.DirectiveConfig{SkipRuntime: true}
cfg.Directives["inaccessible"] = config.DirectiveConfig{SkipRuntime: true}
+ cfg.Directives["authenticated"] = config.DirectiveConfig{SkipRuntime: true}
+ cfg.Directives["requiresScopes"] = config.DirectiveConfig{SkipRuntime: true}
+ cfg.Directives["interfaceObject"] = config.DirectiveConfig{SkipRuntime: true}
+ cfg.Directives["composeDirective"] = config.DirectiveConfig{SkipRuntime: true}
}
return nil
@@ -101,6 +108,7 @@ func (f *federation) InjectSourceEarly() *ast.Source {
`
} else if f.Version == 2 {
input += `
+ directive @authenticated on FIELD_DEFINITION | OBJECT | INTERFACE | SCALAR | ENUM
directive @composeDirective(name: String!) repeatable on SCHEMA
directive @extends on OBJECT | INTERFACE
directive @external on OBJECT | FIELD_DEFINITION
@@ -121,6 +129,12 @@ func (f *federation) InjectSourceEarly() *ast.Source {
directive @override(from: String!) on FIELD_DEFINITION
directive @provides(fields: FieldSet!) on FIELD_DEFINITION
directive @requires(fields: FieldSet!) on FIELD_DEFINITION
+ directive @requiresScopes(scopes: [[federation__Scope!]!]!) on
+ | FIELD_DEFINITION
+ | OBJECT
+ | INTERFACE
+ | SCALAR
+ | ENUM
directive @shareable repeatable on FIELD_DEFINITION | OBJECT
directive @tag(name: String!) repeatable on
| ARGUMENT_DEFINITION
@@ -135,6 +149,7 @@ func (f *federation) InjectSourceEarly() *ast.Source {
| UNION
scalar _Any
scalar FieldSet
+ scalar federation__Scope
`
}
return &ast.Source{
@@ -170,10 +185,14 @@ func (f *federation) InjectSourceLate(schema *ast.Schema) *ast.Source {
}
entityResolverInputDefinitions += "input " + r.InputTypeName + " {\n"
for _, keyField := range r.KeyFields {
- entityResolverInputDefinitions += fmt.Sprintf("\t%s: %s\n", keyField.Field.ToGo(), keyField.Definition.Type.String())
+ entityResolverInputDefinitions += fmt.Sprintf(
+ "\t%s: %s\n",
+ keyField.Field.ToGo(),
+ keyField.Definition.Type.String(),
+ )
}
entityResolverInputDefinitions += "}"
- resolvers += fmt.Sprintf("\t%s(reps: [%s!]!): [%s]\n", r.ResolverName, r.InputTypeName, e.Name)
+ resolvers += fmt.Sprintf("\t%s(reps: [%s]!): [%s]\n", r.ResolverName, r.InputTypeName, e.Name)
} else {
resolverArgs := ""
for _, keyField := range r.KeyFields {
diff --git a/plugin/federation/federation_entityresolver_test.go b/plugin/federation/federation_entityresolver_test.go
index 4cbc160245..cd96c5d498 100644
--- a/plugin/federation/federation_entityresolver_test.go
+++ b/plugin/federation/federation_entityresolver_test.go
@@ -7,10 +7,10 @@ import (
"strings"
"testing"
- "github.com/99designs/gqlgen/client"
- "github.com/99designs/gqlgen/graphql/handler"
"github.com/stretchr/testify/require"
+ "github.com/99designs/gqlgen/client"
+ "github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/plugin/federation/testdata/entityresolver"
"github.com/99designs/gqlgen/plugin/federation/testdata/entityresolver/generated"
)
diff --git a/plugin/federation/federation_test.go b/plugin/federation/federation_test.go
index 7e8d924290..1458743174 100644
--- a/plugin/federation/federation_test.go
+++ b/plugin/federation/federation_test.go
@@ -3,9 +3,10 @@ package federation
import (
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/codegen"
"github.com/99designs/gqlgen/codegen/config"
- "github.com/stretchr/testify/require"
)
func TestWithEntities(t *testing.T) {
@@ -144,6 +145,50 @@ func TestCodeGenerationFederation2(t *testing.T) {
require.NoError(t, f.GenerateCode(data))
}
+// This test is to ensure that the input arguments are not
+// changed when cfg.OmitSliceElementPointers is false OR true
+func TestMultiWithOmitSliceElemPointersCfg(t *testing.T) {
+
+ staticRepsString := "reps: [HelloByNamesInput]!"
+ t.Run("OmitSliceElementPointers true", func(t *testing.T) {
+ f, cfg := load(t, "testdata/multi/multi.yml")
+ cfg.OmitSliceElementPointers = true
+ err := f.MutateConfig(cfg)
+ require.NoError(t, err)
+ require.Len(t, cfg.Schema.Types["_Entity"].Types, 1)
+ require.Len(t, f.Entities, 1)
+
+ entityGraphqlGenerated := false
+ for _, source := range cfg.Sources {
+ if source.Name != "federation/entity.graphql" {
+ continue
+ }
+ entityGraphqlGenerated = true
+ require.Contains(t, source.Input, staticRepsString)
+ }
+ require.True(t, entityGraphqlGenerated)
+ })
+
+ t.Run("OmitSliceElementPointers false", func(t *testing.T) {
+ f, cfg := load(t, "testdata/multi/multi.yml")
+ cfg.OmitSliceElementPointers = false
+ err := f.MutateConfig(cfg)
+ require.NoError(t, err)
+ require.Len(t, cfg.Schema.Types["_Entity"].Types, 1)
+ require.Len(t, f.Entities, 1)
+
+ entityGraphqlGenerated := false
+ for _, source := range cfg.Sources {
+ if source.Name != "federation/entity.graphql" {
+ continue
+ }
+ entityGraphqlGenerated = true
+ require.Contains(t, source.Input, staticRepsString)
+ }
+ require.True(t, entityGraphqlGenerated)
+ })
+}
+
func TestInjectSourceLate(t *testing.T) {
_, cfg := load(t, "testdata/allthethings/gqlgen.yml")
entityGraphqlGenerated := false
diff --git a/plugin/federation/fieldset/fieldset.go b/plugin/federation/fieldset/fieldset.go
index 059a3c8325..59e4775368 100644
--- a/plugin/federation/fieldset/fieldset.go
+++ b/plugin/federation/fieldset/fieldset.go
@@ -4,9 +4,10 @@ import (
"fmt"
"strings"
+ "github.com/vektah/gqlparser/v2/ast"
+
"github.com/99designs/gqlgen/codegen"
"github.com/99designs/gqlgen/codegen/templates"
- "github.com/vektah/gqlparser/v2/ast"
)
// Set represents a FieldSet that is used in federation directives @key and @requires.
diff --git a/plugin/federation/readme.md b/plugin/federation/readme.md
index 4333ed4797..d5dd0628a3 100644
--- a/plugin/federation/readme.md
+++ b/plugin/federation/readme.md
@@ -37,3 +37,6 @@ func (r *entityResolver) FindManyMultiHellosByName(ctx context.Context, reps []*
///
}
```
+
+**Note:**
+If you are using `omit_slice_element_pointers: true` option in your config yaml, your `GetMany` resolver will still generate in the example above the same signature `FindManyMultiHellosByName(ctx context.Context, reps []*generated.ManyMultiHellosByNameInput) ([]*generated.MultiHello, error)`. But all other instances will continue to honor `omit_slice_element_pointers: true`
\ No newline at end of file
diff --git a/plugin/federation/testdata/entityresolver/entity.resolvers.go b/plugin/federation/testdata/entityresolver/entity.resolvers.go
index 85b6a59f18..bc1e3c0d78 100644
--- a/plugin/federation/testdata/entityresolver/entity.resolvers.go
+++ b/plugin/federation/testdata/entityresolver/entity.resolvers.go
@@ -2,7 +2,7 @@ package entityresolver
// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.35-dev
+// Code generated by github.com/99designs/gqlgen version v0.17.40-dev
import (
"context"
diff --git a/plugin/federation/testdata/entityresolver/generated/exec.go b/plugin/federation/testdata/entityresolver/generated/exec.go
index 0b1e4a60ab..25a9f93d9b 100644
--- a/plugin/federation/testdata/entityresolver/generated/exec.go
+++ b/plugin/federation/testdata/entityresolver/generated/exec.go
@@ -24,6 +24,7 @@ import (
// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
return &executableSchema{
+ schema: cfg.Schema,
resolvers: cfg.Resolvers,
directives: cfg.Directives,
complexity: cfg.Complexity,
@@ -31,6 +32,7 @@ func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
}
type Config struct {
+ Schema *ast.Schema
Resolvers ResolverRoot
Directives DirectiveRoot
Complexity ComplexityRoot
@@ -168,12 +170,16 @@ type EntityResolver interface {
}
type executableSchema struct {
+ schema *ast.Schema
resolvers ResolverRoot
directives DirectiveRoot
complexity ComplexityRoot
}
func (e *executableSchema) Schema() *ast.Schema {
+ if e.schema != nil {
+ return e.schema
+ }
return parsedSchema
}
@@ -710,14 +716,14 @@ func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapSchema(parsedSchema), nil
+ return introspection.WrapSchema(ec.Schema()), nil
}
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
- return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
+ return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil
}
var sources = []*ast.Source{
@@ -837,11 +843,11 @@ type Entity {
findHelloByName(name: String!,): Hello!
findHelloMultiSingleKeysByKey1AndKey2(key1: String!,key2: String!,): HelloMultiSingleKeys!
findHelloWithErrorsByName(name: String!,): HelloWithErrors!
- findManyMultiHelloByNames(reps: [MultiHelloByNamesInput!]!): [MultiHello]
- findManyMultiHelloMultipleRequiresByNames(reps: [MultiHelloMultipleRequiresByNamesInput!]!): [MultiHelloMultipleRequires]
- findManyMultiHelloRequiresByNames(reps: [MultiHelloRequiresByNamesInput!]!): [MultiHelloRequires]
- findManyMultiHelloWithErrorByNames(reps: [MultiHelloWithErrorByNamesInput!]!): [MultiHelloWithError]
- findManyMultiPlanetRequiresNestedByNames(reps: [MultiPlanetRequiresNestedByNamesInput!]!): [MultiPlanetRequiresNested]
+ findManyMultiHelloByNames(reps: [MultiHelloByNamesInput]!): [MultiHello]
+ findManyMultiHelloMultipleRequiresByNames(reps: [MultiHelloMultipleRequiresByNamesInput]!): [MultiHelloMultipleRequires]
+ findManyMultiHelloRequiresByNames(reps: [MultiHelloRequiresByNamesInput]!): [MultiHelloRequires]
+ findManyMultiHelloWithErrorByNames(reps: [MultiHelloWithErrorByNamesInput]!): [MultiHelloWithError]
+ findManyMultiPlanetRequiresNestedByNames(reps: [MultiPlanetRequiresNestedByNamesInput]!): [MultiPlanetRequiresNested]
findPlanetMultipleRequiresByName(name: String!,): PlanetMultipleRequires!
findPlanetRequiresByName(name: String!,): PlanetRequires!
findPlanetRequiresNestedByName(name: String!,): PlanetRequiresNested!
@@ -943,7 +949,7 @@ func (ec *executionContext) field_Entity_findManyMultiHelloByNames_args(ctx cont
var arg0 []*model.MultiHelloByNamesInput
if tmp, ok := rawArgs["reps"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("reps"))
- arg0, err = ec.unmarshalNMultiHelloByNamesInput2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloByNamesInputᚄ(ctx, tmp)
+ arg0, err = ec.unmarshalNMultiHelloByNamesInput2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloByNamesInput(ctx, tmp)
if err != nil {
return nil, err
}
@@ -958,7 +964,7 @@ func (ec *executionContext) field_Entity_findManyMultiHelloMultipleRequiresByNam
var arg0 []*model.MultiHelloMultipleRequiresByNamesInput
if tmp, ok := rawArgs["reps"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("reps"))
- arg0, err = ec.unmarshalNMultiHelloMultipleRequiresByNamesInput2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloMultipleRequiresByNamesInputᚄ(ctx, tmp)
+ arg0, err = ec.unmarshalNMultiHelloMultipleRequiresByNamesInput2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloMultipleRequiresByNamesInput(ctx, tmp)
if err != nil {
return nil, err
}
@@ -973,7 +979,7 @@ func (ec *executionContext) field_Entity_findManyMultiHelloRequiresByNames_args(
var arg0 []*model.MultiHelloRequiresByNamesInput
if tmp, ok := rawArgs["reps"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("reps"))
- arg0, err = ec.unmarshalNMultiHelloRequiresByNamesInput2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloRequiresByNamesInputᚄ(ctx, tmp)
+ arg0, err = ec.unmarshalNMultiHelloRequiresByNamesInput2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloRequiresByNamesInput(ctx, tmp)
if err != nil {
return nil, err
}
@@ -988,7 +994,7 @@ func (ec *executionContext) field_Entity_findManyMultiHelloWithErrorByNames_args
var arg0 []*model.MultiHelloWithErrorByNamesInput
if tmp, ok := rawArgs["reps"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("reps"))
- arg0, err = ec.unmarshalNMultiHelloWithErrorByNamesInput2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloWithErrorByNamesInputᚄ(ctx, tmp)
+ arg0, err = ec.unmarshalNMultiHelloWithErrorByNamesInput2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloWithErrorByNamesInput(ctx, tmp)
if err != nil {
return nil, err
}
@@ -1003,7 +1009,7 @@ func (ec *executionContext) field_Entity_findManyMultiPlanetRequiresNestedByName
var arg0 []*model.MultiPlanetRequiresNestedByNamesInput
if tmp, ok := rawArgs["reps"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("reps"))
- arg0, err = ec.unmarshalNMultiPlanetRequiresNestedByNamesInput2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiPlanetRequiresNestedByNamesInputᚄ(ctx, tmp)
+ arg0, err = ec.unmarshalNMultiPlanetRequiresNestedByNamesInput2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiPlanetRequiresNestedByNamesInput(ctx, tmp)
if err != nil {
return nil, err
}
@@ -7586,7 +7592,7 @@ func (ec *executionContext) marshalNInt2int(ctx context.Context, sel ast.Selecti
return res
}
-func (ec *executionContext) unmarshalNMultiHelloByNamesInput2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloByNamesInputᚄ(ctx context.Context, v interface{}) ([]*model.MultiHelloByNamesInput, error) {
+func (ec *executionContext) unmarshalNMultiHelloByNamesInput2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloByNamesInput(ctx context.Context, v interface{}) ([]*model.MultiHelloByNamesInput, error) {
var vSlice []interface{}
if v != nil {
vSlice = graphql.CoerceList(v)
@@ -7595,7 +7601,7 @@ func (ec *executionContext) unmarshalNMultiHelloByNamesInput2ᚕᚖgithubᚗcom
res := make([]*model.MultiHelloByNamesInput, len(vSlice))
for i := range vSlice {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i))
- res[i], err = ec.unmarshalNMultiHelloByNamesInput2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloByNamesInput(ctx, vSlice[i])
+ res[i], err = ec.unmarshalOMultiHelloByNamesInput2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloByNamesInput(ctx, vSlice[i])
if err != nil {
return nil, err
}
@@ -7603,12 +7609,7 @@ func (ec *executionContext) unmarshalNMultiHelloByNamesInput2ᚕᚖgithubᚗcom
return res, nil
}
-func (ec *executionContext) unmarshalNMultiHelloByNamesInput2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloByNamesInput(ctx context.Context, v interface{}) (*model.MultiHelloByNamesInput, error) {
- res, err := ec.unmarshalInputMultiHelloByNamesInput(ctx, v)
- return &res, graphql.ErrorOnPath(ctx, err)
-}
-
-func (ec *executionContext) unmarshalNMultiHelloMultipleRequiresByNamesInput2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloMultipleRequiresByNamesInputᚄ(ctx context.Context, v interface{}) ([]*model.MultiHelloMultipleRequiresByNamesInput, error) {
+func (ec *executionContext) unmarshalNMultiHelloMultipleRequiresByNamesInput2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloMultipleRequiresByNamesInput(ctx context.Context, v interface{}) ([]*model.MultiHelloMultipleRequiresByNamesInput, error) {
var vSlice []interface{}
if v != nil {
vSlice = graphql.CoerceList(v)
@@ -7617,7 +7618,7 @@ func (ec *executionContext) unmarshalNMultiHelloMultipleRequiresByNamesInput2ᚕ
res := make([]*model.MultiHelloMultipleRequiresByNamesInput, len(vSlice))
for i := range vSlice {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i))
- res[i], err = ec.unmarshalNMultiHelloMultipleRequiresByNamesInput2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloMultipleRequiresByNamesInput(ctx, vSlice[i])
+ res[i], err = ec.unmarshalOMultiHelloMultipleRequiresByNamesInput2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloMultipleRequiresByNamesInput(ctx, vSlice[i])
if err != nil {
return nil, err
}
@@ -7625,12 +7626,7 @@ func (ec *executionContext) unmarshalNMultiHelloMultipleRequiresByNamesInput2ᚕ
return res, nil
}
-func (ec *executionContext) unmarshalNMultiHelloMultipleRequiresByNamesInput2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloMultipleRequiresByNamesInput(ctx context.Context, v interface{}) (*model.MultiHelloMultipleRequiresByNamesInput, error) {
- res, err := ec.unmarshalInputMultiHelloMultipleRequiresByNamesInput(ctx, v)
- return &res, graphql.ErrorOnPath(ctx, err)
-}
-
-func (ec *executionContext) unmarshalNMultiHelloRequiresByNamesInput2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloRequiresByNamesInputᚄ(ctx context.Context, v interface{}) ([]*model.MultiHelloRequiresByNamesInput, error) {
+func (ec *executionContext) unmarshalNMultiHelloRequiresByNamesInput2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloRequiresByNamesInput(ctx context.Context, v interface{}) ([]*model.MultiHelloRequiresByNamesInput, error) {
var vSlice []interface{}
if v != nil {
vSlice = graphql.CoerceList(v)
@@ -7639,7 +7635,7 @@ func (ec *executionContext) unmarshalNMultiHelloRequiresByNamesInput2ᚕᚖgithu
res := make([]*model.MultiHelloRequiresByNamesInput, len(vSlice))
for i := range vSlice {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i))
- res[i], err = ec.unmarshalNMultiHelloRequiresByNamesInput2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloRequiresByNamesInput(ctx, vSlice[i])
+ res[i], err = ec.unmarshalOMultiHelloRequiresByNamesInput2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloRequiresByNamesInput(ctx, vSlice[i])
if err != nil {
return nil, err
}
@@ -7647,12 +7643,7 @@ func (ec *executionContext) unmarshalNMultiHelloRequiresByNamesInput2ᚕᚖgithu
return res, nil
}
-func (ec *executionContext) unmarshalNMultiHelloRequiresByNamesInput2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloRequiresByNamesInput(ctx context.Context, v interface{}) (*model.MultiHelloRequiresByNamesInput, error) {
- res, err := ec.unmarshalInputMultiHelloRequiresByNamesInput(ctx, v)
- return &res, graphql.ErrorOnPath(ctx, err)
-}
-
-func (ec *executionContext) unmarshalNMultiHelloWithErrorByNamesInput2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloWithErrorByNamesInputᚄ(ctx context.Context, v interface{}) ([]*model.MultiHelloWithErrorByNamesInput, error) {
+func (ec *executionContext) unmarshalNMultiHelloWithErrorByNamesInput2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloWithErrorByNamesInput(ctx context.Context, v interface{}) ([]*model.MultiHelloWithErrorByNamesInput, error) {
var vSlice []interface{}
if v != nil {
vSlice = graphql.CoerceList(v)
@@ -7661,7 +7652,7 @@ func (ec *executionContext) unmarshalNMultiHelloWithErrorByNamesInput2ᚕᚖgith
res := make([]*model.MultiHelloWithErrorByNamesInput, len(vSlice))
for i := range vSlice {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i))
- res[i], err = ec.unmarshalNMultiHelloWithErrorByNamesInput2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloWithErrorByNamesInput(ctx, vSlice[i])
+ res[i], err = ec.unmarshalOMultiHelloWithErrorByNamesInput2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloWithErrorByNamesInput(ctx, vSlice[i])
if err != nil {
return nil, err
}
@@ -7669,12 +7660,7 @@ func (ec *executionContext) unmarshalNMultiHelloWithErrorByNamesInput2ᚕᚖgith
return res, nil
}
-func (ec *executionContext) unmarshalNMultiHelloWithErrorByNamesInput2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloWithErrorByNamesInput(ctx context.Context, v interface{}) (*model.MultiHelloWithErrorByNamesInput, error) {
- res, err := ec.unmarshalInputMultiHelloWithErrorByNamesInput(ctx, v)
- return &res, graphql.ErrorOnPath(ctx, err)
-}
-
-func (ec *executionContext) unmarshalNMultiPlanetRequiresNestedByNamesInput2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiPlanetRequiresNestedByNamesInputᚄ(ctx context.Context, v interface{}) ([]*model.MultiPlanetRequiresNestedByNamesInput, error) {
+func (ec *executionContext) unmarshalNMultiPlanetRequiresNestedByNamesInput2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiPlanetRequiresNestedByNamesInput(ctx context.Context, v interface{}) ([]*model.MultiPlanetRequiresNestedByNamesInput, error) {
var vSlice []interface{}
if v != nil {
vSlice = graphql.CoerceList(v)
@@ -7683,7 +7669,7 @@ func (ec *executionContext) unmarshalNMultiPlanetRequiresNestedByNamesInput2ᚕ
res := make([]*model.MultiPlanetRequiresNestedByNamesInput, len(vSlice))
for i := range vSlice {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i))
- res[i], err = ec.unmarshalNMultiPlanetRequiresNestedByNamesInput2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiPlanetRequiresNestedByNamesInput(ctx, vSlice[i])
+ res[i], err = ec.unmarshalOMultiPlanetRequiresNestedByNamesInput2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiPlanetRequiresNestedByNamesInput(ctx, vSlice[i])
if err != nil {
return nil, err
}
@@ -7691,11 +7677,6 @@ func (ec *executionContext) unmarshalNMultiPlanetRequiresNestedByNamesInput2ᚕ
return res, nil
}
-func (ec *executionContext) unmarshalNMultiPlanetRequiresNestedByNamesInput2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiPlanetRequiresNestedByNamesInput(ctx context.Context, v interface{}) (*model.MultiPlanetRequiresNestedByNamesInput, error) {
- res, err := ec.unmarshalInputMultiPlanetRequiresNestedByNamesInput(ctx, v)
- return &res, graphql.ErrorOnPath(ctx, err)
-}
-
func (ec *executionContext) marshalNPlanetMultipleRequires2githubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐPlanetMultipleRequires(ctx context.Context, sel ast.SelectionSet, v model.PlanetMultipleRequires) graphql.Marshaler {
return ec._PlanetMultipleRequires(ctx, sel, &v)
}
@@ -8239,6 +8220,14 @@ func (ec *executionContext) marshalOMultiHello2ᚖgithubᚗcomᚋ99designsᚋgql
return ec._MultiHello(ctx, sel, v)
}
+func (ec *executionContext) unmarshalOMultiHelloByNamesInput2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloByNamesInput(ctx context.Context, v interface{}) (*model.MultiHelloByNamesInput, error) {
+ if v == nil {
+ return nil, nil
+ }
+ res, err := ec.unmarshalInputMultiHelloByNamesInput(ctx, v)
+ return &res, graphql.ErrorOnPath(ctx, err)
+}
+
func (ec *executionContext) marshalOMultiHelloMultipleRequires2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloMultipleRequires(ctx context.Context, sel ast.SelectionSet, v []*model.MultiHelloMultipleRequires) graphql.Marshaler {
if v == nil {
return graphql.Null
@@ -8287,6 +8276,14 @@ func (ec *executionContext) marshalOMultiHelloMultipleRequires2ᚖgithubᚗcom
return ec._MultiHelloMultipleRequires(ctx, sel, v)
}
+func (ec *executionContext) unmarshalOMultiHelloMultipleRequiresByNamesInput2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloMultipleRequiresByNamesInput(ctx context.Context, v interface{}) (*model.MultiHelloMultipleRequiresByNamesInput, error) {
+ if v == nil {
+ return nil, nil
+ }
+ res, err := ec.unmarshalInputMultiHelloMultipleRequiresByNamesInput(ctx, v)
+ return &res, graphql.ErrorOnPath(ctx, err)
+}
+
func (ec *executionContext) marshalOMultiHelloRequires2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloRequires(ctx context.Context, sel ast.SelectionSet, v []*model.MultiHelloRequires) graphql.Marshaler {
if v == nil {
return graphql.Null
@@ -8335,6 +8332,14 @@ func (ec *executionContext) marshalOMultiHelloRequires2ᚖgithubᚗcomᚋ99desig
return ec._MultiHelloRequires(ctx, sel, v)
}
+func (ec *executionContext) unmarshalOMultiHelloRequiresByNamesInput2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloRequiresByNamesInput(ctx context.Context, v interface{}) (*model.MultiHelloRequiresByNamesInput, error) {
+ if v == nil {
+ return nil, nil
+ }
+ res, err := ec.unmarshalInputMultiHelloRequiresByNamesInput(ctx, v)
+ return &res, graphql.ErrorOnPath(ctx, err)
+}
+
func (ec *executionContext) marshalOMultiHelloWithError2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloWithError(ctx context.Context, sel ast.SelectionSet, v []*model.MultiHelloWithError) graphql.Marshaler {
if v == nil {
return graphql.Null
@@ -8383,6 +8388,14 @@ func (ec *executionContext) marshalOMultiHelloWithError2ᚖgithubᚗcomᚋ99desi
return ec._MultiHelloWithError(ctx, sel, v)
}
+func (ec *executionContext) unmarshalOMultiHelloWithErrorByNamesInput2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiHelloWithErrorByNamesInput(ctx context.Context, v interface{}) (*model.MultiHelloWithErrorByNamesInput, error) {
+ if v == nil {
+ return nil, nil
+ }
+ res, err := ec.unmarshalInputMultiHelloWithErrorByNamesInput(ctx, v)
+ return &res, graphql.ErrorOnPath(ctx, err)
+}
+
func (ec *executionContext) marshalOMultiPlanetRequiresNested2ᚕᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiPlanetRequiresNested(ctx context.Context, sel ast.SelectionSet, v []*model.MultiPlanetRequiresNested) graphql.Marshaler {
if v == nil {
return graphql.Null
@@ -8431,6 +8444,14 @@ func (ec *executionContext) marshalOMultiPlanetRequiresNested2ᚖgithubᚗcomᚋ
return ec._MultiPlanetRequiresNested(ctx, sel, v)
}
+func (ec *executionContext) unmarshalOMultiPlanetRequiresNestedByNamesInput2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋtestdataᚋentityresolverᚋgeneratedᚋmodelᚐMultiPlanetRequiresNestedByNamesInput(ctx context.Context, v interface{}) (*model.MultiPlanetRequiresNestedByNamesInput, error) {
+ if v == nil {
+ return nil, nil
+ }
+ res, err := ec.unmarshalInputMultiPlanetRequiresNestedByNamesInput(ctx, v)
+ return &res, graphql.ErrorOnPath(ctx, err)
+}
+
func (ec *executionContext) unmarshalOString2string(ctx context.Context, v interface{}) (string, error) {
res, err := graphql.UnmarshalString(v)
return res, graphql.ErrorOnPath(ctx, err)
diff --git a/plugin/federation/testdata/federation2/federation2.graphql b/plugin/federation/testdata/federation2/federation2.graphql
index 770f896970..5355cb804c 100644
--- a/plugin/federation/testdata/federation2/federation2.graphql
+++ b/plugin/federation/testdata/federation2/federation2.graphql
@@ -1,6 +1,6 @@
extend schema
@link(url: "https://specs.apollo.dev/federation/v2.3",
- import: ["@key", "@shareable", "@provides", "@external", "@tag", "@extends", "@override", "@inaccessible"])
+ import: ["@key", "@shareable", "@provides", "@external", "@tag", "@extends", "@override", "@inaccessible", "@interfaceObject"])
schema {
query: CustomQuery
@@ -23,4 +23,3 @@ extend type ExternalExtension @key(fields: " upc ") {
type CustomQuery {
hello: Hello!
}
-
diff --git a/plugin/federation/testdata/multi/multi.graphqls b/plugin/federation/testdata/multi/multi.graphqls
new file mode 100644
index 0000000000..bf37c5a067
--- /dev/null
+++ b/plugin/federation/testdata/multi/multi.graphqls
@@ -0,0 +1,10 @@
+extend schema
+ @link(url: "https://specs.apollo.dev/federation/v2.3",
+ import: ["@key"])
+
+directive @entityResolver(multi: Boolean) on OBJECT
+
+type Hello @key(fields: "name") @entityResolver(multi: true) {
+ name: String!
+ secondary: String!
+}
diff --git a/plugin/federation/testdata/multi/multi.yml b/plugin/federation/testdata/multi/multi.yml
new file mode 100644
index 0000000000..891466c73f
--- /dev/null
+++ b/plugin/federation/testdata/multi/multi.yml
@@ -0,0 +1,8 @@
+schema:
+ - "testdata/multi/multi.graphqls"
+exec:
+ filename: testdata/multi/generated/exec.go
+federation:
+ version: 2
+ filename: testdata/multi/generated/federation.go
+omit_slice_element_pointers: true
\ No newline at end of file
diff --git a/plugin/modelgen/models.go b/plugin/modelgen/models.go
index 6b4f483752..798a936f57 100644
--- a/plugin/modelgen/models.go
+++ b/plugin/modelgen/models.go
@@ -4,14 +4,16 @@ import (
_ "embed"
"fmt"
"go/types"
+ "os"
"sort"
"strings"
"text/template"
+ "github.com/vektah/gqlparser/v2/ast"
+
"github.com/99designs/gqlgen/codegen/config"
"github.com/99designs/gqlgen/codegen/templates"
"github.com/99designs/gqlgen/plugin"
- "github.com/vektah/gqlparser/v2/ast"
)
//go:embed models.gotpl
@@ -51,6 +53,7 @@ type Interface struct {
Fields []*Field
Implements []string
OmitCheck bool
+ Models []*Object
}
type Object struct {
@@ -199,6 +202,15 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error {
cfg.Models.Add(it.Name, cfg.Model.ImportPath()+"."+templates.ToGo(it.Name))
}
for _, it := range b.Interfaces {
+ // On a given interface we want to keep a reference to all the models that implement it
+ for _, model := range b.Models {
+ for _, impl := range model.Implements {
+ if impl == it.Name {
+ // If it does, add it to the Interface's Models
+ it.Models = append(it.Models, model)
+ }
+ }
+ }
cfg.Models.Add(it.Name, cfg.Model.ImportPath()+"."+templates.ToGo(it.Name))
}
for _, it := range b.Scalars {
@@ -282,6 +294,10 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error {
"getInterfaceByName": getInterfaceByName,
"generateGetter": generateGetter,
}
+ newModelTemplate := modelTemplate
+ if cfg.Model.ModelTemplate != "" {
+ newModelTemplate = readModelTemplate(cfg.Model.ModelTemplate)
+ }
err := templates.Render(templates.Options{
PackageName: cfg.Model.Package,
@@ -289,7 +305,7 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error {
Data: b,
GeneratedHeader: true,
Packages: cfg.Packages,
- Template: modelTemplate,
+ Template: newModelTemplate,
Funcs: funcMap,
})
if err != nil {
@@ -553,17 +569,19 @@ func removeDuplicateTags(t string) string {
continue
}
- processed[kv[0]] = true
+ key := kv[0]
+ value := strings.Join(kv[1:], ":")
+ processed[key] = true
if len(returnTags) > 0 {
returnTags = " " + returnTags
}
- isContained := containsInvalidSpace(kv[1])
+ isContained := containsInvalidSpace(value)
if isContained {
- panic(fmt.Errorf("tag value should not contain any leading or trailing spaces: %s", kv[1]))
+ panic(fmt.Errorf("tag value should not contain any leading or trailing spaces: %s", value))
}
- returnTags = kv[0] + ":" + kv[1] + returnTags
+ returnTags = key + ":" + value + returnTags
}
return returnTags
@@ -645,3 +663,11 @@ func findAndHandleCyclicalRelationships(b *ModelBuild) {
}
}
}
+
+func readModelTemplate(customModelTemplate string) string {
+ contentBytes, err := os.ReadFile(customModelTemplate)
+ if err != nil {
+ panic(err)
+ }
+ return string(contentBytes)
+}
diff --git a/plugin/modelgen/models_test.go b/plugin/modelgen/models_test.go
index f4cd43beae..a9182d02f0 100644
--- a/plugin/modelgen/models_test.go
+++ b/plugin/modelgen/models_test.go
@@ -14,6 +14,9 @@ import (
"strings"
"testing"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
"github.com/99designs/gqlgen/codegen/config"
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/plugin/modelgen/internal/extrafields"
@@ -23,8 +26,6 @@ import (
"github.com/99designs/gqlgen/plugin/modelgen/out_enable_model_json_omitempty_tag_true"
"github.com/99designs/gqlgen/plugin/modelgen/out_nullable_input_omittable"
"github.com/99designs/gqlgen/plugin/modelgen/out_struct_pointers"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
)
func TestModelGeneration(t *testing.T) {
@@ -534,6 +535,22 @@ func TestRemoveDuplicate(t *testing.T) {
want: "gorm:\"unique;not null\" json:\"name,name2\"",
wantPanic: false,
},
+ {
+ name: "Test gorm tag with colon",
+ args: args{
+ t: "gorm:\"type:varchar(63);unique_index\"",
+ },
+ want: "gorm:\"type:varchar(63);unique_index\"",
+ wantPanic: false,
+ },
+ {
+ name: "Test mix use of gorm and duplicate json tags with colon",
+ args: args{
+ t: "json:\"name0\" gorm:\"type:varchar(63);unique_index\" json:\"name,name2\"",
+ },
+ want: "gorm:\"type:varchar(63);unique_index\" json:\"name,name2\"",
+ wantPanic: false,
+ },
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@@ -637,3 +654,14 @@ func Test_splitTagsBySpace(t *testing.T) {
})
}
}
+
+func TestCustomTemplate(t *testing.T) {
+ cfg, err := config.LoadConfig("testdata/gqlgen_custom_model_template.yml")
+ require.NoError(t, err)
+ require.NoError(t, cfg.Init())
+ p := Plugin{
+ MutateHook: mutateHook,
+ FieldHook: DefaultFieldMutateHook,
+ }
+ require.NoError(t, p.MutateConfig(cfg))
+}
diff --git a/plugin/modelgen/out/generated.go b/plugin/modelgen/out/generated.go
index f90f8b974a..656913e510 100644
--- a/plugin/modelgen/out/generated.go
+++ b/plugin/modelgen/out/generated.go
@@ -11,6 +11,8 @@ import (
"github.com/99designs/gqlgen/plugin/modelgen/internal/extrafields"
)
+// Add any new functions or any additional code/template functionality here
+
type A interface {
IsA()
GetA() string
diff --git a/plugin/modelgen/testdata/customModelTemplate.gotpl b/plugin/modelgen/testdata/customModelTemplate.gotpl
new file mode 100644
index 0000000000..4ff192a297
--- /dev/null
+++ b/plugin/modelgen/testdata/customModelTemplate.gotpl
@@ -0,0 +1,106 @@
+{{ reserveImport "context" }}
+{{ reserveImport "fmt" }}
+{{ reserveImport "io" }}
+{{ reserveImport "strconv" }}
+{{ reserveImport "time" }}
+{{ reserveImport "sync" }}
+{{ reserveImport "errors" }}
+{{ reserveImport "bytes" }}
+
+{{ reserveImport "github.com/vektah/gqlparser/v2" }}
+{{ reserveImport "github.com/vektah/gqlparser/v2/ast" }}
+{{ reserveImport "github.com/99designs/gqlgen/graphql" }}
+{{ reserveImport "github.com/99designs/gqlgen/graphql/introspection" }}
+
+// Add any new functions or any additional code/template functionality here
+
+{{- range $model := .Interfaces }}
+ {{ with .Description }} {{.|prefixLines "// "}} {{ end }}
+ type {{ goModelName .Name }} interface {
+ {{- if not .OmitCheck }}
+ {{- range $impl := .Implements }}
+ Is{{ goModelName $impl }}()
+ {{- end }}
+ Is{{ goModelName .Name }}()
+ {{- end }}
+ {{- range $field := .Fields }}
+ {{- with .Description }}
+ {{.|prefixLines "// "}}
+ {{- end}}
+ Get{{ $field.GoName }}() {{ $field.Type | ref }}
+ {{- end }}
+ }
+{{- end }}
+
+{{ range $model := .Models }}
+ {{with .Description }} {{.|prefixLines "// "}} {{end}}
+ type {{ goModelName .Name }} struct {
+ {{- range $field := .Fields }}
+ {{- with .Description }}
+ {{.|prefixLines "// "}}
+ {{- end}}
+ {{ $field.GoName }} {{$field.Type | ref}} `{{$field.Tag}}`
+ {{- end }}
+ }
+
+ {{ range .Implements }}
+ func ({{ goModelName $model.Name }}) Is{{ goModelName . }}() {}
+ {{- with getInterfaceByName . }}
+ {{- range .Fields }}
+ {{- with .Description }}
+ {{.|prefixLines "// "}}
+ {{- end}}
+ {{ generateGetter $model . }}
+ {{- end }}
+ {{- end }}
+ {{ end }}
+{{- end}}
+
+{{ range $enum := .Enums }}
+ {{ with .Description }} {{.|prefixLines "// "}} {{end}}
+ type {{ goModelName .Name }} string
+ const (
+ {{- range $value := .Values}}
+ {{- with .Description}}
+ {{.|prefixLines "// "}}
+ {{- end}}
+ {{ goModelName $enum.Name .Name }} {{ goModelName $enum.Name }} = {{ .Name|quote }}
+ {{- end }}
+ )
+
+ var All{{ goModelName .Name }} = []{{ goModelName .Name }}{
+ {{- range $value := .Values}}
+ {{ goModelName $enum.Name .Name }},
+ {{- end }}
+ }
+
+ func (e {{ goModelName .Name }}) IsValid() bool {
+ switch e {
+ case {{ range $index, $element := .Values}}{{if $index}},{{end}}{{ goModelName $enum.Name $element.Name }}{{end}}:
+ return true
+ }
+ return false
+ }
+
+ func (e {{ goModelName .Name }}) String() string {
+ return string(e)
+ }
+
+ func (e *{{ goModelName .Name }}) UnmarshalGQL(v interface{}) error {
+ str, ok := v.(string)
+ if !ok {
+ return fmt.Errorf("enums must be strings")
+ }
+
+ *e = {{ goModelName .Name }}(str)
+ if !e.IsValid() {
+ return fmt.Errorf("%s is not a valid {{ .Name }}", str)
+ }
+ return nil
+ }
+
+ func (e {{ goModelName .Name }}) MarshalGQL(w io.Writer) {
+ fmt.Fprint(w, strconv.Quote(e.String()))
+ }
+
+{{- end }}
diff --git a/plugin/modelgen/testdata/gqlgen_custom_model_template.yml b/plugin/modelgen/testdata/gqlgen_custom_model_template.yml
new file mode 100644
index 0000000000..ea3d96b5b7
--- /dev/null
+++ b/plugin/modelgen/testdata/gqlgen_custom_model_template.yml
@@ -0,0 +1,38 @@
+schema:
+ - "testdata/schema.graphql"
+
+exec:
+ filename: out/ignored.go
+model:
+ filename: out/generated.go
+ model_template: "testdata/customModelTemplate.gotpl"
+
+models:
+ ExistingModel:
+ model: github.com/99designs/gqlgen/plugin/modelgen/out.ExistingModel
+ ExistingInput:
+ model: github.com/99designs/gqlgen/plugin/modelgen/out.ExistingInput
+ ExistingEnum:
+ model: github.com/99designs/gqlgen/plugin/modelgen/out.ExistingEnum
+ ExistingInterface:
+ model: github.com/99designs/gqlgen/plugin/modelgen/out.ExistingInterface
+ ExistingUnion:
+ model: github.com/99designs/gqlgen/plugin/modelgen/out.ExistingUnion
+ ExistingType:
+ model: github.com/99designs/gqlgen/plugin/modelgen/out.ExistingType
+ RenameFieldTest:
+ fields:
+ badName:
+ fieldName: GOODnaME
+ ExtraFieldsTest:
+ extraFields:
+ FieldInternalType:
+ description: "Internal field"
+ type: github.com/99designs/gqlgen/plugin/modelgen/internal/extrafields.Type
+ FieldStringPtr:
+ type: "*string"
+ FieldInt:
+ type: "int64"
+ overrideTags: 'json:"field_int_tag"'
+ FieldIntSlice:
+ type: "[]int64"
diff --git a/plugin/plugin.go b/plugin/plugin.go
index 69801c8816..214c58d9e1 100644
--- a/plugin/plugin.go
+++ b/plugin/plugin.go
@@ -3,9 +3,10 @@
package plugin
import (
+ "github.com/vektah/gqlparser/v2/ast"
+
"github.com/99designs/gqlgen/codegen"
"github.com/99designs/gqlgen/codegen/config"
- "github.com/vektah/gqlparser/v2/ast"
)
type Plugin interface {
diff --git a/plugin/resolvergen/resolver.go b/plugin/resolvergen/resolver.go
index 09cfbab63b..c3a2c40822 100644
--- a/plugin/resolvergen/resolver.go
+++ b/plugin/resolvergen/resolver.go
@@ -81,13 +81,18 @@ func (m *Plugin) generateSingleFile(data *codegen.Data) error {
OmitTemplateComment: data.Config.Resolver.OmitTemplateComment,
}
+ newResolverTemplate := resolverTemplate
+ if data.Config.Resolver.ResolverTemplate != "" {
+ newResolverTemplate = readResolverTemplate(data.Config.Resolver.ResolverTemplate)
+ }
+
return templates.Render(templates.Options{
PackageName: data.Config.Resolver.Package,
FileNotice: `// THIS CODE IS A STARTING POINT ONLY. IT WILL NOT BE UPDATED WITH SCHEMA CHANGES.`,
Filename: data.Config.Resolver.Filename,
Data: resolverBuild,
Packages: data.Config.Packages,
- Template: resolverTemplate,
+ Template: newResolverTemplate,
})
}
@@ -105,9 +110,12 @@ func (m *Plugin) generatePerSchema(data *codegen.Data) error {
for _, o := range objects {
if o.HasResolvers() {
- fn := gqlToResolverName(data.Config.Resolver.Dir(), o.Position.Src.Name, data.Config.Resolver.FilenameTemplate)
+ fnCase := gqlToResolverName(data.Config.Resolver.Dir(), o.Position.Src.Name, data.Config.Resolver.FilenameTemplate)
+ fn := strings.ToLower(fnCase)
if files[fn] == nil {
- files[fn] = &File{}
+ files[fn] = &File{
+ name: fnCase,
+ }
}
caser := cases.Title(language.English, cases.NoLower)
@@ -145,21 +153,28 @@ func (m *Plugin) generatePerSchema(data *codegen.Data) error {
}
resolver := Resolver{o, f, rewriter.GetPrevDecl(structName, f.GoFieldName), comment, implementation}
- fn := gqlToResolverName(data.Config.Resolver.Dir(), f.Position.Src.Name, data.Config.Resolver.FilenameTemplate)
+ fnCase := gqlToResolverName(data.Config.Resolver.Dir(), f.Position.Src.Name, data.Config.Resolver.FilenameTemplate)
+ fn := strings.ToLower(fnCase)
if files[fn] == nil {
- files[fn] = &File{}
+ files[fn] = &File{
+ name: fnCase,
+ }
}
files[fn].Resolvers = append(files[fn].Resolvers, &resolver)
}
}
- for filename, file := range files {
- file.imports = rewriter.ExistingImports(filename)
- file.RemainingSource = rewriter.RemainingSource(filename)
+ for _, file := range files {
+ file.imports = rewriter.ExistingImports(file.name)
+ file.RemainingSource = rewriter.RemainingSource(file.name)
+ }
+ newResolverTemplate := resolverTemplate
+ if data.Config.Resolver.ResolverTemplate != "" {
+ newResolverTemplate = readResolverTemplate(data.Config.Resolver.ResolverTemplate)
}
- for filename, file := range files {
+ for _, file := range files {
resolverBuild := &ResolverBuild{
File: file,
PackageName: data.Config.Resolver.Package,
@@ -183,10 +198,10 @@ func (m *Plugin) generatePerSchema(data *codegen.Data) error {
err := templates.Render(templates.Options{
PackageName: data.Config.Resolver.Package,
FileNotice: fileNotice.String(),
- Filename: filename,
+ Filename: file.name,
Data: resolverBuild,
Packages: data.Config.Packages,
- Template: resolverTemplate,
+ Template: newResolverTemplate,
})
if err != nil {
return err
@@ -221,6 +236,7 @@ type ResolverBuild struct {
}
type File struct {
+ name string
// These are separated because the type definition of the resolver object may live in a different file from the
// resolver method implementations, for example when extending a type in a different graphql schema file
Objects []*codegen.Object
@@ -257,3 +273,11 @@ func gqlToResolverName(base string, gqlname, filenameTmpl string) string {
filename := strings.ReplaceAll(filenameTmpl, "{name}", strings.TrimSuffix(gqlname, ext))
return filepath.Join(base, filename)
}
+
+func readResolverTemplate(customResolverTemplate string) string {
+ contentBytes, err := os.ReadFile(customResolverTemplate)
+ if err != nil {
+ panic(err)
+ }
+ return string(contentBytes)
+}
diff --git a/plugin/resolvergen/resolver_test.go b/plugin/resolvergen/resolver_test.go
index 5a1300113c..17650e8f20 100644
--- a/plugin/resolvergen/resolver_test.go
+++ b/plugin/resolvergen/resolver_test.go
@@ -6,10 +6,11 @@ import (
"syscall"
"testing"
- "github.com/99designs/gqlgen/codegen"
- "github.com/99designs/gqlgen/codegen/config"
"github.com/stretchr/testify/require"
"golang.org/x/tools/go/packages"
+
+ "github.com/99designs/gqlgen/codegen"
+ "github.com/99designs/gqlgen/codegen/config"
)
func TestLayoutSingleFile(t *testing.T) {
@@ -83,6 +84,22 @@ func TestOmitTemplateComment(t *testing.T) {
assertNoErrors(t, "github.com/99designs/gqlgen/plugin/resolvergen/testdata/omit_template_comment/out")
}
+func TestCustomResolverTemplate(t *testing.T) {
+ _ = syscall.Unlink("testdata/resolvertemplate/out/resolver.go")
+ cfg, err := config.LoadConfig("testdata/resolvertemplate/gqlgen.yml")
+ require.NoError(t, err)
+ p := Plugin{}
+
+ require.NoError(t, cfg.Init())
+
+ data, err := codegen.BuildData(cfg)
+ if err != nil {
+ panic(err)
+ }
+
+ require.NoError(t, p.GenerateCode(data))
+}
+
func testFollowSchemaPersistence(t *testing.T, dir string) {
_ = syscall.Unlink(dir + "/out/resolver.go")
diff --git a/plugin/resolvergen/testdata/filetemplate/out/schema.custom.go b/plugin/resolvergen/testdata/filetemplate/out/schema.custom.go
index 63da9a5e14..c0c9b89f85 100644
--- a/plugin/resolvergen/testdata/filetemplate/out/schema.custom.go
+++ b/plugin/resolvergen/testdata/filetemplate/out/schema.custom.go
@@ -2,7 +2,7 @@ package customresolver
// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.33-dev
+// Code generated by github.com/99designs/gqlgen version v0.17.39-dev
import (
"context"
diff --git a/plugin/resolvergen/testdata/followschema/out/schema.resolvers.go b/plugin/resolvergen/testdata/followschema/out/schema.resolvers.go
index 40c378b608..c2b7384156 100644
--- a/plugin/resolvergen/testdata/followschema/out/schema.resolvers.go
+++ b/plugin/resolvergen/testdata/followschema/out/schema.resolvers.go
@@ -2,7 +2,7 @@ package customresolver
// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.33-dev
+// Code generated by github.com/99designs/gqlgen version v0.17.39-dev
import (
"context"
diff --git a/plugin/resolvergen/testdata/omit_template_comment/out/schema.resolvers.go b/plugin/resolvergen/testdata/omit_template_comment/out/schema.resolvers.go
index 31ce8f5741..349f77fc44 100644
--- a/plugin/resolvergen/testdata/omit_template_comment/out/schema.resolvers.go
+++ b/plugin/resolvergen/testdata/omit_template_comment/out/schema.resolvers.go
@@ -2,7 +2,7 @@ package out
// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.33-dev
+// Code generated by github.com/99designs/gqlgen version v0.17.39-dev
import (
"context"
diff --git a/plugin/resolvergen/testdata/resolvertemplate/customResolverTemplate.gotpl b/plugin/resolvergen/testdata/resolvertemplate/customResolverTemplate.gotpl
new file mode 100644
index 0000000000..ff652f0148
--- /dev/null
+++ b/plugin/resolvergen/testdata/resolvertemplate/customResolverTemplate.gotpl
@@ -0,0 +1,54 @@
+{{ reserveImport "context" }}
+{{ reserveImport "fmt" }}
+{{ reserveImport "io" }}
+{{ reserveImport "strconv" }}
+{{ reserveImport "time" }}
+{{ reserveImport "sync" }}
+{{ reserveImport "errors" }}
+{{ reserveImport "bytes" }}
+{{ reserveImport "encoding/json" }}
+
+{{ reserveImport "github.com/vektah/gqlparser/v2" }}
+{{ reserveImport "github.com/vektah/gqlparser/v2/ast" }}
+{{ reserveImport "github.com/99designs/gqlgen/graphql" }}
+{{ reserveImport "github.com/99designs/gqlgen/graphql/introspection" }}
+
+{{ .Imports }}
+
+{{ if .HasRoot }}
+ type {{.ResolverType}} struct {}
+{{ end }}
+
+{{ range $resolver := .Resolvers -}}
+ {{ if $resolver.Comment -}}
+ // {{ $resolver.Comment }}
+ {{- else if not $.OmitTemplateComment -}}
+ // {{ $resolver.Field.GoFieldName }} is the resolver for the {{ $resolver.Field.Name }} field.
+ {{- end }}
+ func (r *{{lcFirst $resolver.Object.Name}}{{ucFirst $.ResolverType}}) {{$resolver.Field.GoFieldName}}{{ with $resolver.PrevDecl }}{{ $resolver.Field.ShortResolverSignature .Type }}{{ else }}{{ $resolver.Field.ShortResolverDeclaration }}{{ end }}{
+ // Custom Resolver implementation
+ panic(fmt.Errorf("custom Resolver not implemented: {{ $resolver.Field.GoFieldName }} - {{lcFirst $resolver.Field.GoFieldName }}"))
+ }
+
+{{ end }}
+
+{{ range $object := .Objects -}}
+ {{ if not $.OmitTemplateComment -}}
+ // {{ucFirst $object.Name}} returns {{ $object.ResolverInterface | ref }} implementation.
+ {{- end }}
+ func (r *{{$.ResolverType}}) {{ucFirst $object.Name}}() {{ $object.ResolverInterface | ref }} { return &{{lcFirst $object.Name}}{{ucFirst $.ResolverType}}{r} }
+{{ end }}
+
+{{ range $object := .Objects -}}
+ type {{lcFirst $object.Name}}{{ucFirst $.ResolverType}} struct { *{{$.ResolverType}} }
+{{ end }}
+
+{{ if (ne .RemainingSource "") }}
+ // !!! WARNING !!!
+ // The code below was going to be deleted when updating resolvers. It has been copied here so you have
+ // one last chance to move it out of harms way if you want. There are two reasons this happens:
+ // - When renaming or deleting a resolver the old code will be put in here. You can safely delete
+ // it when you're done.
+ // - You have helper methods in this file. Move them out to keep these resolver files clean.
+ {{ .RemainingSource }}
+{{ end }}
diff --git a/plugin/resolvergen/testdata/resolvertemplate/gqlgen.yml b/plugin/resolvergen/testdata/resolvertemplate/gqlgen.yml
new file mode 100644
index 0000000000..c7ce0aaddd
--- /dev/null
+++ b/plugin/resolvergen/testdata/resolvertemplate/gqlgen.yml
@@ -0,0 +1,17 @@
+schema:
+ - "testdata/schema.graphql"
+
+exec:
+ filename: testdata/singlefile/out/ignored.go
+model:
+ filename: testdata/singlefile/out/generated.go
+resolver:
+ type: CustomResolverType
+ layout: follow-schema
+ dir: testdata/resolvertemplate/out
+ filename_template: "{name}.resolvers.go"
+ resolver_template: "testdata/resolvertemplate/customResolverTemplate.gotpl"
+
+models:
+ Resolver:
+ model: github.com/99designs/gqlgen/plugin/resolvergen/testdata/singlefile/out.Resolver
diff --git a/plugin/resolvergen/testdata/resolvertemplate/out/resolver.go b/plugin/resolvergen/testdata/resolvertemplate/out/resolver.go
new file mode 100644
index 0000000000..640b3c53ff
--- /dev/null
+++ b/plugin/resolvergen/testdata/resolvertemplate/out/resolver.go
@@ -0,0 +1,7 @@
+package out
+
+// This file will not be regenerated automatically.
+//
+// It serves as dependency injection for your app, add any dependencies you require here.
+
+type CustomResolverType struct{}
diff --git a/plugin/resolvergen/testdata/resolvertemplate/out/schema.resolvers.go b/plugin/resolvergen/testdata/resolvertemplate/out/schema.resolvers.go
new file mode 100644
index 0000000000..27f0503602
--- /dev/null
+++ b/plugin/resolvergen/testdata/resolvertemplate/out/schema.resolvers.go
@@ -0,0 +1,35 @@
+package out
+
+// This file will be automatically regenerated based on the schema, any resolver implementations
+// will be copied through when generating and any unknown code will be moved to the end.
+// Code generated by github.com/99designs/gqlgen version v0.17.39-dev
+
+import (
+ "context"
+ "fmt"
+
+ customresolver "github.com/99designs/gqlgen/plugin/resolvergen/testdata/singlefile/out"
+)
+
+// Resolver is the resolver for the resolver field.
+func (r *queryCustomResolverType) Resolver(ctx context.Context) (*customresolver.Resolver, error) {
+ // Custom Resolver implementation
+ panic(fmt.Errorf("custom Resolver not implemented: Resolver - resolver"))
+}
+
+// Name is the resolver for the name field.
+func (r *resolverCustomResolverType) Name(ctx context.Context, obj *customresolver.Resolver) (string, error) {
+ // Custom Resolver implementation
+ panic(fmt.Errorf("custom Resolver not implemented: Name - name"))
+}
+
+// Query returns customresolver.QueryResolver implementation.
+func (r *CustomResolverType) Query() customresolver.QueryResolver { return &queryCustomResolverType{r} }
+
+// Resolver returns customresolver.ResolverResolver implementation.
+func (r *CustomResolverType) Resolver() customresolver.ResolverResolver {
+ return &resolverCustomResolverType{r}
+}
+
+type queryCustomResolverType struct{ *CustomResolverType }
+type resolverCustomResolverType struct{ *CustomResolverType }
diff --git a/plugin/stubgen/stubs.go b/plugin/stubgen/stubs.go
index 01db65b1f9..8f1b81293c 100644
--- a/plugin/stubgen/stubs.go
+++ b/plugin/stubgen/stubs.go
@@ -5,11 +5,10 @@ import (
"path/filepath"
"syscall"
- "github.com/99designs/gqlgen/internal/code"
-
"github.com/99designs/gqlgen/codegen"
"github.com/99designs/gqlgen/codegen/config"
"github.com/99designs/gqlgen/codegen/templates"
+ "github.com/99designs/gqlgen/internal/code"
"github.com/99designs/gqlgen/plugin"
)