in codegen/field.go [86:230]
func (b *builder) bindField(obj *Object, f *Field) (errret error) {
defer func() {
if f.TypeReference == nil {
tr, err := b.Binder.TypeReference(f.Type, nil)
if err != nil {
errret = err
}
f.TypeReference = tr
}
if f.TypeReference != nil {
dirs, err := b.getDirectives(f.TypeReference.Definition.Directives)
if err != nil {
errret = err
}
for _, dir := range obj.Directives {
if dir.IsLocation(ast.LocationInputObject) {
dirs = append(dirs, dir)
}
}
f.Directives = append(dirs, f.Directives...)
}
}()
f.Stream = obj.Stream
switch {
case f.Name == "__schema":
f.GoFieldType = GoFieldMethod
f.GoReceiverName = "ec"
f.GoFieldName = "introspectSchema"
return nil
case f.Name == "__type":
f.GoFieldType = GoFieldMethod
f.GoReceiverName = "ec"
f.GoFieldName = "introspectType"
return nil
case f.Name == "_entities":
f.GoFieldType = GoFieldMethod
f.GoReceiverName = "ec"
f.GoFieldName = "__resolve_entities"
f.MethodHasContext = true
f.NoErr = true
return nil
case f.Name == "_service":
f.GoFieldType = GoFieldMethod
f.GoReceiverName = "ec"
f.GoFieldName = "__resolve__service"
f.MethodHasContext = true
return nil
case obj.Root:
f.IsResolver = true
return nil
case b.Config.Models[obj.Name].Fields[f.Name].Resolver:
f.IsResolver = true
return nil
case obj.Type == config.MapType:
f.GoFieldType = GoFieldMap
return nil
case b.Config.Models[obj.Name].Fields[f.Name].FieldName != "":
f.GoFieldName = b.Config.Models[obj.Name].Fields[f.Name].FieldName
}
target, err := b.findBindTarget(obj.Type, f.GoFieldName)
if err != nil {
return err
}
pos := b.Binder.ObjectPosition(target)
switch target := target.(type) {
case nil:
// Skips creating a resolver for any root types
if b.Config.IsRoot(b.Schema.Types[f.Type.Name()]) {
return nil
}
objPos := b.Binder.TypePosition(obj.Type)
return fmt.Errorf(
"%s:%d adding resolver method for %s.%s, nothing matched",
objPos.Filename,
objPos.Line,
obj.Name,
f.Name,
)
case *types.Func:
sig := target.Type().(*types.Signature)
if sig.Results().Len() == 1 {
f.NoErr = true
} else if s := sig.Results(); s.Len() == 2 && s.At(1).Type().String() == "bool" {
f.VOkFunc = true
} else if sig.Results().Len() != 2 {
return errors.New("method has wrong number of args")
}
params := sig.Params()
// If the first argument is the context, remove it from the comparison and set
// the MethodHasContext flag so that the context will be passed to this model's method
if params.Len() > 0 && params.At(0).Type().String() == "context.Context" {
f.MethodHasContext = true
vars := make([]*types.Var, params.Len()-1)
for i := 1; i < params.Len(); i++ {
vars[i-1] = params.At(i)
}
params = types.NewTuple(vars...)
}
// Try to match target function's arguments with GraphQL field arguments.
newArgs, err := b.bindArgs(f, sig, params)
if err != nil {
return fmt.Errorf("%s:%d: %w", pos.Filename, pos.Line, err)
}
// Try to match target function's return types with GraphQL field return type
result := sig.Results().At(0)
tr, err := b.Binder.TypeReference(f.Type, result.Type())
if err != nil {
return err
}
// success, args and return type match. Bind to method
f.GoFieldType = GoFieldMethod
f.GoReceiverName = "obj"
f.GoFieldName = target.Name()
f.Args = newArgs
f.TypeReference = tr
return nil
case *types.Var:
tr, err := b.Binder.TypeReference(f.Type, target.Type())
if err != nil {
return err
}
// success, bind to var
f.GoFieldType = GoFieldVariable
f.GoReceiverName = "obj"
f.GoFieldName = target.Name()
f.TypeReference = tr
return nil
default:
panic(fmt.Errorf("unknown bind target %T for %s", target, f.Name))
}
}