Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(756)

Unified Diff: service/datastore/query_test.go

Issue 1355783002: Refactor keys and queries in datastore service and implementation. (Closed) Base URL: https://github.com/luci/gae.git@master
Patch Set: appease errcheck Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « service/datastore/query.go ('k') | service/datastore/raw_interface.go » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: service/datastore/query_test.go
diff --git a/service/datastore/query_test.go b/service/datastore/query_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..c4c71ccca2fb13e15e15001f9cf2879b63dd1580
--- /dev/null
+++ b/service/datastore/query_test.go
@@ -0,0 +1,291 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package datastore
+
+import (
+ "math"
+ "testing"
+
+ . "github.com/luci/luci-go/common/testing/assertions"
+ . "github.com/smartystreets/goconvey/convey"
+)
+
+const (
+ MaxUint = ^uint(0)
+ MaxInt = int(MaxUint >> 1)
+ IntIs32Bits = int64(MaxInt) < math.MaxInt64
+)
+
+func TestDatastoreQueries(t *testing.T) {
+ Convey("Datastore Query suport", t, func() {
+ Convey("can create good queries", func() {
+ q := NewQuery("Foo").Gt("farnsworth", 20).KeysOnly(true).Limit(10).Offset(39)
+
+ start := fakeCursor("hi")
+
+ end := fakeCursor("end")
+
+ q = q.Start(start).End(end)
+ So(q, ShouldNotBeNil)
+ fq, err := q.Finalize()
+ So(fq, ShouldNotBeNil)
+ So(err, ShouldBeNil)
+ })
+
+ Convey("ensures orders make sense", func() {
+ q := NewQuery("Cool")
+ q = q.Eq("cat", 19).Eq("bob", 10).Order("bob", "bob")
+
+ Convey("removes dups and equality orders", func() {
+ q = q.Order("wat")
+ fq, err := q.Finalize()
+ So(err, ShouldBeNil)
+ So(fq.Orders(), ShouldResemble, []IndexColumn{
+ {Property: "wat"}, {Property: "__key__"}})
+ })
+ })
+
+ })
+}
+
+type queryTest struct {
+ // name is the name of the test case
+ name string
+
+ // q is the input query
+ q *Query
+
+ // gql is the expected generated GQL.
+ gql string
+
+ // err is the error to expect after prepping the query (error, string or nil)
+ err interface{}
+
+ // equivalentQuery is another query which ShouldResemble q. This is useful to
+ // see the effects of redundancy pruning on e.g. filters.
+ equivalentQuery *Query
+}
+
+type sillyCursor string
+
+func (s sillyCursor) String() string { return string(s) }
+
+func nq(kinds ...string) *Query {
+ kind := "Foo"
+ if len(kinds) > 0 {
+ kind = kinds[0]
+ }
+ return NewQuery(kind)
+}
+
+func mkKey(elems ...interface{}) *Key {
+ return MakeKey("s~aid", "ns", elems...)
+}
+
+var queryTests = []queryTest{
+ {"only one inequality",
+ nq().Order("bob", "wat").Gt("bob", 10).Lt("wat", 29),
+ "",
+ "inequality filters on multiple properties", nil},
+
+ {"bad order",
+ nq().Order("+Bob"),
+ "",
+ "invalid order", nil},
+
+ {"empty order",
+ nq().Order(""),
+ "",
+ "empty order", nil},
+
+ {"negative offset disables Offset",
+ nq().Offset(100).Offset(-20),
+ "SELECT * FROM `Foo` ORDER BY `__key__`",
+ nil, nq()},
+
+ {"projecting a keys-only query",
+ nq().Project("hello").KeysOnly(true),
+ "",
+ "cannot project a keysOnly query", nil},
+
+ {"projecting a keys-only query (reverse)",
+ nq().KeysOnly(true).Project("hello"),
+ "",
+ "cannot project a keysOnly query", nil},
+
+ {"projecting an empty field",
+ nq().Project("hello", ""),
+ "",
+ "cannot filter/project on: \"\"", nil},
+
+ {"projecting __key__",
+ nq().Project("hello", "__key__"),
+ "",
+ "cannot project on \"__key__\"", nil},
+
+ {"projecting a duplicate",
+ nq().Project("hello", "hello"),
+ "SELECT `hello` FROM `Foo` ORDER BY `hello`, `__key__`",
+ nil, nq().Project("hello")},
+
+ {"projecting a duplicate (style 2)",
+ nq().Project("hello").Project("hello"),
+ "SELECT `hello` FROM `Foo` ORDER BY `hello`, `__key__`",
+ nil, nq().Project("hello")},
+
+ {"bad ancestors",
+ nq().Ancestor(mkKey("goop", 0)),
+ "",
+ ErrInvalidKey, nil},
+
+ {"nil ancestors",
+ nq().Ancestor(nil),
+ "SELECT * FROM `Foo` ORDER BY `__key__`",
+ nil, nq()},
+
+ {"Bad key filters",
+ nq().Gt("__key__", mkKey("goop", 0)),
+ "",
+ ErrInvalidKey, nil},
+
+ {"filters for __key__ that aren't keys",
+ nq().Gt("__key__", 10),
+ "",
+ "filters on \"__key__\" must have type *Key", nil},
+
+ {"multiple inequalities",
+ nq().Gt("bob", 19).Lt("charlie", 20),
+ "",
+ "inequality filters on multiple properties", nil},
+
+ {"inequality must be first sort order",
+ nq().Gt("bob", 19).Order("-charlie"),
+ "",
+ "first sort order", nil},
+
+ {"inequality must be first sort order (reverse)",
+ nq().Order("-charlie").Gt("bob", 19),
+ "",
+ "first sort order", nil},
+
+ {"equality filter projected field",
+ nq().Project("foo").Eq("foo", 10),
+ "",
+ "cannot project", nil},
+
+ {"equality filter projected field (reverse)",
+ nq().Eq("foo", 10).Project("foo"),
+ "",
+ "cannot project", nil},
+
+ {"kindless with non-__key__ filters",
+ nq("").Lt("face", 25.3),
+ "",
+ "kindless queries can only filter on __key__", nil},
+
+ {"kindless with non-__key__ orders",
+ nq("").Order("face"),
+ "",
+ "invalid order for kindless query", nil},
+
+ {"kindless with descending-__key__ order",
+ nq("").Order("-__key__"),
+ "",
+ "invalid order for kindless query", nil},
+
+ {"distinct non-projection",
+ nq().Distinct(true).Gt("marla", 1),
+ "SELECT * FROM `Foo` WHERE `marla` > 1 ORDER BY `marla`, `__key__`",
+ nil, nq().Gt("marla", 1)},
+
+ {"chained errors return the first",
+ nq().Eq("__reserved__", 100).Eq("hello", "wurld").Order(""),
+ "",
+ "__reserved__", nil},
+
+ {"multiple ancestors",
+ nq().Ancestor(mkKey("something", "correct")).Ancestor(mkKey("something", "else")),
+ ("SELECT * FROM `Foo` " +
+ "WHERE __key__ HAS ANCESTOR KEY(DATASET(\"s~aid\"), NAMESPACE(\"ns\"), \"something\", \"else\") " +
+ "ORDER BY `__key__`"),
+ nil, nq().Ancestor(mkKey("something", "else"))},
+
+ {"filter with illegal type",
+ nq().Eq("something", complex(1, 2)),
+ "",
+ "bad type complex", nil},
+
+ {"sort orders used for equality are ignored",
+ nq().Order("a", "b", "c").Eq("b", 2),
+ "SELECT * FROM `Foo` WHERE `b` = 2 ORDER BY `a`, `c`, `__key__`",
+ nil, nq().Order("a", "c").Eq("b", 2)},
+
+ {"sort orders used for equality are ignored (reversed)",
+ nq().Eq("b", 2).Order("a", "b", "c"),
+ "SELECT * FROM `Foo` WHERE `b` = 2 ORDER BY `a`, `c`, `__key__`",
+ nil,
+ nq().Order("a", "c").Eq("b", 2)},
+
+ {"duplicate orders are ignored",
+ nq().Order("a").Order("a").Order("a"),
+ "SELECT * FROM `Foo` ORDER BY `a`, `__key__`",
+ nil,
+ nq().Order("a")},
+
+ {"Filtering on a reserved property is forbidden",
+ nq().Gte("__special__", 10),
+ "",
+ "cannot filter/project on reserved property: \"__special__\"",
+ nil},
+
+ {"in-bound key filters with ancestor OK",
+ nq().Ancestor(mkKey("Hello", 10)).Lt("__key__", mkKey("Hello", 10, "Something", "hi")),
+ ("SELECT * FROM `Foo` " +
+ "WHERE `__key__` < KEY(DATASET(\"s~aid\"), NAMESPACE(\"ns\"), \"Hello\", 10, \"Something\", \"hi\") AND " +
+ "__key__ HAS ANCESTOR KEY(DATASET(\"s~aid\"), NAMESPACE(\"ns\"), \"Hello\", 10) " +
+ "ORDER BY `__key__`"),
+ nil,
+ nil},
+
+ {"projection elements get filled in",
+ nq().Project("Foo", "Bar").Order("-Bar"),
+ "SELECT `Bar`, `Foo` FROM `Foo` ORDER BY `Bar` DESC, `Foo`, `__key__`",
+ nil, nq().Project("Foo", "Bar").Order("-Bar").Order("Foo")},
+
+ {"query without anything is fine",
+ nq(),
+ "SELECT * FROM `Foo` ORDER BY `__key__`",
+ nil,
+ nil},
+}
+
+func TestQueries(t *testing.T) {
+ t.Parallel()
+
+ Convey("queries have tons of condition checking", t, func() {
+ for _, tc := range queryTests {
+ Convey(tc.name, func() {
+ fq, err := tc.q.Finalize()
+ if err == nil {
+ err = fq.Valid("s~aid", "ns")
+ }
+ So(err, ShouldErrLike, tc.err)
+
+ if tc.gql != "" {
+ So(fq.GQL(), ShouldEqual, tc.gql)
+ }
+
+ if tc.equivalentQuery != nil {
+ fq2, err := tc.equivalentQuery.Finalize()
+ So(err, ShouldBeNil)
+
+ fq.original = nil
+ fq2.original = nil
+ So(fq, ShouldResemble, fq2)
+ }
+ })
+ }
+ })
+}
« no previous file with comments | « service/datastore/query.go ('k') | service/datastore/raw_interface.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698