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