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

Side by Side 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 unified diff | Download patch
« no previous file with comments | « service/datastore/query.go ('k') | service/datastore/raw_interface.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package datastore
6
7 import (
8 "math"
9 "testing"
10
11 . "github.com/luci/luci-go/common/testing/assertions"
12 . "github.com/smartystreets/goconvey/convey"
13 )
14
15 const (
16 MaxUint = ^uint(0)
17 MaxInt = int(MaxUint >> 1)
18 IntIs32Bits = int64(MaxInt) < math.MaxInt64
19 )
20
21 func TestDatastoreQueries(t *testing.T) {
22 Convey("Datastore Query suport", t, func() {
23 Convey("can create good queries", func() {
24 q := NewQuery("Foo").Gt("farnsworth", 20).KeysOnly(true) .Limit(10).Offset(39)
25
26 start := fakeCursor("hi")
27
28 end := fakeCursor("end")
29
30 q = q.Start(start).End(end)
31 So(q, ShouldNotBeNil)
32 fq, err := q.Finalize()
33 So(fq, ShouldNotBeNil)
34 So(err, ShouldBeNil)
35 })
36
37 Convey("ensures orders make sense", func() {
38 q := NewQuery("Cool")
39 q = q.Eq("cat", 19).Eq("bob", 10).Order("bob", "bob")
40
41 Convey("removes dups and equality orders", func() {
42 q = q.Order("wat")
43 fq, err := q.Finalize()
44 So(err, ShouldBeNil)
45 So(fq.Orders(), ShouldResemble, []IndexColumn{
46 {Property: "wat"}, {Property: "__key__"} })
47 })
48 })
49
50 })
51 }
52
53 type queryTest struct {
54 // name is the name of the test case
55 name string
56
57 // q is the input query
58 q *Query
59
60 // gql is the expected generated GQL.
61 gql string
62
63 // err is the error to expect after prepping the query (error, string or nil)
64 err interface{}
65
66 // equivalentQuery is another query which ShouldResemble q. This is usef ul to
67 // see the effects of redundancy pruning on e.g. filters.
68 equivalentQuery *Query
69 }
70
71 type sillyCursor string
72
73 func (s sillyCursor) String() string { return string(s) }
74
75 func nq(kinds ...string) *Query {
76 kind := "Foo"
77 if len(kinds) > 0 {
78 kind = kinds[0]
79 }
80 return NewQuery(kind)
81 }
82
83 func mkKey(elems ...interface{}) *Key {
84 return MakeKey("s~aid", "ns", elems...)
85 }
86
87 var queryTests = []queryTest{
88 {"only one inequality",
89 nq().Order("bob", "wat").Gt("bob", 10).Lt("wat", 29),
90 "",
91 "inequality filters on multiple properties", nil},
92
93 {"bad order",
94 nq().Order("+Bob"),
95 "",
96 "invalid order", nil},
97
98 {"empty order",
99 nq().Order(""),
100 "",
101 "empty order", nil},
102
103 {"negative offset disables Offset",
104 nq().Offset(100).Offset(-20),
105 "SELECT * FROM `Foo` ORDER BY `__key__`",
106 nil, nq()},
107
108 {"projecting a keys-only query",
109 nq().Project("hello").KeysOnly(true),
110 "",
111 "cannot project a keysOnly query", nil},
112
113 {"projecting a keys-only query (reverse)",
114 nq().KeysOnly(true).Project("hello"),
115 "",
116 "cannot project a keysOnly query", nil},
117
118 {"projecting an empty field",
119 nq().Project("hello", ""),
120 "",
121 "cannot filter/project on: \"\"", nil},
122
123 {"projecting __key__",
124 nq().Project("hello", "__key__"),
125 "",
126 "cannot project on \"__key__\"", nil},
127
128 {"projecting a duplicate",
129 nq().Project("hello", "hello"),
130 "SELECT `hello` FROM `Foo` ORDER BY `hello`, `__key__`",
131 nil, nq().Project("hello")},
132
133 {"projecting a duplicate (style 2)",
134 nq().Project("hello").Project("hello"),
135 "SELECT `hello` FROM `Foo` ORDER BY `hello`, `__key__`",
136 nil, nq().Project("hello")},
137
138 {"bad ancestors",
139 nq().Ancestor(mkKey("goop", 0)),
140 "",
141 ErrInvalidKey, nil},
142
143 {"nil ancestors",
144 nq().Ancestor(nil),
145 "SELECT * FROM `Foo` ORDER BY `__key__`",
146 nil, nq()},
147
148 {"Bad key filters",
149 nq().Gt("__key__", mkKey("goop", 0)),
150 "",
151 ErrInvalidKey, nil},
152
153 {"filters for __key__ that aren't keys",
154 nq().Gt("__key__", 10),
155 "",
156 "filters on \"__key__\" must have type *Key", nil},
157
158 {"multiple inequalities",
159 nq().Gt("bob", 19).Lt("charlie", 20),
160 "",
161 "inequality filters on multiple properties", nil},
162
163 {"inequality must be first sort order",
164 nq().Gt("bob", 19).Order("-charlie"),
165 "",
166 "first sort order", nil},
167
168 {"inequality must be first sort order (reverse)",
169 nq().Order("-charlie").Gt("bob", 19),
170 "",
171 "first sort order", nil},
172
173 {"equality filter projected field",
174 nq().Project("foo").Eq("foo", 10),
175 "",
176 "cannot project", nil},
177
178 {"equality filter projected field (reverse)",
179 nq().Eq("foo", 10).Project("foo"),
180 "",
181 "cannot project", nil},
182
183 {"kindless with non-__key__ filters",
184 nq("").Lt("face", 25.3),
185 "",
186 "kindless queries can only filter on __key__", nil},
187
188 {"kindless with non-__key__ orders",
189 nq("").Order("face"),
190 "",
191 "invalid order for kindless query", nil},
192
193 {"kindless with descending-__key__ order",
194 nq("").Order("-__key__"),
195 "",
196 "invalid order for kindless query", nil},
197
198 {"distinct non-projection",
199 nq().Distinct(true).Gt("marla", 1),
200 "SELECT * FROM `Foo` WHERE `marla` > 1 ORDER BY `marla`, `__key_ _`",
201 nil, nq().Gt("marla", 1)},
202
203 {"chained errors return the first",
204 nq().Eq("__reserved__", 100).Eq("hello", "wurld").Order(""),
205 "",
206 "__reserved__", nil},
207
208 {"multiple ancestors",
209 nq().Ancestor(mkKey("something", "correct")).Ancestor(mkKey("som ething", "else")),
210 ("SELECT * FROM `Foo` " +
211 "WHERE __key__ HAS ANCESTOR KEY(DATASET(\"s~aid\"), NAME SPACE(\"ns\"), \"something\", \"else\") " +
212 "ORDER BY `__key__`"),
213 nil, nq().Ancestor(mkKey("something", "else"))},
214
215 {"filter with illegal type",
216 nq().Eq("something", complex(1, 2)),
217 "",
218 "bad type complex", nil},
219
220 {"sort orders used for equality are ignored",
221 nq().Order("a", "b", "c").Eq("b", 2),
222 "SELECT * FROM `Foo` WHERE `b` = 2 ORDER BY `a`, `c`, `__key__`" ,
223 nil, nq().Order("a", "c").Eq("b", 2)},
224
225 {"sort orders used for equality are ignored (reversed)",
226 nq().Eq("b", 2).Order("a", "b", "c"),
227 "SELECT * FROM `Foo` WHERE `b` = 2 ORDER BY `a`, `c`, `__key__`" ,
228 nil,
229 nq().Order("a", "c").Eq("b", 2)},
230
231 {"duplicate orders are ignored",
232 nq().Order("a").Order("a").Order("a"),
233 "SELECT * FROM `Foo` ORDER BY `a`, `__key__`",
234 nil,
235 nq().Order("a")},
236
237 {"Filtering on a reserved property is forbidden",
238 nq().Gte("__special__", 10),
239 "",
240 "cannot filter/project on reserved property: \"__special__\"",
241 nil},
242
243 {"in-bound key filters with ancestor OK",
244 nq().Ancestor(mkKey("Hello", 10)).Lt("__key__", mkKey("Hello", 1 0, "Something", "hi")),
245 ("SELECT * FROM `Foo` " +
246 "WHERE `__key__` < KEY(DATASET(\"s~aid\"), NAMESPACE(\"n s\"), \"Hello\", 10, \"Something\", \"hi\") AND " +
247 "__key__ HAS ANCESTOR KEY(DATASET(\"s~aid\"), NAMESPACE( \"ns\"), \"Hello\", 10) " +
248 "ORDER BY `__key__`"),
249 nil,
250 nil},
251
252 {"projection elements get filled in",
253 nq().Project("Foo", "Bar").Order("-Bar"),
254 "SELECT `Bar`, `Foo` FROM `Foo` ORDER BY `Bar` DESC, `Foo`, `__k ey__`",
255 nil, nq().Project("Foo", "Bar").Order("-Bar").Order("Foo")},
256
257 {"query without anything is fine",
258 nq(),
259 "SELECT * FROM `Foo` ORDER BY `__key__`",
260 nil,
261 nil},
262 }
263
264 func TestQueries(t *testing.T) {
265 t.Parallel()
266
267 Convey("queries have tons of condition checking", t, func() {
268 for _, tc := range queryTests {
269 Convey(tc.name, func() {
270 fq, err := tc.q.Finalize()
271 if err == nil {
272 err = fq.Valid("s~aid", "ns")
273 }
274 So(err, ShouldErrLike, tc.err)
275
276 if tc.gql != "" {
277 So(fq.GQL(), ShouldEqual, tc.gql)
278 }
279
280 if tc.equivalentQuery != nil {
281 fq2, err := tc.equivalentQuery.Finalize( )
282 So(err, ShouldBeNil)
283
284 fq.original = nil
285 fq2.original = nil
286 So(fq, ShouldResemble, fq2)
287 }
288 })
289 }
290 })
291 }
OLDNEW
« 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