mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
Refactor query tests
This commit refactors the query package tests to use the standard library testing package instead of goconvey. Goconvey is now completely removed from the repository.
This commit is contained in:
parent
ad0b37d0f1
commit
894ae3598f
6 changed files with 715 additions and 591 deletions
|
|
@ -14,11 +14,6 @@
|
|||
"version": "master",
|
||||
"type": "git"
|
||||
},
|
||||
"goconvey": {
|
||||
"repo": "github.com/smartystreets/goconvey",
|
||||
"version": "master",
|
||||
"type": "git"
|
||||
},
|
||||
"gocql": {
|
||||
"repo": "github.com/gocql/gocql",
|
||||
"version": "f8fb76bb772442ea938e4be46ab1666e542411a5",
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestStorage(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -1,213 +1,279 @@
|
|||
package query
|
||||
package query_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/umbel/pilosa/query"
|
||||
)
|
||||
|
||||
func TestLexer(t *testing.T) {
|
||||
Convey("Basic lexical analysis", t, func() {
|
||||
var tokens []Token
|
||||
var err error
|
||||
|
||||
tokens, err = Lex("get(10)")
|
||||
So(err, ShouldBeNil)
|
||||
So(len(tokens), ShouldEqual, 4)
|
||||
So(tokens, ShouldResemble, []Token{
|
||||
{"get", TYPE_FUNC},
|
||||
{"(", TYPE_LP},
|
||||
{"10", TYPE_VALUE},
|
||||
{")", TYPE_RP},
|
||||
})
|
||||
|
||||
tokens, err = Lex("get(id=10)")
|
||||
So(err, ShouldBeNil)
|
||||
So(tokens, ShouldResemble, []Token{
|
||||
{"get", TYPE_FUNC},
|
||||
{"(", TYPE_LP},
|
||||
{"id", TYPE_KEYWORD},
|
||||
{"=", TYPE_EQUALS},
|
||||
{"10", TYPE_VALUE},
|
||||
{")", TYPE_RP},
|
||||
})
|
||||
|
||||
tokens, err = Lex("get(id=10, frame=brand)")
|
||||
So(err, ShouldBeNil)
|
||||
So(tokens, ShouldResemble, []Token{
|
||||
{"get", TYPE_FUNC},
|
||||
{"(", TYPE_LP},
|
||||
{"id", TYPE_KEYWORD},
|
||||
{"=", TYPE_EQUALS},
|
||||
{"10", TYPE_VALUE},
|
||||
{",", TYPE_COMMA},
|
||||
{"frame", TYPE_KEYWORD},
|
||||
{"=", TYPE_EQUALS},
|
||||
{"brand", TYPE_VALUE},
|
||||
{")", TYPE_RP},
|
||||
})
|
||||
|
||||
tokens, err = Lex("union(get(10))")
|
||||
So(err, ShouldBeNil)
|
||||
So(tokens, ShouldResemble, []Token{
|
||||
{"union", TYPE_FUNC},
|
||||
{"(", TYPE_LP},
|
||||
{"get", TYPE_FUNC},
|
||||
{"(", TYPE_LP},
|
||||
{"10", TYPE_VALUE},
|
||||
{")", TYPE_RP},
|
||||
{")", TYPE_RP},
|
||||
})
|
||||
|
||||
tokens, err = Lex("intersect(get(10), get(11), get(12))")
|
||||
So(err, ShouldBeNil)
|
||||
So(tokens, ShouldResemble, []Token{
|
||||
{"intersect", TYPE_FUNC},
|
||||
{"(", TYPE_LP},
|
||||
{"get", TYPE_FUNC},
|
||||
{"(", TYPE_LP},
|
||||
{"10", TYPE_VALUE},
|
||||
{")", TYPE_RP},
|
||||
{",", TYPE_COMMA},
|
||||
{"get", TYPE_FUNC},
|
||||
{"(", TYPE_LP},
|
||||
{"11", TYPE_VALUE},
|
||||
{")", TYPE_RP},
|
||||
{",", TYPE_COMMA},
|
||||
{"get", TYPE_FUNC},
|
||||
{"(", TYPE_LP},
|
||||
{"12", TYPE_VALUE},
|
||||
{")", TYPE_RP},
|
||||
{")", TYPE_RP},
|
||||
})
|
||||
|
||||
tokens, err = Lex("intersect(get(10), get(11), concat(get(12),get(14)))")
|
||||
So(err, ShouldBeNil)
|
||||
So(tokens, ShouldResemble, []Token{
|
||||
{"intersect", TYPE_FUNC},
|
||||
{"(", TYPE_LP},
|
||||
{"get", TYPE_FUNC},
|
||||
{"(", TYPE_LP},
|
||||
{"10", TYPE_VALUE},
|
||||
{")", TYPE_RP},
|
||||
{",", TYPE_COMMA},
|
||||
{"get", TYPE_FUNC},
|
||||
{"(", TYPE_LP},
|
||||
{"11", TYPE_VALUE},
|
||||
{")", TYPE_RP},
|
||||
{",", TYPE_COMMA},
|
||||
{"concat", TYPE_FUNC},
|
||||
{"(", TYPE_LP},
|
||||
{"get", TYPE_FUNC},
|
||||
{"(", TYPE_LP},
|
||||
{"12", TYPE_VALUE},
|
||||
{")", TYPE_RP},
|
||||
{",", TYPE_COMMA},
|
||||
{"get", TYPE_FUNC},
|
||||
{"(", TYPE_LP},
|
||||
{"14", TYPE_VALUE},
|
||||
{")", TYPE_RP},
|
||||
{")", TYPE_RP},
|
||||
{")", TYPE_RP},
|
||||
})
|
||||
|
||||
tokens, err = Lex("concat(get(1, brand),get(2))")
|
||||
So(err, ShouldBeNil)
|
||||
So(tokens, ShouldResemble, []Token{
|
||||
{"concat", TYPE_FUNC},
|
||||
{"(", TYPE_LP},
|
||||
{"get", TYPE_FUNC},
|
||||
{"(", TYPE_LP},
|
||||
{"1", TYPE_VALUE},
|
||||
{",", TYPE_COMMA},
|
||||
{"brand", TYPE_VALUE},
|
||||
{")", TYPE_RP},
|
||||
{",", TYPE_COMMA},
|
||||
{"get", TYPE_FUNC},
|
||||
{"(", TYPE_LP},
|
||||
{"2", TYPE_VALUE},
|
||||
{")", TYPE_RP},
|
||||
{")", TYPE_RP},
|
||||
})
|
||||
|
||||
tokens, err = Lex("set(1, 987)")
|
||||
So(err, ShouldBeNil)
|
||||
So(tokens, ShouldResemble, []Token{
|
||||
{"set", TYPE_FUNC},
|
||||
{"(", TYPE_LP},
|
||||
{"1", TYPE_VALUE},
|
||||
{",", TYPE_COMMA},
|
||||
{"987", TYPE_VALUE},
|
||||
{")", TYPE_RP},
|
||||
})
|
||||
|
||||
tokens, err = Lex("set(1, general, 987)")
|
||||
So(err, ShouldBeNil)
|
||||
So(tokens, ShouldResemble, []Token{
|
||||
{"set", TYPE_FUNC},
|
||||
{"(", TYPE_LP},
|
||||
{"1", TYPE_VALUE},
|
||||
{",", TYPE_COMMA},
|
||||
{"general", TYPE_VALUE},
|
||||
{",", TYPE_COMMA},
|
||||
{"987", TYPE_VALUE},
|
||||
{")", TYPE_RP},
|
||||
})
|
||||
|
||||
tokens, err = Lex("top-n(get(10), 8)")
|
||||
So(tokens, ShouldResemble, []Token{
|
||||
Token{"top-n", TYPE_FUNC},
|
||||
Token{"(", TYPE_LP},
|
||||
Token{"get", TYPE_FUNC},
|
||||
Token{"(", TYPE_LP},
|
||||
Token{"10", TYPE_VALUE},
|
||||
Token{")", TYPE_RP},
|
||||
Token{",", TYPE_COMMA},
|
||||
Token{"8", TYPE_VALUE},
|
||||
Token{")", TYPE_RP},
|
||||
})
|
||||
|
||||
tokens, err = Lex("top-n(get(10, general), [1,2,3])")
|
||||
So(tokens, ShouldResemble, []Token{
|
||||
Token{"top-n", TYPE_FUNC},
|
||||
Token{"(", TYPE_LP},
|
||||
Token{"get", TYPE_FUNC},
|
||||
Token{"(", TYPE_LP},
|
||||
Token{"10", TYPE_VALUE},
|
||||
Token{",", TYPE_COMMA},
|
||||
Token{"general", TYPE_VALUE},
|
||||
Token{")", TYPE_RP},
|
||||
Token{",", TYPE_COMMA},
|
||||
Token{"[", TYPE_LB},
|
||||
Token{"1", TYPE_VALUE},
|
||||
Token{",", TYPE_COMMA},
|
||||
Token{"2", TYPE_VALUE},
|
||||
Token{",", TYPE_COMMA},
|
||||
Token{"3", TYPE_VALUE},
|
||||
Token{"]", TYPE_RB},
|
||||
Token{")", TYPE_RP},
|
||||
})
|
||||
|
||||
tokens, err = Lex("plugin(get(10, general), [get(11, general)])")
|
||||
So(tokens, ShouldResemble, []Token{
|
||||
Token{"plugin", TYPE_FUNC},
|
||||
Token{"(", TYPE_LP},
|
||||
Token{"get", TYPE_FUNC},
|
||||
Token{"(", TYPE_LP},
|
||||
Token{"10", TYPE_VALUE},
|
||||
Token{",", TYPE_COMMA},
|
||||
Token{"general", TYPE_VALUE},
|
||||
Token{")", TYPE_RP},
|
||||
Token{",", TYPE_COMMA},
|
||||
Token{"[", TYPE_LB},
|
||||
Token{"get", TYPE_FUNC},
|
||||
Token{"(", TYPE_LP},
|
||||
Token{"11", TYPE_VALUE},
|
||||
Token{",", TYPE_COMMA},
|
||||
Token{"general", TYPE_VALUE},
|
||||
Token{")", TYPE_RP},
|
||||
Token{"]", TYPE_RB},
|
||||
Token{")", TYPE_RP},
|
||||
})
|
||||
})
|
||||
// Ensure a simple function and value can be lexed.
|
||||
func TestLexer_Lex_FuncValue(t *testing.T) {
|
||||
if tokens, err := query.Lex("get(10)"); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(tokens, []query.Token{
|
||||
{"get", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"10", query.TYPE_VALUE},
|
||||
{")", query.TYPE_RP},
|
||||
}) {
|
||||
t.Fatalf("unexpected tokens:\n\n%s", spew.Sprint(tokens))
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure a simple function, keyword, & value can be lexed.
|
||||
func TestLexer_Lex_FuncKeywordValue(t *testing.T) {
|
||||
if tokens, err := query.Lex("get(id=10)"); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(tokens, []query.Token{
|
||||
{"get", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"id", query.TYPE_KEYWORD},
|
||||
{"=", query.TYPE_EQUALS},
|
||||
{"10", query.TYPE_VALUE},
|
||||
{")", query.TYPE_RP},
|
||||
}) {
|
||||
t.Fatalf("unexpected tokens:\n\n%s", spew.Sprint(tokens))
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure a more complex function can be lexed.
|
||||
func TestLexer_Lex_FuncComplex(t *testing.T) {
|
||||
if tokens, err := query.Lex("get(id=10, frame=brand)"); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(tokens, []query.Token{
|
||||
{"get", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"id", query.TYPE_KEYWORD},
|
||||
{"=", query.TYPE_EQUALS},
|
||||
{"10", query.TYPE_VALUE},
|
||||
{",", query.TYPE_COMMA},
|
||||
{"frame", query.TYPE_KEYWORD},
|
||||
{"=", query.TYPE_EQUALS},
|
||||
{"brand", query.TYPE_VALUE},
|
||||
{")", query.TYPE_RP},
|
||||
}) {
|
||||
t.Fatalf("unexpected tokens:\n\n%s", spew.Sprint(tokens))
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that nested functions can be lexed.
|
||||
func TestLexer_Lex_FuncNested(t *testing.T) {
|
||||
if tokens, err := query.Lex("union(get(10))"); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(tokens, []query.Token{
|
||||
{"union", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"get", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"10", query.TYPE_VALUE},
|
||||
{")", query.TYPE_RP},
|
||||
{")", query.TYPE_RP},
|
||||
}) {
|
||||
t.Fatalf("unexpected tokens:\n\n%s", spew.Sprint(tokens))
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that a list of nested functions can be lexed.
|
||||
func TestLexer_Lex_FuncNestedList(t *testing.T) {
|
||||
if tokens, err := query.Lex("intersect(get(10), get(11), get(12))"); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(tokens, []query.Token{
|
||||
{"intersect", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"get", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"10", query.TYPE_VALUE},
|
||||
{")", query.TYPE_RP},
|
||||
{",", query.TYPE_COMMA},
|
||||
{"get", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"11", query.TYPE_VALUE},
|
||||
{")", query.TYPE_RP},
|
||||
{",", query.TYPE_COMMA},
|
||||
{"get", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"12", query.TYPE_VALUE},
|
||||
{")", query.TYPE_RP},
|
||||
{")", query.TYPE_RP},
|
||||
}) {
|
||||
t.Fatalf("unexpected tokens:\n\n%s", spew.Sprint(tokens))
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that complex nested functions can be lexed.
|
||||
func TestLexer_Lex_FuncNestedComplex(t *testing.T) {
|
||||
if tokens, err := query.Lex("intersect(get(10), get(11), concat(get(12),get(14)))"); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(tokens, []query.Token{
|
||||
{"intersect", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"get", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"10", query.TYPE_VALUE},
|
||||
{")", query.TYPE_RP},
|
||||
{",", query.TYPE_COMMA},
|
||||
{"get", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"11", query.TYPE_VALUE},
|
||||
{")", query.TYPE_RP},
|
||||
{",", query.TYPE_COMMA},
|
||||
{"concat", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"get", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"12", query.TYPE_VALUE},
|
||||
{")", query.TYPE_RP},
|
||||
{",", query.TYPE_COMMA},
|
||||
{"get", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"14", query.TYPE_VALUE},
|
||||
{")", query.TYPE_RP},
|
||||
{")", query.TYPE_RP},
|
||||
{")", query.TYPE_RP},
|
||||
}) {
|
||||
t.Fatalf("unexpected tokens:\n\n%s", spew.Sprint(tokens))
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that complex nested functions can be lexed.
|
||||
func TestLexer_Lex_FuncNestedComplex2(t *testing.T) {
|
||||
if tokens, err := query.Lex("concat(get(1, brand),get(2))"); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(tokens, []query.Token{
|
||||
{"concat", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"get", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"1", query.TYPE_VALUE},
|
||||
{",", query.TYPE_COMMA},
|
||||
{"brand", query.TYPE_VALUE},
|
||||
{")", query.TYPE_RP},
|
||||
{",", query.TYPE_COMMA},
|
||||
{"get", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"2", query.TYPE_VALUE},
|
||||
{")", query.TYPE_RP},
|
||||
{")", query.TYPE_RP},
|
||||
}) {
|
||||
t.Fatalf("unexpected tokens:\n\n%s", spew.Sprint(tokens))
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that a set function can be lexed.
|
||||
func TestLexer_Lex_Set1(t *testing.T) {
|
||||
if tokens, err := query.Lex("set(1, 987)"); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(tokens, []query.Token{
|
||||
{"set", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"1", query.TYPE_VALUE},
|
||||
{",", query.TYPE_COMMA},
|
||||
{"987", query.TYPE_VALUE},
|
||||
{")", query.TYPE_RP},
|
||||
}) {
|
||||
t.Fatalf("unexpected tokens:\n\n%s", spew.Sprint(tokens))
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that a set function can be lexed.
|
||||
func TestLexer_Lex_Set2(t *testing.T) {
|
||||
if tokens, err := query.Lex("set(1, general, 987)"); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(tokens, []query.Token{
|
||||
{"set", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"1", query.TYPE_VALUE},
|
||||
{",", query.TYPE_COMMA},
|
||||
{"general", query.TYPE_VALUE},
|
||||
{",", query.TYPE_COMMA},
|
||||
{"987", query.TYPE_VALUE},
|
||||
{")", query.TYPE_RP},
|
||||
}) {
|
||||
t.Fatalf("unexpected tokens:\n\n%s", spew.Sprint(tokens))
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that a TopN function can be lexed.
|
||||
func TestLexer_Lex_TopN1(t *testing.T) {
|
||||
if tokens, err := query.Lex("top-n(get(10), 8)"); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(tokens, []query.Token{
|
||||
{"top-n", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"get", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"10", query.TYPE_VALUE},
|
||||
{")", query.TYPE_RP},
|
||||
{",", query.TYPE_COMMA},
|
||||
{"8", query.TYPE_VALUE},
|
||||
{")", query.TYPE_RP},
|
||||
}) {
|
||||
t.Fatalf("unexpected tokens:\n\n%s", spew.Sprint(tokens))
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that a TopN function can be lexed.
|
||||
func TestLexer_Lex_TopN2(t *testing.T) {
|
||||
if tokens, err := query.Lex("top-n(get(10, general), [1,2,3])"); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(tokens, []query.Token{
|
||||
{"top-n", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"get", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"10", query.TYPE_VALUE},
|
||||
{",", query.TYPE_COMMA},
|
||||
{"general", query.TYPE_VALUE},
|
||||
{")", query.TYPE_RP},
|
||||
{",", query.TYPE_COMMA},
|
||||
{"[", query.TYPE_LB},
|
||||
{"1", query.TYPE_VALUE},
|
||||
{",", query.TYPE_COMMA},
|
||||
{"2", query.TYPE_VALUE},
|
||||
{",", query.TYPE_COMMA},
|
||||
{"3", query.TYPE_VALUE},
|
||||
{"]", query.TYPE_RB},
|
||||
{")", query.TYPE_RP},
|
||||
}) {
|
||||
t.Fatalf("unexpected tokens:\n\n%s", spew.Sprint(tokens))
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that a plugin function can be lexed.
|
||||
func TestLexer_Lex_Plugin(t *testing.T) {
|
||||
if tokens, err := query.Lex("plugin(get(10, general), [get(11, general)])"); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !reflect.DeepEqual(tokens, []query.Token{
|
||||
{"plugin", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"get", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"10", query.TYPE_VALUE},
|
||||
{",", query.TYPE_COMMA},
|
||||
{"general", query.TYPE_VALUE},
|
||||
{")", query.TYPE_RP},
|
||||
{",", query.TYPE_COMMA},
|
||||
{"[", query.TYPE_LB},
|
||||
{"get", query.TYPE_FUNC},
|
||||
{"(", query.TYPE_LP},
|
||||
{"11", query.TYPE_VALUE},
|
||||
{",", query.TYPE_COMMA},
|
||||
{"general", query.TYPE_VALUE},
|
||||
{")", query.TYPE_RP},
|
||||
{"]", query.TYPE_RB},
|
||||
{")", query.TYPE_RP},
|
||||
}) {
|
||||
t.Fatalf("unexpected tokens:\n\n%s", spew.Sprint(tokens))
|
||||
}
|
||||
}
|
||||
|
||||
// MustLex lexes s and returns a set of tokens. Panic on error.
|
||||
func MustLex(s string) []query.Token {
|
||||
a, err := query.Lex(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,127 +1,157 @@
|
|||
package query
|
||||
package query_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"github.com/umbel/pilosa/query"
|
||||
)
|
||||
|
||||
func TestQueryParser(t *testing.T) {
|
||||
Convey("Basic parse - get()", t, func() {
|
||||
tokens, err := Lex("get(10)")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
query, err := Parse(tokens)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(query.Operation, ShouldEqual, "get")
|
||||
So(query.Args, ShouldResemble, map[string]interface{}{"id": uint64(10), "frame": "general"})
|
||||
})
|
||||
Convey("Basic parse - clear()", t, func() {
|
||||
tokens, err := Lex("clear(10, general, 0, 20)")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
query, err := Parse(tokens)
|
||||
So(err, ShouldBeNil)
|
||||
spew.Dump(query)
|
||||
So(query.Operation, ShouldEqual, "clear")
|
||||
So(query.Args, ShouldResemble, map[string]interface{}{"id": uint64(10), "frame": "general", "filter": uint64(0), "profile_id": uint64(20)})
|
||||
})
|
||||
Convey("Basic parse - set()", t, func() {
|
||||
tokens, err := Lex("set(10, general, 0, 20)")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
query, err := Parse(tokens)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(query.Operation, ShouldEqual, "set")
|
||||
So(query.Args, ShouldResemble, map[string]interface{}{"id": uint64(10), "frame": "general", "filter": uint64(0), "profile_id": uint64(20)})
|
||||
})
|
||||
Convey("Basic nested query parse", t, func() {
|
||||
tokens, err := Lex("union(get(10,general), get(11,brand), get(12))")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
query, err := Parse(tokens)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(query.Operation, ShouldEqual, "union")
|
||||
So(len(query.Subqueries), ShouldEqual, 3)
|
||||
|
||||
So(query.Subqueries[0].Operation, ShouldEqual, "get")
|
||||
So(query.Subqueries[0].Args, ShouldResemble, map[string]interface{}{"id": uint64(10), "frame": "general"})
|
||||
So(query.Subqueries[1].Operation, ShouldEqual, "get")
|
||||
So(query.Subqueries[1].Args, ShouldResemble, map[string]interface{}{"id": uint64(11), "frame": "brand"})
|
||||
So(query.Subqueries[2].Operation, ShouldEqual, "get")
|
||||
So(query.Subqueries[2].Args, ShouldResemble, map[string]interface{}{"id": uint64(12), "frame": "general"})
|
||||
})
|
||||
Convey("Keyword args", t, func() {
|
||||
tokens, err := Lex("get(id=10)")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
query, err := Parse(tokens)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(query.Operation, ShouldEqual, "get")
|
||||
So(query.Args, ShouldResemble, map[string]interface{}{"id": uint64(10), "frame": "general"})
|
||||
})
|
||||
Convey("Keyword args - multiple", t, func() {
|
||||
tokens, err := Lex("get(id=10, frame=brands)")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
query, err := Parse(tokens)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(query.Operation, ShouldEqual, "get")
|
||||
So(query.Args, ShouldResemble, map[string]interface{}{"id": uint64(10), "frame": "brands"})
|
||||
})
|
||||
Convey("Lists", t, func() {
|
||||
tokens, err := Lex("top-n(get(10, general), [1,2,3], 50)")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
query, err := Parse(tokens)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(query.Operation, ShouldEqual, "top-n")
|
||||
So(query.Args, ShouldResemble, map[string]interface{}{"ids": []uint64{1, 2, 3}, "n": 50})
|
||||
|
||||
So(len(query.Subqueries), ShouldEqual, 1)
|
||||
So(query.Subqueries[0].Operation, ShouldEqual, "get")
|
||||
So(query.Subqueries[0].Args, ShouldResemble, map[string]interface{}{"id": uint64(10), "frame": "general"})
|
||||
})
|
||||
Convey("Bracketed Lists", t, func() {
|
||||
tokens, err := Lex("plugin(get(99), [get(10), get(11)])")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
query, err := Parse(tokens)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
spew.Dump("*********************************************")
|
||||
spew.Dump(query)
|
||||
spew.Dump("*********************************************")
|
||||
})
|
||||
Convey("Lists", t, func() {
|
||||
tokens, err := Lex("wat(50)")
|
||||
_, err = Parse(tokens)
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
Convey("Recall", t, func() {
|
||||
tokens, err := Lex("recall(12345,1,12345,2,12345,3)")
|
||||
q, err := Parse(tokens)
|
||||
spew.Dump(q)
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
Convey("all() query parse", t, func() {
|
||||
tokens, err := Lex("top-n(all(), general, 30)")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
query, err := Parse(tokens)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(query.Operation, ShouldEqual, "top-n")
|
||||
So(len(query.Subqueries), ShouldEqual, 1)
|
||||
|
||||
So(query.Subqueries[0].Operation, ShouldEqual, "all")
|
||||
So(query.Subqueries[0].Args, ShouldResemble, map[string]interface{}{})
|
||||
})
|
||||
// Ensure the parser can parse a get() query.
|
||||
func TestParser_Parse_Get(t *testing.T) {
|
||||
if q, err := query.Parse(MustLex("get(10)")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if q.Operation != "get" {
|
||||
t.Fatalf("unexpected operation: %q", q.Operation)
|
||||
} else if !reflect.DeepEqual(q.Args, map[string]interface{}{
|
||||
"id": uint64(10),
|
||||
"frame": "general",
|
||||
}) {
|
||||
t.Fatalf("unexpected args:\n\n%s", spew.Sprint(q.Args))
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the parser can parse a get() query with a keyword.
|
||||
func TestParser_Parse_Get_Keyword(t *testing.T) {
|
||||
if q, err := query.Parse(MustLex("get(id=10)")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if q.Operation != "get" {
|
||||
t.Fatalf("unexpected operation: %q", q.Operation)
|
||||
} else if !reflect.DeepEqual(q.Args, map[string]interface{}{"id": uint64(10), "frame": "general"}) {
|
||||
t.Fatalf("unexpected args:\n\n%s", spew.Sprint(q.Args))
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the parser can parse a get() query with a keyword.
|
||||
func TestParser_Parse_Get_MultiKeyword(t *testing.T) {
|
||||
if q, err := query.Parse(MustLex("get(id=10, frame=brands)")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if q.Operation != "get" {
|
||||
t.Fatalf("unexpected operation: %q", q.Operation)
|
||||
} else if !reflect.DeepEqual(q.Args, map[string]interface{}{"id": uint64(10), "frame": "brands"}) {
|
||||
t.Fatalf("unexpected args:\n\n%s", spew.Sprint(q.Args))
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the parser can parse a clear() query.
|
||||
func TestParser_Parse_Clear(t *testing.T) {
|
||||
if q, err := query.Parse(MustLex("clear(10, general, 0, 20)")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if q.Operation != "clear" {
|
||||
t.Fatalf("unexpected operation: %q", q.Operation)
|
||||
} else if !reflect.DeepEqual(q.Args, map[string]interface{}{
|
||||
"id": uint64(10),
|
||||
"frame": "general",
|
||||
"filter": uint64(0),
|
||||
"profile_id": uint64(20),
|
||||
}) {
|
||||
t.Fatalf("unexpected args:\n\n%s", spew.Sprint(q.Args))
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the parser can parse a set() query.
|
||||
func TestParser_Parse_Set(t *testing.T) {
|
||||
if q, err := query.Parse(MustLex("set(10, general, 0, 20)")); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if q.Operation != "set" {
|
||||
t.Fatalf("unexpected operation: %q", q.Operation)
|
||||
} else if !reflect.DeepEqual(q.Args, map[string]interface{}{
|
||||
"id": uint64(10),
|
||||
"frame": "general",
|
||||
"filter": uint64(0),
|
||||
"profile_id": uint64(20),
|
||||
}) {
|
||||
t.Fatalf("unexpected args:\n\n%s", spew.Sprint(q.Args))
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the parser can parse a nested query.
|
||||
func TestParser_Parse_Nested(t *testing.T) {
|
||||
q, err := query.Parse(MustLex("union(get(10,general), get(11,brand), get(12))"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
} else if q.Operation != "union" {
|
||||
t.Fatalf("unexpected operation: %q", q.Operation)
|
||||
} else if len(q.Subqueries) != 3 {
|
||||
t.Fatalf("unexpected subquery count: %d", len(q.Subqueries))
|
||||
}
|
||||
|
||||
if sq := q.Subqueries[0]; sq.Operation != "get" {
|
||||
t.Fatalf("unexpected subquery(0) operation: %q", sq.Operation)
|
||||
} else if !reflect.DeepEqual(sq.Args, map[string]interface{}{"id": uint64(10), "frame": "general"}) {
|
||||
t.Fatalf("unexpected subquery(0) args:\n\n%s", spew.Sprint(q.Args))
|
||||
}
|
||||
|
||||
if sq := q.Subqueries[1]; sq.Operation != "get" {
|
||||
t.Fatalf("unexpected subquery(1) operation: %q", sq.Operation)
|
||||
} else if !reflect.DeepEqual(sq.Args, map[string]interface{}{"id": uint64(11), "frame": "brand"}) {
|
||||
t.Fatalf("unexpected subquery(1) args:\n\n%s", spew.Sprint(sq.Args))
|
||||
}
|
||||
|
||||
if sq := q.Subqueries[2]; sq.Operation != "get" {
|
||||
t.Fatalf("unexpected subquery(2) operation: %q", sq.Operation)
|
||||
} else if !reflect.DeepEqual(sq.Args, map[string]interface{}{"id": uint64(12), "frame": "general"}) {
|
||||
t.Fatalf("unexpected subquery(2) args:\n\n%s", spew.Sprint(sq.Args))
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the parser can parse a query with lists.
|
||||
func TestParser_Parse_Lists(t *testing.T) {
|
||||
q, err := query.Parse(MustLex("top-n(get(10, general), [1,2,3], 50)"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
} else if q.Operation != "top-n" {
|
||||
t.Fatalf("unexpected operation: %q", q.Operation)
|
||||
} else if !reflect.DeepEqual(q.Args, map[string]interface{}{"ids": []uint64{1, 2, 3}, "n": 50}) {
|
||||
t.Fatalf("unexpected args:\n\n%s", spew.Sprint(q.Args))
|
||||
}
|
||||
|
||||
if sq := q.Subqueries[0]; sq.Operation != "get" {
|
||||
t.Fatalf("unexpected subquery(0) operation: %q", sq.Operation)
|
||||
} else if !reflect.DeepEqual(sq.Args, map[string]interface{}{"id": uint64(10), "frame": "general"}) {
|
||||
t.Fatalf("unexpected subquery(0) args:\n\n%s", spew.Sprint(q.Args))
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the parser can parse "all()".
|
||||
func TestParser_Parse_All(t *testing.T) {
|
||||
q, err := query.Parse(MustLex("top-n(all(), general, 30)"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
} else if q.Operation != "top-n" {
|
||||
t.Fatalf("unexpected operation: %q", q.Operation)
|
||||
}
|
||||
|
||||
if sq := q.Subqueries[0]; sq.Operation != "all" {
|
||||
t.Fatalf("unexpected subquery(0) operation: %q", sq.Operation)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the parser can parse bracketed lists.
|
||||
func TestParser_Parse_Lists_Bracketed(t *testing.T) {
|
||||
q, err := query.Parse(MustLex("plugin(get(99), [get(10), get(11)])"))
|
||||
if err != nil {
|
||||
t.Fatalf("expected error")
|
||||
}
|
||||
spew.Dump(q)
|
||||
}
|
||||
|
||||
// Ensure the parser can parse a recall query.
|
||||
func TestParser_Parse_Recall(t *testing.T) {
|
||||
q, err := query.Parse(MustLex("recall(12345,1,12345,2,12345,3)"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
spew.Dump(q)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,253 +1,283 @@
|
|||
package query
|
||||
package query_test
|
||||
|
||||
import (
|
||||
"log"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"github.com/umbel/pilosa/db"
|
||||
"github.com/umbel/pilosa/query"
|
||||
"github.com/umbel/pilosa/util"
|
||||
)
|
||||
|
||||
func basic_database() (*db.Database, *db.Fragment) {
|
||||
// create an empty database
|
||||
cluster := db.NewCluster()
|
||||
database := cluster.GetOrCreateDatabase("main")
|
||||
frame := database.GetOrCreateFrame("default")
|
||||
// Ensure the query planner can plan a "get" query.
|
||||
func TestQueryPlanner_Plan_Get(t *testing.T) {
|
||||
q, err := query.QueryForPQL("get(10,default)")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
slice1 := database.GetOrCreateSlice(0)
|
||||
fragment_id1 := util.Id()
|
||||
fragment1 := database.GetOrCreateFragment(frame, slice1, fragment_id1)
|
||||
process_id1 := util.RandomUUID()
|
||||
process1 := db.NewProcess(&process_id1)
|
||||
process1.SetHost("----192.1.1.0----")
|
||||
fragment1.SetProcess(process1)
|
||||
d, frag1 := NewDefaultDB()
|
||||
planner := query.QueryPlanner{Database: d, Query: q}
|
||||
|
||||
slice2 := database.GetOrCreateSlice(1)
|
||||
fragment_id2 := util.Id()
|
||||
fragment2 := database.GetOrCreateFragment(frame, slice2, fragment_id2)
|
||||
process_id2 := util.RandomUUID()
|
||||
process2 := db.NewProcess(&process_id2)
|
||||
process2.SetHost("----192.1.1.1----")
|
||||
fragment2.SetProcess(process2)
|
||||
return database, fragment1
|
||||
id := util.RandomUUID()
|
||||
plan, err := planner.Plan(q, &id, frag1.GetLocation())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if n := len(*plan); n != 3 {
|
||||
t.Fatalf("unexpected plan length: %d", n)
|
||||
}
|
||||
|
||||
if step := (*plan)[0].(query.GetQueryStep); step.Operation != "get" {
|
||||
t.Fatalf("unexpected step(0) operation: %s", step.Operation)
|
||||
} else if step.Slice != 0 {
|
||||
t.Fatalf("unexpected step(0) slice: %d", step.Slice)
|
||||
} else if !reflect.DeepEqual(step.Bitmap, &db.Bitmap{10, "default", 0}) {
|
||||
t.Fatalf("unexpected step(0) bitmap: %s", spew.Sprint(step.Bitmap))
|
||||
}
|
||||
|
||||
if step := (*plan)[1].(query.GetQueryStep); step.Operation != "get" {
|
||||
t.Fatalf("unexpected step(1) operation: %s", step.Operation)
|
||||
} else if step.Slice != 1 {
|
||||
t.Fatalf("unexpected step(1) slice: %d", step.Slice)
|
||||
} else if !reflect.DeepEqual(step.Bitmap, &db.Bitmap{10, "default", 0}) {
|
||||
t.Fatalf("unexpected step(1) bitmap: %s", spew.Sprint(step.Bitmap))
|
||||
}
|
||||
|
||||
if step := (*plan)[2].(query.CatQueryStep); step.Operation != "cat" {
|
||||
t.Fatalf("unexpected step(2) operation: %s", step.Operation)
|
||||
} else if !reflect.DeepEqual(step.Inputs, []*util.GUID{
|
||||
(*plan)[0].(query.GetQueryStep).Id,
|
||||
(*plan)[1].(query.GetQueryStep).Id,
|
||||
}) {
|
||||
t.Fatalf("unexpected step(2) inputs: %s", spew.Sprint(step.Inputs))
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueryPlanner(t *testing.T) {
|
||||
Convey("Union query plan", t, func() {
|
||||
// Ensure the query planner can plan a "set" query.
|
||||
func TestQueryPlanner_Plan_Set(t *testing.T) {
|
||||
q, err := query.QueryForPQL("set(10, default, 0, 100)")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
id1 := util.RandomUUID()
|
||||
query1 := Query{Id: &id1, Operation: "get", Args: map[string]interface{}{"id": uint64(10), "frame": "default"}}
|
||||
d, frag1 := NewDefaultDB()
|
||||
planner := query.QueryPlanner{Database: d, Query: q}
|
||||
|
||||
id2 := util.RandomUUID()
|
||||
query2 := Query{Id: &id2, Operation: "get", Args: map[string]interface{}{"id": uint64(20), "frame": "default"}}
|
||||
id := util.RandomUUID()
|
||||
plan, err := planner.Plan(q, &id, frag1.GetLocation())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
id3 := util.RandomUUID()
|
||||
query := Query{Id: &id3, Operation: "union", Subqueries: []Query{query1, query2}}
|
||||
|
||||
database, fragment1 := basic_database()
|
||||
|
||||
qplanner := QueryPlanner{Database: database, Query: &query}
|
||||
destination := fragment1.GetLocation()
|
||||
|
||||
id := util.RandomUUID()
|
||||
log.Println(id)
|
||||
qpp, err := qplanner.Plan(&query, &id, destination)
|
||||
So(err, ShouldEqual, nil)
|
||||
|
||||
qp := *qpp
|
||||
|
||||
So(len(qp), ShouldEqual, 7)
|
||||
So(qp[0].(GetQueryStep).Operation, ShouldEqual, "get")
|
||||
So(qp[0].(GetQueryStep).Slice, ShouldEqual, 0)
|
||||
So(*(qp[0].(GetQueryStep).Bitmap), ShouldResemble, db.Bitmap{10, "default", 0})
|
||||
So(qp[1].(GetQueryStep).Operation, ShouldEqual, "get")
|
||||
So(qp[1].(GetQueryStep).Slice, ShouldEqual, 0)
|
||||
So(*(qp[1].(GetQueryStep).Bitmap), ShouldResemble, db.Bitmap{20, "default", 0})
|
||||
So(qp[2].(UnionQueryStep).Operation, ShouldEqual, "union")
|
||||
So(qp[2].(UnionQueryStep).Inputs, ShouldResemble, []*util.GUID{
|
||||
qp[0].(GetQueryStep).Id,
|
||||
qp[1].(GetQueryStep).Id,
|
||||
})
|
||||
So(qp[3].(GetQueryStep).Operation, ShouldEqual, "get")
|
||||
So(qp[3].(GetQueryStep).Slice, ShouldEqual, 1)
|
||||
So(*(qp[3].(GetQueryStep).Bitmap), ShouldResemble, db.Bitmap{10, "default", 0})
|
||||
So(qp[4].(GetQueryStep).Operation, ShouldEqual, "get")
|
||||
So(qp[4].(GetQueryStep).Slice, ShouldEqual, 1)
|
||||
So(*(qp[4].(GetQueryStep).Bitmap), ShouldResemble, db.Bitmap{20, "default", 0})
|
||||
So(qp[5].(UnionQueryStep).Operation, ShouldEqual, "union")
|
||||
So(qp[5].(UnionQueryStep).Inputs, ShouldResemble, []*util.GUID{
|
||||
qp[3].(GetQueryStep).Id,
|
||||
qp[4].(GetQueryStep).Id,
|
||||
})
|
||||
So(qp[6].(CatQueryStep).Operation, ShouldEqual, "cat")
|
||||
So(qp[6].(CatQueryStep).Inputs, ShouldResemble, []*util.GUID{
|
||||
qp[2].(UnionQueryStep).Id,
|
||||
qp[5].(UnionQueryStep).Id,
|
||||
})
|
||||
})
|
||||
Convey("Get query plan - including parsing", t, func() {
|
||||
|
||||
query, err := QueryForPQL("get(10,default)")
|
||||
So(err, ShouldEqual, nil)
|
||||
|
||||
database, fragment1 := basic_database()
|
||||
|
||||
qplanner := QueryPlanner{Database: database, Query: query}
|
||||
destination := fragment1.GetLocation()
|
||||
|
||||
id := util.RandomUUID()
|
||||
qpp, err := qplanner.Plan(query, &id, destination)
|
||||
So(err, ShouldEqual, nil)
|
||||
qp := *qpp
|
||||
|
||||
So(len(qp), ShouldEqual, 3)
|
||||
So(qp[0].(GetQueryStep).Operation, ShouldEqual, "get")
|
||||
So(qp[0].(GetQueryStep).Slice, ShouldEqual, 0)
|
||||
So(*(qp[0].(GetQueryStep).Bitmap), ShouldResemble, db.Bitmap{10, "default", 0})
|
||||
So(qp[1].(GetQueryStep).Operation, ShouldEqual, "get")
|
||||
So(qp[1].(GetQueryStep).Slice, ShouldEqual, 1)
|
||||
So(*(qp[1].(GetQueryStep).Bitmap), ShouldResemble, db.Bitmap{10, "default", 0})
|
||||
So(qp[2].(CatQueryStep).Operation, ShouldEqual, "cat")
|
||||
So(qp[2].(CatQueryStep).Inputs, ShouldResemble, []*util.GUID{
|
||||
qp[0].(GetQueryStep).Id,
|
||||
qp[1].(GetQueryStep).Id,
|
||||
})
|
||||
})
|
||||
Convey("Union query plan - including parsing", t, func() {
|
||||
|
||||
query, err := QueryForPQL("union(get(10, default), get(20, default))")
|
||||
So(err, ShouldEqual, nil)
|
||||
|
||||
database, fragment1 := basic_database()
|
||||
|
||||
qplanner := QueryPlanner{Database: database, Query: query}
|
||||
destination := fragment1.GetLocation()
|
||||
|
||||
id := util.RandomUUID()
|
||||
qpp, err := qplanner.Plan(query, &id, destination)
|
||||
So(err, ShouldEqual, nil)
|
||||
qp := *qpp
|
||||
|
||||
So(len(qp), ShouldEqual, 7)
|
||||
So(qp[0].(GetQueryStep).Operation, ShouldEqual, "get")
|
||||
So(qp[0].(GetQueryStep).Slice, ShouldEqual, 0)
|
||||
So(*(qp[0].(GetQueryStep).Bitmap), ShouldResemble, db.Bitmap{10, "default", 0})
|
||||
So(qp[1].(GetQueryStep).Operation, ShouldEqual, "get")
|
||||
So(qp[1].(GetQueryStep).Slice, ShouldEqual, 0)
|
||||
So(*(qp[1].(GetQueryStep).Bitmap), ShouldResemble, db.Bitmap{20, "default", 0})
|
||||
So(qp[2].(UnionQueryStep).Operation, ShouldEqual, "union")
|
||||
So(qp[2].(UnionQueryStep).Inputs, ShouldResemble, []*util.GUID{
|
||||
qp[0].(GetQueryStep).Id,
|
||||
qp[1].(GetQueryStep).Id,
|
||||
})
|
||||
So(qp[3].(GetQueryStep).Operation, ShouldEqual, "get")
|
||||
So(qp[3].(GetQueryStep).Slice, ShouldEqual, 1)
|
||||
So(*(qp[3].(GetQueryStep).Bitmap), ShouldResemble, db.Bitmap{10, "default", 0})
|
||||
So(qp[4].(GetQueryStep).Operation, ShouldEqual, "get")
|
||||
So(qp[4].(GetQueryStep).Slice, ShouldEqual, 1)
|
||||
So(*(qp[4].(GetQueryStep).Bitmap), ShouldResemble, db.Bitmap{20, "default", 0})
|
||||
So(qp[5].(UnionQueryStep).Operation, ShouldEqual, "union")
|
||||
So(qp[5].(UnionQueryStep).Inputs, ShouldResemble, []*util.GUID{
|
||||
qp[3].(GetQueryStep).Id,
|
||||
qp[4].(GetQueryStep).Id,
|
||||
})
|
||||
So(qp[6].(CatQueryStep).Operation, ShouldEqual, "cat")
|
||||
So(qp[6].(CatQueryStep).Inputs, ShouldResemble, []*util.GUID{
|
||||
qp[2].(UnionQueryStep).Id,
|
||||
qp[5].(UnionQueryStep).Id,
|
||||
})
|
||||
})
|
||||
Convey("Set query plan - including parsing", t, func() {
|
||||
query, err := QueryForPQL("set(10, default, 0, 100)")
|
||||
So(err, ShouldEqual, nil)
|
||||
|
||||
database, fragment1 := basic_database()
|
||||
|
||||
qplanner := QueryPlanner{Database: database, Query: query}
|
||||
destination := fragment1.GetLocation()
|
||||
|
||||
id := util.RandomUUID()
|
||||
qpp, err := qplanner.Plan(query, &id, destination)
|
||||
So(err, ShouldEqual, nil)
|
||||
qp := *qpp
|
||||
So(len(qp), ShouldEqual, 1)
|
||||
So(qp[0].(SetQueryStep).Operation, ShouldEqual, "set")
|
||||
So(qp[0].(SetQueryStep).ProfileId, ShouldEqual, 100)
|
||||
So(*(qp[0].(SetQueryStep).Bitmap), ShouldResemble, db.Bitmap{10, "default", 0})
|
||||
})
|
||||
Convey("Top-n query plan - including parsing", t, func() {
|
||||
query, err := QueryForPQL("top-n(get(10, default), default, 50,[1,2,3])")
|
||||
So(err, ShouldEqual, nil)
|
||||
|
||||
database, fragment1 := basic_database()
|
||||
qplanner := QueryPlanner{Database: database, Query: query}
|
||||
destination := fragment1.GetLocation()
|
||||
id := util.RandomUUID()
|
||||
qpp, err := qplanner.Plan(query, &id, destination)
|
||||
|
||||
So(err, ShouldEqual, nil)
|
||||
qp := *qpp
|
||||
So(err, ShouldEqual, nil)
|
||||
So(len(qp), ShouldEqual, 5)
|
||||
So(qp[0].(GetQueryStep).Operation, ShouldEqual, "get")
|
||||
So(*(qp[0].(GetQueryStep).Bitmap), ShouldResemble, db.Bitmap{10, "default", 0})
|
||||
So(qp[1].(*TopNQueryStep).Operation, ShouldEqual, "top-n")
|
||||
So(qp[1].(*TopNQueryStep).Input, ShouldEqual, qp[0].(GetQueryStep).Id)
|
||||
So(qp[1].(*TopNQueryStep).N, ShouldEqual, 50)
|
||||
So(qp[1].(*TopNQueryStep).Filters, ShouldResemble, []uint64{1, 2, 3})
|
||||
So(qp[2].(GetQueryStep).Operation, ShouldEqual, "get")
|
||||
So(*(qp[2].(GetQueryStep).Bitmap), ShouldResemble, db.Bitmap{10, "default", 0})
|
||||
So(qp[3].(*TopNQueryStep).Operation, ShouldEqual, "top-n")
|
||||
So(qp[3].(*TopNQueryStep).Input, ShouldEqual, qp[2].(GetQueryStep).Id)
|
||||
So(qp[3].(*TopNQueryStep).N, ShouldEqual, 50)
|
||||
})
|
||||
Convey("All query plan - including parsing", t, func() {
|
||||
query, err := QueryForPQL("top-n(all(), default, 50, [1,2,3])")
|
||||
So(err, ShouldEqual, nil)
|
||||
|
||||
database, fragment1 := basic_database()
|
||||
qplanner := QueryPlanner{Database: database, Query: query}
|
||||
destination := fragment1.GetLocation()
|
||||
id := util.RandomUUID()
|
||||
qpp, err := qplanner.Plan(query, &id, destination)
|
||||
|
||||
So(err, ShouldEqual, nil)
|
||||
qp := *qpp
|
||||
So(err, ShouldEqual, nil)
|
||||
So(len(qp), ShouldEqual, 3)
|
||||
So(qp[0].(*TopNQueryStep).Operation, ShouldEqual, "top-n")
|
||||
So(qp[0].(*TopNQueryStep).Input, ShouldEqual, nil)
|
||||
So(qp[0].(*TopNQueryStep).N, ShouldEqual, 50)
|
||||
So(qp[0].(*TopNQueryStep).Filters, ShouldResemble, []uint64{1, 2, 3})
|
||||
})
|
||||
Convey("Get query plan - including parsing", t, func() {
|
||||
|
||||
_, err := QueryForPQL("count()")
|
||||
So(err, ShouldNotEqual, nil)
|
||||
_, err = QueryForPQL("count(intersect())")
|
||||
So(err, ShouldNotEqual, nil)
|
||||
_, err = QueryForPQL("count(get(10, default))")
|
||||
So(err, ShouldEqual, nil)
|
||||
_, err = QueryForPQL("count(union())")
|
||||
So(err, ShouldNotEqual, nil)
|
||||
})
|
||||
|
||||
Convey("Stash including parsing", t, func() {
|
||||
qp, err := QueryForPQL("stash(union(get(10,default),get(20,default)))")
|
||||
So(err, ShouldEqual, nil)
|
||||
|
||||
database, fragment1 := basic_database()
|
||||
qplanner := QueryPlanner{Database: database, Query: qp}
|
||||
destination := fragment1.GetLocation()
|
||||
id := util.RandomUUID()
|
||||
qpp, _ := qplanner.Plan(qp, &id, destination)
|
||||
p := *qpp
|
||||
|
||||
So(len(p), ShouldNotEqual, 0)
|
||||
log.Println(len(p))
|
||||
spew.Dump(p[0])
|
||||
})
|
||||
if n := len(*plan); n != 1 {
|
||||
t.Fatalf("unexpected plan length: %d", n)
|
||||
}
|
||||
|
||||
if step := (*plan)[0].(query.SetQueryStep); step.Operation != "set" {
|
||||
t.Fatalf("unexpected step(0) operation: %s", step.Operation)
|
||||
} else if step.ProfileId != 100 {
|
||||
t.Fatalf("unexpected step(0) profile id: %d", step.ProfileId)
|
||||
} else if !reflect.DeepEqual(step.Bitmap, &db.Bitmap{10, "default", 0}) {
|
||||
t.Fatalf("unexpected step(0) bitmap: %s", spew.Sprint(step.Bitmap))
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the query planner can plan a "top-n" query.
|
||||
func TestQueryPlanner_Plan_TopN(t *testing.T) {
|
||||
q, err := query.QueryForPQL("top-n(get(10, default), default, 50,[1,2,3])")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
d, frag1 := NewDefaultDB()
|
||||
planner := query.QueryPlanner{Database: d, Query: q}
|
||||
|
||||
id := util.RandomUUID()
|
||||
plan, err := planner.Plan(q, &id, frag1.GetLocation())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if n := len(*plan); n != 5 {
|
||||
t.Fatalf("unexpected plan length: %d", n)
|
||||
}
|
||||
|
||||
if step := (*plan)[0].(query.GetQueryStep); step.Operation != "get" {
|
||||
t.Fatalf("unexpected step(0) operation: %s", step.Operation)
|
||||
} else if !reflect.DeepEqual(step.Bitmap, &db.Bitmap{10, "default", 0}) {
|
||||
t.Fatalf("unexpected step(0) bitmap: %s", spew.Sprint(step.Bitmap))
|
||||
}
|
||||
|
||||
if step := (*plan)[1].(*query.TopNQueryStep); step.Operation != "top-n" {
|
||||
t.Fatalf("unexpected step(1) operation: %s", step.Operation)
|
||||
} else if step.Input != (*plan)[0].(query.GetQueryStep).Id {
|
||||
t.Fatalf("unexpected step(1) input: %d", step.Input)
|
||||
} else if step.N != 50 {
|
||||
t.Fatalf("unexpected step(1) n: %d", step.N)
|
||||
} else if !reflect.DeepEqual(step.Filters, []uint64{1, 2, 3}) {
|
||||
t.Fatalf("unexpected step(1) filters: %s", spew.Sprint(step.Filters))
|
||||
}
|
||||
|
||||
if step := (*plan)[2].(query.GetQueryStep); step.Operation != "get" {
|
||||
t.Fatalf("unexpected step(2) operation: %s", step.Operation)
|
||||
} else if !reflect.DeepEqual(step.Bitmap, &db.Bitmap{10, "default", 0}) {
|
||||
t.Fatalf("unexpected step(2) bitmap: %s", spew.Sprint(step.Bitmap))
|
||||
}
|
||||
|
||||
if step := (*plan)[3].(*query.TopNQueryStep); step.Operation != "top-n" {
|
||||
t.Fatalf("unexpected step(3) operation: %s", step.Operation)
|
||||
} else if step.Input != (*plan)[2].(query.GetQueryStep).Id {
|
||||
t.Fatalf("unexpected step(3) input: %d", step.Input)
|
||||
} else if step.N != 50 {
|
||||
t.Fatalf("unexpected step(3) n: %d", step.N)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the query planner can plan a "top-n" all() query.
|
||||
func TestQueryPlanner_Plan_TopN_All(t *testing.T) {
|
||||
q, err := query.QueryForPQL("top-n(all(), default, 50, [1,2,3])")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
d, frag1 := NewDefaultDB()
|
||||
planner := query.QueryPlanner{Database: d, Query: q}
|
||||
|
||||
id := util.RandomUUID()
|
||||
plan, err := planner.Plan(q, &id, frag1.GetLocation())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if n := len(*plan); n != 3 {
|
||||
t.Fatalf("unexpected plan length: %d", n)
|
||||
}
|
||||
|
||||
if step := (*plan)[0].(*query.TopNQueryStep); step.Operation != "top-n" {
|
||||
t.Fatalf("unexpected step(0) operation: %s", step.Operation)
|
||||
} else if step.Input != nil {
|
||||
t.Fatalf("unexpected step(0) input: %v", step.Input)
|
||||
} else if step.N != 50 {
|
||||
t.Fatalf("unexpected step(0) n: %d", step.N)
|
||||
} else if !reflect.DeepEqual(step.Filters, []uint64{1, 2, 3}) {
|
||||
t.Fatalf("unexpected step(0) filters: %s", spew.Sprint(step.Filters))
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the query planner can plan a "union" query.
|
||||
func TestQueryPlanner_Plan_Union(t *testing.T) {
|
||||
id1 := util.RandomUUID()
|
||||
q1 := query.Query{Id: &id1, Operation: "get", Args: map[string]interface{}{"id": uint64(10), "frame": "default"}}
|
||||
|
||||
id2 := util.RandomUUID()
|
||||
q2 := query.Query{Id: &id2, Operation: "get", Args: map[string]interface{}{"id": uint64(20), "frame": "default"}}
|
||||
|
||||
id3 := util.RandomUUID()
|
||||
q := query.Query{Id: &id3, Operation: "union", Subqueries: []query.Query{q1, q2}}
|
||||
|
||||
d, frag1 := NewDefaultDB()
|
||||
planner := query.QueryPlanner{Database: d, Query: &q}
|
||||
|
||||
id := util.RandomUUID()
|
||||
plan, err := planner.Plan(&q, &id, frag1.GetLocation())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if n := len(*plan); n != 7 {
|
||||
t.Fatalf("unexpected plan size: %d", n)
|
||||
}
|
||||
|
||||
// First step should be a "get" step.
|
||||
if step := (*plan)[0].(query.GetQueryStep); step.Operation != "get" {
|
||||
t.Fatalf("unexpected step(0) operation: %s", step.Operation)
|
||||
} else if step.Slice != 0 {
|
||||
t.Fatalf("unexpected step(0) slice: %d", step.Slice)
|
||||
} else if !reflect.DeepEqual(step.Bitmap, &db.Bitmap{10, "default", 0}) {
|
||||
t.Fatalf("unexpected step(0) bitmap: %s", spew.Sprint(step.Bitmap))
|
||||
}
|
||||
|
||||
// Second step should also be a "get" step.
|
||||
if step := (*plan)[1].(query.GetQueryStep); step.Operation != "get" {
|
||||
t.Fatalf("unexpected step(1) operation: %s", step.Operation)
|
||||
} else if step.Slice != 0 {
|
||||
t.Fatalf("unexpected step(1) slice: %d", step.Slice)
|
||||
} else if !reflect.DeepEqual(step.Bitmap, &db.Bitmap{20, "default", 0}) {
|
||||
t.Fatalf("unexpected step(1) bitmap: %s", spew.Sprint(step.Bitmap))
|
||||
}
|
||||
|
||||
// Third step should union the first two steps.
|
||||
if step := (*plan)[2].(query.UnionQueryStep); step.Operation != "union" {
|
||||
t.Fatalf("unexpected step(2) operation: %s", step.Operation)
|
||||
} else if !reflect.DeepEqual(step.Inputs, []*util.GUID{
|
||||
(*plan)[0].(query.GetQueryStep).Id,
|
||||
(*plan)[1].(query.GetQueryStep).Id,
|
||||
}) {
|
||||
t.Fatalf("unexpected step(2) inputs: %s", spew.Sprint(step.Inputs))
|
||||
}
|
||||
|
||||
// Fourth step should be a "get" step.
|
||||
if step := (*plan)[3].(query.GetQueryStep); step.Operation != "get" {
|
||||
t.Fatalf("unexpected step(3) operation: %s", step.Operation)
|
||||
} else if step.Slice != 1 {
|
||||
t.Fatalf("unexpected step(3) slice: %d", step.Slice)
|
||||
} else if !reflect.DeepEqual(step.Bitmap, &db.Bitmap{10, "default", 0}) {
|
||||
t.Fatalf("unexpected step(3) bitmap: %s", spew.Sprint(step.Bitmap))
|
||||
}
|
||||
|
||||
// Fifth step should also be a "get" step.
|
||||
if step := (*plan)[4].(query.GetQueryStep); step.Operation != "get" {
|
||||
t.Fatalf("unexpected step(4) operation: %s", step.Operation)
|
||||
} else if step.Slice != 1 {
|
||||
t.Fatalf("unexpected step(4) slice: %d", step.Slice)
|
||||
} else if !reflect.DeepEqual(step.Bitmap, &db.Bitmap{20, "default", 0}) {
|
||||
t.Fatalf("unexpected step(4) bitmap: %s", spew.Sprint(step.Bitmap))
|
||||
}
|
||||
|
||||
// Sixth step should union the previous two steps.
|
||||
if step := (*plan)[5].(query.UnionQueryStep); step.Operation != "union" {
|
||||
t.Fatalf("unexpected step(5) operation: %s", step.Operation)
|
||||
} else if !reflect.DeepEqual(step.Inputs, []*util.GUID{
|
||||
(*plan)[3].(query.GetQueryStep).Id,
|
||||
(*plan)[4].(query.GetQueryStep).Id,
|
||||
}) {
|
||||
t.Fatalf("unexpected step(5) inputs: %s", spew.Sprint(step.Inputs))
|
||||
}
|
||||
|
||||
// Final step should concatenate the two union steps.
|
||||
if step := (*plan)[6].(query.CatQueryStep); step.Operation != "cat" {
|
||||
t.Fatalf("unexpected step(6) operation: %s", step.Operation)
|
||||
} else if !reflect.DeepEqual(step.Inputs, []*util.GUID{
|
||||
(*plan)[2].(query.UnionQueryStep).Id,
|
||||
(*plan)[5].(query.UnionQueryStep).Id,
|
||||
}) {
|
||||
t.Fatalf("unexpected step(6) inputs: %s", spew.Sprint(step.Inputs))
|
||||
}
|
||||
}
|
||||
|
||||
// NewDefaultDB returns a simple, initialized database and fragment.
|
||||
func NewDefaultDB() (*db.Database, *db.Fragment) {
|
||||
// Create an empty database
|
||||
c := db.NewCluster()
|
||||
d := c.GetOrCreateDatabase("main")
|
||||
f := d.GetOrCreateFrame("default")
|
||||
|
||||
s1 := d.GetOrCreateSlice(0)
|
||||
frag1 := d.GetOrCreateFragment(f, s1, util.Id())
|
||||
pid := util.RandomUUID()
|
||||
p1 := db.NewProcess(&pid)
|
||||
p1.SetHost("----192.1.1.0----")
|
||||
frag1.SetProcess(p1)
|
||||
|
||||
s2 := d.GetOrCreateSlice(1)
|
||||
frag2 := d.GetOrCreateFragment(f, s2, util.Id())
|
||||
pid = util.RandomUUID()
|
||||
p2 := db.NewProcess(&pid)
|
||||
p2.SetHost("----192.1.1.1----")
|
||||
frag2.SetProcess(p2)
|
||||
|
||||
return d, frag1
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,32 +1,36 @@
|
|||
package query
|
||||
package query_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/umbel/pilosa/query"
|
||||
)
|
||||
|
||||
func TestQuery(t *testing.T) {
|
||||
Convey("Bracketed Lists 1", t, func() {
|
||||
tokens, err := Lex("plugin(get(88, general), [get(12, general), get(13, general)])")
|
||||
So(err, ShouldBeNil)
|
||||
filter, filters := TokensToFilterStrings(tokens)
|
||||
So(filter, ShouldEqual, "get(88,general)")
|
||||
So(filters, ShouldResemble, []string{"get(12,general)", "get(13,general)"})
|
||||
})
|
||||
Convey("Bracketed Lists 2", t, func() {
|
||||
tokens, err := Lex("plugin(intersect(get(88, general, [0]), get(77, b.n)), [get(12, general), get(13, general)])")
|
||||
So(err, ShouldBeNil)
|
||||
filter, filters := TokensToFilterStrings(tokens)
|
||||
So(filter, ShouldEqual, "intersect(get(88,general,[0]),get(77,b.n))")
|
||||
So(filters, ShouldResemble, []string{"get(12,general)", "get(13,general)"})
|
||||
})
|
||||
Convey("Bracketed Lists 3", t, func() {
|
||||
tokens, err := Lex("plugin(intersect(get(88, general, [0]), get(77, b.n)))")
|
||||
So(err, ShouldBeNil)
|
||||
filter, filters := TokensToFilterStrings(tokens)
|
||||
So(filter, ShouldEqual, "intersect(get(88,general,[0]),get(77,b.n))")
|
||||
var empty []string
|
||||
So(filters, ShouldResemble, empty)
|
||||
})
|
||||
func TestTokensToFilterStrings1(t *testing.T) {
|
||||
filter, filters := query.TokensToFilterStrings(MustLex("plugin(get(88, general), [get(12, general), get(13, general)])"))
|
||||
if filter != "get(88,general)" {
|
||||
t.Fatalf("unexpected filter: %s", filter)
|
||||
} else if !reflect.DeepEqual(filters, []string{"get(12,general)", "get(13,general)"}) {
|
||||
t.Fatalf("unexpected filters: %s", spew.Sprint(filters))
|
||||
}
|
||||
}
|
||||
|
||||
func TestTokensToFilterStrings2(t *testing.T) {
|
||||
filter, filters := query.TokensToFilterStrings(MustLex("plugin(intersect(get(88, general, [0]), get(77, b.n)), [get(12, general), get(13, general)])"))
|
||||
if filter != "intersect(get(88,general,[0]),get(77,b.n))" {
|
||||
t.Fatalf("unexpected filter: %s", filter)
|
||||
} else if !reflect.DeepEqual(filters, []string{"get(12,general)", "get(13,general)"}) {
|
||||
t.Fatalf("unexpected filters: %s", spew.Sprint(filters))
|
||||
}
|
||||
}
|
||||
|
||||
func TestTokensToFilterStrings3(t *testing.T) {
|
||||
filter, filters := query.TokensToFilterStrings(MustLex("plugin(intersect(get(88, general, [0]), get(77, b.n)))"))
|
||||
if filter != "intersect(get(88,general,[0]),get(77,b.n))" {
|
||||
t.Fatalf("unexpected filter: %s", filter)
|
||||
} else if !reflect.DeepEqual(filters, []string(nil)) {
|
||||
t.Fatalf("unexpected filters: %s", spew.Sprint(filters))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue