blob: 715b3029bf157af675938946c343ce06671f02ef [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())
95 for _, term := range s {
96 fleft := left.FieldByName(term.Name)
97 fright := right.FieldByName(term.Name)
98 switch fleft.Kind() {
99 case reflect.Uint:
100 fallthrough
101 case reflect.Uint8:
102 fallthrough
103 case reflect.Uint16:
104 fallthrough
105 case reflect.Uint32:
106 fallthrough
107 case reflect.Uint64:
108 ileft := fleft.Uint()
109 iright := fright.Uint()
110 switch term.Op {
111 case ASC:
112 if ileft < iright {
113 return true
114 } else if ileft > iright {
115 return false
116 }
117 case DSC:
118 if ileft > iright {
119 return true
120 } else if ileft < iright {
121 return false
122 }
123 }
124 case reflect.Int:
125 fallthrough
126 case reflect.Int8:
127 fallthrough
128 case reflect.Int16:
129 fallthrough
130 case reflect.Int32:
131 fallthrough
132 case reflect.Int64:
133 ileft := fleft.Int()
134 iright := fright.Int()
135 switch term.Op {
136 case ASC:
137 if ileft < iright {
138 return true
139 } else if ileft > iright {
140 return false
141 }
142 case DSC:
143 if ileft > iright {
144 return true
145 } else if ileft < iright {
146 return false
147 }
148 }
149 default:
150 sleft := fmt.Sprintf("%v", left.FieldByName(term.Name))
151 sright := fmt.Sprintf("%v", right.FieldByName(term.Name))
152 diff := strings.Compare(sleft, sright)
153 if term.Op != DSC {
154 if diff == -1 {
155 return true
156 } else if diff == 1 {
157 return false
158 }
159 } else {
160 if diff == 1 {
161 return true
162 } else if diff == -1 {
163 return false
164 }
165 }
166 }
167 }
168 return false
169 })
170
171 return data, nil
172}