Chromium Code Reviews| 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 |