Merge pull request #5732 from influxdata/js-5730-binary-expr-column-name
Assign a name to columns with binary expressions in thempull/5745/head
commit
8fc6a0f648
|
@ -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]]}]}]}`,
|
||||
},
|
||||
}...)
|
||||
|
||||
|
|
|
@ -2642,6 +2642,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
|
||||
}
|
||||
|
@ -2922,6 +2927,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