query_impl.go 2.41 KB
Newer Older
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
1 2
package query

Michael Avila's avatar
Michael Avila committed
3 4 5
import (
	"sort"
)
6

7 8 9 10 11 12 13 14 15 16 17
func DerivedResults(qr Results, ch <-chan Result) Results {
	return &results{
		query: qr.Query(),
		proc:  qr.Process(),
		res:   ch,
	}
}

// NaiveFilter applies a filter to the results.
func NaiveFilter(qr Results, filter Filter) Results {
	ch := make(chan Result)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
18 19
	go func() {
		defer close(ch)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
20
		defer qr.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
21

22 23
		for e := range qr.Next() {
			if e.Error != nil || filter.Filter(e.Entry) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
24 25 26 27
				ch <- e
			}
		}
	}()
28

29
	return ResultsWithChan(qr.Query(), ch)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
30 31 32
}

// NaiveLimit truncates the results to a given int limit
33 34
func NaiveLimit(qr Results, limit int) Results {
	ch := make(chan Result)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
35 36
	go func() {
		defer close(ch)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
37
		defer qr.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
38

39 40
		l := 0
		for e := range qr.Next() {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
41
			if e.Error != nil {
42
				ch <- e
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
43
				continue
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
44
			}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
45
			ch <- e
46
			l++
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
47 48 49
			if limit > 0 && l >= limit {
				break
			}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
50 51
		}
	}()
52

Michael Avila's avatar
Michael Avila committed
53
	return ResultsWithChan(qr.Query(), ch)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
54 55 56
}

// NaiveOffset skips a given number of results
57 58
func NaiveOffset(qr Results, offset int) Results {
	ch := make(chan Result)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
59 60
	go func() {
		defer close(ch)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
61
		defer qr.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
62

63 64 65 66 67
		sent := 0
		for e := range qr.Next() {
			if e.Error != nil {
				ch <- e
			}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
68

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
69
			if sent < offset {
70
				sent++
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
71
				continue
72
			}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
73
			ch <- e
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
74 75
		}
	}()
76

77
	return ResultsWithChan(qr.Query(), ch)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
78 79
}

80
// NaiveOrder reorders results according to given orders.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
81
// WARNING: this is the only non-stream friendly operation!
82 83 84 85 86 87
func NaiveOrder(qr Results, orders ...Order) Results {
	// Short circuit.
	if len(orders) == 0 {
		return qr
	}

88 89 90 91
	ch := make(chan Result)
	var entries []Entry
	go func() {
		defer close(ch)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
92
		defer qr.Close()
93 94 95 96 97 98 99 100

		for e := range qr.Next() {
			if e.Error != nil {
				ch <- e
			}

			entries = append(entries, e.Entry)
		}
101
		sort.Slice(entries, func(i int, j int) bool {
Steven Allen's avatar
Steven Allen committed
102
			return Less(orders, entries[i], entries[j])
103
		})
104 105 106 107 108 109 110

		for _, e := range entries {
			ch <- Result{Entry: e}
		}
	}()

	return DerivedResults(qr, ch)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
111 112
}

113
func NaiveQueryApply(q Query, qr Results) Results {
114 115 116
	if q.Prefix != "" {
		qr = NaiveFilter(qr, FilterKeyPrefix{q.Prefix})
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
117 118 119
	for _, f := range q.Filters {
		qr = NaiveFilter(qr, f)
	}
120 121
	if len(q.Orders) > 0 {
		qr = NaiveOrder(qr, q.Orders...)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
122
	}
123 124 125 126
	if q.Offset != 0 {
		qr = NaiveOffset(qr, q.Offset)
	}
	if q.Limit != 0 {
Michael Avila's avatar
Michael Avila committed
127
		// TODO: Offset?
128
		qr = NaiveLimit(qr, q.Limit)
129
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
130 131 132
	return qr
}

133
func ResultEntriesFrom(keys []string, vals [][]byte) []Entry {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
134 135 136 137 138 139
	re := make([]Entry, len(keys))
	for i, k := range keys {
		re[i] = Entry{Key: k, Value: vals[i]}
	}
	return re
}