mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-07-05 13:14:39 +08:00
181 lines
4.2 KiB
Go
181 lines
4.2 KiB
Go
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
|
|
}
|
|
}
|