Merge pull request #5732 from influxdata/js-5730-binary-expr-column-name

Assign a name to columns with binary expressions in them
pull/5745/head
Jonathan A. Sternberg 2016-02-19 14:30:43 -05:00
commit 8fc6a0f648
3 changed files with 72 additions and 23 deletions

View File

@ -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]]}]}]}`,
},
}...)

View File

@ -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

View File

@ -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)
}
}