github.com/mithrandie/csvq@v1.18.1/lib/query/sort_value.go (about) 1 package query 2 3 import ( 4 "bytes" 5 "math" 6 "strings" 7 8 "github.com/mithrandie/csvq/lib/option" 9 "github.com/mithrandie/csvq/lib/parser" 10 "github.com/mithrandie/csvq/lib/value" 11 12 "github.com/mithrandie/ternary" 13 ) 14 15 type SortValueType int 16 17 const ( 18 NullType SortValueType = iota 19 IntegerType 20 FloatType 21 DatetimeType 22 BooleanType 23 StringType 24 ) 25 26 type SortValues []*SortValue 27 28 func (values SortValues) Less(compareValues SortValues, directions []int, nullPositions []int) bool { 29 for i, val := range values { 30 t := val.Less(compareValues[i]) 31 if t != ternary.UNKNOWN { 32 if directions[i] == parser.ASC { 33 return t == ternary.TRUE 34 } else { 35 return t == ternary.FALSE 36 } 37 } 38 39 if val.Type == NullType && compareValues[i].Type != NullType { 40 if nullPositions[i] == parser.FIRST { 41 return true 42 } else { 43 return false 44 } 45 } 46 if val.Type != NullType && compareValues[i].Type == NullType { 47 if nullPositions[i] == parser.FIRST { 48 return false 49 } else { 50 return true 51 } 52 } 53 } 54 return false 55 } 56 57 func (values SortValues) EquivalentTo(compareValues SortValues) bool { 58 if compareValues == nil { 59 return false 60 } 61 62 for i, val := range values { 63 if !val.EquivalentTo(compareValues[i]) { 64 return false 65 } 66 } 67 return true 68 } 69 70 func (values SortValues) Serialize(buf *bytes.Buffer) { 71 for i, val := range values { 72 if 0 < i { 73 buf.WriteByte(58) 74 } 75 76 if val.SerializedKey != nil { 77 buf.Write(val.SerializedKey.Bytes()) 78 continue 79 } 80 81 switch val.Type { 82 case NullType: 83 serializeNull(buf) 84 case IntegerType, BooleanType: 85 serializeInteger(buf, value.Int64ToStr(val.Integer)) 86 case FloatType: 87 serializeFloat(buf, value.Float64ToStr(val.Float, false)) 88 case DatetimeType: 89 serializeDatetimeFromUnixNano(buf, val.Datetime) 90 case StringType: 91 serializeString(buf, val.String) 92 } 93 } 94 } 95 96 type SortValue struct { 97 Type SortValueType 98 99 SerializedKey *bytes.Buffer 100 101 Integer int64 102 Float float64 103 Datetime int64 104 String string 105 } 106 107 func NewSortValue(val value.Primary, flags *option.Flags) *SortValue { 108 sortValue := &SortValue{} 109 110 if value.IsNull(val) { 111 sortValue.Type = NullType 112 } else if i := value.ToIntegerStrictly(val); !value.IsNull(i) { 113 s := value.ToString(val) 114 sortValue.Type = IntegerType 115 sortValue.Integer = i.(*value.Integer).Raw() 116 sortValue.Float = float64(sortValue.Integer) 117 sortValue.String = strings.ToUpper(option.TrimSpace(s.(*value.String).Raw())) 118 value.Discard(i) 119 value.Discard(s) 120 } else if f := value.ToFloat(val); !value.IsNull(f) { 121 s := value.ToString(val) 122 sortValue.Type = FloatType 123 sortValue.Float = f.(*value.Float).Raw() 124 sortValue.String = strings.ToUpper(option.TrimSpace(s.(*value.String).Raw())) 125 value.Discard(f) 126 value.Discard(s) 127 } else if dt := value.ToDatetime(val, flags.DatetimeFormat, flags.GetTimeLocation()); !value.IsNull(dt) { 128 t := dt.(*value.Datetime).Raw() 129 sortValue.Type = DatetimeType 130 sortValue.Datetime = t.UnixNano() 131 value.Discard(dt) 132 } else if b := value.ToBoolean(val); !value.IsNull(b) { 133 sortValue.Type = BooleanType 134 if b.(*value.Boolean).Raw() { 135 sortValue.Integer = 1 136 } else { 137 sortValue.Integer = 0 138 } 139 } else if s, ok := val.(*value.String); ok { 140 sortValue.Type = StringType 141 sortValue.String = strings.ToUpper(option.TrimSpace(s.Raw())) 142 } else { 143 sortValue.Type = NullType 144 } 145 146 if flags.StrictEqual { 147 sortValue.SerializedKey = &bytes.Buffer{} 148 SerializeIdenticalKey(sortValue.SerializedKey, val) 149 } 150 151 return sortValue 152 } 153 154 func (v *SortValue) Less(compareValue *SortValue) ternary.Value { 155 if v.SerializedKey != nil { 156 if bytes.Equal(v.SerializedKey.Bytes(), compareValue.SerializedKey.Bytes()) { 157 return ternary.UNKNOWN 158 } 159 160 if v.SerializedKey.Bytes()[1] == 83 && compareValue.SerializedKey.Bytes()[1] == 83 { 161 return ternary.ConvertFromBool(v.String < compareValue.String) 162 } 163 } 164 165 switch v.Type { 166 case IntegerType: 167 switch compareValue.Type { 168 case IntegerType: 169 if v.Integer == compareValue.Integer { 170 return ternary.UNKNOWN 171 } 172 return ternary.ConvertFromBool(v.Integer < compareValue.Integer) 173 case FloatType: 174 return ternary.ConvertFromBool(v.Float < compareValue.Float) 175 case StringType: 176 return ternary.ConvertFromBool(v.String < compareValue.String) 177 } 178 case FloatType: 179 switch compareValue.Type { 180 case IntegerType, FloatType: 181 if math.IsNaN(v.Float) || math.IsNaN(compareValue.Float) { 182 if math.IsNaN(v.Float) && math.IsNaN(compareValue.Float) { 183 return ternary.UNKNOWN 184 } 185 186 if math.IsNaN(v.Float) { 187 return ternary.FALSE 188 } 189 190 // math.IsNaN(compareValue.Float) 191 return ternary.TRUE 192 } 193 194 if v.Float == compareValue.Float { 195 return ternary.UNKNOWN 196 } 197 198 return ternary.ConvertFromBool(v.Float < compareValue.Float) 199 case StringType: 200 return ternary.ConvertFromBool(v.String < compareValue.String) 201 } 202 case DatetimeType: 203 switch compareValue.Type { 204 case DatetimeType: 205 if v.Datetime == compareValue.Datetime { 206 return ternary.UNKNOWN 207 } 208 return ternary.ConvertFromBool(v.Datetime < compareValue.Datetime) 209 } 210 case StringType: 211 switch compareValue.Type { 212 case IntegerType, FloatType, StringType: 213 if v.String == compareValue.String { 214 return ternary.UNKNOWN 215 } 216 return ternary.ConvertFromBool(v.String < compareValue.String) 217 } 218 } 219 220 return ternary.UNKNOWN 221 } 222 223 func (v *SortValue) EquivalentTo(compareValue *SortValue) bool { 224 if v.SerializedKey != nil { 225 return bytes.Equal(v.SerializedKey.Bytes(), compareValue.SerializedKey.Bytes()) 226 } 227 228 switch v.Type { 229 case IntegerType: 230 switch compareValue.Type { 231 case IntegerType, BooleanType: 232 return v.Integer == compareValue.Integer 233 } 234 case FloatType: 235 switch compareValue.Type { 236 case FloatType: 237 if math.IsNaN(v.Float) && math.IsNaN(compareValue.Float) { 238 return true 239 } 240 return v.Float == compareValue.Float 241 } 242 case DatetimeType: 243 switch compareValue.Type { 244 case DatetimeType: 245 return v.Datetime == compareValue.Datetime 246 } 247 case BooleanType: 248 switch compareValue.Type { 249 case BooleanType, IntegerType: 250 return v.Integer == compareValue.Integer 251 } 252 case StringType: 253 switch compareValue.Type { 254 case StringType: 255 return v.String == compareValue.String 256 } 257 case NullType: 258 return compareValue.Type == NullType 259 } 260 261 return false 262 }