blob: 0f324cd1383912f4b50b8cee84dd5a7f0726eb1d [file] [log] [blame]
Zack Williamse940c7a2019-08-21 14:25:39 -07001/*
2 * Copyright 2019-present Ciena Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package order
17
18import (
19 "fmt"
20 "reflect"
21 "sort"
22 "strings"
23)
24
25type Operation int
26
27const (
28 ASC Operation = iota
29 DSC
30)
31
32type SortTerm struct {
33 Op Operation
34 Name string
35}
36
37func (o Operation) String() string {
38 switch o {
39 default:
40 fallthrough
41 case ASC:
42 return "ASC"
43 case DSC:
44 return "DSC"
45 }
46}
47
48type Sorter []SortTerm
49
50func split(term string) SortTerm {
51 st := SortTerm{}
52 if len(term) > 0 {
53 switch term[0] {
54 case '+':
55 fallthrough
56 case '>':
57 st.Op = ASC
58 st.Name = term[1:]
59 case '-':
60 fallthrough
61 case '<':
62 st.Op = DSC
63 st.Name = term[1:]
64 default:
65 st.Op = ASC
66 st.Name = term
67 }
68 } else {
69 st.Op = ASC
70 st.Name = term
71 }
72 return st
73}
74
75// Parse parses a comma separated list of filter terms
76func Parse(spec string) (Sorter, error) {
77 terms := strings.Split(spec, ",")
78 s := make([]SortTerm, 0)
79 for _, term := range terms {
80 s = append(s, split(term))
81 }
82
83 return s, nil
84}
85
86func (s Sorter) Process(data interface{}) (interface{}, error) {
87 slice := reflect.ValueOf(data)
88 if slice.Kind() != reflect.Slice {
89 return data, nil
90 }
91
92 sort.SliceStable(data, func(i, j int) bool {
93 left := reflect.ValueOf(slice.Index(i).Interface())
94 right := reflect.ValueOf(slice.Index(j).Interface())
Scott Baker34539bf2020-06-04 23:08:57 -070095
96 if left.Kind() == reflect.Ptr {
97 left = reflect.Indirect(left)
98 }
99
100 if right.Kind() == reflect.Ptr {
101 right = reflect.Indirect(right)
102 }
103
Zack Williamse940c7a2019-08-21 14:25:39 -0700104 for _, term := range s {
105 fleft := left.FieldByName(term.Name)
106 fright := right.FieldByName(term.Name)
107 switch fleft.Kind() {
108 case reflect.Uint:
109 fallthrough
110 case reflect.Uint8:
111 fallthrough
112 case reflect.Uint16:
113 fallthrough
114 case reflect.Uint32:
115 fallthrough
116 case reflect.Uint64:
117 ileft := fleft.Uint()
118 iright := fright.Uint()
119 switch term.Op {
120 case ASC:
121 if ileft < iright {
122 return true
123 } else if ileft > iright {
124 return false
125 }
126 case DSC:
127 if ileft > iright {
128 return true
129 } else if ileft < iright {
130 return false
131 }
132 }
133 case reflect.Int:
134 fallthrough
135 case reflect.Int8:
136 fallthrough
137 case reflect.Int16:
138 fallthrough
139 case reflect.Int32:
140 fallthrough
141 case reflect.Int64:
142 ileft := fleft.Int()
143 iright := fright.Int()
144 switch term.Op {
145 case ASC:
146 if ileft < iright {
147 return true
148 } else if ileft > iright {
149 return false
150 }
151 case DSC:
152 if ileft > iright {
153 return true
154 } else if ileft < iright {
155 return false
156 }
157 }
158 default:
159 sleft := fmt.Sprintf("%v", left.FieldByName(term.Name))
160 sright := fmt.Sprintf("%v", right.FieldByName(term.Name))
161 diff := strings.Compare(sleft, sright)
162 if term.Op != DSC {
163 if diff == -1 {
164 return true
165 } else if diff == 1 {
166 return false
167 }
168 } else {
169 if diff == 1 {
170 return true
171 } else if diff == -1 {
172 return false
173 }
174 }
175 }
176 }
177 return false
178 })
179
180 return data, nil
181}