diff --git a/codegen/config/config.go b/codegen/config/config.go index 14e28c11e5..bec8e00fb2 100644 --- a/codegen/config/config.go +++ b/codegen/config/config.go @@ -296,19 +296,21 @@ func (cfg *Config) normalize() error { } builtins := TypeMap{ - "__Directive": {Model: "github.com/99designs/gqlgen/graphql/introspection.Directive"}, - "__Type": {Model: "github.com/99designs/gqlgen/graphql/introspection.Type"}, - "__Field": {Model: "github.com/99designs/gqlgen/graphql/introspection.Field"}, - "__EnumValue": {Model: "github.com/99designs/gqlgen/graphql/introspection.EnumValue"}, - "__InputValue": {Model: "github.com/99designs/gqlgen/graphql/introspection.InputValue"}, - "__Schema": {Model: "github.com/99designs/gqlgen/graphql/introspection.Schema"}, - "Int": {Model: "github.com/99designs/gqlgen/graphql.Int"}, - "Float": {Model: "github.com/99designs/gqlgen/graphql.Float"}, - "String": {Model: "github.com/99designs/gqlgen/graphql.String"}, - "Boolean": {Model: "github.com/99designs/gqlgen/graphql.Boolean"}, - "ID": {Model: "github.com/99designs/gqlgen/graphql.ID"}, - "Time": {Model: "github.com/99designs/gqlgen/graphql.Time"}, - "Map": {Model: "github.com/99designs/gqlgen/graphql.Map"}, + "__Directive": {Model: "github.com/99designs/gqlgen/graphql/introspection.Directive"}, + "__DirectiveLocation": {Model: "github.com/99designs/gqlgen/graphql.String"}, + "__Type": {Model: "github.com/99designs/gqlgen/graphql/introspection.Type"}, + "__TypeKind": {Model: "github.com/99designs/gqlgen/graphql.String"}, + "__Field": {Model: "github.com/99designs/gqlgen/graphql/introspection.Field"}, + "__EnumValue": {Model: "github.com/99designs/gqlgen/graphql/introspection.EnumValue"}, + "__InputValue": {Model: "github.com/99designs/gqlgen/graphql/introspection.InputValue"}, + "__Schema": {Model: "github.com/99designs/gqlgen/graphql/introspection.Schema"}, + "Int": {Model: "github.com/99designs/gqlgen/graphql.Int"}, + "Float": {Model: "github.com/99designs/gqlgen/graphql.Float"}, + "String": {Model: "github.com/99designs/gqlgen/graphql.String"}, + "Boolean": {Model: "github.com/99designs/gqlgen/graphql.Boolean"}, + "ID": {Model: "github.com/99designs/gqlgen/graphql.ID"}, + "Time": {Model: "github.com/99designs/gqlgen/graphql.Time"}, + "Map": {Model: "github.com/99designs/gqlgen/graphql.Map"}, } if cfg.Models == nil { diff --git a/codegen/directive.go b/codegen/directive.go index 4cc30d36c5..f9f000bafb 100644 --- a/codegen/directive.go +++ b/codegen/directive.go @@ -25,7 +25,7 @@ func (d *Directive) CallArgs() string { args := []string{"ctx", "obj", "n"} for _, arg := range d.Args { - args = append(args, "args["+strconv.Quote(arg.GQLName)+"].("+arg.Signature()+")") + args = append(args, "args["+strconv.Quote(arg.GQLName)+"].("+templates.CurrentImports.LookupType(arg.GoType)+")") } return strings.Join(args, ", ") @@ -56,7 +56,7 @@ func (d *Directive) Declaration() string { res := ucFirst(d.Name) + " func(ctx context.Context, obj interface{}, next graphql.Resolver" for _, arg := range d.Args { - res += fmt.Sprintf(", %s %s", arg.GoVarName, arg.Signature()) + res += fmt.Sprintf(", %s %s", arg.GoVarName, templates.CurrentImports.LookupType(arg.GoType)) } res += ") (res interface{}, err error)" diff --git a/codegen/models_build.go b/codegen/models_build.go index 4377537657..bef81fac25 100644 --- a/codegen/models_build.go +++ b/codegen/models_build.go @@ -17,7 +17,7 @@ func (g *Generator) buildModels(types NamedTypes, prog *loader.Program) ([]Model } switch typ.Kind { case ast.Object: - obj, err := g.buildObject(types, typ) + obj, err := g.buildObject(prog, types, typ) if err != nil { return nil, err } diff --git a/codegen/object.go b/codegen/object.go index fbcb6dabbb..62b1835e69 100644 --- a/codegen/object.go +++ b/codegen/object.go @@ -174,10 +174,10 @@ func (f *Field) ShortResolverDeclaration() string { res += fmt.Sprintf(", obj *%s", templates.CurrentImports.LookupType(f.Object.Definition.GoType)) } for _, arg := range f.Args { - res += fmt.Sprintf(", %s %s", arg.GoVarName, arg.Signature()) + res += fmt.Sprintf(", %s %s", arg.GoVarName, templates.CurrentImports.LookupType(arg.GoType)) } - result := f.Signature() + result := templates.CurrentImports.LookupType(f.GoType) if f.Object.Stream { result = "<-chan " + result } @@ -196,10 +196,10 @@ func (f *Field) ResolverDeclaration() string { res += fmt.Sprintf(", obj *%s", templates.CurrentImports.LookupType(f.Object.Definition.GoType)) } for _, arg := range f.Args { - res += fmt.Sprintf(", %s %s", arg.GoVarName, arg.Signature()) + res += fmt.Sprintf(", %s %s", arg.GoVarName, templates.CurrentImports.LookupType(arg.GoType)) } - result := f.Signature() + result := templates.CurrentImports.LookupType(f.GoType) if f.Object.Stream { result = "<-chan " + result } @@ -211,7 +211,7 @@ func (f *Field) ResolverDeclaration() string { func (f *Field) ComplexitySignature() string { res := fmt.Sprintf("func(childComplexity int") for _, arg := range f.Args { - res += fmt.Sprintf(", %s %s", arg.GoVarName, arg.Signature()) + res += fmt.Sprintf(", %s %s", arg.GoVarName, templates.CurrentImports.LookupType(arg.GoType)) } res += ") int" return res @@ -220,7 +220,7 @@ func (f *Field) ComplexitySignature() string { func (f *Field) ComplexityArgs() string { var args []string for _, arg := range f.Args { - args = append(args, "args["+strconv.Quote(arg.GQLName)+"].("+arg.Signature()+")") + args = append(args, "args["+strconv.Quote(arg.GQLName)+"].("+templates.CurrentImports.LookupType(arg.GoType)+")") } return strings.Join(args, ", ") @@ -242,7 +242,7 @@ func (f *Field) CallArgs() string { } for _, arg := range f.Args { - args = append(args, "args["+strconv.Quote(arg.GQLName)+"].("+arg.Signature()+")") + args = append(args, "args["+strconv.Quote(arg.GQLName)+"].("+templates.CurrentImports.LookupType(arg.GoType)+")") } return strings.Join(args, ", ") @@ -250,12 +250,12 @@ func (f *Field) CallArgs() string { // should be in the template, but its recursive and has a bunch of args func (f *Field) WriteJson() string { - return f.doWriteJson("res", f.TypeReference.Modifiers, f.ASTType, false, 1) + return f.doWriteJson("res", f.GoType, f.ASTType, false, 1) } -func (f *Field) doWriteJson(val string, remainingMods []string, astType *ast.Type, isPtr bool, depth int) string { - switch { - case len(remainingMods) > 0 && remainingMods[0] == modPtr: +func (f *Field) doWriteJson(val string, destType types.Type, astType *ast.Type, isPtr bool, depth int) string { + switch destType := destType.(type) { + case *types.Pointer: return tpl(` if {{.val}} == nil { {{- if .nonNull }} @@ -268,18 +268,22 @@ func (f *Field) doWriteJson(val string, remainingMods []string, astType *ast.Typ {{.next }}`, map[string]interface{}{ "val": val, "nonNull": astType.NonNull, - "next": f.doWriteJson(val, remainingMods[1:], astType, true, depth+1), + "next": f.doWriteJson(val, destType.Elem(), astType, true, depth+1), }) - case len(remainingMods) > 0 && remainingMods[0] == modList: + case *types.Slice: if isPtr { val = "*" + val } var arr = "arr" + strconv.Itoa(depth) var index = "idx" + strconv.Itoa(depth) var usePtr bool - if len(remainingMods) == 1 && !isPtr { - usePtr = true + if !isPtr { + switch destType.Elem().(type) { + case *types.Pointer, *types.Array: + default: + usePtr = true + } } return tpl(` @@ -327,16 +331,17 @@ func (f *Field) doWriteJson(val string, remainingMods []string, astType *ast.Typ "arrayLen": len(val), "isScalar": f.Definition.IsScalar, "usePtr": usePtr, - "next": f.doWriteJson(val+"["+index+"]", remainingMods[1:], astType.Elem, false, depth+1), + "next": f.doWriteJson(val+"["+index+"]", destType.Elem(), astType.Elem, false, depth+1), }) - case f.Definition.IsScalar: - if isPtr { - val = "*" + val + default: + if f.Definition.IsScalar { + if isPtr { + val = "*" + val + } + return f.Marshal(val) } - return f.Marshal(val) - default: if !isPtr { val = "&" + val } diff --git a/codegen/object_build.go b/codegen/object_build.go index 8d4e6a0e2e..0b506eb6f9 100644 --- a/codegen/object_build.go +++ b/codegen/object_build.go @@ -20,7 +20,7 @@ func (g *Generator) buildObjects(ts NamedTypes, prog *loader.Program) (Objects, continue } - obj, err := g.buildObject(ts, typ) + obj, err := g.buildObject(prog, ts, typ) if err != nil { return nil, err } @@ -80,7 +80,7 @@ func sanitizeArgName(name string) string { return name } -func (g *Generator) buildObject(ts NamedTypes, typ *ast.Definition) (*Object, error) { +func (g *Generator) buildObject(prog *loader.Program, ts NamedTypes, typ *ast.Definition) (*Object, error) { obj := &Object{Definition: ts[typ.Name]} typeEntry, entryExists := g.Models[typ.Name] @@ -109,8 +109,13 @@ func (g *Generator) buildObject(ts NamedTypes, typ *ast.Definition) (*Object, er for _, field := range typ.Fields { if typ == g.schema.Query && field.Name == "__type" { + schemaType, err := findGoType(prog, "github.com/99designs/gqlgen/graphql/introspection", "Schema") + if err != nil { + return nil, errors.Wrap(err, "unable to find root schema introspection type") + } + obj.Fields = append(obj.Fields, Field{ - TypeReference: &TypeReference{ts["__Schema"], []string{modPtr}, ast.NamedType("__Schema", nil)}, + TypeReference: &TypeReference{ts["__Schema"], types.NewPointer(schemaType.Type()), ast.NamedType("__Schema", nil)}, GQLName: "__schema", GoFieldType: GoFieldMethod, GoReceiverName: "ec", @@ -121,14 +126,19 @@ func (g *Generator) buildObject(ts NamedTypes, typ *ast.Definition) (*Object, er continue } if typ == g.schema.Query && field.Name == "__schema" { + typeType, err := findGoType(prog, "github.com/99designs/gqlgen/graphql/introspection", "Type") + if err != nil { + return nil, errors.Wrap(err, "unable to find root schema introspection type") + } + obj.Fields = append(obj.Fields, Field{ - TypeReference: &TypeReference{ts["__Type"], []string{modPtr}, ast.NamedType("__Schema", nil)}, + TypeReference: &TypeReference{ts["__Type"], types.NewPointer(typeType.Type()), ast.NamedType("__Schema", nil)}, GQLName: "__type", GoFieldType: GoFieldMethod, GoReceiverName: "ec", GoFieldName: "introspectType", Args: []FieldArgument{ - {GQLName: "name", TypeReference: &TypeReference{ts["String"], []string{}, ast.NamedType("String", nil)}, Object: &Object{}}, + {GQLName: "name", TypeReference: &TypeReference{ts["String"], types.Typ[types.String], ast.NamedType("String", nil)}, Object: &Object{}}, }, Object: obj, }) diff --git a/codegen/templates/args.gotpl b/codegen/templates/args.gotpl index 57eca14088..18d11700e8 100644 --- a/codegen/templates/args.gotpl +++ b/codegen/templates/args.gotpl @@ -1,6 +1,6 @@ args := map[string]interface{}{} {{- range $i, $arg := . }} - var arg{{$i}} {{$arg.Signature }} + var arg{{$i}} {{$arg.GoType | ref }} if tmp, ok := rawArgs[{{$arg.GQLName|quote}}]; ok { {{- if $arg.Directives }} argm{{$i}}, err := chainFieldMiddleware([]graphql.FieldMiddleware{ @@ -25,10 +25,10 @@ if err != nil { return nil, err } - if data, ok := argm{{$i}}.({{$arg.Signature }}); ok { + if data, ok := argm{{$i}}.({{$arg.GoType | ref }}); ok { arg{{$i}} = data } else { - return nil, errors.New("expect {{$arg.Signature }}") + return nil, errors.New("expect {{$arg.GoType | ref }}") } {{- else }} var err error diff --git a/codegen/templates/data.go b/codegen/templates/data.go index ec6f00da1f..2acdce22ea 100644 --- a/codegen/templates/data.go +++ b/codegen/templates/data.go @@ -1,12 +1,12 @@ package templates var data = map[string]string{ - "args.gotpl": "\targs := map[string]interface{}{}\n\t{{- range $i, $arg := . }}\n\t\tvar arg{{$i}} {{$arg.Signature }}\n\t\tif tmp, ok := rawArgs[{{$arg.GQLName|quote}}]; ok {\n\t\t\t{{- if $arg.Directives }}\n\t\t\t\targm{{$i}}, err := chainFieldMiddleware([]graphql.FieldMiddleware{\n\t\t\t\t{{- range $directive := $arg.Directives }}\n\t\t\t\t\tfunc(ctx context.Context, n graphql.Resolver) (res interface{}, err error) {\n\t\t\t\t\t{{- range $dArg := $directive.Args }}\n\t\t\t\t\t\t{{- if and $dArg.IsPtr ( notNil \"Value\" $dArg ) }}\n\t\t\t\t\t\t\t{{ $dArg.GoVarName }} := {{ $dArg.Value | dump }}\n\t\t\t\t\t\t{{- end }}\n\t\t\t\t\t{{- end }}\n\t\t\t\t\t\treturn e.directives.{{$directive.Name|ucFirst}}({{$directive.ResolveArgs \"tmp\" \"n\" }})\n\t\t\t\t\t},\n\t\t\t\t{{- end }}\n\t\t\t\t}...)(ctx, func(ctx2 context.Context) (interface{}, error) {\n\t\t\t\t\tvar err error\n\t\t\t\t\t{{$arg.Unmarshal (print \"arg\" $i) \"tmp\" }}\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\treturn arg{{ $i }}, nil\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tif data, ok := argm{{$i}}.({{$arg.Signature }}); ok {\n\t\t\t\t\targ{{$i}} = data\n\t\t\t\t} else {\n\t\t\t\t\treturn nil, errors.New(\"expect {{$arg.Signature }}\")\n\t\t\t\t}\n\t\t\t{{- else }}\n\t\t\t\tvar err error\n\t\t\t\t{{ $arg.Unmarshal (print \"arg\" $i) \"tmp\" }}\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t{{- end }}\n\t\t\t{{- if $arg.Definition.IsInput }}\n\t\t\t\t{{ $arg.Middleware (print \"arg\" $i) (print \"arg\" $i) }}\n\t\t\t{{- end }}\n\t\t}\n\t\targs[{{$arg.GQLName|quote}}] = arg{{$i}}\n\t{{- end }}\n\treturn args, nil\n", - "field.gotpl": "{{ $field := . }}\n{{ $object := $field.Object }}\n\n{{- if $object.Stream }}\n\tfunc (ec *executionContext) _{{$object.Definition.GQLType}}_{{$field.GQLName}}(ctx context.Context, field graphql.CollectedField) func() graphql.Marshaler {\n\t\tctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{\n\t\t\tField: field,\n\t\t\tArgs: nil,\n\t\t})\n\t\t{{- if $field.Args }}\n\t\t\trawArgs := field.ArgumentMap(ec.Variables)\n\t\t\targs, err := ec.{{ $field.ArgsFunc }}(ctx,rawArgs)\n\t\t\tif err != nil {\n\t\t\t\tec.Error(ctx, err)\n\t\t\t\treturn nil\n\t\t\t}\n\t\t{{- end }}\n\t\t// FIXME: subscriptions are missing request middleware stack https://github.com/99designs/gqlgen/issues/259\n\t\t// and Tracer stack\n\t\trctx := ctx\n\t\tresults, err := ec.resolvers.{{ $field.ShortInvocation }}\n\t\tif err != nil {\n\t\t\tec.Error(ctx, err)\n\t\t\treturn nil\n\t\t}\n\t\treturn func() graphql.Marshaler {\n\t\t\tres, ok := <-results\n\t\t\tif !ok {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn graphql.WriterFunc(func(w io.Writer) {\n\t\t\t\tw.Write([]byte{'{'})\n\t\t\t\tgraphql.MarshalString(field.Alias).MarshalGQL(w)\n\t\t\t\tw.Write([]byte{':'})\n\t\t\t\tfunc() graphql.Marshaler {\n\t\t\t\t\t{{ $field.WriteJson }}\n\t\t\t\t}().MarshalGQL(w)\n\t\t\t\tw.Write([]byte{'}'})\n\t\t\t})\n\t\t}\n\t}\n{{ else }}\n\t// nolint: vetshadow\n\tfunc (ec *executionContext) _{{$object.Definition.GQLType}}_{{$field.GQLName}}(ctx context.Context, field graphql.CollectedField, {{if not $object.Root}}obj *{{$object.Definition.GoType | ref}}{{end}}) graphql.Marshaler {\n\t\tctx = ec.Tracer.StartFieldExecution(ctx, field)\n\t\tdefer func () { ec.Tracer.EndFieldExecution(ctx) }()\n\t\trctx := &graphql.ResolverContext{\n\t\t\tObject: {{$object.Definition.GQLType|quote}},\n\t\t\tField: field,\n\t\t\tArgs: nil,\n\t\t}\n\t\tctx = graphql.WithResolverContext(ctx, rctx)\n\t\t{{- if $field.Args }}\n\t\t\trawArgs := field.ArgumentMap(ec.Variables)\n\t\t\targs, err := ec.{{ $field.ArgsFunc }}(ctx,rawArgs)\n\t\t\tif err != nil {\n\t\t\t\tec.Error(ctx, err)\n\t\t\t\treturn graphql.Null\n\t\t\t}\n\t\t\trctx.Args = args\n\t\t{{- end }}\n\t\tctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)\n\t\tresTmp := ec.FieldMiddleware(ctx, {{if $object.Root}}nil{{else}}obj{{end}}, func(rctx context.Context) (interface{}, error) {\n\t\t\tctx = rctx // use context from middleware stack in children\n\t\t\t{{- if $field.IsResolver }}\n\t\t\t\treturn ec.resolvers.{{ $field.ShortInvocation }}\n\t\t\t{{- else if $field.IsMethod }}\n\t\t\t\t{{- if $field.NoErr }}\n\t\t\t\t\treturn {{$field.GoReceiverName}}.{{$field.GoFieldName}}({{ $field.CallArgs }}), nil\n\t\t\t\t{{- else }}\n\t\t\t\t\treturn {{$field.GoReceiverName}}.{{$field.GoFieldName}}({{ $field.CallArgs }})\n\t\t\t\t{{- end }}\n\t\t\t{{- else if $field.IsVariable }}\n\t\t\t\treturn {{$field.GoReceiverName}}.{{$field.GoFieldName}}, nil\n\t\t\t{{- end }}\n\t\t})\n\t\tif resTmp == nil {\n\t\t\t{{- if $field.ASTType.NonNull }}\n\t\t\t\tif !ec.HasError(rctx) {\n\t\t\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t\t\t}\n\t\t\t{{- end }}\n\t\t\treturn graphql.Null\n\t\t}\n\t\tres := resTmp.({{$field.Signature}})\n\t\trctx.Result = res\n\t\tctx = ec.Tracer.StartFieldChildExecution(ctx)\n\t\t{{ $field.WriteJson }}\n\t}\n{{ end }}\n", + "args.gotpl": "\targs := map[string]interface{}{}\n\t{{- range $i, $arg := . }}\n\t\tvar arg{{$i}} {{$arg.GoType | ref }}\n\t\tif tmp, ok := rawArgs[{{$arg.GQLName|quote}}]; ok {\n\t\t\t{{- if $arg.Directives }}\n\t\t\t\targm{{$i}}, err := chainFieldMiddleware([]graphql.FieldMiddleware{\n\t\t\t\t{{- range $directive := $arg.Directives }}\n\t\t\t\t\tfunc(ctx context.Context, n graphql.Resolver) (res interface{}, err error) {\n\t\t\t\t\t{{- range $dArg := $directive.Args }}\n\t\t\t\t\t\t{{- if and $dArg.IsPtr ( notNil \"Value\" $dArg ) }}\n\t\t\t\t\t\t\t{{ $dArg.GoVarName }} := {{ $dArg.Value | dump }}\n\t\t\t\t\t\t{{- end }}\n\t\t\t\t\t{{- end }}\n\t\t\t\t\t\treturn e.directives.{{$directive.Name|ucFirst}}({{$directive.ResolveArgs \"tmp\" \"n\" }})\n\t\t\t\t\t},\n\t\t\t\t{{- end }}\n\t\t\t\t}...)(ctx, func(ctx2 context.Context) (interface{}, error) {\n\t\t\t\t\tvar err error\n\t\t\t\t\t{{$arg.Unmarshal (print \"arg\" $i) \"tmp\" }}\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\treturn arg{{ $i }}, nil\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tif data, ok := argm{{$i}}.({{$arg.GoType | ref }}); ok {\n\t\t\t\t\targ{{$i}} = data\n\t\t\t\t} else {\n\t\t\t\t\treturn nil, errors.New(\"expect {{$arg.GoType | ref }}\")\n\t\t\t\t}\n\t\t\t{{- else }}\n\t\t\t\tvar err error\n\t\t\t\t{{ $arg.Unmarshal (print \"arg\" $i) \"tmp\" }}\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t{{- end }}\n\t\t\t{{- if $arg.Definition.IsInput }}\n\t\t\t\t{{ $arg.Middleware (print \"arg\" $i) (print \"arg\" $i) }}\n\t\t\t{{- end }}\n\t\t}\n\t\targs[{{$arg.GQLName|quote}}] = arg{{$i}}\n\t{{- end }}\n\treturn args, nil\n", + "field.gotpl": "{{ $field := . }}\n{{ $object := $field.Object }}\n\n{{- if $object.Stream }}\n\tfunc (ec *executionContext) _{{$object.Definition.GQLType}}_{{$field.GQLName}}(ctx context.Context, field graphql.CollectedField) func() graphql.Marshaler {\n\t\tctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{\n\t\t\tField: field,\n\t\t\tArgs: nil,\n\t\t})\n\t\t{{- if $field.Args }}\n\t\t\trawArgs := field.ArgumentMap(ec.Variables)\n\t\t\targs, err := ec.{{ $field.ArgsFunc }}(ctx,rawArgs)\n\t\t\tif err != nil {\n\t\t\t\tec.Error(ctx, err)\n\t\t\t\treturn nil\n\t\t\t}\n\t\t{{- end }}\n\t\t// FIXME: subscriptions are missing request middleware stack https://github.com/99designs/gqlgen/issues/259\n\t\t// and Tracer stack\n\t\trctx := ctx\n\t\tresults, err := ec.resolvers.{{ $field.ShortInvocation }}\n\t\tif err != nil {\n\t\t\tec.Error(ctx, err)\n\t\t\treturn nil\n\t\t}\n\t\treturn func() graphql.Marshaler {\n\t\t\tres, ok := <-results\n\t\t\tif !ok {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn graphql.WriterFunc(func(w io.Writer) {\n\t\t\t\tw.Write([]byte{'{'})\n\t\t\t\tgraphql.MarshalString(field.Alias).MarshalGQL(w)\n\t\t\t\tw.Write([]byte{':'})\n\t\t\t\tfunc() graphql.Marshaler {\n\t\t\t\t\t{{ $field.WriteJson }}\n\t\t\t\t}().MarshalGQL(w)\n\t\t\t\tw.Write([]byte{'}'})\n\t\t\t})\n\t\t}\n\t}\n{{ else }}\n\t// nolint: vetshadow\n\tfunc (ec *executionContext) _{{$object.Definition.GQLType}}_{{$field.GQLName}}(ctx context.Context, field graphql.CollectedField, {{if not $object.Root}}obj *{{$object.Definition.GoType | ref}}{{end}}) graphql.Marshaler {\n\t\tctx = ec.Tracer.StartFieldExecution(ctx, field)\n\t\tdefer func () { ec.Tracer.EndFieldExecution(ctx) }()\n\t\trctx := &graphql.ResolverContext{\n\t\t\tObject: {{$object.Definition.GQLType|quote}},\n\t\t\tField: field,\n\t\t\tArgs: nil,\n\t\t}\n\t\tctx = graphql.WithResolverContext(ctx, rctx)\n\t\t{{- if $field.Args }}\n\t\t\trawArgs := field.ArgumentMap(ec.Variables)\n\t\t\targs, err := ec.{{ $field.ArgsFunc }}(ctx,rawArgs)\n\t\t\tif err != nil {\n\t\t\t\tec.Error(ctx, err)\n\t\t\t\treturn graphql.Null\n\t\t\t}\n\t\t\trctx.Args = args\n\t\t{{- end }}\n\t\tctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)\n\t\tresTmp := ec.FieldMiddleware(ctx, {{if $object.Root}}nil{{else}}obj{{end}}, func(rctx context.Context) (interface{}, error) {\n\t\t\tctx = rctx // use context from middleware stack in children\n\t\t\t{{- if $field.IsResolver }}\n\t\t\t\treturn ec.resolvers.{{ $field.ShortInvocation }}\n\t\t\t{{- else if $field.IsMethod }}\n\t\t\t\t{{- if $field.NoErr }}\n\t\t\t\t\treturn {{$field.GoReceiverName}}.{{$field.GoFieldName}}({{ $field.CallArgs }}), nil\n\t\t\t\t{{- else }}\n\t\t\t\t\treturn {{$field.GoReceiverName}}.{{$field.GoFieldName}}({{ $field.CallArgs }})\n\t\t\t\t{{- end }}\n\t\t\t{{- else if $field.IsVariable }}\n\t\t\t\treturn {{$field.GoReceiverName}}.{{$field.GoFieldName}}, nil\n\t\t\t{{- end }}\n\t\t})\n\t\tif resTmp == nil {\n\t\t\t{{- if $field.ASTType.NonNull }}\n\t\t\t\tif !ec.HasError(rctx) {\n\t\t\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t\t\t}\n\t\t\t{{- end }}\n\t\t\treturn graphql.Null\n\t\t}\n\t\tres := resTmp.({{$field.GoType | ref}})\n\t\trctx.Result = res\n\t\tctx = ec.Tracer.StartFieldChildExecution(ctx)\n\t\t{{ $field.WriteJson }}\n\t}\n{{ end }}\n", "generated.gotpl": "// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.\n\npackage {{ .PackageName }}\n\nimport (\n\t%%%IMPORTS%%%\n\n\t{{ reserveImport \"context\" }}\n\t{{ reserveImport \"fmt\" }}\n\t{{ reserveImport \"io\" }}\n\t{{ reserveImport \"strconv\" }}\n\t{{ reserveImport \"time\" }}\n\t{{ reserveImport \"sync\" }}\n\t{{ reserveImport \"errors\" }}\n\t{{ reserveImport \"bytes\" }}\n\n\t{{ reserveImport \"github.com/vektah/gqlparser\" }}\n\t{{ reserveImport \"github.com/vektah/gqlparser/ast\" }}\n\t{{ reserveImport \"github.com/99designs/gqlgen/graphql\" }}\n\t{{ reserveImport \"github.com/99designs/gqlgen/graphql/introspection\" }}\n)\n\n// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.\nfunc NewExecutableSchema(cfg Config) graphql.ExecutableSchema {\n\treturn &executableSchema{\n\t\tresolvers: cfg.Resolvers,\n\t\tdirectives: cfg.Directives,\n\t\tcomplexity: cfg.Complexity,\n\t}\n}\n\ntype Config struct {\n\tResolvers ResolverRoot\n\tDirectives DirectiveRoot\n\tComplexity ComplexityRoot\n}\n\ntype ResolverRoot interface {\n{{- range $object := .Objects -}}\n\t{{ if $object.HasResolvers -}}\n\t\t{{$object.Definition.GQLType}}() {{$object.Definition.GQLType}}Resolver\n\t{{ end }}\n{{- end }}\n}\n\ntype DirectiveRoot struct {\n{{ range $directive := .Directives }}\n\t{{ $directive.Declaration }}\n{{ end }}\n}\n\ntype ComplexityRoot struct {\n{{ range $object := .Objects }}\n\t{{ if not $object.IsReserved -}}\n\t\t{{ $object.Definition.GQLType|toCamel }} struct {\n\t\t{{ range $field := $object.Fields -}}\n\t\t\t{{ if not $field.IsReserved -}}\n\t\t\t\t{{ $field.GQLName|toCamel }} {{ $field.ComplexitySignature }}\n\t\t\t{{ end }}\n\t\t{{- end }}\n\t\t}\n\t{{- end }}\n{{ end }}\n}\n\n{{ range $object := .Objects -}}\n\t{{ if $object.HasResolvers }}\n\t\ttype {{$object.Definition.GQLType}}Resolver interface {\n\t\t{{ range $field := $object.Fields -}}\n\t\t\t{{ $field.ShortResolverDeclaration }}\n\t\t{{ end }}\n\t\t}\n\t{{- end }}\n{{- end }}\n\n{{ range $object := .Objects -}}\n\t{{ range $field := $object.Fields -}}\n\t\t{{ if $field.Args }}\n\t\t\tfunc (e *executableSchema){{ $field.ArgsFunc }}(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {\n\t\t\t{{ template \"args.gotpl\" $field.Args }}\n\t\t\t}\n\t\t{{ end }}\n\t{{ end }}\n{{- end }}\n\n{{ range $directive := .Directives }}\n\t{{ if $directive.Args }}\n\t\tfunc (e *executableSchema){{ $directive.ArgsFunc }}(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {\n\t\t{{ template \"args.gotpl\" $directive.Args }}\n\t\t}\n\t{{ end }}\n{{ end }}\n\ntype executableSchema struct {\n\tresolvers ResolverRoot\n\tdirectives DirectiveRoot\n\tcomplexity ComplexityRoot\n}\n\nfunc (e *executableSchema) Schema() *ast.Schema {\n\treturn parsedSchema\n}\n\nfunc (e *executableSchema) Complexity(typeName, field string, childComplexity int, rawArgs map[string]interface{}) (int, bool) {\n\tswitch typeName + \".\" + field {\n\t{{ range $object := .Objects }}\n\t\t{{ if not $object.IsReserved }}\n\t\t\t{{ range $field := $object.Fields }}\n\t\t\t\t{{ if not $field.IsReserved }}\n\t\t\t\t\tcase \"{{$object.Definition.GQLType}}.{{$field.GQLName}}\":\n\t\t\t\t\t\tif e.complexity.{{$object.Definition.GQLType|toCamel}}.{{$field.GQLName|toCamel}} == nil {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\t{{ if $field.Args }}\n\t\t\t\t\t\t\targs, err := e.{{ $field.ArgsFunc }}(context.TODO(),rawArgs)\n\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\treturn 0, false\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t{{ end }}\n\t\t\t\t\t\treturn e.complexity.{{$object.Definition.GQLType|toCamel}}.{{$field.GQLName|toCamel}}(childComplexity{{if $field.Args}}, {{$field.ComplexityArgs}} {{end}}), true\n\t\t\t\t{{ end }}\n\t\t\t{{ end }}\n\t\t{{ end }}\n\t{{ end }}\n\t}\n\treturn 0, false\n}\n\nfunc (e *executableSchema) Query(ctx context.Context, op *ast.OperationDefinition) *graphql.Response {\n\t{{- if .QueryRoot }}\n\t\tec := executionContext{graphql.GetRequestContext(ctx), e}\n\n\t\tbuf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte {\n\t\t\tdata := ec._{{.QueryRoot.Definition.GQLType}}(ctx, op.SelectionSet)\n\t\t\tvar buf bytes.Buffer\n\t\t\tdata.MarshalGQL(&buf)\n\t\t\treturn buf.Bytes()\n\t\t})\n\n\t\treturn &graphql.Response{\n\t\t\tData: buf,\n\t\t\tErrors: ec.Errors,\n\t\t\tExtensions: ec.Extensions,\t\t}\n\t{{- else }}\n\t\treturn graphql.ErrorResponse(ctx, \"queries are not supported\")\n\t{{- end }}\n}\n\nfunc (e *executableSchema) Mutation(ctx context.Context, op *ast.OperationDefinition) *graphql.Response {\n\t{{- if .MutationRoot }}\n\t\tec := executionContext{graphql.GetRequestContext(ctx), e}\n\n\t\tbuf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte {\n\t\t\tdata := ec._{{.MutationRoot.Definition.GQLType}}(ctx, op.SelectionSet)\n\t\t\tvar buf bytes.Buffer\n\t\t\tdata.MarshalGQL(&buf)\n\t\t\treturn buf.Bytes()\n\t\t})\n\n\t\treturn &graphql.Response{\n\t\t\tData: buf,\n\t\t\tErrors: ec.Errors,\n\t\t\tExtensions: ec.Extensions,\n\t\t}\n\t{{- else }}\n\t\treturn graphql.ErrorResponse(ctx, \"mutations are not supported\")\n\t{{- end }}\n}\n\nfunc (e *executableSchema) Subscription(ctx context.Context, op *ast.OperationDefinition) func() *graphql.Response {\n\t{{- if .SubscriptionRoot }}\n\t\tec := executionContext{graphql.GetRequestContext(ctx), e}\n\n\t\tnext := ec._{{.SubscriptionRoot.Definition.GQLType}}(ctx, op.SelectionSet)\n\t\tif ec.Errors != nil {\n\t\t\treturn graphql.OneShot(&graphql.Response{Data: []byte(\"null\"), Errors: ec.Errors})\n\t\t}\n\n\t\tvar buf bytes.Buffer\n\t\treturn func() *graphql.Response {\n\t\t\tbuf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte {\n\t\t\t\tbuf.Reset()\n\t\t\t\tdata := next()\n\n\t\t\t\tif data == nil {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\tdata.MarshalGQL(&buf)\n\t\t\t\treturn buf.Bytes()\n\t\t\t})\n\n\t\t\tif buf == nil {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn &graphql.Response{\n\t\t\t\tData: buf,\n\t\t\t\tErrors: ec.Errors,\n\t\t\t\tExtensions: ec.Extensions,\n\t\t\t}\n\t\t}\n\t{{- else }}\n\t\treturn graphql.OneShot(graphql.ErrorResponse(ctx, \"subscriptions are not supported\"))\n\t{{- end }}\n}\n\ntype executionContext struct {\n\t*graphql.RequestContext\n\t*executableSchema\n}\n\n{{- range $object := .Objects }}\n\t{{ template \"object.gotpl\" $object }}\n\n\t{{- range $field := $object.Fields }}\n\t\t{{ template \"field.gotpl\" $field }}\n\t{{ end }}\n{{- end}}\n\n{{- range $interface := .Interfaces }}\n\t{{ template \"interface.gotpl\" $interface }}\n{{- end }}\n\n{{- range $input := .Inputs }}\n\t{{ template \"input.gotpl\" $input }}\n{{- end }}\n\nfunc (ec *executionContext) FieldMiddleware(ctx context.Context, obj interface{}, next graphql.Resolver) (ret interface{}) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = nil\n\t\t}\n\t}()\n\t{{- if .Directives }}\n\trctx := graphql.GetResolverContext(ctx)\n\tfor _, d := range rctx.Field.Definition.Directives {\n\t\tswitch d.Name {\n\t\t{{- range $directive := .Directives }}\n\t\tcase \"{{$directive.Name}}\":\n\t\t\tif ec.directives.{{$directive.Name|ucFirst}} != nil {\n\t\t\t\t{{- if $directive.Args }}\n\t\t\t\t\trawArgs := d.ArgumentMap(ec.Variables)\n\t\t\t\t\targs, err := ec.{{ $directive.ArgsFunc }}(ctx,rawArgs)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tec.Error(ctx, err)\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}\n\t\t\t\t{{- end }}\n\t\t\t\tn := next\n\t\t\t\tnext = func(ctx context.Context) (interface{}, error) {\n\t\t\t\t\treturn ec.directives.{{$directive.Name|ucFirst}}({{$directive.CallArgs}})\n\t\t\t\t}\n\t\t\t}\n\t\t{{- end }}\n\t\t}\n\t}\n\t{{- end }}\n\tres, err := ec.ResolverMiddleware(ctx, next)\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn nil\n\t}\n\treturn res\n}\n\nfunc (ec *executionContext) introspectSchema() (*introspection.Schema, error) {\n\tif ec.DisableIntrospection {\n\t\treturn nil, errors.New(\"introspection disabled\")\n\t}\n\treturn introspection.WrapSchema(parsedSchema), nil\n}\n\nfunc (ec *executionContext) introspectType(name string) (*introspection.Type, error) {\n\tif ec.DisableIntrospection {\n\t\treturn nil, errors.New(\"introspection disabled\")\n\t}\n\treturn introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil\n}\n\nvar parsedSchema = gqlparser.MustLoadSchema(\n\t{{- range $filename, $schema := .SchemaRaw }}\n\t\t&ast.Source{Name: {{$filename|quote}}, Input: {{$schema|rawQuote}}},\n\t{{- end }}\n)\n\n\n\n// ChainFieldMiddleware add chain by FieldMiddleware\n// nolint: deadcode\nfunc chainFieldMiddleware(handleFunc ...graphql.FieldMiddleware) graphql.FieldMiddleware {\n\tn := len(handleFunc)\n\n\tif n > 1 {\n\t\tlastI := n - 1\n\t\treturn func(ctx context.Context, next graphql.Resolver) (interface{}, error) {\n\t\t\tvar (\n\t\t\t\tchainHandler graphql.Resolver\n\t\t\t\tcurI int\n\t\t\t)\n\t\t\tchainHandler = func(currentCtx context.Context) (interface{}, error) {\n\t\t\t\tif curI == lastI {\n\t\t\t\t\treturn next(currentCtx)\n\t\t\t\t}\n\t\t\t\tcurI++\n\t\t\t\tres, err := handleFunc[curI](currentCtx, chainHandler)\n\t\t\t\tcurI--\n\t\t\t\treturn res, err\n\n\t\t\t}\n\t\t\treturn handleFunc[0](ctx, chainHandler)\n\t\t}\n\t}\n\n\tif n == 1 {\n\t\treturn handleFunc[0]\n\t}\n\n\treturn func(ctx context.Context, next graphql.Resolver) (interface{}, error) {\n\t\treturn next(ctx)\n\t}\n}\n", - "input.gotpl": "\t{{- if .Definition.IsMarshaled }}\n\tfunc Unmarshal{{ .Definition.GQLType }}(v interface{}) ({{.Definition.GoType | ref}}, error) {\n\t\tvar it {{.Definition.GoType | ref}}\n\t\tvar asMap = v.(map[string]interface{})\n\t\t{{ range $field := .Fields}}\n\t\t\t{{- if $field.Default}}\n\t\t\t\tif _, present := asMap[{{$field.GQLName|quote}}] ; !present {\n\t\t\t\t\tasMap[{{$field.GQLName|quote}}] = {{ $field.Default | dump }}\n\t\t\t\t}\n\t\t\t{{- end}}\n\t\t{{- end }}\n\n\t\tfor k, v := range asMap {\n\t\t\tswitch k {\n\t\t\t{{- range $field := .Fields }}\n\t\t\tcase {{$field.GQLName|quote}}:\n\t\t\t\tvar err error\n\t\t\t\t{{ $field.Unmarshal (print \"it.\" $field.GoFieldName) \"v\" }}\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn it, err\n\t\t\t\t}\n\t\t\t{{- end }}\n\t\t\t}\n\t\t}\n\n\t\treturn it, nil\n\t}\n\t{{- end }}\n\n\tfunc (e *executableSchema) {{ .Definition.GQLType }}Middleware(ctx context.Context, obj *{{.Definition.GoType | ref}}) (*{{.Definition.GoType | ref}}, error) {\n\t\t\t{{ if .Directives }}\n\t\tcObj, err := chainFieldMiddleware(\n\t\t\t[]graphql.FieldMiddleware{\n\t\t\t\t{{- range $directive := .Directives }}\n\t\t\t\t\tfunc(ctx context.Context, n graphql.Resolver) (res interface{}, err error) {\n\t\t\t\t\t{{- if $directive.Args }}\n\t\t\t\t\t{{- range $arg := $directive.Args }}\n\t\t\t\t\t\t{{- if and $arg.IsPtr ( notNil \"Value\" $arg ) }}\n\t\t\t\t\t\t\t{{ $arg.GoVarName }} := {{ $arg.Value | dump }}\n\t\t\t\t\t\t{{- end }}\n\t\t\t\t\t{{- end }}\n\t\t\t\t\t{{- end -}}\n\t\t\t\t\t\treturn e.directives.{{$directive.Name|ucFirst}}({{$directive.ResolveArgs \"obj\" \"n\"}})\n\t\t\t\t\t},\n\t\t\t\t{{ end }}\n\t\t\t}...\n\t\t)(ctx, func(ctx context.Context)(interface{}, error){\n\t\t\treturn obj, nil\n\t\t})\n\t\tif err != nil || cObj == nil {\n\t\t\treturn nil ,err\n\t\t}\n\t\tobj, ok := cObj.(*{{.Definition.GoType | ref}})\n\t\tif !ok {\n\t\t\treturn nil, errors.New(\"expect {{.Definition.GoType | ref}}\")\n\t\t}\n\t\t{{ end }}\n\n\t\t{{- range $field := .Fields }}\n\t\t{{ if $field.HasDirectives }}\n\t\t\tc{{$field.GoFieldName}}, err := chainFieldMiddleware(\n\t\t\t\t[]graphql.FieldMiddleware{\n\t\t\t\t\t{{- range $directive := $field.Directives }}\n\t\t\t\t\t\tfunc(ctx context.Context, n graphql.Resolver) (res interface{}, err error) {\n\t\t\t\t\t\t{{- if $directive.Args }}\n\t\t\t\t\t\t{{- range $arg := $directive.Args }}\n\t\t\t\t\t\t\t{{- if and $arg.IsPtr ( notNil \"Value\" $arg ) }}\n\t\t\t\t\t\t\t\t{{ $arg.GoVarName }} := {{ $arg.Value | dump }}\n\t\t\t\t\t\t\t{{- end }}\n\t\t\t\t\t\t{{- end }}\n\t\t\t\t\t\t{{- end }}\n\t\t\t\t\t\t\t{{ if $field.IsPtr -}}\n\t\t\t\t\t\t\t\treturn e.directives.{{$directive.Name|ucFirst}}({{$directive.ResolveArgs ( print \"*obj.\" $field.GoFieldName ) \"n\"}})\n\t\t\t\t\t\t\t{{- else -}}\n\t\t\t\t\t\t\t\treturn e.directives.{{$directive.Name|ucFirst}}({{$directive.ResolveArgs ( print \"obj.\" $field.GoFieldName ) \"n\"}})\n\t\t\t\t\t\t\t{{- end }}\n\t\t\t\t\t\t},\n\t\t\t\t\t{{ end }}\n\t\t\t\t}...\n\t\t\t)(ctx, func(ctx context.Context)(interface{}, error){\n\t\t\t\treturn {{ if $field.IsPtr }}*{{end}}obj.{{$field.GoFieldName}}, nil\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn obj ,err\n\t\t\t}\n\n\t\t\t{{ if $field.IsPtr }}\n\t\t\t\tif data, ok := c{{$field.GoFieldName}}.({{ $field.Definition.GoType | ref }}); ok {\n \t\tobj.{{$field.GoFieldName}} = &data\n \t} else {\n \t\treturn obj, errors.New(\"expect {{ $field.Signature }}\")\n \t}\n\t\t\t{{else}}\n \tif data, ok := c{{$field.GoFieldName}}.({{ $field.Signature }}); ok{\n \t\tobj.{{$field.GoFieldName}} = data\n \t}else{\n \t\treturn obj, errors.New(\"{{$field.GoFieldName}} expect {{$field.Signature }}\")\n \t}\n\t\t\t{{ end }}\n\n\t\t\t{{- end }}\n\n\t\t\t{{ if $field.Definition.IsInput }}\n\t\t\t\t{{ $field.Middleware (print \"obj.\" $field.GoFieldName ) (print \"obj.\" $field.GoFieldName ) }}\n\t\t\t{{- end }}\n\t\t{{- end }}\n\t\treturn obj, nil\n\t}\n", + "input.gotpl": "\t{{- if .Definition.IsMarshaled }}\n\tfunc Unmarshal{{ .Definition.GQLType }}(v interface{}) ({{.Definition.GoType | ref}}, error) {\n\t\tvar it {{.Definition.GoType | ref}}\n\t\tvar asMap = v.(map[string]interface{})\n\t\t{{ range $field := .Fields}}\n\t\t\t{{- if $field.Default}}\n\t\t\t\tif _, present := asMap[{{$field.GQLName|quote}}] ; !present {\n\t\t\t\t\tasMap[{{$field.GQLName|quote}}] = {{ $field.Default | dump }}\n\t\t\t\t}\n\t\t\t{{- end}}\n\t\t{{- end }}\n\n\t\tfor k, v := range asMap {\n\t\t\tswitch k {\n\t\t\t{{- range $field := .Fields }}\n\t\t\tcase {{$field.GQLName|quote}}:\n\t\t\t\tvar err error\n\t\t\t\t{{ $field.Unmarshal (print \"it.\" $field.GoFieldName) \"v\" }}\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn it, err\n\t\t\t\t}\n\t\t\t{{- end }}\n\t\t\t}\n\t\t}\n\n\t\treturn it, nil\n\t}\n\t{{- end }}\n\n\tfunc (e *executableSchema) {{ .Definition.GQLType }}Middleware(ctx context.Context, obj *{{.Definition.GoType | ref}}) (*{{.Definition.GoType | ref}}, error) {\n\t\t\t{{ if .Directives }}\n\t\tcObj, err := chainFieldMiddleware(\n\t\t\t[]graphql.FieldMiddleware{\n\t\t\t\t{{- range $directive := .Directives }}\n\t\t\t\t\tfunc(ctx context.Context, n graphql.Resolver) (res interface{}, err error) {\n\t\t\t\t\t{{- if $directive.Args }}\n\t\t\t\t\t{{- range $arg := $directive.Args }}\n\t\t\t\t\t\t{{- if and $arg.IsPtr ( notNil \"Value\" $arg ) }}\n\t\t\t\t\t\t\t{{ $arg.GoVarName }} := {{ $arg.Value | dump }}\n\t\t\t\t\t\t{{- end }}\n\t\t\t\t\t{{- end }}\n\t\t\t\t\t{{- end -}}\n\t\t\t\t\t\treturn e.directives.{{$directive.Name|ucFirst}}({{$directive.ResolveArgs \"obj\" \"n\"}})\n\t\t\t\t\t},\n\t\t\t\t{{ end }}\n\t\t\t}...\n\t\t)(ctx, func(ctx context.Context)(interface{}, error){\n\t\t\treturn obj, nil\n\t\t})\n\t\tif err != nil || cObj == nil {\n\t\t\treturn nil ,err\n\t\t}\n\t\tobj, ok := cObj.(*{{.Definition.GoType | ref}})\n\t\tif !ok {\n\t\t\treturn nil, errors.New(\"expect {{.Definition.GoType | ref}}\")\n\t\t}\n\t\t{{ end }}\n\n\t\t{{- range $field := .Fields }}\n\t\t{{ if $field.HasDirectives }}\n\t\t\tc{{$field.GoFieldName}}, err := chainFieldMiddleware(\n\t\t\t\t[]graphql.FieldMiddleware{\n\t\t\t\t\t{{- range $directive := $field.Directives }}\n\t\t\t\t\t\tfunc(ctx context.Context, n graphql.Resolver) (res interface{}, err error) {\n\t\t\t\t\t\t{{- if $directive.Args }}\n\t\t\t\t\t\t{{- range $arg := $directive.Args }}\n\t\t\t\t\t\t\t{{- if and $arg.IsPtr ( notNil \"Value\" $arg ) }}\n\t\t\t\t\t\t\t\t{{ $arg.GoVarName }} := {{ $arg.Value | dump }}\n\t\t\t\t\t\t\t{{- end }}\n\t\t\t\t\t\t{{- end }}\n\t\t\t\t\t\t{{- end }}\n\t\t\t\t\t\t\t{{ if $field.IsPtr -}}\n\t\t\t\t\t\t\t\treturn e.directives.{{$directive.Name|ucFirst}}({{$directive.ResolveArgs ( print \"*obj.\" $field.GoFieldName ) \"n\"}})\n\t\t\t\t\t\t\t{{- else -}}\n\t\t\t\t\t\t\t\treturn e.directives.{{$directive.Name|ucFirst}}({{$directive.ResolveArgs ( print \"obj.\" $field.GoFieldName ) \"n\"}})\n\t\t\t\t\t\t\t{{- end }}\n\t\t\t\t\t\t},\n\t\t\t\t\t{{ end }}\n\t\t\t\t}...\n\t\t\t)(ctx, func(ctx context.Context)(interface{}, error){\n\t\t\t\treturn {{ if $field.IsPtr }}*{{end}}obj.{{$field.GoFieldName}}, nil\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn obj ,err\n\t\t\t}\n\n\t\t\t{{ if $field.IsPtr }}\n\t\t\t\tif data, ok := c{{$field.GoFieldName}}.({{ $field.Definition.GoType | ref }}); ok {\n \t\tobj.{{$field.GoFieldName}} = &data\n \t} else {\n \t\treturn obj, errors.New(\"expect {{ $field.GoType | ref }}\")\n \t}\n\t\t\t{{else}}\n \tif data, ok := c{{$field.GoFieldName}}.({{ $field.GoType | ref }}); ok{\n \t\tobj.{{$field.GoFieldName}} = data\n \t}else{\n \t\treturn obj, errors.New(\"{{$field.GoFieldName}} expect {{$field.GoType | ref }}\")\n \t}\n\t\t\t{{ end }}\n\n\t\t\t{{- end }}\n\n\t\t\t{{ if $field.Definition.IsInput }}\n\t\t\t\t{{ $field.Middleware (print \"obj.\" $field.GoFieldName ) (print \"obj.\" $field.GoFieldName ) }}\n\t\t\t{{- end }}\n\t\t{{- end }}\n\t\treturn obj, nil\n\t}\n", "interface.gotpl": "{{- $interface := . }}\n\nfunc (ec *executionContext) _{{$interface.Definition.GQLType}}(ctx context.Context, sel ast.SelectionSet, obj *{{$interface.Definition.GoType | ref}}) graphql.Marshaler {\n\tswitch obj := (*obj).(type) {\n\tcase nil:\n\t\treturn graphql.Null\n\t{{- range $implementor := $interface.Implementors }}\n\t\t{{- if $implementor.ValueReceiver }}\n\t\t\tcase {{$implementor.Definition.GoType | ref}}:\n\t\t\t\treturn ec._{{$implementor.Definition.GQLType}}(ctx, sel, &obj)\n\t\t{{- end}}\n\t\tcase *{{$implementor.Definition.GoType | ref}}:\n\t\t\treturn ec._{{$implementor.Definition.GQLType}}(ctx, sel, obj)\n\t{{- end }}\n\tdefault:\n\t\tpanic(fmt.Errorf(\"unexpected type %T\", obj))\n\t}\n}\n", - "models.gotpl": "// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.\n\npackage {{ .PackageName }}\n\nimport (\n\t%%%IMPORTS%%%\n\n\t{{ reserveImport \"context\" }}\n\t{{ reserveImport \"fmt\" }}\n\t{{ reserveImport \"io\" }}\n\t{{ reserveImport \"strconv\" }}\n\t{{ reserveImport \"time\" }}\n\t{{ reserveImport \"sync\" }}\n\t{{ reserveImport \"errors\" }}\n\t{{ reserveImport \"bytes\" }}\n\n\t{{ reserveImport \"github.com/vektah/gqlparser\" }}\n\t{{ reserveImport \"github.com/vektah/gqlparser/ast\" }}\n\t{{ reserveImport \"github.com/99designs/gqlgen/graphql\" }}\n\t{{ reserveImport \"github.com/99designs/gqlgen/graphql/introspection\" }}\n)\n\n{{ range $model := .Models }}\n\t{{with .Description}} {{.|prefixLines \"// \"}} {{end}}\n\t{{- if .Definition.IsInterface }}\n\t\ttype {{.Definition.GoType | ref }} interface {\n\t\t\tIs{{.Definition.GoType | ref }}()\n\t\t}\n\t{{- else }}\n\t\ttype {{.Definition.GoType | ref }} struct {\n\t\t\t{{- range $field := .Fields }}\n\t\t\t\t{{- with .Description}}\n\t\t\t\t\t{{.|prefixLines \"// \"}}\n\t\t\t\t{{- end}}\n\t\t\t\t{{ $field.GoFieldName }} {{$field.Signature}} `json:\"{{$field.GQLName}}\"`\n\t\t\t{{- end }}\n\t\t}\n\n\t\t{{- range $iface := .Implements }}\n\t\t\tfunc ({{$model.Definition.GoType | ref }}) Is{{$iface.GoType | ref }}() {}\n\t\t{{- end }}\n\n\t{{- end }}\n{{- end}}\n\n{{ range $enum := .Enums }}\n\t{{with .Description}}{{.|prefixLines \"// \"}} {{end}}\n\ttype {{.Definition.GoType | ref }} string\n\tconst (\n\t{{- range $value := .Values}}\n\t\t{{- with .Description}}\n\t\t\t{{.|prefixLines \"// \"}}\n\t\t{{- end}}\n\t\t{{$enum.Definition.GoType | ref }}{{ .Name|toCamel }} {{$enum.Definition.GoType | ref }} = {{.Name|quote}}\n\t{{- end }}\n\t)\n\n\tvar All{{.Definition.GoType | ref }} = []{{.Definition.GoType | ref }}{\n\t{{- range $value := .Values}}\n\t\t{{$enum.Definition.GoType | ref }}{{ .Name|toCamel }},\n\t{{- end }}\n\t}\n\n\tfunc (e {{.Definition.GoType | ref }}) IsValid() bool {\n\t\tswitch e {\n\t\tcase {{ range $index, $element := .Values}}{{if $index}},{{end}}{{ $enum.Definition.GoType | ref }}{{ $element.Name|toCamel }}{{end}}:\n\t\t\treturn true\n\t\t}\n\t\treturn false\n\t}\n\n\tfunc (e {{.Definition.GoType | ref }}) String() string {\n\t\treturn string(e)\n\t}\n\n\tfunc (e *{{.Definition.GoType | ref }}) UnmarshalGQL(v interface{}) error {\n\t\tstr, ok := v.(string)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"enums must be strings\")\n\t\t}\n\n\t\t*e = {{.Definition.GoType | ref }}(str)\n\t\tif !e.IsValid() {\n\t\t\treturn fmt.Errorf(\"%s is not a valid {{.Definition.GQLType}}\", str)\n\t\t}\n\t\treturn nil\n\t}\n\n\tfunc (e {{.Definition.GoType | ref }}) MarshalGQL(w io.Writer) {\n\t\tfmt.Fprint(w, strconv.Quote(e.String()))\n\t}\n\n{{- end }}\n", + "models.gotpl": "// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.\n\npackage {{ .PackageName }}\n\nimport (\n\t%%%IMPORTS%%%\n\n\t{{ reserveImport \"context\" }}\n\t{{ reserveImport \"fmt\" }}\n\t{{ reserveImport \"io\" }}\n\t{{ reserveImport \"strconv\" }}\n\t{{ reserveImport \"time\" }}\n\t{{ reserveImport \"sync\" }}\n\t{{ reserveImport \"errors\" }}\n\t{{ reserveImport \"bytes\" }}\n\n\t{{ reserveImport \"github.com/vektah/gqlparser\" }}\n\t{{ reserveImport \"github.com/vektah/gqlparser/ast\" }}\n\t{{ reserveImport \"github.com/99designs/gqlgen/graphql\" }}\n\t{{ reserveImport \"github.com/99designs/gqlgen/graphql/introspection\" }}\n)\n\n{{ range $model := .Models }}\n\t{{with .Description}} {{.|prefixLines \"// \"}} {{end}}\n\t{{- if .Definition.IsInterface }}\n\t\ttype {{.Definition.GoType | ref }} interface {\n\t\t\tIs{{.Definition.GoType | ref }}()\n\t\t}\n\t{{- else }}\n\t\ttype {{.Definition.GoType | ref }} struct {\n\t\t\t{{- range $field := .Fields }}\n\t\t\t\t{{- with .Description}}\n\t\t\t\t\t{{.|prefixLines \"// \"}}\n\t\t\t\t{{- end}}\n\t\t\t\t{{ $field.GoFieldName }} {{$field.GoType | ref}} `json:\"{{$field.GQLName}}\"`\n\t\t\t{{- end }}\n\t\t}\n\n\t\t{{- range $iface := .Implements }}\n\t\t\tfunc ({{$model.Definition.GoType | ref }}) Is{{$iface.GoType | ref }}() {}\n\t\t{{- end }}\n\n\t{{- end }}\n{{- end}}\n\n{{ range $enum := .Enums }}\n\t{{with .Description}}{{.|prefixLines \"// \"}} {{end}}\n\ttype {{.Definition.GoType | ref }} string\n\tconst (\n\t{{- range $value := .Values}}\n\t\t{{- with .Description}}\n\t\t\t{{.|prefixLines \"// \"}}\n\t\t{{- end}}\n\t\t{{$enum.Definition.GoType | ref }}{{ .Name|toCamel }} {{$enum.Definition.GoType | ref }} = {{.Name|quote}}\n\t{{- end }}\n\t)\n\n\tvar All{{.Definition.GoType | ref }} = []{{.Definition.GoType | ref }}{\n\t{{- range $value := .Values}}\n\t\t{{$enum.Definition.GoType | ref }}{{ .Name|toCamel }},\n\t{{- end }}\n\t}\n\n\tfunc (e {{.Definition.GoType | ref }}) IsValid() bool {\n\t\tswitch e {\n\t\tcase {{ range $index, $element := .Values}}{{if $index}},{{end}}{{ $enum.Definition.GoType | ref }}{{ $element.Name|toCamel }}{{end}}:\n\t\t\treturn true\n\t\t}\n\t\treturn false\n\t}\n\n\tfunc (e {{.Definition.GoType | ref }}) String() string {\n\t\treturn string(e)\n\t}\n\n\tfunc (e *{{.Definition.GoType | ref }}) UnmarshalGQL(v interface{}) error {\n\t\tstr, ok := v.(string)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"enums must be strings\")\n\t\t}\n\n\t\t*e = {{.Definition.GoType | ref }}(str)\n\t\tif !e.IsValid() {\n\t\t\treturn fmt.Errorf(\"%s is not a valid {{.Definition.GQLType}}\", str)\n\t\t}\n\t\treturn nil\n\t}\n\n\tfunc (e {{.Definition.GoType | ref }}) MarshalGQL(w io.Writer) {\n\t\tfmt.Fprint(w, strconv.Quote(e.String()))\n\t}\n\n{{- end }}\n", "object.gotpl": "{{ $object := . }}\n\nvar {{ $object.Definition.GQLType|lcFirst}}Implementors = {{$object.Implementors}}\n\n// nolint: gocyclo, errcheck, gas, goconst\n{{- if .Stream }}\nfunc (ec *executionContext) _{{$object.Definition.GQLType}}(ctx context.Context, sel ast.SelectionSet) func() graphql.Marshaler {\n\tfields := graphql.CollectFields(ctx, sel, {{$object.Definition.GQLType|lcFirst}}Implementors)\n\tctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{\n\t\tObject: {{$object.Definition.GQLType|quote}},\n\t})\n\tif len(fields) != 1 {\n\t\tec.Errorf(ctx, \"must subscribe to exactly one stream\")\n\t\treturn nil\n\t}\n\n\tswitch fields[0].Name {\n\t{{- range $field := $object.Fields }}\n\tcase \"{{$field.GQLName}}\":\n\t\treturn ec._{{$object.Definition.GQLType}}_{{$field.GQLName}}(ctx, fields[0])\n\t{{- end }}\n\tdefault:\n\t\tpanic(\"unknown field \" + strconv.Quote(fields[0].Name))\n\t}\n}\n{{- else }}\nfunc (ec *executionContext) _{{$object.Definition.GQLType}}(ctx context.Context, sel ast.SelectionSet{{if not $object.Root}}, obj *{{$object.Definition.GoType | ref }} {{end}}) graphql.Marshaler {\n\tfields := graphql.CollectFields(ctx, sel, {{$object.Definition.GQLType|lcFirst}}Implementors)\n\t{{if $object.Root}}\n\t\tctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{\n\t\t\tObject: {{$object.Definition.GQLType|quote}},\n\t\t})\n\t{{end}}\n\n\tout := graphql.NewFieldSet(fields)\n\tinvalid := false\n\tfor i, field := range fields {\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString({{$object.Definition.GQLType|quote}})\n\t\t{{- range $field := $object.Fields }}\n\t\tcase \"{{$field.GQLName}}\":\n\t\t\t{{- if $field.IsConcurrent }}\n\t\t\t\tfield := field\n\t\t\t\tout.Concurrently(i, func() (res graphql.Marshaler) {\n\t\t\t\t\tres = ec._{{$object.Definition.GQLType}}_{{$field.GQLName}}(ctx, field{{if not $object.Root}}, obj{{end}})\n\t\t\t\t\t{{- if $field.ASTType.NonNull }}\n\t\t\t\t\t\tif res == graphql.Null {\n\t\t\t\t\t\t\tinvalid = true\n\t\t\t\t\t\t}\n\t\t\t\t\t{{- end }}\n\t\t\t\t\treturn res\n\t\t\t\t})\n\t\t\t{{- else }}\n\t\t\t\tout.Values[i] = ec._{{$object.Definition.GQLType}}_{{$field.GQLName}}(ctx, field{{if not $object.Root}}, obj{{end}})\n\t\t\t\t{{- if $field.ASTType.NonNull }}\n\t\t\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\t\t\tinvalid = true\n\t\t\t\t\t}\n\t\t\t\t{{- end }}\n\t\t\t{{- end }}\n\t\t{{- end }}\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\tout.Dispatch()\n\tif invalid { return graphql.Null }\n\treturn out\n}\n{{- end }}\n", "resolver.gotpl": "package {{ .PackageName }}\n\nimport (\n\t%%%IMPORTS%%%\n\n\t{{ reserveImport \"context\" }}\n\t{{ reserveImport \"fmt\" }}\n\t{{ reserveImport \"io\" }}\n\t{{ reserveImport \"strconv\" }}\n\t{{ reserveImport \"time\" }}\n\t{{ reserveImport \"sync\" }}\n\t{{ reserveImport \"errors\" }}\n\t{{ reserveImport \"bytes\" }}\n\n\t{{ reserveImport \"github.com/99designs/gqlgen/handler\" }}\n\t{{ reserveImport \"github.com/vektah/gqlparser\" }}\n\t{{ reserveImport \"github.com/vektah/gqlparser/ast\" }}\n\t{{ reserveImport \"github.com/99designs/gqlgen/graphql\" }}\n\t{{ reserveImport \"github.com/99designs/gqlgen/graphql/introspection\" }}\n)\n\ntype {{.ResolverType}} struct {}\n\n{{ range $object := .Objects -}}\n\t{{- if $object.HasResolvers -}}\n\t\tfunc (r *{{$.ResolverType}}) {{$object.Definition.GQLType}}() {{ $object.ResolverInterface | ref }} {\n\t\t\treturn &{{lcFirst $object.Definition.GQLType}}Resolver{r}\n\t\t}\n\t{{ end -}}\n{{ end }}\n\n{{ range $object := .Objects -}}\n\t{{- if $object.HasResolvers -}}\n\t\ttype {{lcFirst $object.Definition.GQLType}}Resolver struct { *Resolver }\n\n\t\t{{ range $field := $object.Fields -}}\n\t\t\t{{- if $field.IsResolver -}}\n\t\t\tfunc (r *{{lcFirst $object.Definition.GQLType}}Resolver) {{ $field.ShortResolverDeclaration }} {\n\t\t\t\tpanic(\"not implemented\")\n\t\t\t}\n\t\t\t{{ end -}}\n\t\t{{ end -}}\n\t{{ end -}}\n{{ end }}\n", "server.gotpl": "package main\n\nimport (\n\t%%%IMPORTS%%%\n\n\t{{ reserveImport \"context\" }}\n\t{{ reserveImport \"log\" }}\n\t{{ reserveImport \"net/http\" }}\n\t{{ reserveImport \"os\" }}\n\t{{ reserveImport \"github.com/99designs/gqlgen/handler\" }}\n)\n\nconst defaultPort = \"8080\"\n\nfunc main() {\n\tport := os.Getenv(\"PORT\")\n\tif port == \"\" {\n\t\tport = defaultPort\n\t}\n\n\thttp.Handle(\"/\", handler.Playground(\"GraphQL playground\", \"/query\"))\n\thttp.Handle(\"/query\", handler.GraphQL({{ lookupImport .ExecPackageName }}.NewExecutableSchema({{ lookupImport .ExecPackageName}}.Config{Resolvers: &{{ lookupImport .ResolverPackageName}}.Resolver{}})))\n\n\tlog.Printf(\"connect to http://localhost:%s/ for GraphQL playground\", port)\n\tlog.Fatal(http.ListenAndServe(\":\" + port, nil))\n}\n", diff --git a/codegen/templates/field.gotpl b/codegen/templates/field.gotpl index 2c1f89aa35..5a678cba42 100644 --- a/codegen/templates/field.gotpl +++ b/codegen/templates/field.gotpl @@ -82,7 +82,7 @@ {{- end }} return graphql.Null } - res := resTmp.({{$field.Signature}}) + res := resTmp.({{$field.GoType | ref}}) rctx.Result = res ctx = ec.Tracer.StartFieldChildExecution(ctx) {{ $field.WriteJson }} diff --git a/codegen/templates/input.gotpl b/codegen/templates/input.gotpl index 6b9167ec74..6e98739be0 100644 --- a/codegen/templates/input.gotpl +++ b/codegen/templates/input.gotpl @@ -88,13 +88,13 @@ if data, ok := c{{$field.GoFieldName}}.({{ $field.Definition.GoType | ref }}); ok { obj.{{$field.GoFieldName}} = &data } else { - return obj, errors.New("expect {{ $field.Signature }}") + return obj, errors.New("expect {{ $field.GoType | ref }}") } {{else}} - if data, ok := c{{$field.GoFieldName}}.({{ $field.Signature }}); ok{ + if data, ok := c{{$field.GoFieldName}}.({{ $field.GoType | ref }}); ok{ obj.{{$field.GoFieldName}} = data }else{ - return obj, errors.New("{{$field.GoFieldName}} expect {{$field.Signature }}") + return obj, errors.New("{{$field.GoFieldName}} expect {{$field.GoType | ref }}") } {{ end }} diff --git a/codegen/templates/models.gotpl b/codegen/templates/models.gotpl index 606f732e31..b00b84ab13 100644 --- a/codegen/templates/models.gotpl +++ b/codegen/templates/models.gotpl @@ -32,7 +32,7 @@ import ( {{- with .Description}} {{.|prefixLines "// "}} {{- end}} - {{ $field.GoFieldName }} {{$field.Signature}} `json:"{{$field.GQLName}}"` + {{ $field.GoFieldName }} {{$field.GoType | ref}} `json:"{{$field.GQLName}}"` {{- end }} } diff --git a/codegen/testserver/generated.go b/codegen/testserver/generated.go index f74b893383..c017307773 100644 --- a/codegen/testserver/generated.go +++ b/codegen/testserver/generated.go @@ -144,7 +144,7 @@ type QueryResolver interface { NestedInputs(ctx context.Context, input [][]*OuterInput) (*bool, error) NestedOutputs(ctx context.Context) ([][]*OuterObject, error) Keywords(ctx context.Context, input *Keywords) (bool, error) - Shapes(ctx context.Context) ([]*Shape, error) + Shapes(ctx context.Context) ([]Shape, error) ErrorBubble(ctx context.Context) (*Error, error) ModelMethods(ctx context.Context) (*ModelMethods, error) Valid(ctx context.Context) (string, error) @@ -2317,7 +2317,7 @@ func (ec *executionContext) _Query_nestedOutputs(ctx context.Context, field grap idx1 := idx1 rctx := &graphql.ResolverContext{ Index: &idx1, - Result: res[idx1], + Result: &res[idx1], } ctx := graphql.WithResolverContext(ctx, rctx) f := func(idx1 int) { @@ -2427,7 +2427,7 @@ func (ec *executionContext) _Query_shapes(ctx context.Context, field graphql.Col if resTmp == nil { return graphql.Null } - res := resTmp.([]*Shape) + res := resTmp.([]Shape) rctx.Result = res ctx = ec.Tracer.StartFieldChildExecution(ctx) @@ -2443,7 +2443,7 @@ func (ec *executionContext) _Query_shapes(ctx context.Context, field graphql.Col idx1 := idx1 rctx := &graphql.ResolverContext{ Index: &idx1, - Result: res[idx1], + Result: &res[idx1], } ctx := graphql.WithResolverContext(ctx, rctx) f := func(idx1 int) { @@ -2452,11 +2452,7 @@ func (ec *executionContext) _Query_shapes(ctx context.Context, field graphql.Col } arr1[idx1] = func() graphql.Marshaler { - if res[idx1] == nil { - return graphql.Null - } - - return ec._Shape(ctx, field.Selections, res[idx1]) + return ec._Shape(ctx, field.Selections, &res[idx1]) }() } if isLen1 { diff --git a/codegen/testserver/resolver.go b/codegen/testserver/resolver.go index e48a0354ac..99f5e3b860 100644 --- a/codegen/testserver/resolver.go +++ b/codegen/testserver/resolver.go @@ -60,7 +60,7 @@ func (r *queryResolver) NestedOutputs(ctx context.Context) ([][]*OuterObject, er func (r *queryResolver) Keywords(ctx context.Context, input *Keywords) (bool, error) { panic("not implemented") } -func (r *queryResolver) Shapes(ctx context.Context) ([]*Shape, error) { +func (r *queryResolver) Shapes(ctx context.Context) ([]Shape, error) { panic("not implemented") } func (r *queryResolver) ErrorBubble(ctx context.Context) (*Error, error) { diff --git a/codegen/type_build.go b/codegen/type_build.go index bb6f2aa8f7..f384c8fe28 100644 --- a/codegen/type_build.go +++ b/codegen/type_build.go @@ -28,7 +28,7 @@ func (g *Generator) buildNamedTypes(prog *loader.Program) (NamedTypes, error) { } pkgName, typeName = pkgAndType(userEntry.Model) - } else if t.IsScalar { + } else if t.IsScalar && schemaType.Kind != ast.Enum { pkgName = "github.com/99designs/gqlgen/graphql" typeName = "String" } else { diff --git a/codegen/type_definition.go b/codegen/type_definition.go index f7f68c41a7..20b5353c21 100644 --- a/codegen/type_definition.go +++ b/codegen/type_definition.go @@ -20,11 +20,6 @@ type TypeDefinition struct { Unmarshaler *types.Func // When using external marshalling functions this will point to the Unmarshal function } -const ( - modList = "[]" - modPtr = "*" -) - func (t TypeDefinition) IsMarshaled() bool { return t.Marshaler != nil || t.Unmarshaler != nil } @@ -34,31 +29,28 @@ func (t TypeDefinition) IsEmptyInterface() bool { return isInterface && i.NumMethods() == 0 } -func (n NamedTypes) getType(t *ast.Type) *TypeReference { - orig := t - var modifiers []string - for { - if t.Elem != nil { - modifiers = append(modifiers, modList) - t = t.Elem - } else { - if !t.NonNull { - modifiers = append(modifiers, modPtr) - } - if n[t.NamedType] == nil { - panic("missing type " + t.NamedType) - } - res := &TypeReference{ - Definition: n[t.NamedType], - Modifiers: modifiers, - ASTType: orig, - } +func (n NamedTypes) goTypeForAst(t *ast.Type) types.Type { + if t.Elem != nil { + return types.NewSlice(n.goTypeForAst(t.Elem)) + } + + nt := n[t.NamedType] + gt := nt.GoType + if gt == nil { + panic("missing type " + t.NamedType) + } - if res.Definition.IsInterface { - res.StripPtr() - } + if !t.NonNull && !nt.IsInterface { + return types.NewPointer(gt) + } - return res - } + return gt +} + +func (n NamedTypes) getType(t *ast.Type) *TypeReference { + return &TypeReference{ + Definition: n[t.Name()], + GoType: n.goTypeForAst(t), + ASTType: t, } } diff --git a/codegen/type_reference.go b/codegen/type_reference.go index c8a9eb1183..1a2aaf48fb 100644 --- a/codegen/type_reference.go +++ b/codegen/type_reference.go @@ -3,7 +3,6 @@ package codegen import ( "go/types" "strconv" - "strings" "github.com/99designs/gqlgen/codegen/templates" "github.com/vektah/gqlparser/ast" @@ -13,57 +12,39 @@ import ( type TypeReference struct { Definition *TypeDefinition - Modifiers []string - ASTType *ast.Type -} - -func (t TypeReference) Signature() string { - return strings.Join(t.Modifiers, "") + templates.CurrentImports.LookupType(t.Definition.GoType) -} - -func (t TypeReference) FullSignature() string { - return strings.Join(t.Modifiers, "") + types.TypeString(t.Definition.GoType, nil) + GoType types.Type + ASTType *ast.Type } +// todo @vektah: This should probably go away, its too easy to conflate gql required vs go pointer func (t TypeReference) IsPtr() bool { - return len(t.Modifiers) > 0 && t.Modifiers[0] == modPtr -} - -func (t *TypeReference) StripPtr() { - if !t.IsPtr() { - return - } - t.Modifiers = t.Modifiers[0 : len(t.Modifiers)-1] -} - -func (t TypeReference) IsSlice() bool { - return len(t.Modifiers) > 0 && t.Modifiers[0] == modList || - len(t.Modifiers) > 1 && t.Modifiers[0] == modPtr && t.Modifiers[1] == modList + _, isPtr := t.GoType.(*types.Pointer) + return isPtr } func (t TypeReference) Unmarshal(result, raw string) string { - return t.unmarshal(result, raw, t.Modifiers, 1) + return t.unmarshal(result, raw, t.GoType, 1) } -func (t TypeReference) unmarshal(result, raw string, remainingMods []string, depth int) string { - switch { - case len(remainingMods) > 0 && remainingMods[0] == modPtr: +func (t TypeReference) unmarshal(result, raw string, destType types.Type, depth int) string { + switch destType := destType.(type) { + case *types.Pointer: ptr := "ptr" + strconv.Itoa(depth) - return tpl(`var {{.ptr}} {{.mods}}{{.t.Definition.GoType | ref }} + return tpl(`var {{.ptr}} {{.destType | ref }} if {{.raw}} != nil { {{.next}} {{.result}} = &{{.ptr -}} } `, map[string]interface{}{ - "ptr": ptr, - "t": t, - "raw": raw, - "result": result, - "mods": strings.Join(remainingMods[1:], ""), - "next": t.unmarshal(ptr, raw, remainingMods[1:], depth+1), + "ptr": ptr, + "t": t, + "raw": raw, + "result": result, + "destType": destType.Elem(), + "next": t.unmarshal(ptr, raw, destType.Elem(), depth+1), }) - case len(remainingMods) > 0 && remainingMods[0] == modList: + case *types.Slice: var rawIf = "rawIf" + strconv.Itoa(depth) var index = "idx" + strconv.Itoa(depth) @@ -75,7 +56,7 @@ func (t TypeReference) unmarshal(result, raw string, remainingMods []string, dep {{.rawSlice}} = []interface{}{ {{.raw}} } } } - {{.result}} = make({{.type}}, len({{.rawSlice}})) + {{.result}} = make({{.destType | ref}}, len({{.rawSlice}})) for {{.index}} := range {{.rawSlice}} { {{ .next -}} }`, map[string]interface{}{ @@ -83,8 +64,8 @@ func (t TypeReference) unmarshal(result, raw string, remainingMods []string, dep "rawSlice": rawIf, "index": index, "result": result, - "type": strings.Join(remainingMods, "") + templates.CurrentImports.LookupType(t.Definition.GoType), - "next": t.unmarshal(result+"["+index+"]", rawIf+"["+index+"]", remainingMods[1:], depth+1), + "destType": destType, + "next": t.unmarshal(result+"["+index+"]", rawIf+"["+index+"]", destType.Elem(), depth+1), }) } @@ -106,12 +87,24 @@ func (t TypeReference) unmarshal(result, raw string, remainingMods []string, dep } func (t TypeReference) Middleware(result, raw string) string { - return t.middleware(result, raw, t.Modifiers, 1) + return t.middleware(result, raw, t.GoType, 1) } -func (t TypeReference) middleware(result, raw string, remainingMods []string, depth int) string { - if len(remainingMods) == 1 && remainingMods[0] == modPtr { - return tpl(` +func (t TypeReference) middleware(result, raw string, destType types.Type, depth int) string { + switch destType := destType.(type) { + case *types.Pointer: + switch destType.Elem().(type) { + case *types.Pointer, *types.Slice: + return tpl(`if {{.raw}} != nil { + {{.next}} + }`, map[string]interface{}{ + "t": t, + "raw": raw, + "result": result, + "next": t.middleware(result, raw, destType.Elem(), depth+1), + }) + default: + return tpl(` if {{.raw}} != nil { var err error {{.result}}, err = e.{{ .t.Definition.GQLType }}Middleware(ctx, {{.raw}}) @@ -119,24 +112,13 @@ func (t TypeReference) middleware(result, raw string, remainingMods []string, de return nil, err } }`, map[string]interface{}{ - "result": result, - "raw": raw, - "t": t, - }) - } - switch { - case len(remainingMods) > 0 && remainingMods[0] == modPtr: - return tpl(`if {{.raw}} != nil { - {{.next}} - }`, map[string]interface{}{ - "t": t, - "raw": raw, - "result": result, - "mods": strings.Join(remainingMods[1:], ""), - "next": t.middleware(result, raw, remainingMods[1:], depth+1), - }) + "result": result, + "raw": raw, + "t": t, + }) + } - case len(remainingMods) > 0 && remainingMods[0] == modList: + case *types.Slice: var index = "idx" + strconv.Itoa(depth) return tpl(`for {{.index}} := range {{.raw}} { @@ -145,8 +127,7 @@ func (t TypeReference) middleware(result, raw string, remainingMods []string, de "raw": raw, "index": index, "result": result, - "type": strings.Join(remainingMods, "") + templates.CurrentImports.LookupType(t.Definition.GoType), - "next": t.middleware(result+"["+index+"]", raw+"["+index+"]", remainingMods[1:], depth+1), + "next": t.middleware(result+"["+index+"]", raw+"["+index+"]", destType.Elem(), depth+1), }) } diff --git a/codegen/util.go b/codegen/util.go index 2c91b45ccb..0b72abada3 100644 --- a/codegen/util.go +++ b/codegen/util.go @@ -319,7 +319,7 @@ nextArg: for _, oldArg := range field.Args { if strings.EqualFold(oldArg.GQLName, param.Name()) { if !field.ForceResolver { - oldArg.TypeReference.Modifiers = modifiersFromGoType(param.Type()) + oldArg.TypeReference.GoType = param.Type() } newArgs = append(newArgs, oldArg) continue nextArg @@ -333,36 +333,17 @@ nextArg: } func validateTypeBinding(field *Field, goType types.Type) error { - gqlType := normalizeVendor(field.TypeReference.FullSignature()) + gqlType := normalizeVendor(field.TypeReference.GoType.String()) goTypeStr := normalizeVendor(goType.String()) if equalTypes(goTypeStr, gqlType) { - field.TypeReference.Modifiers = modifiersFromGoType(goType) + field.TypeReference.GoType = goType return nil } return fmt.Errorf("%s is not compatible with %s", gqlType, goTypeStr) } -func modifiersFromGoType(t types.Type) []string { - var modifiers []string - for { - switch val := t.(type) { - case *types.Pointer: - modifiers = append(modifiers, modPtr) - t = val.Elem() - case *types.Array: - modifiers = append(modifiers, modList) - t = val.Elem() - case *types.Slice: - modifiers = append(modifiers, modList) - t = val.Elem() - default: - return modifiers - } - } -} - var modsRegex = regexp.MustCompile(`^(\*|\[\])*`) func normalizeVendor(pkg string) string { diff --git a/example/dataloader/generated.go b/example/dataloader/generated.go index 5abb745658..046d597b4c 100644 --- a/example/dataloader/generated.go +++ b/example/dataloader/generated.go @@ -1106,7 +1106,7 @@ func (ec *executionContext) _Query_torture2d(ctx context.Context, field graphql. idx1 := idx1 rctx := &graphql.ResolverContext{ Index: &idx1, - Result: res[idx1], + Result: &res[idx1], } ctx := graphql.WithResolverContext(ctx, rctx) f := func(idx1 int) {