/** * Given a type and any value, return a runtime value coerced to match the type. */ func coerceValue(typ typs.QLType, value interface{}) interface{} { if typ, ok := typ.(*typs.QLNonNull); ok { nullableType := typ.OfType return coerceValue(nullableType, value) } v := reflect.ValueOf(value) if value == nil || v.IsNil() { return nil } switch typ := typ.(type) { case *typs.QLList: itemType := typ.OfType if v.Kind() == reflect.Slice || v.Kind() == reflect.Array { result := make([]interface{}, v.Len())[:0] for i, n := 0, v.Len(); i < n; i++ { fieldValue := v.Field(i) result = append(result, coerceValue(itemType, fieldValue)) } return result } return []interface{}{coerceValue(itemType, value)} case *typs.QLInputObject: fields := typ.GetFields() obj := make(map[string]interface{}) for fieldName, field := range fields { runtimeField := v.FieldByName(fieldName) if !runtimeField.IsValid() { continue } fieldValue := coerceValue(field.Type, runtimeField.Interface()) if fieldValue == nil { fieldValue = field.DefaultValue } if fieldValue != nil { obj[fieldName] = fieldValue } } return obj case *typs.QLScalar: return typ.ParseValue(value) case *typs.QLEnum: return typ.ParseValue(value) default: panic("Must be input type") } }
func ASTFromValue(value interface{}, typ typs.QLType) lang.IValue { if typ, ok := typ.(*typs.QLNonNull); ok { return ASTFromValue(value, typ.OfType) } if IsNil(value) { return nil } val := reflect.ValueOf(value) val = reflect.Indirect(val) if val.Kind() == reflect.Array || val.Kind() == reflect.Slice { var itemType typs.QLType if typ, ok := typ.(*typs.QLList); ok { itemType = typ.OfType } values := []lang.IValue{} for i := 0; i < val.Len(); i++ { values = append(values, ASTFromValue(val.Index(i), itemType)) } return &lang.ListValue{ Values: values, } } else if typ, ok := typ.(*typs.QLList); ok { return ASTFromValue(value, typ.OfType) } if val.Kind() == reflect.Bool { return &lang.BooleanValue{ Value: strconv.FormatBool(val.Bool()), } } if _, ok := typ.(*typs.QLScalar); ok { if val.Kind() == reflect.Int { return &lang.IntValue{ Value: fmt.Sprintf("%v", val.Int()), } } if val.Kind() == reflect.Float64 { return &lang.FloatValue{ Value: fmt.Sprintf("%v", val.Float()), } } } if val.Kind() == reflect.String { if _, ok := typ.(*typs.QLEnum); ok { matched, _ := regexp.MatchString(`^[_a-zA-Z][_a-zA-Z0-9]*$`, val.String()) if matched { return &lang.EnumValue{ Value: val.String(), } } } return &lang.StringValue{ Value: val.String()[1 : val.Len()-1], } } v := val.Elem() fields := []*lang.ObjectField{} for i := 0; i < v.NumField(); i++ { valueField := v.Field(i) typeField := val.Type().Field(i) var fieldTyp typs.QLType if typ, ok := typ.(*typs.QLInputObject); ok { fieldDef := typ.GetFields()[typeField.Name] if fieldDef != nil { fieldTyp = fieldDef.Type } } fieldValue := ASTFromValue(valueField, fieldTyp) if fieldValue != nil { fields = append(fields, &lang.ObjectField{ Name: &lang.Name{ Value: typeField.Name, }, Value: fieldValue, }) } } return &lang.ObjectValue{ Fields: fields, } return nil }
func (c *_Context) completeValue( returnType typs.QLType, fieldASTs []*lang.Field, info typs.QLResolveInfo, result interface{}, ) interface{} { if returnType, ok := returnType.(*typs.QLNonNull); ok { completed := c.completeValue(returnType.OfType, fieldASTs, info, result) if completed == nil { nodes := make([]lang.INode, len(fieldASTs)) for i, node := range fieldASTs { nodes[i] = node } panic(lang.NewQLError( fmt.Sprintf( `Cannot return null for non-nullable field %v.%v.`, info.ParentType, info.FieldName), nodes)) } return completed } v := reflect.ValueOf(result) if result == nil { return nil } v = reflect.Indirect(v) t := v.Type() switch returnType := returnType.(type) { case *typs.QLList: if t.Kind() == reflect.Slice || t.Kind() == reflect.Array { itemType := returnType.OfType list := make([]interface{}, t.NumField()) for i, n := 0, t.NumField(); i < n; i++ { list[i] = c.completeValueCatchingError(itemType, fieldASTs, info, v.Field(i).Interface()) } return list } panic("User Error: expected array of slice, but did not find one.") case *typs.QLScalar: if returnType.Serialize == nil { panic("Missing serialize method on type") } serializedResult := returnType.Serialize(result) if serializedResult == nil { return nil } return serializedResult case *typs.QLEnum: return returnType.Serialize(result) case *typs.QLObject: runtimeType := returnType subFieldASTs := map[string][]*lang.Field{} visitedFragmentNames := map[string]struct{}{} for _, fieldAST := range fieldASTs { selectionSet := fieldAST.SelectionSet if selectionSet != nil { subFieldASTs = c.collectFields(runtimeType, selectionSet, subFieldASTs, visitedFragmentNames) } } return c.executeFields(runtimeType, result, subFieldASTs) case typs.QLAbstractType: panic("not implemented") default: panic("unreachable") } }