Chromium Code Reviews| Index: impl/memory/datastore_query.go |
| diff --git a/impl/memory/datastore_query.go b/impl/memory/datastore_query.go |
| index ed49a79820546cfda2b50916961a24563b302a4d..856f4c19bf0c110f29999217dfff28464245c12c 100644 |
| --- a/impl/memory/datastore_query.go |
| +++ b/impl/memory/datastore_query.go |
| @@ -102,57 +102,32 @@ func numComponents(fq *ds.FinalizedQuery) int { |
| return numComponents |
| } |
| -func reduce(fq *ds.FinalizedQuery, ns string, isTxn bool) (*reducedQuery, error) { |
| - if err := fq.Valid(globalAppID, ns); err != nil { |
| - return nil, err |
| - } |
| - if isTxn && fq.Ancestor() == nil { |
| - return nil, fmt.Errorf("queries within a transaction must include an Ancestor filter") |
| - } |
| - if num := numComponents(fq); num > MaxQueryComponents { |
| - return nil, fmt.Errorf( |
| - "gae/memory: query is too large. may not have more than "+ |
| - "%d filters + sort orders + ancestor total: had %d", |
| - MaxQueryComponents, num) |
| - } |
| - |
| - ret := &reducedQuery{ |
| - ns: ns, |
| - kind: fq.Kind(), |
| - suffixFormat: fq.Orders(), |
| - } |
| - |
| - eqFilts := fq.EqFilters() |
| - ret.eqFilters = make(map[string]stringset.Set, len(eqFilts)) |
| - for prop, vals := range eqFilts { |
| - sVals := stringset.New(len(vals)) |
| - for _, v := range vals { |
| - sVals.Add(string(serialize.ToBytes(v))) |
| - } |
| - ret.eqFilters[prop] = sVals |
| - } |
| - |
| +// GetBinaryBounds gets the binary encoding of the upper and lower bounds of |
| +// the inequality filter on fq, if any is defined. If a bound does not exist, |
| +// it is nil. |
| +// |
| +// NOTE: if fq specifies a descending sort order for the inequality, the bounds |
| +// will be inverted, incremented, and fliped. |
| +func GetBinaryBounds(fq *ds.FinalizedQuery) (lower, upper []byte) { |
|
iannucci
2015/09/29 04:43:27
This was factored out to allow toComparableString
|
| // Pick up the start/end range from the inequalities, if any. |
| // |
| // start and end in the reducedQuery are normalized so that `start >= |
| // X < end`. Because of that, we need to tweak the inequality filters |
| // contained in the query if they use the > or <= operators. |
| - startD := []byte(nil) |
| - endD := []byte(nil) |
| if ineqProp := fq.IneqFilterProp(); ineqProp != "" { |
| _, startOp, startV := fq.IneqFilterLow() |
| if startOp != "" { |
| - startD = serialize.ToBytes(startV) |
| + lower = serialize.ToBytes(startV) |
| if startOp == ">" { |
| - startD = increment(startD) |
| + lower = increment(lower) |
| } |
| } |
| _, endOp, endV := fq.IneqFilterHigh() |
| if endOp != "" { |
| - endD = serialize.ToBytes(endV) |
| + upper = serialize.ToBytes(endV) |
| if endOp == "<=" { |
| - endD = increment(endD) |
| + upper = increment(upper) |
| } |
| } |
| @@ -165,18 +140,53 @@ func reduce(fq *ds.FinalizedQuery, ns string, isTxn bool) (*reducedQuery, error) |
| // Swap so that our iterators still go from >= start to < end. |
| // Increment so that >= and < get correctly bounded (since the iterator is |
| // still using natrual bytes ordering) |
| - if ret.suffixFormat[0].Descending { |
| + if fq.Orders()[0].Descending { |
| hi, lo := []byte(nil), []byte(nil) |
| - if len(startD) > 0 { |
| - lo = increment(serialize.Invert(startD)) |
| + if len(lower) > 0 { |
| + lo = increment(serialize.Invert(lower)) |
| } |
| - if len(endD) > 0 { |
| - hi = increment(serialize.Invert(endD)) |
| + if len(upper) > 0 { |
| + hi = increment(serialize.Invert(upper)) |
| } |
| - endD, startD = lo, hi |
| + upper, lower = lo, hi |
| + } |
| + } |
| + return |
| +} |
| + |
| +func reduce(fq *ds.FinalizedQuery, aid, ns string, isTxn bool) (*reducedQuery, error) { |
| + if err := fq.Valid(aid, ns); err != nil { |
| + return nil, err |
| + } |
| + if isTxn && fq.Ancestor() == nil { |
| + return nil, fmt.Errorf("queries within a transaction must include an Ancestor filter") |
| + } |
| + if num := numComponents(fq); num > MaxQueryComponents { |
| + return nil, fmt.Errorf( |
| + "gae/memory: query is too large. may not have more than "+ |
| + "%d filters + sort orders + ancestor total: had %d", |
| + MaxQueryComponents, num) |
| + } |
| + |
| + ret := &reducedQuery{ |
| + aid: aid, |
| + ns: ns, |
| + kind: fq.Kind(), |
| + suffixFormat: fq.Orders(), |
| + } |
| + |
| + eqFilts := fq.EqFilters() |
| + ret.eqFilters = make(map[string]stringset.Set, len(eqFilts)) |
| + for prop, vals := range eqFilts { |
| + sVals := stringset.New(len(vals)) |
| + for _, v := range vals { |
| + sVals.Add(string(serialize.ToBytes(v))) |
| } |
| + ret.eqFilters[prop] = sVals |
| } |
| + startD, endD := GetBinaryBounds(fq) |
| + |
| // Now we check the start and end cursors. |
| // |
| // Cursors are composed of a list of IndexColumns at the beginning, followed |