func astFromValue(value interface{}, ttype Type) ast.Value { if ttype, ok := ttype.(*NonNull); ok { // Note: we're not checking that the result is non-null. // This function is not responsible for validating the input value. val := astFromValue(value, ttype.OfType) return val } if isNullish(value) { return nil } valueVal := reflect.ValueOf(value) if !valueVal.IsValid() { return nil } if valueVal.Type().Kind() == reflect.Ptr { valueVal = valueVal.Elem() } if !valueVal.IsValid() { return nil } // Convert Golang slice to GraphQL list. If the Type is a list, but // the value is not an array, convert the value using the list's item type. if ttype, ok := ttype.(*List); ok { if valueVal.Type().Kind() == reflect.Slice { itemType := ttype.OfType values := []ast.Value{} for i := 0; i < valueVal.Len(); i++ { item := valueVal.Index(i).Interface() itemAST := astFromValue(item, itemType) if itemAST != nil { values = append(values, itemAST) } } return ast.NewListValue(&ast.ListValue{ Values: values, }) } // Because GraphQL will accept single values as a "list of one" when // expecting a list, if there's a non-array value and an expected list type, // create an AST using the list's item type. val := astFromValue(value, ttype.OfType) return val } if valueVal.Type().Kind() == reflect.Map { // TODO: implement astFromValue from Map to Value } if value, ok := value.(bool); ok { return ast.NewBooleanValue(&ast.BooleanValue{ Value: value, }) } if value, ok := value.(int); ok { if ttype == Float { return ast.NewIntValue(&ast.IntValue{ Value: fmt.Sprintf("%v.0", value), }) } return ast.NewIntValue(&ast.IntValue{ Value: fmt.Sprintf("%v", value), }) } if value, ok := value.(float32); ok { return ast.NewFloatValue(&ast.FloatValue{ Value: fmt.Sprintf("%v", value), }) } if value, ok := value.(float64); ok { return ast.NewFloatValue(&ast.FloatValue{ Value: fmt.Sprintf("%v", value), }) } if value, ok := value.(string); ok { if _, ok := ttype.(*Enum); ok { return ast.NewEnumValue(&ast.EnumValue{ Value: fmt.Sprintf("%v", value), }) } return ast.NewStringValue(&ast.StringValue{ Value: fmt.Sprintf("%v", value), }) } // fallback, treat as string return ast.NewStringValue(&ast.StringValue{ Value: fmt.Sprintf("%v", value), }) }
/** * Value[Const] : * - [~Const] Variable * - IntValue * - FloatValue * - StringValue * - BooleanValue * - EnumValue * - ListValue[?Const] * - ObjectValue[?Const] * * BooleanValue : one of `true` `false` * * EnumValue : Name but not `true`, `false` or `null` */ func parseValueLiteral(parser *Parser, isConst bool) (ast.Value, error) { token := parser.Token switch token.Kind { case lexer.TokenKind[lexer.BRACKET_L]: return parseList(parser, isConst) case lexer.TokenKind[lexer.BRACE_L]: return parseObject(parser, isConst) case lexer.TokenKind[lexer.INT]: if err := advance(parser); err != nil { return nil, err } return ast.NewIntValue(&ast.IntValue{ Value: token.Value, Loc: loc(parser, token.Start), }), nil case lexer.TokenKind[lexer.FLOAT]: if err := advance(parser); err != nil { return nil, err } return ast.NewFloatValue(&ast.FloatValue{ Value: token.Value, Loc: loc(parser, token.Start), }), nil case lexer.TokenKind[lexer.STRING]: if err := advance(parser); err != nil { return nil, err } return ast.NewStringValue(&ast.StringValue{ Value: token.Value, Loc: loc(parser, token.Start), }), nil case lexer.TokenKind[lexer.NAME]: if token.Value == "true" || token.Value == "false" { if err := advance(parser); err != nil { return nil, err } value := true if token.Value == "false" { value = false } return ast.NewBooleanValue(&ast.BooleanValue{ Value: value, Loc: loc(parser, token.Start), }), nil } else if token.Value != "null" { if err := advance(parser); err != nil { return nil, err } return ast.NewEnumValue(&ast.EnumValue{ Value: token.Value, Loc: loc(parser, token.Start), }), nil } case lexer.TokenKind[lexer.DOLLAR]: if !isConst { return parseVariable(parser) } } if err := unexpected(parser, lexer.Token{}); err != nil { return nil, err } return nil, nil }