/** * Produces a Go value given a GraphQL Value AST. * * A GraphQL type must be provided, which will be used to interpret different * GraphQL Value literals. * * | GraphQL Value | JSON Value | * | -------------------- | ------------- | * | Input Object | Object | * | List | Array | * | Boolean | Boolean | * | String / Enum Value | String | * | Int / Float | Number | * */ func ValueFromAST( valueAST lang.IValue, typ typs.QLInputType, variables map[string]interface{}, ) interface{} { if typ, ok := typ.(*typs.QLNonNull); ok { nullableType := typ.OfType.(typs.QLInputType) return ValueFromAST(valueAST, nullableType, variables) } if IsNil(valueAST) { return nil } if valueAST, ok := valueAST.(*lang.Variable); ok { variableName := valueAST.Name.Value return variables[variableName] } switch typ := typ.(type) { case *typs.QLList: if valueAST, ok := valueAST.(*lang.ListValue); ok { itemType := typ.OfType.(typs.QLInputType) result := make([]interface{}, len(valueAST.Values))[:0] for _, itemAST := range valueAST.Values { result = append(result, ValueFromAST(itemAST, itemType, variables)) } return result } return []interface{}{ValueFromAST(valueAST, typ, variables)} case *typs.QLInputObject: valueAST, ok := valueAST.(*lang.ObjectValue) if !ok { return nil } fieldASTMap := make(map[string]*lang.ObjectField) for _, fieldAST := range valueAST.Fields { fieldASTMap[fieldAST.Name.Value] = fieldAST } result := make(map[string]interface{}) fields := typ.GetFields() for fieldName, field := range fields { fieldAST := fieldASTMap[fieldName] var fieldValue interface{} if fieldAST != nil { fieldValue = ValueFromAST(fieldAST.Value, field.Type, variables) } if IsNil(fieldValue) { fieldValue = field.DefaultValue } if !IsNil(fieldValue) { result[fieldName] = fieldValue } } return result case *typs.QLScalar: parsed := typ.ParseLiteral(valueAST) if IsNil(parsed) { return nil } return parsed default: throw("Must be input type") return nil } }
func IsValidLiteralValue(typ typs.QLInputType, valueAST lang.IValue) bool { if typ, ok := typ.(*typs.QLNonNull); ok { if IsNil(valueAST) { return false } ofType := typ.OfType.(typs.QLInputType) return IsValidLiteralValue(ofType, valueAST) } if IsNil(valueAST) { return false } if _, ok := valueAST.(*lang.Variable); ok { return true } if typ, ok := typ.(*typs.QLList); ok { itemType := typ.OfType.(typs.QLInputType) if valueAST, ok := valueAST.(*lang.ListValue); ok { for i := range valueAST.Values { return IsValidLiteralValue(itemType, valueAST.Values[i]) } } } if typ, ok := typ.(*typs.QLInputObject); ok { if _, ok := valueAST.(*lang.ObjectValue); !ok { return false } fields := typ.GetFields() fieldASTs := valueAST.(*lang.ObjectValue).Fields refinedFieldASTs := []interface{}{} for i := range fieldASTs { if fields[fieldASTs[i].Name.Value] == nil { return false } refinedFieldASTs = append(refinedFieldASTs, fieldASTs[i]) } fieldASTMap := make(map[string]interface{}) for _, fieldAST := range refinedFieldASTs { fieldASTMap[fieldAST.(lang.ObjectField).Name.Value] = fieldAST } for k, v := range fields { return IsValidLiteralValue(v.Type, fieldASTMap[k].(*lang.ObjectField).Value) } } if typ, ok := typ.(*typs.QLScalar); ok { return !IsNil(typ.ParseLiteral(valueAST)) } if typ, ok := typ.(*typs.QLEnum); ok { return !IsNil(typ.ParseLiteral(valueAST)) } return false }