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