func()

in codegen/config/binder.go [365:491]


func (b *Binder) TypeReference(schemaType *ast.Type, bindTarget types.Type) (ret *TypeReference, err error) {
	if bindTarget != nil {
		bindTarget = code.Unalias(bindTarget)
	}
	if innerType, ok := unwrapOmittable(bindTarget); ok {
		if schemaType.NonNull {
			return nil, fmt.Errorf("%s is wrapped with Omittable but non-null", schemaType.Name())
		}

		ref, err := b.TypeReference(schemaType, innerType)
		if err != nil {
			return nil, err
		}

		ref.IsOmittable = true
		return ref, err
	}

	if !isValid(bindTarget) {
		b.SawInvalid = true
		return nil, fmt.Errorf("%s has an invalid type", schemaType.Name())
	}

	var pkgName, typeName string
	def := b.schema.Types[schemaType.Name()]
	defer func() {
		if err == nil && ret != nil {
			b.PushRef(ret)
		}
	}()

	if len(b.cfg.Models[schemaType.Name()].Model) == 0 {
		return nil, fmt.Errorf("%s was not found", schemaType.Name())
	}

	for _, model := range b.cfg.Models[schemaType.Name()].Model {
		if model == "map[string]interface{}" {
			if !isMap(bindTarget) {
				continue
			}
			return &TypeReference{
				Definition: def,
				GQL:        schemaType,
				GO:         MapType,
				IsRoot:     b.cfg.IsRoot(def),
			}, nil
		}

		if model == "interface{}" {
			if !isIntf(bindTarget) {
				continue
			}
			return &TypeReference{
				Definition: def,
				GQL:        schemaType,
				GO:         InterfaceType,
				IsRoot:     b.cfg.IsRoot(def),
			}, nil
		}

		pkgName, typeName = code.PkgAndType(model)
		if pkgName == "" {
			return nil, fmt.Errorf("missing package name for %s", schemaType.Name())
		}

		ref := &TypeReference{
			Definition: def,
			GQL:        schemaType,
			IsRoot:     b.cfg.IsRoot(def),
		}

		obj, err := b.FindObject(pkgName, typeName)
		if err != nil {
			return nil, err
		}
		t := code.Unalias(obj.Type())
		if values := b.enumValues(def); len(values) > 0 {
			err = b.enumReference(ref, obj, values)
			if err != nil {
				return nil, err
			}
		} else if fun, isFunc := obj.(*types.Func); isFunc {
			ref.GO = code.Unalias(t.(*types.Signature).Params().At(0).Type())
			ref.IsContext = code.Unalias(t.(*types.Signature).Results().At(0).Type()).String() == "github.com/99designs/gqlgen/graphql.ContextMarshaler"
			ref.Marshaler = fun
			ref.Unmarshaler = types.NewFunc(0, fun.Pkg(), "Unmarshal"+typeName, nil)
		} else if hasMethod(t, "MarshalGQLContext") && hasMethod(t, "UnmarshalGQLContext") {
			ref.GO = t
			ref.IsContext = true
			ref.IsMarshaler = true
		} else if hasMethod(t, "MarshalGQL") && hasMethod(t, "UnmarshalGQL") {
			ref.GO = t
			ref.IsMarshaler = true
		} else if underlying := basicUnderlying(t); def.IsLeafType() && underlying != nil && underlying.Kind() == types.String {
			// TODO delete before v1. Backwards compatibility case for named types wrapping strings (see #595)

			ref.GO = t
			ref.CastType = underlying

			underlyingRef, err := b.TypeReference(&ast.Type{NamedType: "String"}, nil)
			if err != nil {
				return nil, err
			}

			ref.Marshaler = underlyingRef.Marshaler
			ref.Unmarshaler = underlyingRef.Unmarshaler
		} else {
			ref.GO = t
		}

		ref.Target = ref.GO
		ref.GO = b.CopyModifiersFromAst(schemaType, ref.GO)

		if bindTarget != nil {
			if err = code.CompatibleTypes(ref.GO, bindTarget); err != nil {
				continue
			}
			ref.GO = bindTarget
		}

		ref.PointersInUnmarshalInput = b.cfg.ReturnPointersInUnmarshalInput

		return ref, nil
	}

	return nil, fmt.Errorf("%s is incompatible with %s", schemaType.Name(), bindTarget.String())
}