func()

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))
	}
}