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

Side by Side Diff: impl/memory/raw_datastore_query.go

Issue 1259593005: Add 'user friendly' datastore API. (Closed) Base URL: https://github.com/luci/gae.git@master
Patch Set: 100% coverage of new code Created 5 years, 4 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
OLDNEW
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 "errors"
10 "fmt" 10 "fmt"
11 "math" 11 "math"
12 "strings" 12 "strings"
13 13
14 » rds "github.com/luci/gae/service/rawdatastore" 14 » ds "github.com/luci/gae/service/datastore"
15 "github.com/luci/gkvlite" 15 "github.com/luci/gkvlite"
16 "github.com/luci/luci-go/common/cmpbin" 16 "github.com/luci/luci-go/common/cmpbin"
17 ) 17 )
18 18
19 type qDirection bool 19 type qDirection bool
20 20
21 const ( 21 const (
22 qASC qDirection = true 22 qASC qDirection = true
23 qDEC = false 23 qDEC = false
24 ) 24 )
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
212 212
213 type queryCursor string 213 type queryCursor string
214 214
215 func (q queryCursor) String() string { return string(q) } 215 func (q queryCursor) String() string { return string(q) }
216 func (q queryCursor) Valid() bool { return q != "" } 216 func (q queryCursor) Valid() bool { return q != "" }
217 217
218 type queryImpl struct { 218 type queryImpl struct {
219 ns string 219 ns string
220 220
221 kind string 221 kind string
222 » ancestor rds.Key 222 » ancestor ds.Key
223 filter []queryFilter 223 filter []queryFilter
224 order []queryOrder 224 order []queryOrder
225 project []string 225 project []string
226 226
227 distinct bool 227 distinct bool
228 eventualConsistency bool 228 eventualConsistency bool
229 keysOnly bool 229 keysOnly bool
230 limit int32 230 limit int32
231 offset int32 231 offset int32
232 232
233 start queryCursor 233 start queryCursor
234 end queryCursor 234 end queryCursor
235 235
236 err error 236 err error
237 } 237 }
238 238
239 var _ rds.Query = (*queryImpl)(nil) 239 var _ ds.Query = (*queryImpl)(nil)
240 240
241 func (q *queryImpl) normalize() (ret *queryImpl) { 241 func (q *queryImpl) normalize() (ret *queryImpl) {
242 // ported from GAE SDK datastore_index.py;Normalize() 242 // ported from GAE SDK datastore_index.py;Normalize()
243 ret = q.clone() 243 ret = q.clone()
244 244
245 bs := newMemStore() 245 bs := newMemStore()
246 246
247 eqProperties := bs.MakePrivateCollection(nil) 247 eqProperties := bs.MakePrivateCollection(nil)
248 248
249 ineqProperties := bs.MakePrivateCollection(nil) 249 ineqProperties := bs.MakePrivateCollection(nil)
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
359 // "query app is x but ancestor app is x" 359 // "query app is x but ancestor app is x"
360 // if ret.ancestor.namespace() != current namespace 360 // if ret.ancestor.namespace() != current namespace
361 // "query namespace is x but ancestor namespace is x" 361 // "query namespace is x but ancestor namespace is x"
362 362
363 // if not all(g in orders for g in group_by) 363 // if not all(g in orders for g in group_by)
364 // "items in the group by clause must be specified first in the orderin g" 364 // "items in the group by clause must be specified first in the orderin g"
365 365
366 ineqPropName := "" 366 ineqPropName := ""
367 for _, f := range ret.filter { 367 for _, f := range ret.filter {
368 if f.field == "__key__" { 368 if f.field == "__key__" {
369 » » » k, ok := f.value.(rds.Key) 369 » » » k, ok := f.value.(ds.Key)
370 if !ok { 370 if !ok {
371 ret.err = errors.New( 371 ret.err = errors.New(
372 "gae/memory: __key__ filter value must b e a Key") 372 "gae/memory: __key__ filter value must b e a Key")
373 return 373 return
374 } 374 }
375 » » » if !rds.KeyValid(k, false, globalAppID, q.ns) { 375 » » » if !ds.KeyValid(k, false, globalAppID, q.ns) {
376 // See the comment in queryImpl.Ancestor; basica lly this check 376 // See the comment in queryImpl.Ancestor; basica lly this check
377 // never happens in the real env because the SDK silently swallows 377 // never happens in the real env because the SDK silently swallows
378 // this condition :/ 378 // this condition :/
379 » » » » ret.err = rds.ErrInvalidKey 379 » » » » ret.err = ds.ErrInvalidKey
380 return 380 return
381 } 381 }
382 if k.Namespace() != ns { 382 if k.Namespace() != ns {
383 ret.err = fmt.Errorf("bad namespace: %q (expecte d %q)", k.Namespace(), ns) 383 ret.err = fmt.Errorf("bad namespace: %q (expecte d %q)", k.Namespace(), ns)
384 return 384 return
385 } 385 }
386 // __key__ filter app is X but query app is X 386 // __key__ filter app is X but query app is X
387 // __key__ filter namespace is X but query namespace is X 387 // __key__ filter namespace is X but query namespace is X
388 } 388 }
389 // if f.op == qEqual and f.field in ret.project_fields 389 // if f.op == qEqual and f.field in ret.project_fields
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
451 } 451 }
452 452
453 func (q *queryImpl) clone() *queryImpl { 453 func (q *queryImpl) clone() *queryImpl {
454 ret := *q 454 ret := *q
455 ret.filter = append([]queryFilter(nil), q.filter...) 455 ret.filter = append([]queryFilter(nil), q.filter...)
456 ret.order = append([]queryOrder(nil), q.order...) 456 ret.order = append([]queryOrder(nil), q.order...)
457 ret.project = append([]string(nil), q.project...) 457 ret.project = append([]string(nil), q.project...)
458 return &ret 458 return &ret
459 } 459 }
460 460
461 func (q *queryImpl) Ancestor(k rds.Key) rds.Query { 461 func (q *queryImpl) Ancestor(k ds.Key) ds.Query {
462 q = q.clone() 462 q = q.clone()
463 q.ancestor = k 463 q.ancestor = k
464 if k == nil { 464 if k == nil {
465 // SDK has an explicit nil-check 465 // SDK has an explicit nil-check
466 q.err = errors.New("datastore: nil query ancestor") 466 q.err = errors.New("datastore: nil query ancestor")
467 » } else if !rds.KeyValid(k, false, globalAppID, q.ns) { 467 » } else if !ds.KeyValid(k, false, globalAppID, q.ns) {
468 // technically the SDK implementation does a Weird Thing (tm) if both the 468 // technically the SDK implementation does a Weird Thing (tm) if both the
469 // stringID and intID are set on a key; it only serializes the s tringID in 469 // stringID and intID are set on a key; it only serializes the s tringID in
470 // the proto. This means that if you set the Ancestor to an inva lid key, 470 // the proto. This means that if you set the Ancestor to an inva lid key,
471 // you'll never actually hear about it. Instead of doing that in sanity, we 471 // you'll never actually hear about it. Instead of doing that in sanity, we
472 // just swap to an error here. 472 // just swap to an error here.
473 » » q.err = rds.ErrInvalidKey 473 » » q.err = ds.ErrInvalidKey
474 } else if k.Namespace() != q.ns { 474 } else if k.Namespace() != q.ns {
475 q.err = fmt.Errorf("bad namespace: %q (expected %q)", k.Namespac e(), q.ns) 475 q.err = fmt.Errorf("bad namespace: %q (expected %q)", k.Namespac e(), q.ns)
476 } 476 }
477 return q 477 return q
478 } 478 }
479 479
480 func (q *queryImpl) Distinct() rds.Query { 480 func (q *queryImpl) Distinct() ds.Query {
481 q = q.clone() 481 q = q.clone()
482 q.distinct = true 482 q.distinct = true
483 return q 483 return q
484 } 484 }
485 485
486 func (q *queryImpl) Filter(fStr string, val interface{}) rds.Query { 486 func (q *queryImpl) Filter(fStr string, val interface{}) ds.Query {
487 q = q.clone() 487 q = q.clone()
488 f, err := parseFilter(fStr, val) 488 f, err := parseFilter(fStr, val)
489 if err != nil { 489 if err != nil {
490 q.err = err 490 q.err = err
491 return q 491 return q
492 } 492 }
493 q.filter = append(q.filter, f) 493 q.filter = append(q.filter, f)
494 return q 494 return q
495 } 495 }
496 496
497 func (q *queryImpl) Order(field string) rds.Query { 497 func (q *queryImpl) Order(field string) ds.Query {
498 q = q.clone() 498 q = q.clone()
499 field = strings.TrimSpace(field) 499 field = strings.TrimSpace(field)
500 o := queryOrder{field, qASC} 500 o := queryOrder{field, qASC}
501 if strings.HasPrefix(field, "-") { 501 if strings.HasPrefix(field, "-") {
502 o.direction = qDEC 502 o.direction = qDEC
503 o.field = strings.TrimSpace(field[1:]) 503 o.field = strings.TrimSpace(field[1:])
504 } else if strings.HasPrefix(field, "+") { 504 } else if strings.HasPrefix(field, "+") {
505 q.err = fmt.Errorf("datastore: invalid order: %q", field) 505 q.err = fmt.Errorf("datastore: invalid order: %q", field)
506 return q 506 return q
507 } 507 }
508 if len(o.field) == 0 { 508 if len(o.field) == 0 {
509 q.err = errors.New("datastore: empty order") 509 q.err = errors.New("datastore: empty order")
510 return q 510 return q
511 } 511 }
512 q.order = append(q.order, o) 512 q.order = append(q.order, o)
513 return q 513 return q
514 } 514 }
515 515
516 func (q *queryImpl) Project(fieldName ...string) rds.Query { 516 func (q *queryImpl) Project(fieldName ...string) ds.Query {
517 q = q.clone() 517 q = q.clone()
518 q.project = append(q.project, fieldName...) 518 q.project = append(q.project, fieldName...)
519 return q 519 return q
520 } 520 }
521 521
522 func (q *queryImpl) KeysOnly() rds.Query { 522 func (q *queryImpl) KeysOnly() ds.Query {
523 q = q.clone() 523 q = q.clone()
524 q.keysOnly = true 524 q.keysOnly = true
525 return q 525 return q
526 } 526 }
527 527
528 func (q *queryImpl) Limit(limit int) rds.Query { 528 func (q *queryImpl) Limit(limit int) ds.Query {
529 q = q.clone() 529 q = q.clone()
530 if limit < math.MinInt32 || limit > math.MaxInt32 { 530 if limit < math.MinInt32 || limit > math.MaxInt32 {
531 q.err = errors.New("datastore: query limit overflow") 531 q.err = errors.New("datastore: query limit overflow")
532 return q 532 return q
533 } 533 }
534 q.limit = int32(limit) 534 q.limit = int32(limit)
535 return q 535 return q
536 } 536 }
537 537
538 func (q *queryImpl) Offset(offset int) rds.Query { 538 func (q *queryImpl) Offset(offset int) ds.Query {
539 q = q.clone() 539 q = q.clone()
540 if offset < 0 { 540 if offset < 0 {
541 q.err = errors.New("datastore: negative query offset") 541 q.err = errors.New("datastore: negative query offset")
542 return q 542 return q
543 } 543 }
544 if offset > math.MaxInt32 { 544 if offset > math.MaxInt32 {
545 q.err = errors.New("datastore: query offset overflow") 545 q.err = errors.New("datastore: query offset overflow")
546 return q 546 return q
547 } 547 }
548 q.offset = int32(offset) 548 q.offset = int32(offset)
549 return q 549 return q
550 } 550 }
551 551
552 func (q *queryImpl) Start(c rds.Cursor) rds.Query { 552 func (q *queryImpl) Start(c ds.Cursor) ds.Query {
553 q = q.clone() 553 q = q.clone()
554 curs := c.(queryCursor) 554 curs := c.(queryCursor)
555 if !curs.Valid() { 555 if !curs.Valid() {
556 q.err = errors.New("datastore: invalid cursor") 556 q.err = errors.New("datastore: invalid cursor")
557 return q 557 return q
558 } 558 }
559 q.start = curs 559 q.start = curs
560 return q 560 return q
561 } 561 }
562 562
563 func (q *queryImpl) End(c rds.Cursor) rds.Query { 563 func (q *queryImpl) End(c ds.Cursor) ds.Query {
564 q = q.clone() 564 q = q.clone()
565 curs := c.(queryCursor) 565 curs := c.(queryCursor)
566 if !curs.Valid() { 566 if !curs.Valid() {
567 q.err = errors.New("datastore: invalid cursor") 567 q.err = errors.New("datastore: invalid cursor")
568 return q 568 return q
569 } 569 }
570 q.end = curs 570 q.end = curs
571 return q 571 return q
572 } 572 }
573 573
574 func (q *queryImpl) EventualConsistency() rds.Query { 574 func (q *queryImpl) EventualConsistency() ds.Query {
575 q = q.clone() 575 q = q.clone()
576 q.eventualConsistency = true 576 q.eventualConsistency = true
577 return q 577 return q
578 } 578 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698