refactor(query/influxql): move transpiler spec tests to its own package

The package contains all of the transpiler specs and allows them to be
put into different files instead of keeping all of the tests in the same
file. They are all Go code so they are type checked rather than being
loaded as JSON from disk.

Additionally, to make it easier for a developer, the tests will report
the exact file and line where the test was created. So rather than
hunting for which file a test is located in, you will get something nice
like the following:

    --- FAIL: TestTranspiler/SELECT_count(value)_FROM_db0..cpu_WHERE_host_=_'server01' (0.00s)
        testing.go:51: aggregates_with_condition.go:16: unexpected error: unimplemented function: "count"

As can be seen, the test that failed can be found in the
`aggregates_with_condition.go` file at line 16 which is where the test
was created by the `AggregateTest` function and the relevant spec can be
found in that same file.
pull/10616/head
Jonathan A. Sternberg 2018-07-06 12:12:08 -05:00
parent 55f0c59eca
commit f694fa9637
11 changed files with 1684 additions and 1468 deletions

View File

@ -0,0 +1,160 @@
package spectests
import (
"fmt"
"path/filepath"
"runtime"
"time"
"github.com/influxdata/influxql"
"github.com/influxdata/platform/query"
"github.com/influxdata/platform/query/ast"
"github.com/influxdata/platform/query/execute"
"github.com/influxdata/platform/query/functions"
"github.com/influxdata/platform/query/semantic"
)
var aggregateCreateFuncs = []func(config execute.AggregateConfig) query.OperationSpec{
func(config execute.AggregateConfig) query.OperationSpec {
return &functions.MeanOpSpec{AggregateConfig: config}
},
}
func AggregateTest(fn func(aggregate query.Operation) (string, *query.Spec)) Fixture {
_, file, line, _ := runtime.Caller(1)
fixture := &collection{
file: filepath.Base(file),
line: line,
}
for _, aggregateSpecFn := range aggregateCreateFuncs {
spec := aggregateSpecFn(execute.AggregateConfig{
TimeSrc: execute.DefaultStartColLabel,
TimeDst: execute.DefaultTimeColLabel,
Columns: []string{execute.DefaultValueColLabel},
})
op := query.Operation{
ID: query.OperationID(fmt.Sprintf("%s0", spec.Kind())),
Spec: spec,
}
fixture.Add(fn(op))
}
return fixture
}
func init() {
RegisterFixture(
AggregateTest(func(aggregate query.Operation) (stmt string, spec *query.Spec) {
return fmt.Sprintf(`SELECT %s(value) FROM db0..cpu`, aggregate.Spec.Kind()),
&query.Spec{
Operations: []*query.Operation{
{
ID: "from0",
Spec: &functions.FromOpSpec{
Bucket: "db0/autogen",
},
},
{
ID: "range0",
Spec: &functions.RangeOpSpec{
Start: query.Time{Absolute: time.Unix(0, influxql.MinTime)},
Stop: query.Time{Absolute: time.Unix(0, influxql.MaxTime)},
},
},
{
ID: "filter0",
Spec: &functions.FilterOpSpec{
Fn: &semantic.FunctionExpression{
Params: []*semantic.FunctionParam{
{Key: &semantic.Identifier{Name: "r"}},
},
Body: &semantic.LogicalExpression{
Operator: ast.AndOperator,
Left: &semantic.BinaryExpression{
Operator: ast.EqualOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_measurement",
},
Right: &semantic.StringLiteral{
Value: "cpu",
},
},
Right: &semantic.BinaryExpression{
Operator: ast.EqualOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_field",
},
Right: &semantic.StringLiteral{
Value: "value",
},
},
},
},
},
},
{
ID: "group0",
Spec: &functions.GroupOpSpec{
By: []string{"_measurement"},
},
},
&aggregate,
{
ID: "map0",
Spec: &functions.MapOpSpec{
Fn: &semantic.FunctionExpression{
Params: []*semantic.FunctionParam{{
Key: &semantic.Identifier{Name: "r"},
}},
Body: &semantic.ObjectExpression{
Properties: []*semantic.Property{
{
Key: &semantic.Identifier{Name: "_time"},
Value: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_time",
},
},
{
Key: &semantic.Identifier{Name: string(aggregate.Spec.Kind())},
Value: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_value",
},
},
},
},
},
MergeKey: true,
},
},
{
ID: "yield0",
Spec: &functions.YieldOpSpec{
Name: "0",
},
},
},
Edges: []query.Edge{
{Parent: "from0", Child: "range0"},
{Parent: "range0", Child: "filter0"},
{Parent: "filter0", Child: "group0"},
{Parent: "group0", Child: aggregate.ID},
{Parent: aggregate.ID, Child: "map0"},
{Parent: "map0", Child: "yield0"},
},
}
}),
)
}

View File

@ -0,0 +1,151 @@
package spectests
import (
"fmt"
"time"
"github.com/influxdata/influxql"
"github.com/influxdata/platform/query"
"github.com/influxdata/platform/query/ast"
"github.com/influxdata/platform/query/functions"
"github.com/influxdata/platform/query/semantic"
)
func init() {
RegisterFixture(
AggregateTest(func(aggregate query.Operation) (stmt string, spec *query.Spec) {
return fmt.Sprintf(`SELECT %s(value) FROM db0..cpu WHERE host = 'server01'`, aggregate.Spec.Kind()),
&query.Spec{
Operations: []*query.Operation{
{
ID: "from0",
Spec: &functions.FromOpSpec{
Bucket: "db0/autogen",
},
},
{
ID: "range0",
Spec: &functions.RangeOpSpec{
Start: query.Time{Absolute: time.Unix(0, influxql.MinTime)},
Stop: query.Time{Absolute: time.Unix(0, influxql.MaxTime)},
},
},
{
ID: "filter0",
Spec: &functions.FilterOpSpec{
Fn: &semantic.FunctionExpression{
Params: []*semantic.FunctionParam{
{Key: &semantic.Identifier{Name: "r"}},
},
Body: &semantic.LogicalExpression{
Operator: ast.AndOperator,
Left: &semantic.BinaryExpression{
Operator: ast.EqualOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_measurement",
},
Right: &semantic.StringLiteral{
Value: "cpu",
},
},
Right: &semantic.BinaryExpression{
Operator: ast.EqualOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_field",
},
Right: &semantic.StringLiteral{
Value: "value",
},
},
},
},
},
},
{
ID: "filter1",
Spec: &functions.FilterOpSpec{
Fn: &semantic.FunctionExpression{
Params: []*semantic.FunctionParam{
{Key: &semantic.Identifier{Name: "r"}},
},
Body: &semantic.BinaryExpression{
Operator: ast.EqualOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "host",
},
Right: &semantic.StringLiteral{
Value: "server01",
},
},
},
},
},
{
ID: "group0",
Spec: &functions.GroupOpSpec{
By: []string{"_measurement"},
},
},
&aggregate,
{
ID: "map0",
Spec: &functions.MapOpSpec{
Fn: &semantic.FunctionExpression{
Params: []*semantic.FunctionParam{{
Key: &semantic.Identifier{Name: "r"},
}},
Body: &semantic.ObjectExpression{
Properties: []*semantic.Property{
{
Key: &semantic.Identifier{Name: "_time"},
Value: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_time",
},
},
{
Key: &semantic.Identifier{Name: string(aggregate.Spec.Kind())},
Value: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_value",
},
},
},
},
},
MergeKey: true,
},
},
{
ID: "yield0",
Spec: &functions.YieldOpSpec{
Name: "0",
},
},
},
Edges: []query.Edge{
{Parent: "from0", Child: "range0"},
{Parent: "range0", Child: "filter0"},
{Parent: "filter0", Child: "filter1"},
{Parent: "filter1", Child: "group0"},
{Parent: "group0", Child: aggregate.ID},
{Parent: aggregate.ID, Child: "map0"},
{Parent: "map0", Child: "yield0"},
},
}
}),
)
}

View File

@ -0,0 +1,128 @@
package spectests
import (
"fmt"
"time"
"github.com/influxdata/influxql"
"github.com/influxdata/platform/query"
"github.com/influxdata/platform/query/ast"
"github.com/influxdata/platform/query/functions"
"github.com/influxdata/platform/query/semantic"
)
func init() {
RegisterFixture(
AggregateTest(func(aggregate query.Operation) (stmt string, spec *query.Spec) {
return fmt.Sprintf(`SELECT %s(value) FROM db0..cpu GROUP BY host`, aggregate.Spec.Kind()),
&query.Spec{
Operations: []*query.Operation{
{
ID: "from0",
Spec: &functions.FromOpSpec{
Bucket: "db0/autogen",
},
},
{
ID: "range0",
Spec: &functions.RangeOpSpec{
Start: query.Time{Absolute: time.Unix(0, influxql.MinTime)},
Stop: query.Time{Absolute: time.Unix(0, influxql.MaxTime)},
},
},
{
ID: "filter0",
Spec: &functions.FilterOpSpec{
Fn: &semantic.FunctionExpression{
Params: []*semantic.FunctionParam{
{Key: &semantic.Identifier{Name: "r"}},
},
Body: &semantic.LogicalExpression{
Operator: ast.AndOperator,
Left: &semantic.BinaryExpression{
Operator: ast.EqualOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_measurement",
},
Right: &semantic.StringLiteral{
Value: "cpu",
},
},
Right: &semantic.BinaryExpression{
Operator: ast.EqualOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_field",
},
Right: &semantic.StringLiteral{
Value: "value",
},
},
},
},
},
},
{
ID: "group0",
Spec: &functions.GroupOpSpec{
By: []string{"_measurement", "host"},
},
},
&aggregate,
{
ID: "map0",
Spec: &functions.MapOpSpec{
Fn: &semantic.FunctionExpression{
Params: []*semantic.FunctionParam{{
Key: &semantic.Identifier{Name: "r"},
}},
Body: &semantic.ObjectExpression{
Properties: []*semantic.Property{
{
Key: &semantic.Identifier{Name: "_time"},
Value: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_time",
},
},
{
Key: &semantic.Identifier{Name: string(aggregate.Spec.Kind())},
Value: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_value",
},
},
},
},
},
MergeKey: true,
},
},
{
ID: "yield0",
Spec: &functions.YieldOpSpec{
Name: "0",
},
},
},
Edges: []query.Edge{
{Parent: "from0", Child: "range0"},
{Parent: "range0", Child: "filter0"},
{Parent: "filter0", Child: "group0"},
{Parent: "group0", Child: aggregate.ID},
{Parent: aggregate.ID, Child: "map0"},
{Parent: "map0", Child: "yield0"},
},
}
}),
)
}

View File

@ -0,0 +1,153 @@
package spectests
import (
"fmt"
"math"
"time"
"github.com/influxdata/platform/query"
"github.com/influxdata/platform/query/ast"
"github.com/influxdata/platform/query/execute"
"github.com/influxdata/platform/query/functions"
"github.com/influxdata/platform/query/semantic"
)
func init() {
RegisterFixture(
AggregateTest(func(aggregate query.Operation) (stmt string, spec *query.Spec) {
return fmt.Sprintf(`SELECT %s(value) FROM db0..cpu WHERE time >= now() - 10m GROUP BY time(1m)`, aggregate.Spec.Kind()),
&query.Spec{
Operations: []*query.Operation{
{
ID: "from0",
Spec: &functions.FromOpSpec{
Bucket: "db0/autogen",
},
},
{
ID: "range0",
Spec: &functions.RangeOpSpec{
Start: query.Time{Absolute: Now().Add(-10 * time.Minute)},
Stop: query.Time{Absolute: Now()},
},
},
{
ID: "filter0",
Spec: &functions.FilterOpSpec{
Fn: &semantic.FunctionExpression{
Params: []*semantic.FunctionParam{
{Key: &semantic.Identifier{Name: "r"}},
},
Body: &semantic.LogicalExpression{
Operator: ast.AndOperator,
Left: &semantic.BinaryExpression{
Operator: ast.EqualOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_measurement",
},
Right: &semantic.StringLiteral{
Value: "cpu",
},
},
Right: &semantic.BinaryExpression{
Operator: ast.EqualOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_field",
},
Right: &semantic.StringLiteral{
Value: "value",
},
},
},
},
},
},
{
ID: "group0",
Spec: &functions.GroupOpSpec{
By: []string{"_measurement"},
},
},
{
ID: "window0",
Spec: &functions.WindowOpSpec{
Every: query.Duration(time.Minute),
Period: query.Duration(time.Minute),
IgnoreGlobalBounds: true,
TimeCol: execute.DefaultTimeColLabel,
StartColLabel: execute.DefaultStartColLabel,
StopColLabel: execute.DefaultStopColLabel,
},
},
&aggregate,
{
ID: "window1",
Spec: &functions.WindowOpSpec{
Every: query.Duration(math.MaxInt64),
Period: query.Duration(math.MaxInt64),
IgnoreGlobalBounds: true,
TimeCol: execute.DefaultTimeColLabel,
StartColLabel: execute.DefaultStartColLabel,
StopColLabel: execute.DefaultStopColLabel,
},
},
{
ID: "map0",
Spec: &functions.MapOpSpec{
Fn: &semantic.FunctionExpression{
Params: []*semantic.FunctionParam{{
Key: &semantic.Identifier{Name: "r"},
}},
Body: &semantic.ObjectExpression{
Properties: []*semantic.Property{
{
Key: &semantic.Identifier{Name: "_time"},
Value: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_time",
},
},
{
Key: &semantic.Identifier{Name: string(aggregate.Spec.Kind())},
Value: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_value",
},
},
},
},
},
MergeKey: true,
},
},
{
ID: "yield0",
Spec: &functions.YieldOpSpec{
Name: "0",
},
},
},
Edges: []query.Edge{
{Parent: "from0", Child: "range0"},
{Parent: "range0", Child: "filter0"},
{Parent: "filter0", Child: "group0"},
{Parent: "group0", Child: "window0"},
{Parent: "window0", Child: aggregate.ID},
{Parent: aggregate.ID, Child: "window1"},
{Parent: "window1", Child: "map0"},
{Parent: "map0", Child: "yield0"},
},
}
}),
)
}

View File

@ -0,0 +1,225 @@
package spectests
import (
"time"
"github.com/influxdata/influxql"
"github.com/influxdata/platform/query"
"github.com/influxdata/platform/query/ast"
"github.com/influxdata/platform/query/functions"
"github.com/influxdata/platform/query/semantic"
)
func init() {
RegisterFixture(
NewFixture(
`SELECT a + b FROM db0..cpu`,
&query.Spec{
Operations: []*query.Operation{
{
ID: "from0",
Spec: &functions.FromOpSpec{
Bucket: "db0/autogen",
},
},
{
ID: "range0",
Spec: &functions.RangeOpSpec{
Start: query.Time{Absolute: time.Unix(0, influxql.MinTime)},
Stop: query.Time{Absolute: time.Unix(0, influxql.MaxTime)},
},
},
{
ID: "filter0",
Spec: &functions.FilterOpSpec{
Fn: &semantic.FunctionExpression{
Params: []*semantic.FunctionParam{
{Key: &semantic.Identifier{Name: "r"}},
},
Body: &semantic.LogicalExpression{
Operator: ast.AndOperator,
Left: &semantic.BinaryExpression{
Operator: ast.EqualOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_measurement",
},
Right: &semantic.StringLiteral{
Value: "cpu",
},
},
Right: &semantic.BinaryExpression{
Operator: ast.EqualOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_field",
},
Right: &semantic.StringLiteral{
Value: "a",
},
},
},
},
},
},
{
ID: "from1",
Spec: &functions.FromOpSpec{
Bucket: "db0/autogen",
},
},
{
ID: "range1",
Spec: &functions.RangeOpSpec{
Start: query.Time{Absolute: time.Unix(0, influxql.MinTime)},
Stop: query.Time{Absolute: time.Unix(0, influxql.MaxTime)},
},
},
{
ID: "filter1",
Spec: &functions.FilterOpSpec{
Fn: &semantic.FunctionExpression{
Params: []*semantic.FunctionParam{
{Key: &semantic.Identifier{Name: "r"}},
},
Body: &semantic.LogicalExpression{
Operator: ast.AndOperator,
Left: &semantic.BinaryExpression{
Operator: ast.EqualOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_measurement",
},
Right: &semantic.StringLiteral{
Value: "cpu",
},
},
Right: &semantic.BinaryExpression{
Operator: ast.EqualOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_field",
},
Right: &semantic.StringLiteral{
Value: "b",
},
},
},
},
},
},
{
ID: "join0",
Spec: &functions.JoinOpSpec{
On: []string{"_measurement"},
Fn: &semantic.FunctionExpression{
Params: []*semantic.FunctionParam{{
Key: &semantic.Identifier{Name: "tables"},
}},
Body: &semantic.ObjectExpression{
Properties: []*semantic.Property{
{
Key: &semantic.Identifier{Name: "val0"},
Value: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "tables",
},
Property: "t0",
},
},
{
Key: &semantic.Identifier{Name: "val1"},
Value: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "tables",
},
Property: "t1",
},
},
},
},
},
TableNames: map[query.OperationID]string{
"filter0": "t0",
"filter1": "t1",
},
},
},
{
ID: "group0",
Spec: &functions.GroupOpSpec{
By: []string{"_measurement"},
},
},
{
ID: "map0",
Spec: &functions.MapOpSpec{
Fn: &semantic.FunctionExpression{
Params: []*semantic.FunctionParam{{
Key: &semantic.Identifier{Name: "r"},
}},
Body: &semantic.ObjectExpression{
Properties: []*semantic.Property{
{
Key: &semantic.Identifier{Name: "_time"},
Value: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_time",
},
},
{
Key: &semantic.Identifier{Name: "a_b"},
Value: &semantic.BinaryExpression{
Operator: ast.AdditionOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "val0",
},
Right: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "val1",
},
},
},
},
},
},
MergeKey: true,
},
},
{
ID: "yield0",
Spec: &functions.YieldOpSpec{
Name: "0",
},
},
},
Edges: []query.Edge{
{Parent: "from0", Child: "range0"},
{Parent: "range0", Child: "filter0"},
{Parent: "from1", Child: "range1"},
{Parent: "range1", Child: "filter1"},
{Parent: "filter0", Child: "join0"},
{Parent: "filter1", Child: "join0"},
{Parent: "join0", Child: "group0"},
{Parent: "group0", Child: "map0"},
{Parent: "map0", Child: "yield0"},
},
},
),
)
}

View File

@ -0,0 +1,253 @@
package spectests
import (
"time"
"github.com/influxdata/influxql"
"github.com/influxdata/platform/query"
"github.com/influxdata/platform/query/ast"
"github.com/influxdata/platform/query/execute"
"github.com/influxdata/platform/query/functions"
"github.com/influxdata/platform/query/semantic"
)
func init() {
RegisterFixture(
NewFixture(
`SELECT mean(value), max(value) FROM db0..cpu`,
&query.Spec{
Operations: []*query.Operation{
{
ID: "from0",
Spec: &functions.FromOpSpec{
Bucket: "db0/autogen",
},
},
{
ID: "range0",
Spec: &functions.RangeOpSpec{
Start: query.Time{Absolute: time.Unix(0, influxql.MinTime)},
Stop: query.Time{Absolute: time.Unix(0, influxql.MaxTime)},
},
},
{
ID: "filter0",
Spec: &functions.FilterOpSpec{
Fn: &semantic.FunctionExpression{
Params: []*semantic.FunctionParam{
{Key: &semantic.Identifier{Name: "r"}},
},
Body: &semantic.LogicalExpression{
Operator: ast.AndOperator,
Left: &semantic.BinaryExpression{
Operator: ast.EqualOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_measurement",
},
Right: &semantic.StringLiteral{
Value: "cpu",
},
},
Right: &semantic.BinaryExpression{
Operator: ast.EqualOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_field",
},
Right: &semantic.StringLiteral{
Value: "value",
},
},
},
},
},
},
{
ID: "group0",
Spec: &functions.GroupOpSpec{
By: []string{"_measurement"},
},
},
{
ID: "mean0",
Spec: &functions.MeanOpSpec{
AggregateConfig: execute.AggregateConfig{
TimeSrc: execute.DefaultStartColLabel,
TimeDst: execute.DefaultTimeColLabel,
Columns: []string{execute.DefaultValueColLabel},
},
},
},
{
ID: "from1",
Spec: &functions.FromOpSpec{
Bucket: "db0/autogen",
},
},
{
ID: "range1",
Spec: &functions.RangeOpSpec{
Start: query.Time{Absolute: time.Unix(0, influxql.MinTime)},
Stop: query.Time{Absolute: time.Unix(0, influxql.MaxTime)},
},
},
{
ID: "filter1",
Spec: &functions.FilterOpSpec{
Fn: &semantic.FunctionExpression{
Params: []*semantic.FunctionParam{
{Key: &semantic.Identifier{Name: "r"}},
},
Body: &semantic.LogicalExpression{
Operator: ast.AndOperator,
Left: &semantic.BinaryExpression{
Operator: ast.EqualOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_measurement",
},
Right: &semantic.StringLiteral{
Value: "cpu",
},
},
Right: &semantic.BinaryExpression{
Operator: ast.EqualOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_field",
},
Right: &semantic.StringLiteral{
Value: "value",
},
},
},
},
},
},
{
ID: "group1",
Spec: &functions.GroupOpSpec{
By: []string{"_measurement"},
},
},
{
ID: "max0",
Spec: &functions.MaxOpSpec{
SelectorConfig: execute.SelectorConfig{
Column: execute.DefaultValueColLabel,
},
},
},
{
ID: "join0",
Spec: &functions.JoinOpSpec{
On: []string{"_measurement"},
Fn: &semantic.FunctionExpression{
Params: []*semantic.FunctionParam{{
Key: &semantic.Identifier{Name: "tables"},
}},
Body: &semantic.ObjectExpression{
Properties: []*semantic.Property{
{
Key: &semantic.Identifier{Name: "val0"},
Value: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "tables",
},
Property: "t0",
},
},
{
Key: &semantic.Identifier{Name: "val1"},
Value: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "tables",
},
Property: "t1",
},
},
},
},
},
TableNames: map[query.OperationID]string{
"mean0": "t0",
"max0": "t1",
},
},
},
{
ID: "map0",
Spec: &functions.MapOpSpec{
Fn: &semantic.FunctionExpression{
Params: []*semantic.FunctionParam{{
Key: &semantic.Identifier{Name: "r"},
}},
Body: &semantic.ObjectExpression{
Properties: []*semantic.Property{
{
Key: &semantic.Identifier{Name: "_time"},
Value: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_time",
},
},
{
Key: &semantic.Identifier{Name: "mean"},
Value: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "val0",
},
},
{
Key: &semantic.Identifier{Name: "max"},
Value: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "val1",
},
},
},
},
},
MergeKey: true,
},
},
{
ID: "yield0",
Spec: &functions.YieldOpSpec{
Name: "0",
},
},
},
Edges: []query.Edge{
{Parent: "from0", Child: "range0"},
{Parent: "range0", Child: "filter0"},
{Parent: "filter0", Child: "group0"},
{Parent: "group0", Child: "mean0"},
{Parent: "from1", Child: "range1"},
{Parent: "range1", Child: "filter1"},
{Parent: "filter1", Child: "group1"},
{Parent: "group1", Child: "max0"},
{Parent: "mean0", Child: "join0"},
{Parent: "max0", Child: "join0"},
{Parent: "join0", Child: "map0"},
{Parent: "map0", Child: "yield0"},
},
},
),
)
}

View File

@ -0,0 +1,246 @@
package spectests
import (
"time"
"github.com/influxdata/influxql"
"github.com/influxdata/platform/query"
"github.com/influxdata/platform/query/ast"
"github.com/influxdata/platform/query/execute"
"github.com/influxdata/platform/query/functions"
"github.com/influxdata/platform/query/semantic"
)
func init() {
RegisterFixture(
NewFixture(
`SELECT mean(value) FROM db0..cpu; SELECT max(value) FROM db0..cpu`,
&query.Spec{
Operations: []*query.Operation{
{
ID: "from0",
Spec: &functions.FromOpSpec{
Bucket: "db0/autogen",
},
},
{
ID: "range0",
Spec: &functions.RangeOpSpec{
Start: query.Time{Absolute: time.Unix(0, influxql.MinTime)},
Stop: query.Time{Absolute: time.Unix(0, influxql.MaxTime)},
},
},
{
ID: "filter0",
Spec: &functions.FilterOpSpec{
Fn: &semantic.FunctionExpression{
Params: []*semantic.FunctionParam{
{Key: &semantic.Identifier{Name: "r"}},
},
Body: &semantic.LogicalExpression{
Operator: ast.AndOperator,
Left: &semantic.BinaryExpression{
Operator: ast.EqualOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_measurement",
},
Right: &semantic.StringLiteral{
Value: "cpu",
},
},
Right: &semantic.BinaryExpression{
Operator: ast.EqualOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_field",
},
Right: &semantic.StringLiteral{
Value: "value",
},
},
},
},
},
},
{
ID: "group0",
Spec: &functions.GroupOpSpec{
By: []string{"_measurement"},
},
},
{
ID: "mean0",
Spec: &functions.MeanOpSpec{
AggregateConfig: execute.AggregateConfig{
TimeSrc: execute.DefaultStartColLabel,
TimeDst: execute.DefaultTimeColLabel,
Columns: []string{execute.DefaultValueColLabel},
},
},
},
{
ID: "map0",
Spec: &functions.MapOpSpec{
Fn: &semantic.FunctionExpression{
Params: []*semantic.FunctionParam{{
Key: &semantic.Identifier{Name: "r"},
}},
Body: &semantic.ObjectExpression{
Properties: []*semantic.Property{
{
Key: &semantic.Identifier{Name: "_time"},
Value: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_time",
},
},
{
Key: &semantic.Identifier{Name: "mean"},
Value: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_value",
},
},
},
},
},
MergeKey: true,
},
},
{
ID: "yield0",
Spec: &functions.YieldOpSpec{
Name: "0",
},
},
{
ID: "from1",
Spec: &functions.FromOpSpec{
Bucket: "db0/autogen",
},
},
{
ID: "range1",
Spec: &functions.RangeOpSpec{
Start: query.Time{Absolute: time.Unix(0, influxql.MinTime)},
Stop: query.Time{Absolute: time.Unix(0, influxql.MaxTime)},
},
},
{
ID: "filter1",
Spec: &functions.FilterOpSpec{
Fn: &semantic.FunctionExpression{
Params: []*semantic.FunctionParam{
{Key: &semantic.Identifier{Name: "r"}},
},
Body: &semantic.LogicalExpression{
Operator: ast.AndOperator,
Left: &semantic.BinaryExpression{
Operator: ast.EqualOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_measurement",
},
Right: &semantic.StringLiteral{
Value: "cpu",
},
},
Right: &semantic.BinaryExpression{
Operator: ast.EqualOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_field",
},
Right: &semantic.StringLiteral{
Value: "value",
},
},
},
},
},
},
{
ID: "group1",
Spec: &functions.GroupOpSpec{
By: []string{"_measurement"},
},
},
{
ID: "max0",
Spec: &functions.MaxOpSpec{
SelectorConfig: execute.SelectorConfig{
Column: execute.DefaultValueColLabel,
},
},
},
{
ID: "map1",
Spec: &functions.MapOpSpec{
Fn: &semantic.FunctionExpression{
Params: []*semantic.FunctionParam{{
Key: &semantic.Identifier{Name: "r"},
}},
Body: &semantic.ObjectExpression{
Properties: []*semantic.Property{
{
Key: &semantic.Identifier{Name: "_time"},
Value: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_time",
},
},
{
Key: &semantic.Identifier{Name: "max"},
Value: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_value",
},
},
},
},
},
MergeKey: true,
},
},
{
ID: "yield1",
Spec: &functions.YieldOpSpec{
Name: "1",
},
},
},
Edges: []query.Edge{
{Parent: "from0", Child: "range0"},
{Parent: "range0", Child: "filter0"},
{Parent: "filter0", Child: "group0"},
{Parent: "group0", Child: "mean0"},
{Parent: "mean0", Child: "map0"},
{Parent: "map0", Child: "yield0"},
{Parent: "from1", Child: "range1"},
{Parent: "range1", Child: "filter1"},
{Parent: "filter1", Child: "group1"},
{Parent: "group1", Child: "max0"},
{Parent: "max0", Child: "map1"},
{Parent: "map1", Child: "yield1"},
},
},
),
)
}

View File

@ -0,0 +1,125 @@
package spectests
import (
"time"
"github.com/influxdata/influxql"
"github.com/influxdata/platform/query"
"github.com/influxdata/platform/query/ast"
"github.com/influxdata/platform/query/functions"
"github.com/influxdata/platform/query/semantic"
)
func init() {
RegisterFixture(
NewFixture(
`SELECT value FROM db0..cpu`,
&query.Spec{
Operations: []*query.Operation{
{
ID: "from0",
Spec: &functions.FromOpSpec{
Bucket: "db0/autogen",
},
},
{
ID: "range0",
Spec: &functions.RangeOpSpec{
Start: query.Time{Absolute: time.Unix(0, influxql.MinTime)},
Stop: query.Time{Absolute: time.Unix(0, influxql.MaxTime)},
},
},
{
ID: "filter0",
Spec: &functions.FilterOpSpec{
Fn: &semantic.FunctionExpression{
Params: []*semantic.FunctionParam{
{Key: &semantic.Identifier{Name: "r"}},
},
Body: &semantic.LogicalExpression{
Operator: ast.AndOperator,
Left: &semantic.BinaryExpression{
Operator: ast.EqualOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_measurement",
},
Right: &semantic.StringLiteral{
Value: "cpu",
},
},
Right: &semantic.BinaryExpression{
Operator: ast.EqualOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_field",
},
Right: &semantic.StringLiteral{
Value: "value",
},
},
},
},
},
},
{
ID: "group0",
Spec: &functions.GroupOpSpec{
By: []string{"_measurement"},
},
},
{
ID: "map0",
Spec: &functions.MapOpSpec{
Fn: &semantic.FunctionExpression{
Params: []*semantic.FunctionParam{{
Key: &semantic.Identifier{Name: "r"},
}},
Body: &semantic.ObjectExpression{
Properties: []*semantic.Property{
{
Key: &semantic.Identifier{Name: "_time"},
Value: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_time",
},
},
{
Key: &semantic.Identifier{Name: "value"},
Value: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_value",
},
},
},
},
},
MergeKey: true,
},
},
{
ID: "yield0",
Spec: &functions.YieldOpSpec{
Name: "0",
},
},
},
Edges: []query.Edge{
{Parent: "from0", Child: "range0"},
{Parent: "range0", Child: "filter0"},
{Parent: "filter0", Child: "group0"},
{Parent: "group0", Child: "map0"},
{Parent: "map0", Child: "yield0"},
},
},
),
)
}

View File

@ -0,0 +1,125 @@
package spectests
import (
"time"
"github.com/influxdata/influxql"
"github.com/influxdata/platform/query"
"github.com/influxdata/platform/query/ast"
"github.com/influxdata/platform/query/functions"
"github.com/influxdata/platform/query/semantic"
)
func init() {
RegisterFixture(
NewFixture(
`SELECT value FROM db0.alternate.cpu`,
&query.Spec{
Operations: []*query.Operation{
{
ID: "from0",
Spec: &functions.FromOpSpec{
Bucket: "db0/alternate",
},
},
{
ID: "range0",
Spec: &functions.RangeOpSpec{
Start: query.Time{Absolute: time.Unix(0, influxql.MinTime)},
Stop: query.Time{Absolute: time.Unix(0, influxql.MaxTime)},
},
},
{
ID: "filter0",
Spec: &functions.FilterOpSpec{
Fn: &semantic.FunctionExpression{
Params: []*semantic.FunctionParam{
{Key: &semantic.Identifier{Name: "r"}},
},
Body: &semantic.LogicalExpression{
Operator: ast.AndOperator,
Left: &semantic.BinaryExpression{
Operator: ast.EqualOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_measurement",
},
Right: &semantic.StringLiteral{
Value: "cpu",
},
},
Right: &semantic.BinaryExpression{
Operator: ast.EqualOperator,
Left: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_field",
},
Right: &semantic.StringLiteral{
Value: "value",
},
},
},
},
},
},
{
ID: "group0",
Spec: &functions.GroupOpSpec{
By: []string{"_measurement"},
},
},
{
ID: "map0",
Spec: &functions.MapOpSpec{
Fn: &semantic.FunctionExpression{
Params: []*semantic.FunctionParam{{
Key: &semantic.Identifier{Name: "r"},
}},
Body: &semantic.ObjectExpression{
Properties: []*semantic.Property{
{
Key: &semantic.Identifier{Name: "_time"},
Value: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_time",
},
},
{
Key: &semantic.Identifier{Name: "value"},
Value: &semantic.MemberExpression{
Object: &semantic.IdentifierExpression{
Name: "r",
},
Property: "_value",
},
},
},
},
},
MergeKey: true,
},
},
{
ID: "yield0",
Spec: &functions.YieldOpSpec{
Name: "0",
},
},
},
Edges: []query.Edge{
{Parent: "from0", Child: "range0"},
{Parent: "range0", Child: "filter0"},
{Parent: "filter0", Child: "group0"},
{Parent: "group0", Child: "map0"},
{Parent: "map0", Child: "yield0"},
},
},
),
)
}

View File

@ -0,0 +1,115 @@
package spectests
import (
"bytes"
"context"
"encoding/json"
"path/filepath"
"runtime"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/influxdata/platform/query"
"github.com/influxdata/platform/query/influxql"
)
// Fixture is a structure that will run tests.
type Fixture interface {
Run(t *testing.T)
}
type fixture struct {
stmt string
spec *query.Spec
file string
line int
}
func NewFixture(stmt string, spec *query.Spec) Fixture {
_, file, line, _ := runtime.Caller(1)
return &fixture{
stmt: stmt,
spec: spec,
file: filepath.Base(file),
line: line,
}
}
func (f *fixture) Run(t *testing.T) {
t.Run(f.stmt, func(t *testing.T) {
if err := f.spec.Validate(); err != nil {
t.Fatalf("%s:%d: expected spec is not valid: %s", f.file, f.line, err)
}
transpiler := influxql.NewTranspilerWithConfig(influxql.Config{
NowFn: Now,
})
spec, err := transpiler.Transpile(context.Background(), f.stmt)
if err != nil {
t.Fatalf("%s:%d: unexpected error: %s", f.file, f.line, err)
} else if err := spec.Validate(); err != nil {
t.Fatalf("%s:%d: spec is not valid: %s", f.file, f.line, err)
}
// Encode both of these to JSON and compare the results.
exp, _ := json.Marshal(f.spec)
got, _ := json.Marshal(spec)
if !bytes.Equal(exp, got) {
// Unmarshal into objects so we can compare the key/value pairs.
var expObj, gotObj interface{}
json.Unmarshal(exp, &expObj)
json.Unmarshal(got, &gotObj)
// If there is no diff, then they were trivial byte differences and
// there is no error.
if diff := cmp.Diff(expObj, gotObj); diff != "" {
t.Fatalf("unexpected spec in test at %s:%d\n%s", f.file, f.line, diff)
}
}
})
}
type collection struct {
stmts []string
specs []*query.Spec
file string
line int
}
func (c *collection) Add(stmt string, spec *query.Spec) {
c.stmts = append(c.stmts, stmt)
c.specs = append(c.specs, spec)
}
func (c *collection) Run(t *testing.T) {
for i, stmt := range c.stmts {
f := fixture{
stmt: stmt,
spec: c.specs[i],
file: c.file,
line: c.line,
}
f.Run(t)
}
}
var allFixtures []Fixture
func RegisterFixture(fixtures ...Fixture) {
allFixtures = append(allFixtures, fixtures...)
}
func All() []Fixture {
return allFixtures
}
func Now() time.Time {
t, err := time.Parse(time.RFC3339, "2010-09-15T09:00:00Z")
if err != nil {
panic(err)
}
return t
}

File diff suppressed because it is too large Load Diff