github.com/influxdata/influxql@v1.1.0/params.go (about) 1 package influxql 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "strconv" 7 "strings" 8 "time" 9 ) 10 11 // Value represents a value that can be bound 12 // to a parameter when parsing the query. 13 type Value interface { 14 TokenType() Token 15 Value() string 16 } 17 18 type ( 19 // Identifier is an identifier value. 20 Identifier string 21 22 // StringValue is a string literal. 23 StringValue string 24 25 // RegexValue is a regexp literal. 26 RegexValue string 27 28 // NumberValue is a number literal. 29 NumberValue float64 30 31 // IntegerValue is an integer literal. 32 IntegerValue int64 33 34 // BooleanValue is a boolean literal. 35 BooleanValue bool 36 37 // DurationValue is a duration literal. 38 DurationValue string 39 40 // ErrorValue is a special value that returns an error during parsing 41 // when it is used. 42 ErrorValue string 43 ) 44 45 // BindValue will bind an interface value to its influxql value. 46 // This method of binding values only supports literals. 47 func BindValue(v interface{}) Value { 48 if jv, ok := v.(json.Number); ok { 49 var err error 50 v, err = jsonNumberToValue(jv) 51 if err != nil { 52 return ErrorValue(err.Error()) 53 } 54 } 55 56 switch v := v.(type) { 57 case float64: 58 return NumberValue(v) 59 case int64: 60 return IntegerValue(v) 61 case string: 62 return StringValue(v) 63 case bool: 64 return BooleanValue(v) 65 case map[string]interface{}: 66 return bindObjectValue(v) 67 default: 68 s := fmt.Sprintf("unable to bind parameter with type %T", v) 69 return ErrorValue(s) 70 } 71 } 72 73 // bindObjectValue will bind an object to a value. 74 func bindObjectValue(m map[string]interface{}) Value { 75 if len(m) != 1 { 76 return ErrorValue("bound object parameter value must have exactly one entry") 77 } 78 79 var ( 80 k string 81 v interface{} 82 ) 83 for k, v = range m { 84 // Nothing done here. 85 } 86 87 if jv, ok := v.(json.Number); ok { 88 var err error 89 v, err = jsonNumberToValue(jv) 90 if err != nil { 91 return ErrorValue(err.Error()) 92 } 93 } 94 95 switch k { 96 case "ident", "identifier": 97 s, ok := v.(string) 98 if !ok { 99 return ErrorValue("identifier must be a string value") 100 } 101 return Identifier(s) 102 case "regex": 103 s, ok := v.(string) 104 if !ok { 105 return ErrorValue("regex literal must be a string value") 106 } 107 return RegexValue(s) 108 case "string": 109 s, ok := v.(string) 110 if !ok { 111 return ErrorValue("string literal must be a string value") 112 } 113 return StringValue(s) 114 case "float", "number": 115 switch f := v.(type) { 116 case float64: 117 return NumberValue(f) 118 case int64: 119 return NumberValue(f) 120 default: 121 return ErrorValue("number literal must be a float value") 122 } 123 case "int", "integer": 124 i, ok := v.(int64) 125 if !ok { 126 return ErrorValue("integer literal must be an integer value") 127 } 128 return IntegerValue(i) 129 case "duration": 130 switch d := v.(type) { 131 case string: 132 return DurationValue(d) 133 case int64: 134 return DurationValue(FormatDuration(time.Duration(d))) 135 default: 136 return ErrorValue("duration literal must be a string or integer value") 137 } 138 default: 139 return ErrorValue(fmt.Sprintf("unknown bind object type: %s", k)) 140 } 141 } 142 143 func (v Identifier) TokenType() Token { return IDENT } 144 func (v Identifier) Value() string { return string(v) } 145 func (v StringValue) TokenType() Token { return STRING } 146 func (v StringValue) Value() string { return string(v) } 147 func (v RegexValue) TokenType() Token { return REGEX } 148 func (v RegexValue) Value() string { return string(v) } 149 func (v NumberValue) TokenType() Token { return NUMBER } 150 func (v NumberValue) Value() string { return strconv.FormatFloat(float64(v), 'f', -1, 64) } 151 func (v IntegerValue) TokenType() Token { return INTEGER } 152 func (v IntegerValue) Value() string { return strconv.FormatInt(int64(v), 10) } 153 func (v BooleanValue) TokenType() Token { 154 if v { 155 return TRUE 156 } else { 157 return FALSE 158 } 159 } 160 func (v BooleanValue) Value() string { return "" } 161 func (v DurationValue) TokenType() Token { return DURATIONVAL } 162 func (v DurationValue) Value() string { return string(v) } 163 func (e ErrorValue) TokenType() Token { return BOUNDPARAM } 164 func (e ErrorValue) Value() string { return string(e) } 165 166 func jsonNumberToValue(v json.Number) (interface{}, error) { 167 if strings.Contains(string(v), ".") { 168 f, err := v.Float64() 169 if err != nil { 170 return nil, err 171 } 172 return f, nil 173 } else { 174 i, err := v.Int64() 175 if err != nil { 176 return nil, err 177 } 178 return i, nil 179 } 180 }