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

3 4
import "sort"

5 6 7 8 9 10 11 12 13 14 15
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
16 17
	go func() {
		defer close(ch)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
18
		defer qr.Close()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
19

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

	return DerivedResults(qr, ch)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
28 29 30
}

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

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

	return DerivedResults(qr, ch)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
52 53 54
}

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

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

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

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

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

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

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

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

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

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

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

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