1package query
2
3import (
4	"bytes"
5	"sort"
6	"strings"
7)
8
9// Order is an object used to order objects
10type Order interface {
11	Compare(a, b Entry) int
12}
13
14// OrderByFunction orders the results based on the result of the given function.
15type OrderByFunction func(a, b Entry) int
16
17func (o OrderByFunction) Compare(a, b Entry) int {
18	return o(a, b)
19}
20
21func (OrderByFunction) String() string {
22	return "FN"
23}
24
25// OrderByValue is used to signal to datastores they should apply internal
26// orderings.
27type OrderByValue struct{}
28
29func (o OrderByValue) Compare(a, b Entry) int {
30	return bytes.Compare(a.Value, b.Value)
31}
32
33func (OrderByValue) String() string {
34	return "VALUE"
35}
36
37// OrderByValueDescending is used to signal to datastores they
38// should apply internal orderings.
39type OrderByValueDescending struct{}
40
41func (o OrderByValueDescending) Compare(a, b Entry) int {
42	return -bytes.Compare(a.Value, b.Value)
43}
44
45func (OrderByValueDescending) String() string {
46	return "desc(VALUE)"
47}
48
49// OrderByKey
50type OrderByKey struct{}
51
52func (o OrderByKey) Compare(a, b Entry) int {
53	return strings.Compare(a.Key, b.Key)
54}
55
56func (OrderByKey) String() string {
57	return "KEY"
58}
59
60// OrderByKeyDescending
61type OrderByKeyDescending struct{}
62
63func (o OrderByKeyDescending) Compare(a, b Entry) int {
64	return -strings.Compare(a.Key, b.Key)
65}
66
67func (OrderByKeyDescending) String() string {
68	return "desc(KEY)"
69}
70
71// Less returns true if a comes before b with the requested orderings.
72func Less(orders []Order, a, b Entry) bool {
73	for _, cmp := range orders {
74		switch cmp.Compare(a, b) {
75		case 0:
76		case -1:
77			return true
78		case 1:
79			return false
80		}
81	}
82
83	// This gives us a *stable* sort for free. We don't care
84	// preserving the order from the underlying datastore
85	// because it's undefined.
86	return a.Key < b.Key
87}
88
89// Sort sorts the given entries using the given orders.
90func Sort(orders []Order, entries []Entry) {
91	sort.Slice(entries, func(i int, j int) bool {
92		return Less(orders, entries[i], entries[j])
93	})
94}
95