Skip to content

Commit cc69ea0

Browse files
committed
Support distinguishing the top-level names on the roo resolver by prefixing them with
Query, Mutation and Subscription.
1 parent 28e4eac commit cc69ea0

File tree

2 files changed

+33
-15
lines changed

2 files changed

+33
-15
lines changed

graphql.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func ParseSchema(schemaString string, resolver interface{}, opts ...SchemaOpt) (
3838
}
3939

4040
if resolver != nil {
41-
r, err := resolvable.ApplyResolver(s.schema, resolver)
41+
r, err := resolvable.ApplyResolver(s.schema, resolver, s.prefixRootFunctions)
4242
if err != nil {
4343
return nil, err
4444
}
@@ -69,6 +69,7 @@ type Schema struct {
6969
logger log.Logger
7070
useStringDescriptions bool
7171
disableIntrospection bool
72+
prefixRootFunctions bool
7273
}
7374

7475
// SchemaOpt is an option to pass to ParseSchema or MustParseSchema.
@@ -98,6 +99,13 @@ func MaxDepth(n int) SchemaOpt {
9899
}
99100
}
100101

102+
// Add the Query, Subscription and Mutation prefixes to the root resolver function when doing reflection from schema to Go code.
103+
func PrefixRootFunctions() SchemaOpt {
104+
return func(s *Schema) {
105+
s.prefixRootFunctions = true
106+
}
107+
}
108+
101109
// MaxParallelism specifies the maximum number of resolvers per request allowed to run in parallel. The default is 10.
102110
func MaxParallelism(n int) SchemaOpt {
103111
return func(s *Schema) {

internal/exec/resolvable/resolvable.go

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -60,25 +60,25 @@ func (*Object) isResolvable() {}
6060
func (*List) isResolvable() {}
6161
func (*Scalar) isResolvable() {}
6262

63-
func ApplyResolver(s *schema.Schema, resolver interface{}) (*Schema, error) {
63+
func ApplyResolver(s *schema.Schema, resolver interface{}, prefixRootFuncs bool) (*Schema, error) {
6464
b := newBuilder(s)
6565

6666
var query, mutation, subscription Resolvable
6767

6868
if t, ok := s.EntryPoints["query"]; ok {
69-
if err := b.assignExec(&query, t, reflect.TypeOf(resolver)); err != nil {
69+
if err := b.assignExec(&query, t, reflect.TypeOf(resolver), prefixRootFuncs); err != nil {
7070
return nil, err
7171
}
7272
}
7373

7474
if t, ok := s.EntryPoints["mutation"]; ok {
75-
if err := b.assignExec(&mutation, t, reflect.TypeOf(resolver)); err != nil {
75+
if err := b.assignExec(&mutation, t, reflect.TypeOf(resolver), prefixRootFuncs); err != nil {
7676
return nil, err
7777
}
7878
}
7979

8080
if t, ok := s.EntryPoints["subscription"]; ok {
81-
if err := b.assignExec(&subscription, t, reflect.TypeOf(resolver)); err != nil {
81+
if err := b.assignExec(&subscription, t, reflect.TypeOf(resolver), prefixRootFuncs); err != nil {
8282
return nil, err
8383
}
8484
}
@@ -130,14 +130,14 @@ func (b *execBuilder) finish() error {
130130
return b.packerBuilder.Finish()
131131
}
132132

133-
func (b *execBuilder) assignExec(target *Resolvable, t common.Type, resolverType reflect.Type) error {
133+
func (b *execBuilder) assignExec(target *Resolvable, t common.Type, resolverType reflect.Type, prefixFuncs bool) error {
134134
k := typePair{t, resolverType}
135135
ref, ok := b.resMap[k]
136136
if !ok {
137137
ref = &resMapEntry{}
138138
b.resMap[k] = ref
139139
var err error
140-
ref.exec, err = b.makeExec(t, resolverType)
140+
ref.exec, err = b.makeExec(t, resolverType, prefixFuncs)
141141
if err != nil {
142142
return err
143143
}
@@ -146,13 +146,13 @@ func (b *execBuilder) assignExec(target *Resolvable, t common.Type, resolverType
146146
return nil
147147
}
148148

149-
func (b *execBuilder) makeExec(t common.Type, resolverType reflect.Type) (Resolvable, error) {
149+
func (b *execBuilder) makeExec(t common.Type, resolverType reflect.Type, prefixFuncs bool) (Resolvable, error) {
150150
var nonNull bool
151151
t, nonNull = unwrapNonNull(t)
152152

153153
switch t := t.(type) {
154154
case *schema.Object:
155-
return b.makeObjectExec(t.Name, t.Fields, nil, nonNull, resolverType)
155+
return b.makeObjectExecWithPrefix(t.Name, t.Fields, nil, nonNull, resolverType, prefixFuncs)
156156

157157
case *schema.Interface:
158158
return b.makeObjectExec(t.Name, t.Fields, t.PossibleTypes, nonNull, resolverType)
@@ -180,7 +180,7 @@ func (b *execBuilder) makeExec(t common.Type, resolverType reflect.Type) (Resolv
180180
return nil, fmt.Errorf("%s is not a slice", resolverType)
181181
}
182182
e := &List{}
183-
if err := b.assignExec(&e.Elem, t.OfType, resolverType.Elem()); err != nil {
183+
if err := b.assignExec(&e.Elem, t.OfType, resolverType.Elem(), false); err != nil {
184184
return nil, err
185185
}
186186
return e, nil
@@ -212,6 +212,9 @@ func makeScalarExec(t *schema.Scalar, resolverType reflect.Type) (Resolvable, er
212212

213213
func (b *execBuilder) makeObjectExec(typeName string, fields schema.FieldList, possibleTypes []*schema.Object,
214214
nonNull bool, resolverType reflect.Type) (*Object, error) {
215+
return b.makeObjectExecWithPrefix(typeName, fields, possibleTypes, nonNull, resolverType, false)
216+
}
217+
func (b *execBuilder) makeObjectExecWithPrefix(typeName string, fields schema.FieldList, possibleTypes []*schema.Object, nonNull bool, resolverType reflect.Type, prefixFuncs bool) (*Object, error) {
215218
if !nonNull {
216219
if resolverType.Kind() != reflect.Ptr && resolverType.Kind() != reflect.Interface {
217220
return nil, fmt.Errorf("%s is not a pointer or interface", resolverType)
@@ -223,17 +226,23 @@ func (b *execBuilder) makeObjectExec(typeName string, fields schema.FieldList, p
223226
Fields := make(map[string]*Field)
224227
rt := unwrapPtr(resolverType)
225228
for _, f := range fields {
229+
230+
methodName := f.Name
231+
if prefixFuncs {
232+
methodName = typeName + f.Name
233+
}
234+
226235
fieldIndex := -1
227-
methodIndex := findMethod(resolverType, f.Name)
236+
methodIndex := findMethod(resolverType, methodName)
228237
if b.schema.UseFieldResolvers && methodIndex == -1 {
229238
fieldIndex = findField(rt, f.Name)
230239
}
231240
if methodIndex == -1 && fieldIndex == -1 {
232241
hint := ""
233-
if findMethod(reflect.PtrTo(resolverType), f.Name) != -1 {
242+
if findMethod(reflect.PtrTo(resolverType), methodName) != -1 {
234243
hint = " (hint: the method exists on the pointer type)"
235244
}
236-
return nil, fmt.Errorf("%s does not resolve %q: missing method for field %q%s", resolverType, typeName, f.Name, hint)
245+
return nil, fmt.Errorf("%s does not resolve %q: missing method for field %q%s", resolverType, typeName, methodName, hint)
237246
}
238247

239248
var m reflect.Method
@@ -266,7 +275,7 @@ func (b *execBuilder) makeObjectExec(typeName string, fields schema.FieldList, p
266275
a := &TypeAssertion{
267276
MethodIndex: methodIndex,
268277
}
269-
if err := b.assignExec(&a.TypeExec, impl, resolverType.Method(methodIndex).Type.Out(0)); err != nil {
278+
if err := b.assignExec(&a.TypeExec, impl, resolverType.Method(methodIndex).Type.Out(0), false); err != nil {
270279
return nil, err
271280
}
272281
typeAssertions[impl.Name] = a
@@ -358,7 +367,7 @@ func (b *execBuilder) makeFieldExec(typeName string, f *schema.Field, m reflect.
358367
} else {
359368
out = sf.Type
360369
}
361-
if err := b.assignExec(&fe.ValueExec, f.Type, out); err != nil {
370+
if err := b.assignExec(&fe.ValueExec, f.Type, out, false); err != nil {
362371
return nil, err
363372
}
364373

@@ -375,6 +384,7 @@ func findMethod(t reflect.Type, name string) int {
375384
}
376385

377386
func findField(t reflect.Type, name string) int {
387+
fmt.Println("MAMA", name, t)
378388
for i := 0; i < t.NumField(); i++ {
379389
if strings.EqualFold(stripUnderscore(name), stripUnderscore(t.Field(i).Name)) {
380390
return i

0 commit comments

Comments
 (0)