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

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

Issue 1378613003: Fix bugs in service/datastore (Closed) Base URL: https://github.com/luci/gae.git@add_has_ancestor
Patch Set: 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
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
dnj 2015/09/29 19:06:23 nit: IMO just split this out into a "with ancestor
iannucci 2015/09/29 19:19:55 but there's only one case. We're computing the thr
480 » » » » return fmt.Errorf("kindless queries not have any equality filters") 486 » » » if ancestor != nil {
487 » » » » allowedEqs = 1
488 » » » }
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 ancestor != nil && !q.ineqFiltLow.Val ue().(*Key).HasAncestor(ancestor) {
519 return fmt.Errorf(
520 "inequality filters on _ _key__ must be descendants of the __ancestor__")
521 }
522 }
523 if q.ineqFiltHighSet {
524 if ancestor != nil && !q.ineqFiltHigh.Va lue().(*Key).HasAncestor(ancestor) {
525 return fmt.Errorf(
526 "inequality filters on _ _key__ must be descendants of the __ancestor__")
527 }
528 }
529 }
506 } 530 }
507 531
508 err := error(nil) 532 err := error(nil)
509 if q.project != nil { 533 if q.project != nil {
510 q.project.Iter(func(p string) bool { 534 q.project.Iter(func(p string) bool {
511 if _, iseq := q.eqFilts[p]; iseq { 535 if _, iseq := q.eqFilts[p]; iseq {
512 err = fmt.Errorf("cannot project on equa lity filter field: %s", p) 536 err = fmt.Errorf("cannot project on equa lity filter field: %s", p)
513 return false 537 return false
514 } 538 }
515 return true 539 return true
516 }) 540 })
517 } 541 }
518 return err 542 return err
519 }() 543 }()
520 if err != nil { 544 if err != nil {
521 q.err = err 545 q.err = err
522 return nil, err 546 return nil, err
523 } 547 }
524 548
525 ret := &FinalizedQuery{ 549 ret := &FinalizedQuery{
526 original: q, 550 original: q,
527 kind: q.kind, 551 kind: q.kind,
528 552
529 keysOnly: q.keysOnly, 553 keysOnly: q.keysOnly,
530 » » eventuallyConsistent: q.eventualConsistency || q.eqFilts["__ance stor__"] == nil, 554 » » eventuallyConsistent: q.eventualConsistency || ancestor == nil,
531 limit: q.limit, 555 limit: q.limit,
532 offset: q.offset, 556 offset: q.offset,
533 start: q.start, 557 start: q.start,
534 end: q.end, 558 end: q.end,
535 559
536 eqFilts: q.eqFilts, 560 eqFilts: q.eqFilts,
537 561
538 ineqFiltProp: q.ineqFiltProp, 562 ineqFiltProp: q.ineqFiltProp,
539 ineqFiltLow: q.ineqFiltLow, 563 ineqFiltLow: q.ineqFiltLow,
540 ineqFiltLowIncl: q.ineqFiltLowIncl, 564 ineqFiltLowIncl: q.ineqFiltLowIncl,
541 ineqFiltLowSet: q.ineqFiltLowSet, 565 ineqFiltLowSet: q.ineqFiltLowSet,
542 ineqFiltHigh: q.ineqFiltHigh, 566 ineqFiltHigh: q.ineqFiltHigh,
543 ineqFiltHighIncl: q.ineqFiltHighIncl, 567 ineqFiltHighIncl: q.ineqFiltHighIncl,
544 ineqFiltHighSet: q.ineqFiltHighSet, 568 ineqFiltHighSet: q.ineqFiltHighSet,
545 } 569 }
546 570
547 if q.project != nil { 571 if q.project != nil {
548 ret.project = q.project.ToSlice() 572 ret.project = q.project.ToSlice()
549 ret.distinct = q.distinct && q.project.Len() > 0 573 ret.distinct = q.distinct && q.project.Len() > 0
550 } 574 }
551 575
576 seenOrders := stringset.New(len(q.order))
577
552 // if len(q.order) > 0, we already enforce that the first order 578 // 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. 579 // is the same as the inequality above. Otherwise we need to add it.
554 if len(q.order) == 0 && q.ineqFiltProp != "" { 580 if len(q.order) == 0 && q.ineqFiltProp != "" {
555 ret.orders = []IndexColumn{{Property: q.ineqFiltProp}} 581 ret.orders = []IndexColumn{{Property: q.ineqFiltProp}}
582 seenOrders.Add(q.ineqFiltProp)
556 } 583 }
557 584
558 seenOrders := stringset.New(len(q.order))
559
560 // drop orders where there's an equality filter 585 // 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 586 // https://cloud.google.com/appengine/docs/go/datastore/queries#sort_o rders_are_ignored_on_properties_with_equality_filters
562 // Deduplicate orders 587 // Deduplicate orders
563 for _, o := range q.order { 588 for _, o := range q.order {
564 if _, iseq := q.eqFilts[o.Property]; !iseq { 589 if _, iseq := q.eqFilts[o.Property]; !iseq {
565 if seenOrders.Add(o.Property) { 590 if seenOrders.Add(o.Property) {
566 ret.orders = append(ret.orders, o) 591 ret.orders = append(ret.orders, o)
567 } 592 }
568 } 593 }
569 } 594 }
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
700 if q.keysOnly { 725 if q.keysOnly {
701 p("KeysOnly") 726 p("KeysOnly")
702 } 727 }
703 728
704 if _, err := ret.WriteRune(')'); err != nil { 729 if _, err := ret.WriteRune(')'); err != nil {
705 panic(err) 730 panic(err)
706 } 731 }
707 732
708 return ret.String() 733 return ret.String()
709 } 734 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698