/** * 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 }