-
Notifications
You must be signed in to change notification settings - Fork 0
/
orderby.go
105 lines (95 loc) · 2.73 KB
/
orderby.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/*
* Copyright (c) 2021 BlueStorm
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package datatable
import (
"sort"
)
func (dt *DataTable) OrderBy(query string) *DataTable {
if dt.Count <= 1 {
return dt
}
exp := OrderBy([]byte(query))
count := len(exp.OrderExpr)
if count == 0 {
return dt
}
var less = make([]lessFunc, count)
for i, item := range exp.OrderExpr {
less[i] = func(c1, c2 map[string]interface{}) bool {
v1, ok1 := FormatFloat(c1[item.Name])
v2, ok2 := FormatFloat(c2[item.Name])
if ok1 && ok2 {
if item.Op == "desc" {
return v1 > v2
} else {
return v1 < v2
}
} else {
if item.Op == "desc" {
return ToString(c1[item.Name]) > ToString(c2[item.Name])
} else {
return ToString(c1[item.Name]) < ToString(c2[item.Name])
}
}
}
}
fn(less...).sorts(dt.Rows)
return dt
}
type lessFunc func(p1, p2 map[string]interface{}) bool
type multiSorter struct {
changes []map[string]interface{}
less []lessFunc
}
func (ms *multiSorter) sorts(changes []map[string]interface{}) {
ms.changes = changes
sort.Sort(ms)
}
func fn(less ...lessFunc) *multiSorter {
return &multiSorter{
less: less,
}
}
func (ms *multiSorter) Len() int {
return len(ms.changes)
}
func (ms *multiSorter) Swap(i, j int) {
ms.changes[i], ms.changes[j] = ms.changes[j], ms.changes[i]
}
func (ms *multiSorter) Less(i, j int) bool {
p, q := ms.changes[i], ms.changes[j]
// Try all but the last comparison.
var k int
for k = 0; k < len(ms.less)-1; k++ {
less := ms.less[k]
switch {
case less(p, q):
// p < q, so we have a decision.
return true
case less(q, p):
// p > q, so we have a decision.
return false
}
// p == q; try the next comparison.
}
return ms.less[k](p, q)
}