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

Side by Side Diff: service/datastore/query.go

Issue 1309803004: Add transaction buffer filter. (Closed) Base URL: https://github.com/luci/gae.git@add_query_support
Patch Set: make data flow clearer, implement Count Created 5 years, 2 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
« service/datastore/index.go ('K') | « service/datastore/key.go ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 datastore 5 package datastore
6 6
7 import ( 7 import (
8 "bytes" 8 "bytes"
9 "fmt" 9 "fmt"
10 "sort" 10 "sort"
(...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after
463 } 463 }
464 464
465 // Finalize converts this Query to a FinalizedQuery. If the Query has any 465 // Finalize converts this Query to a FinalizedQuery. If the Query has any
466 // inconsistencies or violates any of the query rules, that will be returned 466 // inconsistencies or violates any of the query rules, that will be returned
467 // here. 467 // here.
468 func (q *Query) Finalize() (*FinalizedQuery, error) { 468 func (q *Query) Finalize() (*FinalizedQuery, error) {
469 if q.err != nil || q.finalized != nil { 469 if q.err != nil || q.finalized != nil {
470 return q.finalized, q.err 470 return q.finalized, q.err
471 } 471 }
472 472
473 ancestor := (*Key)(nil)
474 if slice, ok := q.eqFilts["__ancestor__"]; ok {
475 ancestor = slice[0].Value().(*Key)
476 }
477
473 err := func() error { 478 err := func() error {
479
474 if q.kind == "" { // kindless query checks 480 if q.kind == "" { // kindless query checks
475 if q.ineqFiltProp != "" && q.ineqFiltProp != "__key__" { 481 if q.ineqFiltProp != "" && q.ineqFiltProp != "__key__" {
476 return fmt.Errorf( 482 return fmt.Errorf(
477 "kindless queries can only filter on __k ey__, got %q", q.ineqFiltProp) 483 "kindless queries can only filter on __k ey__, got %q", q.ineqFiltProp)
478 } 484 }
479 » » » if len(q.eqFilts) > 0 { 485 » » » allowedEqs := 0
480 » » » » return fmt.Errorf("kindless queries not have any equality filters") 486 » » » if ancestor != nil {
487 » » » » allowedEqs = 1
488 » » » }
iannucci 2015/09/29 04:43:28 ancestor filters are technically equality filters
489 » » » if len(q.eqFilts) > allowedEqs {
490 » » » » return fmt.Errorf("kindless queries may not have any equality filters")
481 } 491 }
482 for _, o := range q.order { 492 for _, o := range q.order {
483 if o.Property != "__key__" || o.Descending { 493 if o.Property != "__key__" || o.Descending {
484 return fmt.Errorf("invalid order for kin dless query: %#v", o) 494 return fmt.Errorf("invalid order for kin dless query: %#v", o)
485 } 495 }
486 } 496 }
487 } 497 }
488 498
489 if q.keysOnly && q.project != nil && q.project.Len() > 0 { 499 if q.keysOnly && q.project != nil && q.project.Len() > 0 {
490 return errors.New("cannot project a keysOnly query") 500 return errors.New("cannot project a keysOnly query")
491 } 501 }
492 502
493 if q.ineqFiltProp != "" { 503 if q.ineqFiltProp != "" {
494 if len(q.order) > 0 && q.order[0].Property != q.ineqFilt Prop { 504 if len(q.order) > 0 && q.order[0].Property != q.ineqFilt Prop {
495 return fmt.Errorf( 505 return fmt.Errorf(
496 "first sort order must match inequality filter: %q v %q", 506 "first sort order must match inequality filter: %q v %q",
497 q.order[0].Property, q.ineqFiltProp) 507 q.order[0].Property, q.ineqFiltProp)
498 } 508 }
499 if q.ineqFiltLowSet && q.ineqFiltHighSet { 509 if q.ineqFiltLowSet && q.ineqFiltHighSet {
500 if q.ineqFiltHigh.Less(&q.ineqFiltLow) && 510 if q.ineqFiltHigh.Less(&q.ineqFiltLow) &&
501 (q.ineqFiltHigh.Equal(&q.ineqFiltLow) && 511 (q.ineqFiltHigh.Equal(&q.ineqFiltLow) &&
502 (!q.ineqFiltLowIncl || !q.ineqFi ltHighIncl)) { 512 (!q.ineqFiltLowIncl || !q.ineqFi ltHighIncl)) {
503 return ErrNullQuery 513 return ErrNullQuery
504 } 514 }
505 } 515 }
516 if q.ineqFiltProp == "__key__" {
517 if q.ineqFiltLowSet {
518 if q.ineqFiltLow.Type() != PTKey {
519 return fmt.Errorf(
520 "inequality filters on _ _key__ must use *ds.Key values")
521 }
522 if ancestor != nil && !q.ineqFiltLow.Val ue().(*Key).HasAncestor(ancestor) {
523 return fmt.Errorf(
524 "inequality filters on _ _key__ must be descendants of the __ancestor__")
525 }
526 }
527 if q.ineqFiltHighSet {
528 if q.ineqFiltHigh.Type() != PTKey {
529 return fmt.Errorf(
530 "inequality filters on _ _key__ must use *ds.Key values")
531 }
532 if ancestor != nil && !q.ineqFiltHigh.Va lue().(*Key).HasAncestor(ancestor) {
533 return fmt.Errorf(
534 "inequality filters on _ _key__ must be descendants of the __ancestor__")
535 }
536 }
537 }
506 } 538 }
507 539
508 err := error(nil) 540 err := error(nil)
509 if q.project != nil { 541 if q.project != nil {
510 q.project.Iter(func(p string) bool { 542 q.project.Iter(func(p string) bool {
511 if _, iseq := q.eqFilts[p]; iseq { 543 if _, iseq := q.eqFilts[p]; iseq {
512 err = fmt.Errorf("cannot project on equa lity filter field: %s", p) 544 err = fmt.Errorf("cannot project on equa lity filter field: %s", p)
513 return false 545 return false
514 } 546 }
515 return true 547 return true
516 }) 548 })
517 } 549 }
518 return err 550 return err
519 }() 551 }()
520 if err != nil { 552 if err != nil {
521 q.err = err 553 q.err = err
522 return nil, err 554 return nil, err
523 } 555 }
524 556
525 ret := &FinalizedQuery{ 557 ret := &FinalizedQuery{
526 original: q, 558 original: q,
527 kind: q.kind, 559 kind: q.kind,
528 560
529 keysOnly: q.keysOnly, 561 keysOnly: q.keysOnly,
530 » » eventuallyConsistent: q.eventualConsistency || q.eqFilts["__ance stor__"] == nil, 562 » » eventuallyConsistent: q.eventualConsistency || ancestor == nil,
531 limit: q.limit, 563 limit: q.limit,
532 offset: q.offset, 564 offset: q.offset,
533 start: q.start, 565 start: q.start,
534 end: q.end, 566 end: q.end,
535 567
536 eqFilts: q.eqFilts, 568 eqFilts: q.eqFilts,
537 569
538 ineqFiltProp: q.ineqFiltProp, 570 ineqFiltProp: q.ineqFiltProp,
539 ineqFiltLow: q.ineqFiltLow, 571 ineqFiltLow: q.ineqFiltLow,
540 ineqFiltLowIncl: q.ineqFiltLowIncl, 572 ineqFiltLowIncl: q.ineqFiltLowIncl,
541 ineqFiltLowSet: q.ineqFiltLowSet, 573 ineqFiltLowSet: q.ineqFiltLowSet,
542 ineqFiltHigh: q.ineqFiltHigh, 574 ineqFiltHigh: q.ineqFiltHigh,
543 ineqFiltHighIncl: q.ineqFiltHighIncl, 575 ineqFiltHighIncl: q.ineqFiltHighIncl,
544 ineqFiltHighSet: q.ineqFiltHighSet, 576 ineqFiltHighSet: q.ineqFiltHighSet,
545 } 577 }
546 578
547 if q.project != nil { 579 if q.project != nil {
548 ret.project = q.project.ToSlice() 580 ret.project = q.project.ToSlice()
549 ret.distinct = q.distinct && q.project.Len() > 0 581 ret.distinct = q.distinct && q.project.Len() > 0
550 } 582 }
551 583
584 seenOrders := stringset.New(len(q.order))
iannucci 2015/09/29 04:43:28 was getting duplicated orders because the if state
585
552 // if len(q.order) > 0, we already enforce that the first order 586 // if len(q.order) > 0, we already enforce that the first order
553 // is the same as the inequality above. Otherwise we need to add it. 587 // is the same as the inequality above. Otherwise we need to add it.
554 if len(q.order) == 0 && q.ineqFiltProp != "" { 588 if len(q.order) == 0 && q.ineqFiltProp != "" {
555 ret.orders = []IndexColumn{{Property: q.ineqFiltProp}} 589 ret.orders = []IndexColumn{{Property: q.ineqFiltProp}}
590 seenOrders.Add(q.ineqFiltProp)
556 } 591 }
557 592
558 seenOrders := stringset.New(len(q.order))
559
560 // drop orders where there's an equality filter 593 // drop orders where there's an equality filter
561 // https://cloud.google.com/appengine/docs/go/datastore/queries#sort_o rders_are_ignored_on_properties_with_equality_filters 594 // https://cloud.google.com/appengine/docs/go/datastore/queries#sort_o rders_are_ignored_on_properties_with_equality_filters
562 // Deduplicate orders 595 // Deduplicate orders
563 for _, o := range q.order { 596 for _, o := range q.order {
564 if _, iseq := q.eqFilts[o.Property]; !iseq { 597 if _, iseq := q.eqFilts[o.Property]; !iseq {
565 if seenOrders.Add(o.Property) { 598 if seenOrders.Add(o.Property) {
566 ret.orders = append(ret.orders, o) 599 ret.orders = append(ret.orders, o)
567 } 600 }
568 } 601 }
569 } 602 }
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
700 if q.keysOnly { 733 if q.keysOnly {
701 p("KeysOnly") 734 p("KeysOnly")
702 } 735 }
703 736
704 if _, err := ret.WriteRune(')'); err != nil { 737 if _, err := ret.WriteRune(')'); err != nil {
705 panic(err) 738 panic(err)
706 } 739 }
707 740
708 return ret.String() 741 return ret.String()
709 } 742 }
OLDNEW
« service/datastore/index.go ('K') | « service/datastore/key.go ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698