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