OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package memory | 5 package memory |
6 | 6 |
7 import ( | 7 import ( |
8 "bytes" | 8 "bytes" |
9 "errors" | |
9 "fmt" | 10 "fmt" |
11 "strings" | |
10 | 12 |
11 ds "github.com/luci/gae/service/datastore" | 13 ds "github.com/luci/gae/service/datastore" |
12 "github.com/luci/gae/service/datastore/serialize" | 14 "github.com/luci/gae/service/datastore/serialize" |
13 "github.com/luci/luci-go/common/cmpbin" | 15 "github.com/luci/luci-go/common/cmpbin" |
14 "github.com/luci/luci-go/common/stringset" | 16 "github.com/luci/luci-go/common/stringset" |
15 ) | 17 ) |
16 | 18 |
17 type queryStrategy interface { | 19 type queryStrategy interface { |
18 // handle applies the strategy to the embedded user callback. | 20 // handle applies the strategy to the embedded user callback. |
19 // - rawData is the slice of encoded Properties from the index row | 21 // - rawData is the slice of encoded Properties from the index row |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
171 return | 173 return |
172 } | 174 } |
173 } | 175 } |
174 err = executeQuery(fq, aid, ns, isTxn, idx, head, func(_ *ds.Key, _ ds.P ropertyMap, _ ds.CursorCB) error { | 176 err = executeQuery(fq, aid, ns, isTxn, idx, head, func(_ *ds.Key, _ ds.P ropertyMap, _ ds.CursorCB) error { |
175 ret++ | 177 ret++ |
176 return nil | 178 return nil |
177 }) | 179 }) |
178 return | 180 return |
179 } | 181 } |
180 | 182 |
183 func executeNamespaceQuery(fq *ds.FinalizedQuery, aid string, head *memStore, cb ds.RawRunCB) error { | |
184 // these objects have no properties, so any filters on properties cause an | |
185 // empty result. | |
186 if len(fq.EqFilters()) > 0 || len(fq.Project()) > 0 || len(fq.Orders()) > 1 { | |
187 return nil | |
188 } | |
189 if !(fq.IneqFilterProp() == "" || fq.IneqFilterProp() == "__key__") { | |
190 return nil | |
191 } | |
192 colls := head.GetCollectionNames() | |
193 foundEnts := false | |
194 limit, hasLimit := fq.Limit() | |
195 offset, hasOffset := fq.Offset() | |
196 start, end := fq.Bounds() | |
197 | |
198 cursErr := errors.New("cursors not supported for __namespace__ query") | |
199 cursFn := func() (ds.Cursor, error) { return nil, cursErr } | |
200 if !(start == nil && end == nil) { | |
201 return cursErr | |
202 } | |
203 for _, c := range colls { | |
204 if !strings.HasPrefix(c, "ents:") { | |
205 if foundEnts { | |
206 break | |
207 } | |
208 continue | |
209 } | |
210 foundEnts = true | |
211 if hasOffset && offset > 0 { | |
212 offset-- | |
213 continue | |
214 } | |
215 if hasLimit { | |
216 if limit <= 0 { | |
217 return ds.Stop | |
218 } | |
219 limit-- | |
220 } | |
221 k := (*ds.Key)(nil) | |
222 ns := c[len("ents:"):] | |
223 if ns == "" { | |
dnj
2016/04/16 00:18:26
WDYT about adding a comment here about how datasto
iannucci
2016/04/16 00:51:52
Sure. Done.
| |
224 k = ds.MakeKey(aid, "", "__namespace__", 1) | |
225 } else { | |
226 k = ds.MakeKey(aid, "", "__namespace__", ns) | |
227 } | |
228 if err := cb(k, nil, cursFn); err != nil { | |
229 return err | |
230 } | |
231 } | |
232 return nil | |
233 } | |
234 | |
181 func executeQuery(fq *ds.FinalizedQuery, aid, ns string, isTxn bool, idx, head * memStore, cb ds.RawRunCB) error { | 235 func executeQuery(fq *ds.FinalizedQuery, aid, ns string, isTxn bool, idx, head * memStore, cb ds.RawRunCB) error { |
182 rq, err := reduce(fq, aid, ns, isTxn) | 236 rq, err := reduce(fq, aid, ns, isTxn) |
183 if err == ds.ErrNullQuery { | 237 if err == ds.ErrNullQuery { |
184 return nil | 238 return nil |
185 } | 239 } |
186 if err != nil { | 240 if err != nil { |
187 return err | 241 return err |
188 } | 242 } |
189 | 243 |
244 if rq.kind == "__namespace__" { | |
245 return executeNamespaceQuery(fq, aid, head, cb) | |
246 } | |
247 | |
190 idxs, err := getIndexes(rq, idx) | 248 idxs, err := getIndexes(rq, idx) |
191 if err == ds.ErrNullQuery { | 249 if err == ds.ErrNullQuery { |
192 return nil | 250 return nil |
193 } | 251 } |
194 if err != nil { | 252 if err != nil { |
195 return err | 253 return err |
196 } | 254 } |
197 | 255 |
198 strategy := pickQueryStrategy(fq, rq, cb, head) | 256 strategy := pickQueryStrategy(fq, rq, cb, head) |
199 if strategy == nil { | 257 if strategy == nil { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
242 keyProp := decodedProps[len(decodedProps)-1] | 300 keyProp := decodedProps[len(decodedProps)-1] |
243 if keyProp.Type() != ds.PTKey { | 301 if keyProp.Type() != ds.PTKey { |
244 impossible(fmt.Errorf("decoded index row doesn't end wit h a Key: %#v", keyProp)) | 302 impossible(fmt.Errorf("decoded index row doesn't end wit h a Key: %#v", keyProp)) |
245 } | 303 } |
246 | 304 |
247 return strategy.handle( | 305 return strategy.handle( |
248 rawData, decodedProps, keyProp.Value().(*ds.Key), | 306 rawData, decodedProps, keyProp.Value().(*ds.Key), |
249 getCursorFn(suffix)) | 307 getCursorFn(suffix)) |
250 }) | 308 }) |
251 } | 309 } |
OLD | NEW |