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