-
Notifications
You must be signed in to change notification settings - Fork 0
/
a_model_body.go
149 lines (133 loc) · 3.63 KB
/
a_model_body.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
package pipe
import (
"fmt"
"github.com/kataras/iris/v12"
"go.mongodb.org/mongo-driver/bson/primitive"
"reflect"
"strings"
"time"
)
func getTagName(tag string) string {
parts := strings.Split(tag, ",")
return parts[0]
}
// findFieldByJSONTag recursively searches for a struct field with the specified JSON tag.
func findFieldByJSONTag(v reflect.Value, tag string) (reflect.Value, bool) {
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
if v.Kind() != reflect.Struct {
return reflect.Value{}, false
}
typ := v.Type()
for i := 0; i < typ.NumField(); i++ {
fieldJson := getTagName(typ.Field(i).Tag.Get("json"))
if len(fieldJson) < 1 || fieldJson == "-" {
continue
}
if fieldJson == tag {
return v.Field(i), true
}
if v.Field(i).Kind() == reflect.Struct {
if field, found := findFieldByJSONTag(v.Field(i), tag); found {
return field, true
}
}
}
return reflect.Value{}, false
}
func setFieldValue(field reflect.Value, value interface{}) error {
switch field.Type() {
case reflect.TypeOf(primitive.ObjectID{}):
if strValue, ok := value.(string); ok {
oid, err := primitive.ObjectIDFromHex(strValue)
if err != nil {
return err
}
field.Set(reflect.ValueOf(oid))
} else {
return fmt.Errorf("cannot convert %v to ObjectID", value)
}
case reflect.TypeOf(time.Time{}):
if strValue, ok := value.(string); ok {
t, err := time.Parse(time.RFC3339, strValue)
if err != nil {
return err
}
field.Set(reflect.ValueOf(t))
} else {
return fmt.Errorf("cannot convert %v to Time", value)
}
default:
valueV := reflect.ValueOf(value)
if valueV.Type() != field.Type() {
return fmt.Errorf("type mismatch: cannot assign %v to field with type %v", valueV.Type(), field.Type())
}
field.Set(valueV)
}
return nil
}
// ModelCtxMapperPack 解析body数据包 所有map key 支持 a.b.c 但是对应的是json tag标签名
type ModelCtxMapperPack struct {
InjectData map[string]any `json:"inject_data,omitempty"` // 注入数据 默认覆盖
DropKeys []string `json:"drop_keys,omitempty"` // 需要丢弃的key
}
func (m *ModelCtxMapperPack) processStruct(data any) error {
v := reflect.ValueOf(data).Elem()
// Drop keys.
for _, key := range m.DropKeys {
field, found := findFieldByJSONTag(v, key)
if !found {
continue
}
field.Set(reflect.Zero(field.Type()))
}
// Inject data.
for key, value := range m.InjectData {
field, found := findFieldByJSONTag(v, key)
if !found {
return fmt.Errorf("field with JSON tag %q not found", key)
}
if err := setFieldValue(field, value); err != nil {
return err
}
}
return nil
}
func (m *ModelCtxMapperPack) processMap(data map[string]any) error {
for _, key := range m.DropKeys {
delete(data, key)
}
for key, val := range m.InjectData {
data[key] = val
}
return nil
}
func (m *ModelCtxMapperPack) Process(data any) error {
switch v := data.(type) {
case map[string]any:
return m.processMap(v)
default:
return m.processStruct(data)
}
}
var (
// ModelMapper 模型body中映射取出对应的map 不需要db
// 必传origin 支持map和struct struct以json的tag为key进行匹配
// 必传params ModelCtxMapperPack new(ModelCtxMapperPack)都可以 但是必传
ModelMapper = &RunnerContext[any, *ModelCtxMapperPack, any, any]{
Key: "model_ctx_mapper",
Name: "模型body取map",
call: func(ctx iris.Context, origin any, params *ModelCtxMapperPack, db any, more ...any) *RunResp[any] {
var bodyData = origin
if origin == nil {
return NewPipeErr[any](PipeOriginError)
}
err := params.Process(bodyData)
if err != nil {
return NewPipeErr[any](err)
}
return NewPipeResult(bodyData)
},
}
)