-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmapping.go
More file actions
202 lines (181 loc) · 4.59 KB
/
mapping.go
File metadata and controls
202 lines (181 loc) · 4.59 KB
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
package utils
import (
"reflect"
"strings"
"unicode"
)
// KeyFunc defines a function type for generating map keys from struct fields
type KeyFunc func(field reflect.StructField) string
// omit specify field in target struct
//
// type People struct {
// Name string
// Age int
// Address string
// }
//
// p := &People{
// Name: "william",
// Age: 20,
// Address: "BC",
// }
//
// Omit(p,"Name")
func Omit[T any](target T, fields ...string) map[string]any {
mapping := map[string]bool{}
for _, value := range fields {
mapping[SnakeCase(value)] = true
mapping[value] = true
mapping[value] = true
}
result := StructFilter(target, func(field string, val reflect.Value) bool {
_, ok := mapping[field]
return !ok
}, nil)
return result
}
// pick specify field in target struct
//
// type People struct {
// Name string
// Age int
// Address string
// }
//
// p := &People{
// Name: "william",
// Age: 20,
// Address: "BC",
// }
//
// Pick(p,[]string{"Name"})
func Pick[T any](target T, fields ...string) map[string]any {
mapping := map[string]bool{}
for _, value := range fields {
mapping[value] = true
}
result := StructFilter(target, func(field string, val reflect.Value) bool {
_, ok := mapping[field]
return ok
}, nil)
return result
}
func jsonKeyFunc(field reflect.StructField) string {
if jsonTag := field.Tag.Get("json"); jsonTag != "" && jsonTag != "-" {
return jsonTag
}
return ""
}
// SnakeCase 将 CamelCase 转换为 snake_case,并处理缩写词
func SnakeCase(s string) string {
var result []rune
n := len(s)
allUpper := true
for _, r := range s {
if unicode.IsLower(r) {
allUpper = false
break
}
}
if allUpper {
return strings.ToLower(s)
}
for i := 0; i < n; i++ {
r := rune(s[i])
if unicode.IsUpper(r) {
if i > 0 && !unicode.IsUpper(rune(s[i-1])) {
result = append(result, '_')
}
result = append(result, unicode.ToLower(r))
} else {
result = append(result, r)
}
}
return string(result)
}
// GetFieldName 根据字段的 JSON 标签或字段名返回正确的字段名称
func GetFieldName(field reflect.StructField) string {
jsonTag := field.Tag.Get("json")
if jsonTag == "" {
return SnakeCase(field.Name)
}
jsonName := strings.Split(jsonTag, ",")[0] // 获取 JSON 标签的第一个部分
if jsonName != "" && jsonName != "-" {
return jsonName
}
return SnakeCase(field.Name)
}
func structFilterRecursive(
value reflect.Value,
t reflect.Type,
callback func(field string, val reflect.Value) bool,
keyFunc KeyFunc,
result map[string]any,
) {
for i := 0; i < value.NumField(); i++ {
field := t.Field(i)
fieldValue := value.Field(i)
key := keyFunc(field)
if field.Anonymous {
// If the field is an embedded struct, recurse into it
structFilterRecursive(fieldValue, fieldValue.Type(), callback, keyFunc, result)
} else if callback(key, fieldValue) && key != "" {
result[key] = fieldValue.Interface()
}
}
}
func StructFilter[T any](
target T,
callback func(field string, val reflect.Value) bool,
key KeyFunc,
) map[string]any {
reflectValue := reflect.ValueOf(target)
reflectType := reflect.TypeOf(target)
if reflectValue.Kind() == reflect.Pointer {
reflectValue = reflectValue.Elem()
reflectType = reflectType.Elem()
}
GenKey := key
if key == nil {
GenKey = GetFieldName
}
result := make(map[string]any)
structFilterRecursive(reflectValue, reflectType, callback, GenKey, result)
return result
}
func resolvePointer(value reflect.Value) reflect.Value {
if value.Kind() == reflect.Pointer {
return reflect.Indirect(value)
}
return value
}
func GetFields[T any](target T, callback func(reflect.Value)) {
reflectValue := reflect.ValueOf(target)
reflectValue = resolvePointer(reflectValue)
for i := 0; i < reflectValue.NumField(); i++ {
field := reflectValue.Field(i)
fieldType := reflectValue.Type().Field(i)
if fieldType.Anonymous {
embeddedValue := resolvePointer(field)
if embeddedValue.Kind() == reflect.Struct {
field := embeddedValue.FieldByName(field.Type().Name())
callback(field)
}
} else {
callback(field)
}
}
}
// 泛型函数 ArrayFilter,接收一个目标数组 target 和回调函数 cb
func ArrayFilter[T any](target []T, cb func(T) []map[string]any) []map[string]any {
var result []map[string]any // 存储过滤后的结果
for _, item := range target {
// 调用回调函数 cb,对每个元素进行处理
filtered := cb(item)
// 如果 cb 函数返回非空的结果,则将其添加到最终结果中
if len(filtered) > 0 {
result = append(result, filtered...)
}
}
return result
}