Assign a name to columns with binary expressions in them
The name of the column will be every measurement located inside of the math expression in the order they are encountered in within the expression. Also handle `*influxql.ParenExpr` in the function `(*influxql.Field).Name()` Fixes #5730.pull/5732/head
parent
7479584afd
commit
983f810539
|
@ -807,37 +807,37 @@ func TestServer_Query_Math(t *testing.T) {
|
|||
&Query{
|
||||
name: "SELECT multiple of float value",
|
||||
command: `SELECT value * 2 from db.rp.float`,
|
||||
exp: fmt.Sprintf(`{"results":[{"series":[{"name":"float","columns":["time",""],"values":[["%s",84]]}]}]}`, now.Format(time.RFC3339Nano)),
|
||||
exp: fmt.Sprintf(`{"results":[{"series":[{"name":"float","columns":["time","value"],"values":[["%s",84]]}]}]}`, now.Format(time.RFC3339Nano)),
|
||||
},
|
||||
&Query{
|
||||
name: "SELECT multiple of float value",
|
||||
command: `SELECT 2 * value from db.rp.float`,
|
||||
exp: fmt.Sprintf(`{"results":[{"series":[{"name":"float","columns":["time",""],"values":[["%s",84]]}]}]}`, now.Format(time.RFC3339Nano)),
|
||||
exp: fmt.Sprintf(`{"results":[{"series":[{"name":"float","columns":["time","value"],"values":[["%s",84]]}]}]}`, now.Format(time.RFC3339Nano)),
|
||||
},
|
||||
&Query{
|
||||
name: "SELECT multiple of integer value",
|
||||
command: `SELECT value * 2 from db.rp.integer`,
|
||||
exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time",""],"values":[["%s",84]]}]}]}`, now.Format(time.RFC3339Nano)),
|
||||
exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time","value"],"values":[["%s",84]]}]}]}`, now.Format(time.RFC3339Nano)),
|
||||
},
|
||||
&Query{
|
||||
name: "SELECT float multiple of integer value",
|
||||
command: `SELECT value * 2.0 from db.rp.integer`,
|
||||
exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time",""],"values":[["%s",84]]}]}]}`, now.Format(time.RFC3339Nano)),
|
||||
exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time","value"],"values":[["%s",84]]}]}]}`, now.Format(time.RFC3339Nano)),
|
||||
},
|
||||
&Query{
|
||||
name: "SELECT square of float value",
|
||||
command: `SELECT value * value from db.rp.float`,
|
||||
exp: fmt.Sprintf(`{"results":[{"series":[{"name":"float","columns":["time",""],"values":[["%s",1764]]}]}]}`, now.Format(time.RFC3339Nano)),
|
||||
exp: fmt.Sprintf(`{"results":[{"series":[{"name":"float","columns":["time","value_value"],"values":[["%s",1764]]}]}]}`, now.Format(time.RFC3339Nano)),
|
||||
},
|
||||
&Query{
|
||||
name: "SELECT square of integer value",
|
||||
command: `SELECT value * value from db.rp.integer`,
|
||||
exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time",""],"values":[["%s",1764]]}]}]}`, now.Format(time.RFC3339Nano)),
|
||||
exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time","value_value"],"values":[["%s",1764]]}]}]}`, now.Format(time.RFC3339Nano)),
|
||||
},
|
||||
&Query{
|
||||
name: "SELECT square of integer, float value",
|
||||
command: `SELECT value * value,float from db.rp.integer`,
|
||||
exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time","","float"],"values":[["%s",1764,null]]}]}]}`, now.Format(time.RFC3339Nano)),
|
||||
exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time","value_value","float"],"values":[["%s",1764,null]]}]}]}`, now.Format(time.RFC3339Nano)),
|
||||
},
|
||||
&Query{
|
||||
name: "SELECT square of integer value with alias",
|
||||
|
@ -847,17 +847,17 @@ func TestServer_Query_Math(t *testing.T) {
|
|||
&Query{
|
||||
name: "SELECT sum of aggregates",
|
||||
command: `SELECT max(value) + min(value) from db.rp.integer`,
|
||||
exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time",""],"values":[["1970-01-01T00:00:00Z",84]]}]}]}`),
|
||||
exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time","max_min"],"values":[["1970-01-01T00:00:00Z",84]]}]}]}`),
|
||||
},
|
||||
&Query{
|
||||
name: "SELECT square of enclosed integer value",
|
||||
command: `SELECT ((value) * (value)) from db.rp.integer`,
|
||||
exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time",""],"values":[["%s",1764]]}]}]}`, now.Format(time.RFC3339Nano)),
|
||||
exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time","value_value"],"values":[["%s",1764]]}]}]}`, now.Format(time.RFC3339Nano)),
|
||||
},
|
||||
&Query{
|
||||
name: "SELECT square of enclosed integer value",
|
||||
command: `SELECT (value * value) from db.rp.integer`,
|
||||
exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time",""],"values":[["%s",1764]]}]}]}`, now.Format(time.RFC3339Nano)),
|
||||
exp: fmt.Sprintf(`{"results":[{"series":[{"name":"integer","columns":["time","value_value"],"values":[["%s",1764]]}]}]}`, now.Format(time.RFC3339Nano)),
|
||||
},
|
||||
}...)
|
||||
|
||||
|
@ -2871,13 +2871,13 @@ func TestServer_Query_Aggregates_Load(t *testing.T) {
|
|||
name: "group by multiple dimensions",
|
||||
params: url.Values{"db": []string{"db0"}},
|
||||
command: `SELECT sum(value)*2 FROM load`,
|
||||
exp: `{"results":[{"series":[{"name":"load","columns":["time",""],"values":[["1970-01-01T00:00:00Z",300]]}]}]}`,
|
||||
exp: `{"results":[{"series":[{"name":"load","columns":["time","sum"],"values":[["1970-01-01T00:00:00Z",300]]}]}]}`,
|
||||
},
|
||||
&Query{
|
||||
name: "group by multiple dimensions",
|
||||
params: url.Values{"db": []string{"db0"}},
|
||||
command: `SELECT sum(value)/2 FROM load`,
|
||||
exp: `{"results":[{"series":[{"name":"load","columns":["time",""],"values":[["1970-01-01T00:00:00Z",75]]}]}]}`,
|
||||
exp: `{"results":[{"series":[{"name":"load","columns":["time","sum"],"values":[["1970-01-01T00:00:00Z",75]]}]}]}`,
|
||||
},
|
||||
}...)
|
||||
|
||||
|
|
|
@ -2639,6 +2639,11 @@ func (f *Field) Name() string {
|
|||
switch expr := f.Expr.(type) {
|
||||
case *Call:
|
||||
return expr.Name
|
||||
case *BinaryExpr:
|
||||
return BinaryExprName(expr)
|
||||
case *ParenExpr:
|
||||
f := Field{Expr: expr.Expr}
|
||||
return f.Name()
|
||||
case *VarRef:
|
||||
return expr.Val
|
||||
}
|
||||
|
@ -2919,6 +2924,27 @@ func (e *BinaryExpr) String() string {
|
|||
return fmt.Sprintf("%s %s %s", e.LHS.String(), e.Op.String(), e.RHS.String())
|
||||
}
|
||||
|
||||
func BinaryExprName(expr *BinaryExpr) string {
|
||||
v := binaryExprNameVisitor{}
|
||||
Walk(&v, expr)
|
||||
return strings.Join(v.names, "_")
|
||||
}
|
||||
|
||||
type binaryExprNameVisitor struct {
|
||||
names []string
|
||||
}
|
||||
|
||||
func (v *binaryExprNameVisitor) Visit(n Node) Visitor {
|
||||
switch n := n.(type) {
|
||||
case *VarRef:
|
||||
v.names = append(v.names, n.Val)
|
||||
case *Call:
|
||||
v.names = append(v.names, n.Name)
|
||||
return nil
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// ParenExpr represents a parenthesized expression.
|
||||
type ParenExpr struct {
|
||||
Expr Expr
|
||||
|
|
|
@ -717,6 +717,29 @@ func TestSelectStatement_HasCountDistinct(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Ensure binary expression names can be evaluated.
|
||||
func TestBinaryExprName(t *testing.T) {
|
||||
for i, tt := range []struct {
|
||||
expr string
|
||||
name string
|
||||
}{
|
||||
{expr: `value + 1`, name: `value`},
|
||||
{expr: `"user" / total`, name: `user_total`},
|
||||
{expr: `("user" + total) / total`, name: `user_total_total`},
|
||||
} {
|
||||
expr := influxql.MustParseExpr(tt.expr)
|
||||
switch expr := expr.(type) {
|
||||
case *influxql.BinaryExpr:
|
||||
name := influxql.BinaryExprName(expr)
|
||||
if name != tt.name {
|
||||
t.Errorf("%d. unexpected name %s, got %s", i, name, tt.name)
|
||||
}
|
||||
default:
|
||||
t.Errorf("%d. unexpected expr type: %T", i, expr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the time range of an expression can be extracted.
|
||||
func TestTimeRange(t *testing.T) {
|
||||
for i, tt := range []struct {
|
||||
|
@ -1070,12 +1093,12 @@ func Test_fieldsNames(t *testing.T) {
|
|||
{ //case: binary expr(valRef)
|
||||
in: []string{"value+value"},
|
||||
out: []string{"value", "value"},
|
||||
alias: []string{""},
|
||||
alias: []string{"value_value"},
|
||||
},
|
||||
{ //case: binary expr + valRef
|
||||
in: []string{"value+value", "temperature"},
|
||||
out: []string{"value", "value", "temperature"},
|
||||
alias: []string{"", "temperature"},
|
||||
alias: []string{"value_value", "temperature"},
|
||||
},
|
||||
{ //case: aggregate expr
|
||||
in: []string{"mean(value)"},
|
||||
|
@ -1085,37 +1108,37 @@ func Test_fieldsNames(t *testing.T) {
|
|||
{ //case: binary expr(aggregate expr)
|
||||
in: []string{"mean(value) + max(value)"},
|
||||
out: []string{"value", "value"},
|
||||
alias: []string{""},
|
||||
alias: []string{"mean_max"},
|
||||
},
|
||||
{ //case: binary expr(aggregate expr) + valRef
|
||||
in: []string{"mean(value) + max(value)", "temperature"},
|
||||
out: []string{"value", "value", "temperature"},
|
||||
alias: []string{"", "temperature"},
|
||||
alias: []string{"mean_max", "temperature"},
|
||||
},
|
||||
{ //case: mixed aggregate and varRef
|
||||
in: []string{"mean(value) + temperature"},
|
||||
out: []string{"value", "temperature"},
|
||||
alias: []string{""},
|
||||
alias: []string{"mean_temperature"},
|
||||
},
|
||||
{ //case: ParenExpr(varRef)
|
||||
in: []string{"(value)"},
|
||||
out: []string{"value"},
|
||||
alias: []string{""},
|
||||
alias: []string{"value"},
|
||||
},
|
||||
{ //case: ParenExpr(varRef + varRef)
|
||||
in: []string{"(value + value)"},
|
||||
out: []string{"value", "value"},
|
||||
alias: []string{""},
|
||||
alias: []string{"value_value"},
|
||||
},
|
||||
{ //case: ParenExpr(aggregate)
|
||||
in: []string{"(mean(value))"},
|
||||
out: []string{"value"},
|
||||
alias: []string{""},
|
||||
alias: []string{"mean"},
|
||||
},
|
||||
{ //case: ParenExpr(aggregate + aggregate)
|
||||
in: []string{"(mean(value) + max(value))"},
|
||||
out: []string{"value", "value"},
|
||||
alias: []string{""},
|
||||
alias: []string{"mean_max"},
|
||||
},
|
||||
} {
|
||||
fields := influxql.Fields{}
|
||||
|
@ -1125,11 +1148,11 @@ func Test_fieldsNames(t *testing.T) {
|
|||
}
|
||||
got := fields.Names()
|
||||
if !reflect.DeepEqual(got, test.out) {
|
||||
t.Errorf("get fileds name:\nexp=%v\ngot=%v\n", test.out, got)
|
||||
t.Errorf("get fields name:\nexp=%v\ngot=%v\n", test.out, got)
|
||||
}
|
||||
alias := fields.AliasNames()
|
||||
if !reflect.DeepEqual(alias, test.alias) {
|
||||
t.Errorf("get fileds alias name:\nexp=%v\ngot=%v\n", test.alias, alias)
|
||||
t.Errorf("get fields alias name:\nexp=%v\ngot=%v\n", test.alias, alias)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue