-
Notifications
You must be signed in to change notification settings - Fork 52
/
Copy pathhelpers.go
157 lines (132 loc) · 2.97 KB
/
helpers.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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package jsonlogic
import (
"math"
"reflect"
"strconv"
"strings"
)
func is(obj any, kind reflect.Kind) bool {
return obj != nil && reflect.TypeOf(obj).Kind() == kind
}
func isBool(obj any) bool {
return is(obj, reflect.Bool)
}
func isString(obj any) bool {
return is(obj, reflect.String)
}
func isNumber(obj any) bool {
switch obj.(type) {
case int, float64:
return true
default:
return false
}
}
func isPrimitive(obj any) bool {
return isBool(obj) || isString(obj) || isNumber(obj)
}
func isMap(obj any) bool {
return is(obj, reflect.Map)
}
func isSlice(obj any) bool {
return is(obj, reflect.Slice)
}
func isEmptySlice(obj any) bool {
if !isSlice(obj) {
return false
}
for _, v := range obj.([]any) {
if isTrue(v) {
return false
}
}
return true
}
func isTrue(obj any) bool {
if isBool(obj) {
return obj.(bool)
}
if isNumber(obj) {
return toNumber(obj) != 0
}
if isString(obj) || isSlice(obj) || isMap(obj) {
return reflect.ValueOf(obj).Len() > 0
}
return false
}
func toSliceOfNumbers(values any) []float64 {
_values := values.([]any)
numbers := make([]float64, len(_values))
for i, n := range _values {
numbers[i] = toNumber(n)
}
return numbers
}
func toNumber(value any) float64 {
if isString(value) {
w, _ := strconv.ParseFloat(value.(string), 64)
return w
}
switch value := value.(type) {
case int:
return float64(value)
default:
return value.(float64)
}
}
// toNumberFromAny converts various input types to float64.
//
// Examples:
//
// toNumberFromAny(42) // Returns: 42.0
// toNumberFromAny("3.14") // Returns: 3.14
// toNumberFromAny(true) // Returns: 1.0
// toNumberFromAny(false) // Returns: 0.0
// toNumberFromAny([]int{1, 2, 3}) // Returns: 3.0 (length of slice)
// toNumberFromAny(map[string]int{"a": 1, "b": 2}) // Returns: 2.0 (length of map)
// toNumberFromAny(nil) // Returns: 0.0
//
// Note: For unsupported types, it returns 0.0
func toNumberFromAny(v any) float64 {
switch value := v.(type) {
case nil:
return 0
case undefinedType:
return math.NaN()
case float32, float64, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
return reflect.ValueOf(value).Convert(reflect.TypeOf(float64(0))).Float()
case bool: // Boolean values true and false are converted to 1 and 0 respectively.
if value {
return 1
} else {
return 0
}
case string:
if strings.TrimSpace(value) == "" {
return 0
}
n, err := strconv.ParseFloat(value, 64)
switch err {
case strconv.ErrRange, nil:
return n
default:
return math.NaN()
}
default:
return math.NaN()
}
}
func toString(value any) string {
if isNumber(value) {
switch value := value.(type) {
case int:
return strconv.FormatInt(int64(value), 10)
default:
return strconv.FormatFloat(value.(float64), 'f', -1, 64)
}
}
if value == nil {
return ""
}
return value.(string)
}