package query import ( "sort" goprocess "github.com/jbenet/goprocess" ) // NaiveFilter applies a filter to the results. func NaiveFilter(qr Results, filter Filter) Results { return ResultsFromIterator(qr.Query(), Iterator{ Next: func() (Result, bool) { for { e, ok := qr.NextSync() if !ok { return Result{}, false } if e.Error != nil || filter.Filter(e.Entry) { return e, true } } }, Close: func() error { return qr.Close() }, }) } // NaiveLimit truncates the results to a given int limit func NaiveLimit(qr Results, limit int) Results { if limit == 0 { // 0 means no limit return qr } closed := false return ResultsFromIterator(qr.Query(), Iterator{ Next: func() (Result, bool) { if limit == 0 { if !closed { closed = true err := qr.Close() if err != nil { return Result{Error: err}, true } } return Result{}, false } limit-- return qr.NextSync() }, Close: func() error { if closed { return nil } closed = true return qr.Close() }, }) } // NaiveOffset skips a given number of results func NaiveOffset(qr Results, offset int) Results { return ResultsFromIterator(qr.Query(), Iterator{ Next: func() (Result, bool) { for ; offset > 0; offset-- { res, ok := qr.NextSync() if !ok || res.Error != nil { return res, ok } } return qr.NextSync() }, Close: func() error { return qr.Close() }, }) } // NaiveOrder reorders results according to given orders. // WARNING: this is the only non-stream friendly operation! func NaiveOrder(qr Results, orders ...Order) Results { // Short circuit. if len(orders) == 0 { return qr } return ResultsWithProcess(qr.Query(), func(worker goprocess.Process, out chan<- Result) { defer qr.Close() var entries []Entry collect: for { select { case <-worker.Closing(): return case e, ok := <-qr.Next(): if !ok { break collect } if e.Error != nil { out <- e continue } entries = append(entries, e.Entry) } } sort.Slice(entries, func(i int, j int) bool { return Less(orders, entries[i], entries[j]) }) for _, e := range entries { select { case <-worker.Closing(): return case out <- Result{Entry: e}: } } }) } func NaiveQueryApply(q Query, qr Results) Results { if q.Prefix != "" { qr = NaiveFilter(qr, FilterKeyPrefix{q.Prefix}) } for _, f := range q.Filters { qr = NaiveFilter(qr, f) } if len(q.Orders) > 0 { qr = NaiveOrder(qr, q.Orders...) } if q.Offset != 0 { qr = NaiveOffset(qr, q.Offset) } if q.Limit != 0 { qr = NaiveLimit(qr, q.Limit) } return qr } func ResultEntriesFrom(keys []string, vals [][]byte) []Entry { re := make([]Entry, len(keys)) for i, k := range keys { re[i] = Entry{Key: k, Value: vals[i]} } return re }