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 "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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |