func numComponents(fq *ds.FinalizedQuery) int { numComponents := len(fq.Orders()) if p, _, _ := fq.IneqFilterLow(); p != "" { numComponents++ } if p, _, _ := fq.IneqFilterHigh(); p != "" { numComponents++ } for _, v := range fq.EqFilters() { numComponents += v.Len() } return numComponents }
// 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 flipped. func GetBinaryBounds(fq *ds.FinalizedQuery) (lower, upper []byte) { // 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. if ineqProp := fq.IneqFilterProp(); ineqProp != "" { _, startOp, startV := fq.IneqFilterLow() if startOp != "" { lower = serialize.ToBytes(startV) if startOp == ">" { lower = increment(lower) } } _, endOp, endV := fq.IneqFilterHigh() if endOp != "" { upper = serialize.ToBytes(endV) if endOp == "<=" { upper = increment(upper) } } // The inequality is specified in natural (ascending) order in the query's // Filter syntax, but the order information may indicate to use a descending // index column for it. If that's the case, then we must invert, swap and // increment the inequality endpoints. // // Invert so that the desired numbers are represented correctly in the index. // 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 fq.Orders()[0].Descending { hi, lo := []byte(nil), []byte(nil) if len(lower) > 0 { lo = increment(serialize.Invert(lower)) } if len(upper) > 0 { hi = increment(serialize.Invert(upper)) } upper, lower = lo, hi } } return }
func (d rdsImpl) fixQuery(fq *ds.FinalizedQuery) (*datastore.Query, error) { ret := datastore.NewQuery(fq.Kind()) start, end := fq.Bounds() if start != nil { ret = ret.Start(start.(datastore.Cursor)) } if end != nil { ret = ret.End(end.(datastore.Cursor)) } for prop, vals := range fq.EqFilters() { if prop == "__ancestor__" { p, err := dsF2RProp(d.aeCtx, vals[0]) if err != nil { return nil, err } ret = ret.Ancestor(p.Value.(*datastore.Key)) } else { filt := prop + "=" for _, v := range vals { p, err := dsF2RProp(d.aeCtx, v) if err != nil { return nil, err } ret = ret.Filter(filt, p.Value) } } } if lnam, lop, lprop := fq.IneqFilterLow(); lnam != "" { p, err := dsF2RProp(d.aeCtx, lprop) if err != nil { return nil, err } ret = ret.Filter(lnam+" "+lop, p.Value) } if hnam, hop, hprop := fq.IneqFilterHigh(); hnam != "" { p, err := dsF2RProp(d.aeCtx, hprop) if err != nil { return nil, err } ret = ret.Filter(hnam+" "+hop, p.Value) } if fq.EventuallyConsistent() { ret = ret.EventualConsistency() } if fq.KeysOnly() { ret = ret.KeysOnly() } if lim, ok := fq.Limit(); ok { ret = ret.Limit(int(lim)) } if off, ok := fq.Offset(); ok { ret = ret.Offset(int(off)) } for _, o := range fq.Orders() { ret = ret.Order(o.String()) } ret = ret.Project(fq.Project()...) if fq.Distinct() { ret = ret.Distinct() } return ret, nil }