diff --git a/codegen/config/binder.go b/codegen/config/binder.go index 51f23ede21..2835f49400 100644 --- a/codegen/config/binder.go +++ b/codegen/config/binder.go @@ -252,6 +252,14 @@ func (t *TypeReference) IsPtrToSlice() bool { return false } +func (t *TypeReference) IsPtrToIntf() bool { + if t.IsPtr() { + _, isPointerToInterface := t.GO.(*types.Pointer).Elem().(*types.Interface) + return isPointerToInterface + } + return false +} + func (t *TypeReference) IsNamed() bool { _, isSlice := t.GO.(*types.Named) return isSlice diff --git a/codegen/testserver/followschema/ptr_to_any.generated.go b/codegen/testserver/followschema/ptr_to_any.generated.go new file mode 100644 index 0000000000..10674b344f --- /dev/null +++ b/codegen/testserver/followschema/ptr_to_any.generated.go @@ -0,0 +1,199 @@ +// Code generated by github.com/99designs/gqlgen, DO NOT EDIT. + +package followschema + +import ( + "context" + "errors" + "strconv" + + "github.com/99designs/gqlgen/graphql" + "github.com/vektah/gqlparser/v2/ast" +) + +// region ************************** generated!.gotpl ************************** + +// endregion ************************** generated!.gotpl ************************** + +// region ***************************** args.gotpl ***************************** + +// endregion ***************************** args.gotpl ***************************** + +// region ************************** directives.gotpl ************************** + +// endregion ************************** directives.gotpl ************************** + +// region **************************** field.gotpl ***************************** + +func (ec *executionContext) _PtrToAnyContainer_ptrToAny(ctx context.Context, field graphql.CollectedField, obj *PtrToAnyContainer) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_PtrToAnyContainer_ptrToAny(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.PtrToAny, nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*any) + fc.Result = res + return ec.marshalOAny2ᚖinterface(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_PtrToAnyContainer_ptrToAny(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "PtrToAnyContainer", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Any does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _PtrToAnyContainer_binding(ctx context.Context, field graphql.CollectedField, obj *PtrToAnyContainer) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_PtrToAnyContainer_binding(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.Binding(), nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*any) + fc.Result = res + return ec.marshalOAny2ᚖinterface(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_PtrToAnyContainer_binding(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "PtrToAnyContainer", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Any does not have child fields") + }, + } + return fc, nil +} + +// endregion **************************** field.gotpl ***************************** + +// region **************************** input.gotpl ***************************** + +// endregion **************************** input.gotpl ***************************** + +// region ************************** interface.gotpl *************************** + +// endregion ************************** interface.gotpl *************************** + +// region **************************** object.gotpl **************************** + +var ptrToAnyContainerImplementors = []string{"PtrToAnyContainer"} + +func (ec *executionContext) _PtrToAnyContainer(ctx context.Context, sel ast.SelectionSet, obj *PtrToAnyContainer) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, ptrToAnyContainerImplementors) + + 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("PtrToAnyContainer") + case "ptrToAny": + out.Values[i] = ec._PtrToAnyContainer_ptrToAny(ctx, field, obj) + case "binding": + out.Values[i] = ec._PtrToAnyContainer_binding(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + // assign deferred groups to main executionContext + for label, dfs := range deferred { + ec.deferredGroups = append(ec.deferredGroups, graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +// endregion **************************** object.gotpl **************************** + +// region ***************************** type.gotpl ***************************** + +func (ec *executionContext) marshalNPtrToAnyContainer2githubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋfollowschemaᚐPtrToAnyContainer(ctx context.Context, sel ast.SelectionSet, v PtrToAnyContainer) graphql.Marshaler { + return ec._PtrToAnyContainer(ctx, sel, &v) +} + +func (ec *executionContext) marshalNPtrToAnyContainer2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋfollowschemaᚐPtrToAnyContainer(ctx context.Context, sel ast.SelectionSet, v *PtrToAnyContainer) 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._PtrToAnyContainer(ctx, sel, v) +} + +func (ec *executionContext) unmarshalOAny2interface(ctx context.Context, v interface{}) (any, error) { + if v == nil { + return nil, nil + } + res, err := graphql.UnmarshalAny(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOAny2interface(ctx context.Context, sel ast.SelectionSet, v any) graphql.Marshaler { + if v == nil { + return graphql.Null + } + res := graphql.MarshalAny(v) + return res +} + +func (ec *executionContext) unmarshalOAny2ᚖinterface(ctx context.Context, v interface{}) (*any, error) { + if v == nil { + return nil, nil + } + res, err := ec.unmarshalOAny2interface(ctx, v) + return &res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOAny2ᚖinterface(ctx context.Context, sel ast.SelectionSet, v *any) graphql.Marshaler { + return ec.marshalOAny2interface(ctx, sel, *v) +} + +// endregion ***************************** type.gotpl ***************************** diff --git a/codegen/testserver/followschema/ptr_to_any.go b/codegen/testserver/followschema/ptr_to_any.go new file mode 100644 index 0000000000..655fcb69da --- /dev/null +++ b/codegen/testserver/followschema/ptr_to_any.go @@ -0,0 +1,9 @@ +package followschema + +type PtrToAnyContainer struct { + PtrToAny *any +} + +func (c *PtrToAnyContainer) Binding() *any { + return c.PtrToAny +} diff --git a/codegen/testserver/followschema/ptr_to_any.graphql b/codegen/testserver/followschema/ptr_to_any.graphql new file mode 100644 index 0000000000..c86bf38f83 --- /dev/null +++ b/codegen/testserver/followschema/ptr_to_any.graphql @@ -0,0 +1,10 @@ +scalar Any + +type PtrToAnyContainer { + ptrToAny: Any + binding: Any +} + +extend type Query { + ptrToAnyContainer: PtrToAnyContainer! +} diff --git a/codegen/testserver/followschema/ptr_to_any_test.go b/codegen/testserver/followschema/ptr_to_any_test.go new file mode 100644 index 0000000000..c1e78b8d80 --- /dev/null +++ b/codegen/testserver/followschema/ptr_to_any_test.go @@ -0,0 +1,37 @@ +package followschema + +import ( + "context" + "testing" + + "github.com/99designs/gqlgen/client" + "github.com/99designs/gqlgen/graphql/handler" + "github.com/stretchr/testify/require" +) + +func TestPtrToAny(t *testing.T) { + resolvers := &Stub{} + + c := client.New(handler.NewDefaultServer(NewExecutableSchema(Config{Resolvers: resolvers}))) + + var a any = `{"some":"thing"}` + resolvers.QueryResolver.PtrToAnyContainer = func(ctx context.Context) (wrappedStruct *PtrToAnyContainer, e error) { + ptrToAnyContainer := PtrToAnyContainer{ + PtrToAny: &a, + } + return &ptrToAnyContainer, nil + } + + t.Run("binding to pointer to any", func(t *testing.T) { + var resp struct { + PtrToAnyContainer struct { + Binding *any + } + } + + err := c.Post(`query { ptrToAnyContainer { binding }}`, &resp) + require.NoError(t, err) + + require.Equal(t, &a, resp.PtrToAnyContainer.Binding) + }) +} diff --git a/codegen/testserver/followschema/resolver.go b/codegen/testserver/followschema/resolver.go index 7efd695ec8..9da9ba5702 100644 --- a/codegen/testserver/followschema/resolver.go +++ b/codegen/testserver/followschema/resolver.go @@ -362,6 +362,11 @@ func (r *queryResolver) PrimitiveStringObject(ctx context.Context) ([]PrimitiveS panic("not implemented") } +// PtrToAnyContainer is the resolver for the ptrToAnyContainer field. +func (r *queryResolver) PtrToAnyContainer(ctx context.Context) (*PtrToAnyContainer, error) { + panic("not implemented") +} + // PtrToSliceContainer is the resolver for the ptrToSliceContainer field. func (r *queryResolver) PtrToSliceContainer(ctx context.Context) (*PtrToSliceContainer, error) { panic("not implemented") diff --git a/codegen/testserver/followschema/root_.generated.go b/codegen/testserver/followschema/root_.generated.go index 8fa0670fb2..8ed39c2e3c 100644 --- a/codegen/testserver/followschema/root_.generated.go +++ b/codegen/testserver/followschema/root_.generated.go @@ -276,6 +276,11 @@ type ComplexityRoot struct { Value func(childComplexity int) int } + PtrToAnyContainer struct { + Binding func(childComplexity int) int + PtrToAny func(childComplexity int) int + } + PtrToPtrInner struct { Key func(childComplexity int) int Value func(childComplexity int) int @@ -342,6 +347,7 @@ type ComplexityRoot struct { Panics func(childComplexity int) int PrimitiveObject func(childComplexity int) int PrimitiveStringObject func(childComplexity int) int + PtrToAnyContainer func(childComplexity int) int PtrToSliceContainer func(childComplexity int) int Recursive func(childComplexity int, input *RecursiveInputSlice) int ScalarSlice func(childComplexity int) int @@ -1080,6 +1086,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.PrimitiveString.Value(childComplexity), true + case "PtrToAnyContainer.binding": + if e.complexity.PtrToAnyContainer.Binding == nil { + break + } + + return e.complexity.PtrToAnyContainer.Binding(childComplexity), true + + case "PtrToAnyContainer.ptrToAny": + if e.complexity.PtrToAnyContainer.PtrToAny == nil { + break + } + + return e.complexity.PtrToAnyContainer.PtrToAny(childComplexity), true + case "PtrToPtrInner.key": if e.complexity.PtrToPtrInner.Key == nil { break @@ -1562,6 +1582,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Query.PrimitiveStringObject(childComplexity), true + case "Query.ptrToAnyContainer": + if e.complexity.Query.PtrToAnyContainer == nil { + break + } + + return e.complexity.Query.PtrToAnyContainer(childComplexity), true + case "Query.ptrToSliceContainer": if e.complexity.Query.PtrToSliceContainer == nil { break @@ -2139,7 +2166,7 @@ func (ec *executionContext) introspectType(name string) (*introspection.Type, er return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil } -//go:embed "builtinscalar.graphql" "complexity.graphql" "defaults.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_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" +//go:embed "builtinscalar.graphql" "complexity.graphql" "defaults.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" var sourcesFS embed.FS func sourceData(filename string) string { @@ -2166,6 +2193,7 @@ var sources = []*ast.Source{ {Name: "nulls.graphql", Input: sourceData("nulls.graphql"), BuiltIn: false}, {Name: "panics.graphql", Input: sourceData("panics.graphql"), BuiltIn: false}, {Name: "primitive_objects.graphql", Input: sourceData("primitive_objects.graphql"), BuiltIn: false}, + {Name: "ptr_to_any.graphql", Input: sourceData("ptr_to_any.graphql"), BuiltIn: false}, {Name: "ptr_to_ptr_input.graphql", Input: sourceData("ptr_to_ptr_input.graphql"), BuiltIn: false}, {Name: "ptr_to_slice.graphql", Input: sourceData("ptr_to_slice.graphql"), BuiltIn: false}, {Name: "scalar_context.graphql", Input: sourceData("scalar_context.graphql"), BuiltIn: false}, diff --git a/codegen/testserver/followschema/schema.generated.go b/codegen/testserver/followschema/schema.generated.go index cfbf138c4f..d98ed39a91 100644 --- a/codegen/testserver/followschema/schema.generated.go +++ b/codegen/testserver/followschema/schema.generated.go @@ -83,6 +83,7 @@ type QueryResolver interface { Panics(ctx context.Context) (*Panics, error) PrimitiveObject(ctx context.Context) ([]Primitive, error) PrimitiveStringObject(ctx context.Context) ([]PrimitiveString, error) + PtrToAnyContainer(ctx context.Context) (*PtrToAnyContainer, error) PtrToSliceContainer(ctx context.Context) (*PtrToSliceContainer, error) Infinity(ctx context.Context) (float64, error) StringFromContextInterface(ctx context.Context) (*StringFromContextInterface, error) @@ -4006,6 +4007,53 @@ func (ec *executionContext) fieldContext_Query_primitiveStringObject(ctx context return fc, nil } +func (ec *executionContext) _Query_ptrToAnyContainer(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_ptrToAnyContainer(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, nil, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().PtrToAnyContainer(rctx) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*PtrToAnyContainer) + fc.Result = res + return ec.marshalNPtrToAnyContainer2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋfollowschemaᚐPtrToAnyContainer(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_ptrToAnyContainer(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 "ptrToAny": + return ec.fieldContext_PtrToAnyContainer_ptrToAny(ctx, field) + case "binding": + return ec.fieldContext_PtrToAnyContainer_binding(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type PtrToAnyContainer", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _Query_ptrToSliceContainer(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Query_ptrToSliceContainer(ctx, field) if err != nil { @@ -7329,6 +7377,28 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "ptrToAnyContainer": + 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_ptrToAnyContainer(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 "ptrToSliceContainer": field := field diff --git a/codegen/testserver/followschema/stub.go b/codegen/testserver/followschema/stub.go index 47d6773bad..25f659a352 100644 --- a/codegen/testserver/followschema/stub.go +++ b/codegen/testserver/followschema/stub.go @@ -102,6 +102,7 @@ type Stub struct { Panics func(ctx context.Context) (*Panics, error) PrimitiveObject func(ctx context.Context) ([]Primitive, error) PrimitiveStringObject func(ctx context.Context) ([]PrimitiveString, error) + PtrToAnyContainer func(ctx context.Context) (*PtrToAnyContainer, error) PtrToSliceContainer func(ctx context.Context) (*PtrToSliceContainer, error) Infinity func(ctx context.Context) (float64, error) StringFromContextInterface func(ctx context.Context) (*StringFromContextInterface, error) @@ -438,6 +439,9 @@ func (r *stubQuery) PrimitiveObject(ctx context.Context) ([]Primitive, error) { func (r *stubQuery) PrimitiveStringObject(ctx context.Context) ([]PrimitiveString, error) { return r.QueryResolver.PrimitiveStringObject(ctx) } +func (r *stubQuery) PtrToAnyContainer(ctx context.Context) (*PtrToAnyContainer, error) { + return r.QueryResolver.PtrToAnyContainer(ctx) +} func (r *stubQuery) PtrToSliceContainer(ctx context.Context) (*PtrToSliceContainer, error) { return r.QueryResolver.PtrToSliceContainer(ctx) } diff --git a/codegen/testserver/singlefile/generated.go b/codegen/testserver/singlefile/generated.go index 8113af520c..0b093d2367 100644 --- a/codegen/testserver/singlefile/generated.go +++ b/codegen/testserver/singlefile/generated.go @@ -286,6 +286,11 @@ type ComplexityRoot struct { Value func(childComplexity int) int } + PtrToAnyContainer struct { + Binding func(childComplexity int) int + PtrToAny func(childComplexity int) int + } + PtrToPtrInner struct { Key func(childComplexity int) int Value func(childComplexity int) int @@ -352,6 +357,7 @@ type ComplexityRoot struct { Panics func(childComplexity int) int PrimitiveObject func(childComplexity int) int PrimitiveStringObject func(childComplexity int) int + PtrToAnyContainer func(childComplexity int) int PtrToSliceContainer func(childComplexity int) int Recursive func(childComplexity int, input *RecursiveInputSlice) int ScalarSlice func(childComplexity int) int @@ -552,6 +558,7 @@ type QueryResolver interface { Panics(ctx context.Context) (*Panics, error) PrimitiveObject(ctx context.Context) ([]Primitive, error) PrimitiveStringObject(ctx context.Context) ([]PrimitiveString, error) + PtrToAnyContainer(ctx context.Context) (*PtrToAnyContainer, error) PtrToSliceContainer(ctx context.Context) (*PtrToSliceContainer, error) Infinity(ctx context.Context) (float64, error) StringFromContextInterface(ctx context.Context) (*StringFromContextInterface, error) @@ -1227,6 +1234,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.PrimitiveString.Value(childComplexity), true + case "PtrToAnyContainer.binding": + if e.complexity.PtrToAnyContainer.Binding == nil { + break + } + + return e.complexity.PtrToAnyContainer.Binding(childComplexity), true + + case "PtrToAnyContainer.ptrToAny": + if e.complexity.PtrToAnyContainer.PtrToAny == nil { + break + } + + return e.complexity.PtrToAnyContainer.PtrToAny(childComplexity), true + case "PtrToPtrInner.key": if e.complexity.PtrToPtrInner.Key == nil { break @@ -1709,6 +1730,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Query.PrimitiveStringObject(childComplexity), true + case "Query.ptrToAnyContainer": + if e.complexity.Query.PtrToAnyContainer == nil { + break + } + + return e.complexity.Query.PtrToAnyContainer(childComplexity), true + case "Query.ptrToSliceContainer": if e.complexity.Query.PtrToSliceContainer == nil { break @@ -2287,7 +2315,7 @@ func (ec *executionContext) introspectType(name string) (*introspection.Type, er return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil } -//go:embed "builtinscalar.graphql" "complexity.graphql" "defaults.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_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" +//go:embed "builtinscalar.graphql" "complexity.graphql" "defaults.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" var sourcesFS embed.FS func sourceData(filename string) string { @@ -2314,6 +2342,7 @@ var sources = []*ast.Source{ {Name: "nulls.graphql", Input: sourceData("nulls.graphql"), BuiltIn: false}, {Name: "panics.graphql", Input: sourceData("panics.graphql"), BuiltIn: false}, {Name: "primitive_objects.graphql", Input: sourceData("primitive_objects.graphql"), BuiltIn: false}, + {Name: "ptr_to_any.graphql", Input: sourceData("ptr_to_any.graphql"), BuiltIn: false}, {Name: "ptr_to_ptr_input.graphql", Input: sourceData("ptr_to_ptr_input.graphql"), BuiltIn: false}, {Name: "ptr_to_slice.graphql", Input: sourceData("ptr_to_slice.graphql"), BuiltIn: false}, {Name: "scalar_context.graphql", Input: sourceData("scalar_context.graphql"), BuiltIn: false}, @@ -7214,6 +7243,82 @@ func (ec *executionContext) fieldContext_PrimitiveString_len(ctx context.Context return fc, nil } +func (ec *executionContext) _PtrToAnyContainer_ptrToAny(ctx context.Context, field graphql.CollectedField, obj *PtrToAnyContainer) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_PtrToAnyContainer_ptrToAny(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.PtrToAny, nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*any) + fc.Result = res + return ec.marshalOAny2ᚖinterface(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_PtrToAnyContainer_ptrToAny(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "PtrToAnyContainer", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Any does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _PtrToAnyContainer_binding(ctx context.Context, field graphql.CollectedField, obj *PtrToAnyContainer) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_PtrToAnyContainer_binding(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.Binding(), nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*any) + fc.Result = res + return ec.marshalOAny2ᚖinterface(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_PtrToAnyContainer_binding(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "PtrToAnyContainer", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Any does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _PtrToPtrInner_key(ctx context.Context, field graphql.CollectedField, obj *PtrToPtrInner) (ret graphql.Marshaler) { fc, err := ec.fieldContext_PtrToPtrInner_key(ctx, field) if err != nil { @@ -10011,6 +10116,53 @@ func (ec *executionContext) fieldContext_Query_primitiveStringObject(ctx context return fc, nil } +func (ec *executionContext) _Query_ptrToAnyContainer(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_ptrToAnyContainer(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, nil, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().PtrToAnyContainer(rctx) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*PtrToAnyContainer) + fc.Result = res + return ec.marshalNPtrToAnyContainer2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋsinglefileᚐPtrToAnyContainer(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_ptrToAnyContainer(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 "ptrToAny": + return ec.fieldContext_PtrToAnyContainer_ptrToAny(ctx, field) + case "binding": + return ec.fieldContext_PtrToAnyContainer_binding(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type PtrToAnyContainer", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _Query_ptrToSliceContainer(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Query_ptrToSliceContainer(ctx, field) if err != nil { @@ -17734,6 +17886,43 @@ func (ec *executionContext) _PrimitiveString(ctx context.Context, sel ast.Select return out } +var ptrToAnyContainerImplementors = []string{"PtrToAnyContainer"} + +func (ec *executionContext) _PtrToAnyContainer(ctx context.Context, sel ast.SelectionSet, obj *PtrToAnyContainer) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, ptrToAnyContainerImplementors) + + 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("PtrToAnyContainer") + case "ptrToAny": + out.Values[i] = ec._PtrToAnyContainer_ptrToAny(ctx, field, obj) + case "binding": + out.Values[i] = ec._PtrToAnyContainer_binding(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + // assign deferred groups to main executionContext + for label, dfs := range deferred { + ec.deferredGroups = append(ec.deferredGroups, graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + var ptrToPtrInnerImplementors = []string{"PtrToPtrInner"} func (ec *executionContext) _PtrToPtrInner(ctx context.Context, sel ast.SelectionSet, obj *PtrToPtrInner) graphql.Marshaler { @@ -18883,6 +19072,28 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "ptrToAnyContainer": + 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_ptrToAnyContainer(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 "ptrToSliceContainer": field := field @@ -20845,6 +21056,20 @@ func (ec *executionContext) marshalNPrimitiveString2ᚕgithubᚗcomᚋ99designs return ret } +func (ec *executionContext) marshalNPtrToAnyContainer2githubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋsinglefileᚐPtrToAnyContainer(ctx context.Context, sel ast.SelectionSet, v PtrToAnyContainer) graphql.Marshaler { + return ec._PtrToAnyContainer(ctx, sel, &v) +} + +func (ec *executionContext) marshalNPtrToAnyContainer2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋsinglefileᚐPtrToAnyContainer(ctx context.Context, sel ast.SelectionSet, v *PtrToAnyContainer) 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._PtrToAnyContainer(ctx, sel, v) +} + func (ec *executionContext) marshalNPtrToPtrOuter2githubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋsinglefileᚐPtrToPtrOuter(ctx context.Context, sel ast.SelectionSet, v PtrToPtrOuter) graphql.Marshaler { return ec._PtrToPtrOuter(ctx, sel, &v) } @@ -21441,6 +21666,34 @@ func (ec *executionContext) marshalOAnimal2githubᚗcomᚋ99designsᚋgqlgenᚋc return ec._Animal(ctx, sel, v) } +func (ec *executionContext) unmarshalOAny2interface(ctx context.Context, v interface{}) (any, error) { + if v == nil { + return nil, nil + } + res, err := graphql.UnmarshalAny(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOAny2interface(ctx context.Context, sel ast.SelectionSet, v any) graphql.Marshaler { + if v == nil { + return graphql.Null + } + res := graphql.MarshalAny(v) + return res +} + +func (ec *executionContext) unmarshalOAny2ᚖinterface(ctx context.Context, v interface{}) (*any, error) { + if v == nil { + return nil, nil + } + res, err := ec.unmarshalOAny2interface(ctx, v) + return &res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOAny2ᚖinterface(ctx context.Context, sel ast.SelectionSet, v *any) graphql.Marshaler { + return ec.marshalOAny2interface(ctx, sel, *v) +} + func (ec *executionContext) marshalOAutobind2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋcodegenᚋtestserverᚋsinglefileᚐAutobind(ctx context.Context, sel ast.SelectionSet, v *Autobind) graphql.Marshaler { if v == nil { return graphql.Null diff --git a/codegen/testserver/singlefile/ptr_to_any.go b/codegen/testserver/singlefile/ptr_to_any.go new file mode 100644 index 0000000000..37a1c3dd1d --- /dev/null +++ b/codegen/testserver/singlefile/ptr_to_any.go @@ -0,0 +1,9 @@ +package singlefile + +type PtrToAnyContainer struct { + PtrToAny *any +} + +func (c *PtrToAnyContainer) Binding() *any { + return c.PtrToAny +} diff --git a/codegen/testserver/singlefile/ptr_to_any.graphql b/codegen/testserver/singlefile/ptr_to_any.graphql new file mode 100644 index 0000000000..c86bf38f83 --- /dev/null +++ b/codegen/testserver/singlefile/ptr_to_any.graphql @@ -0,0 +1,10 @@ +scalar Any + +type PtrToAnyContainer { + ptrToAny: Any + binding: Any +} + +extend type Query { + ptrToAnyContainer: PtrToAnyContainer! +} diff --git a/codegen/testserver/singlefile/ptr_to_any_test.go b/codegen/testserver/singlefile/ptr_to_any_test.go new file mode 100644 index 0000000000..88feadecc7 --- /dev/null +++ b/codegen/testserver/singlefile/ptr_to_any_test.go @@ -0,0 +1,37 @@ +package singlefile + +import ( + "context" + "testing" + + "github.com/99designs/gqlgen/client" + "github.com/99designs/gqlgen/graphql/handler" + "github.com/stretchr/testify/require" +) + +func TestPtrToAny(t *testing.T) { + resolvers := &Stub{} + + c := client.New(handler.NewDefaultServer(NewExecutableSchema(Config{Resolvers: resolvers}))) + + var a any = `{"some":"thing"}` + resolvers.QueryResolver.PtrToAnyContainer = func(ctx context.Context) (wrappedStruct *PtrToAnyContainer, e error) { + ptrToAnyContainer := PtrToAnyContainer{ + PtrToAny: &a, + } + return &ptrToAnyContainer, nil + } + + t.Run("binding to pointer to any", func(t *testing.T) { + var resp struct { + PtrToAnyContainer struct { + Binding *any + } + } + + err := c.Post(`query { ptrToAnyContainer { binding }}`, &resp) + require.NoError(t, err) + + require.Equal(t, &a, resp.PtrToAnyContainer.Binding) + }) +} diff --git a/codegen/testserver/singlefile/resolver.go b/codegen/testserver/singlefile/resolver.go index 219c6ce774..9b7e6159ba 100644 --- a/codegen/testserver/singlefile/resolver.go +++ b/codegen/testserver/singlefile/resolver.go @@ -362,6 +362,11 @@ func (r *queryResolver) PrimitiveStringObject(ctx context.Context) ([]PrimitiveS panic("not implemented") } +// PtrToAnyContainer is the resolver for the ptrToAnyContainer field. +func (r *queryResolver) PtrToAnyContainer(ctx context.Context) (*PtrToAnyContainer, error) { + panic("not implemented") +} + // PtrToSliceContainer is the resolver for the ptrToSliceContainer field. func (r *queryResolver) PtrToSliceContainer(ctx context.Context) (*PtrToSliceContainer, error) { panic("not implemented") diff --git a/codegen/testserver/singlefile/stub.go b/codegen/testserver/singlefile/stub.go index 07b243dd02..3528b0a316 100644 --- a/codegen/testserver/singlefile/stub.go +++ b/codegen/testserver/singlefile/stub.go @@ -102,6 +102,7 @@ type Stub struct { Panics func(ctx context.Context) (*Panics, error) PrimitiveObject func(ctx context.Context) ([]Primitive, error) PrimitiveStringObject func(ctx context.Context) ([]PrimitiveString, error) + PtrToAnyContainer func(ctx context.Context) (*PtrToAnyContainer, error) PtrToSliceContainer func(ctx context.Context) (*PtrToSliceContainer, error) Infinity func(ctx context.Context) (float64, error) StringFromContextInterface func(ctx context.Context) (*StringFromContextInterface, error) @@ -438,6 +439,9 @@ func (r *stubQuery) PrimitiveObject(ctx context.Context) ([]Primitive, error) { func (r *stubQuery) PrimitiveStringObject(ctx context.Context) ([]PrimitiveString, error) { return r.QueryResolver.PrimitiveStringObject(ctx) } +func (r *stubQuery) PtrToAnyContainer(ctx context.Context) (*PtrToAnyContainer, error) { + return r.QueryResolver.PtrToAnyContainer(ctx) +} func (r *stubQuery) PtrToSliceContainer(ctx context.Context) (*PtrToSliceContainer, error) { return r.QueryResolver.PtrToSliceContainer(ctx) } diff --git a/codegen/type.go b/codegen/type.go index 20b09dc975..dcd9d29105 100644 --- a/codegen/type.go +++ b/codegen/type.go @@ -26,7 +26,7 @@ func processType(ret map[string]*config.TypeReference, ref *config.TypeReference } ret[key] = ref - if ref.IsSlice() || ref.IsPtrToSlice() || ref.IsPtrToPtr() { + if ref.IsSlice() || ref.IsPtrToSlice() || ref.IsPtrToPtr() || ref.IsPtrToIntf() { processType(ret, ref.Elem()) } } diff --git a/codegen/type.gotpl b/codegen/type.gotpl index eaa1718436..5cbd737c77 100644 --- a/codegen/type.gotpl +++ b/codegen/type.gotpl @@ -4,7 +4,7 @@ {{- if and $type.IsNilable (not $type.GQL.NonNull) (not $type.IsPtrToPtr) }} if v == nil { return nil, nil } {{- end }} - {{- if $type.IsPtrToSlice }} + {{- if or $type.IsPtrToSlice $type.IsPtrToIntf }} res, err := ec.{{ $type.Elem.UnmarshalFunc }}(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) {{- else if $type.IsSlice }} @@ -89,7 +89,7 @@ {{ with $type.MarshalFunc }} func (ec *executionContext) {{ . }}(ctx context.Context, sel ast.SelectionSet, v {{ $type.GO | ref }}) graphql.Marshaler { - {{- if $type.IsPtrToSlice }} + {{- if or $type.IsPtrToSlice $type.IsPtrToIntf }} return ec.{{ $type.Elem.MarshalFunc }}(ctx, sel, *v) {{- else if $type.IsSlice }} {{- if not $type.GQL.NonNull }}