github.com/niko0xdev/gqlgen@v0.17.55-0.20240120102243-2ecff98c3e37/graphql/input.go (about) 1 package graphql 2 3 import ( 4 "context" 5 "errors" 6 "reflect" 7 ) 8 9 const unmarshalInputCtx key = "unmarshal_input_context" 10 11 // BuildUnmarshalerMap returns a map of unmarshal functions of the ExecutableContext 12 // to use with the WithUnmarshalerMap function. 13 func BuildUnmarshalerMap(unmarshaler ...interface{}) map[reflect.Type]reflect.Value { 14 maps := make(map[reflect.Type]reflect.Value) 15 for _, v := range unmarshaler { 16 ft := reflect.TypeOf(v) 17 if ft.Kind() == reflect.Func { 18 maps[ft.Out(0)] = reflect.ValueOf(v) 19 } 20 } 21 22 return maps 23 } 24 25 // WithUnmarshalerMap returns a new context with a map from input types to their unmarshaler functions. 26 func WithUnmarshalerMap(ctx context.Context, maps map[reflect.Type]reflect.Value) context.Context { 27 return context.WithValue(ctx, unmarshalInputCtx, maps) 28 } 29 30 // UnmarshalInputFromContext allows unmarshaling input object from a context. 31 func UnmarshalInputFromContext(ctx context.Context, raw, v interface{}) error { 32 m, ok := ctx.Value(unmarshalInputCtx).(map[reflect.Type]reflect.Value) 33 if m == nil || !ok { 34 return errors.New("graphql: the input context is empty") 35 } 36 37 rv := reflect.ValueOf(v) 38 if rv.Kind() != reflect.Ptr || rv.IsNil() { 39 return errors.New("graphql: input must be a non-nil pointer") 40 } 41 if fn, ok := m[rv.Elem().Type()]; ok { 42 res := fn.Call([]reflect.Value{ 43 reflect.ValueOf(ctx), 44 reflect.ValueOf(raw), 45 }) 46 if err := res[1].Interface(); err != nil { 47 return err.(error) 48 } 49 50 rv.Elem().Set(res[0]) 51 return nil 52 } 53 54 return errors.New("graphql: no unmarshal function found") 55 }