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]: advance(parser) return ast.NewIntValue(&ast.IntValue{ Value: token.Value, Loc: loc(parser, token.Start), }), nil case lexer.TokenKind[lexer.FLOAT]: advance(parser) return ast.NewFloatValue(&ast.FloatValue{ Value: token.Value, Loc: loc(parser, token.Start), }), nil case lexer.TokenKind[lexer.STRING]: advance(parser) 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" { advance(parser) 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" { advance(parser) 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 }
/** * Produces a GraphQL Value AST given a Golang value. * * Optionally, a GraphQL type may be provided, which will be used to * disambiguate between value primitives. * * | JSON Value | GraphQL Value | * | ------------- | -------------------- | * | Object | Input Object | * | Array | List | * | Boolean | Boolean | * | String | String / Enum Value | * | Number | Int / Float | * */ 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, }) } else { // 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), }) }