func (d *dsTxnBuf) Run(fq *ds.FinalizedQuery, cb ds.RawRunCB) error { if start, end := fq.Bounds(); start != nil || end != nil { return errors.New("txnBuf filter does not support query cursors") } limit, limitSet := fq.Limit() offset, _ := fq.Offset() keysOnly := fq.KeysOnly() project := fq.Project() bufDS, parentDS, sizes := func() (ds.RawInterface, ds.RawInterface, *sizeTracker) { if !d.haveLock { d.state.Lock() defer d.state.Unlock() } return d.state.bufDS, d.state.parentDS, d.state.entState.dup() }() return runMergedQueries(fq, sizes, bufDS, parentDS, func(key *ds.Key, data ds.PropertyMap) error { if offset > 0 { offset-- return nil } if limitSet { if limit == 0 { return ds.Stop } limit-- } if keysOnly { data = nil } else if len(project) > 0 { newData := make(ds.PropertyMap, len(project)) for _, p := range project { newData[p] = data[p] } data = newData } return cb(key, data, nil) }) }
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 }
func executeQuery(fq *ds.FinalizedQuery, aid, ns string, isTxn bool, idx, head *memStore, cb ds.RawRunCB) error { rq, err := reduce(fq, aid, ns, isTxn) if err == ds.ErrNullQuery { return nil } if err != nil { return err } idxs, err := getIndexes(rq, idx) if err == ds.ErrNullQuery { return nil } if err != nil { return err } strategy := pickQueryStrategy(fq, rq, cb, head) if strategy == nil { // e.g. the normalStrategy found that there were NO entities in the current // namespace. return nil } offset, _ := fq.Offset() limit, hasLimit := fq.Limit() cursorPrefix := []byte(nil) getCursorFn := func(suffix []byte) func() (ds.Cursor, error) { return func() (ds.Cursor, error) { if cursorPrefix == nil { buf := &bytes.Buffer{} _, err := cmpbin.WriteUint(buf, uint64(len(rq.suffixFormat))) memoryCorruption(err) for _, col := range rq.suffixFormat { err := serialize.WriteIndexColumn(buf, col) memoryCorruption(err) } cursorPrefix = buf.Bytes() } // TODO(riannucci): Do we need to decrement suffix instead of increment // if we're sorting by __key__ DESCENDING? return queryCursor(serialize.Join(cursorPrefix, increment(suffix))), nil } } return multiIterate(idxs, func(suffix []byte) error { if offset > 0 { offset-- return nil } if hasLimit { if limit <= 0 { return ds.Stop } limit-- } rawData, decodedProps := parseSuffix(aid, ns, rq.suffixFormat, suffix, -1) keyProp := decodedProps[len(decodedProps)-1] if keyProp.Type() != ds.PTKey { impossible(fmt.Errorf("decoded index row doesn't end with a Key: %#v", keyProp)) } return strategy.handle( rawData, decodedProps, keyProp.Value().(*ds.Key), getCursorFn(suffix)) }) }