github.com/songzhibin97/gkit@v1.2.13/tools/vto/votodo.go (about) 1 package vto 2 3 import ( 4 "reflect" 5 "strings" 6 7 "github.com/songzhibin97/gkit/tools" 8 9 "github.com/songzhibin97/gkit/tools/bind" 10 ) 11 12 type BindModel int 13 14 const ( 15 FieldBind BindModel = 1 << iota 16 TagBind 17 DefaultValueBind // 默认值绑定,在最后的情况下,如果还未绑定到相关值则设置为默认值 18 OverlayBind // 设置多个条件的情况下可以覆盖,根据代码语义,应该是会以tag优先,不设置以field为优先 19 ) 20 21 type ModelParameters struct { 22 Model BindModel `json:"model"` // 绑定参数 默认值为 field bind 23 Tag string `json:"tag"` // tag bind 指定tag,default 为 json 24 TagSqlite string `json:"tag_sqlite"` // 切分tag标识 25 FilterTag []string `json:"filter_tag"` // 过滤tag 26 } 27 28 // VoToDo 试图对象与domino对象转换,只能转相同字段且类型相同的 29 // dst: 目标 30 // src: 源位置 31 // 支持简单的 default模式 在基础类型增加default可以指定默认值 32 func VoToDo(dst interface{}, src interface{}) error { 33 dstT, srcT := reflect.TypeOf(dst), reflect.TypeOf(src) 34 if dstT.Kind() != srcT.Kind() { 35 return tools.ErrorNoEquals 36 } 37 if dstT.Kind() != reflect.Ptr { 38 return tools.ErrorMustPtr 39 } 40 dstT, srcT = dstT.Elem(), srcT.Elem() 41 if dstT.Kind() != reflect.Struct || srcT.Kind() != reflect.Struct { 42 return tools.ErrorMustStructPtr 43 } 44 dstV, srcV := reflect.ValueOf(dst).Elem(), reflect.ValueOf(src).Elem() 45 for i := 0; i < dstT.NumField(); i++ { 46 field := dstT.Field(i) 47 if !field.IsExported() { 48 continue 49 } 50 defaultTag := field.Tag.Get("default") 51 if _, ok := srcT.FieldByName(field.Name); !ok { 52 continue 53 } 54 d := dstV.Field(i) 55 s := srcV.FieldByName(field.Name) 56 for s.Kind() == reflect.Ptr && d.Kind() != s.Kind() { 57 s = s.Elem() 58 } 59 60 if d.Kind() != s.Kind() && !d.CanConvert(s.Type()) { 61 continue 62 } 63 64 if d.Kind() != s.Kind() && d.Kind() == reflect.Struct { 65 err := VoToDo(d.Addr().Interface(), s.Addr().Interface()) 66 if err != nil { 67 return err 68 } 69 continue 70 } 71 72 if !s.IsZero() { 73 if d.Type() == s.Type() { 74 d.Set(s) 75 } else if s.CanConvert(d.Type()) { 76 d.Set(reflect.ValueOf(s.Interface()).Convert(d.Type())) 77 } 78 } 79 80 // 如果源位置的内容为空,并且默认值不为0 81 if d.IsZero() && len(defaultTag) > 0 { 82 if d.Kind() == reflect.Ptr { 83 ss := reflect.New(d.Type().Elem()) 84 err := bindDefault(ss.Elem(), defaultTag, field) 85 if err != nil { 86 return err 87 } 88 d.Set(ss) 89 } else { 90 err := bindDefault(d, defaultTag, field) 91 if err != nil { 92 return err 93 } 94 } 95 } 96 } 97 return nil 98 } 99 100 // VoToDoPlus View对象与domino对象转换,根据不同模式进行转换 101 // dst: 目标 102 // src: 源位置 103 // ModelParameters: 模式匹配 104 func VoToDoPlus(dst interface{}, src interface{}, model ModelParameters) error { 105 dstT, srcT := reflect.TypeOf(dst), reflect.TypeOf(src) 106 if dstT.Kind() != srcT.Kind() { 107 return tools.ErrorNoEquals 108 } 109 if dstT.Kind() != reflect.Ptr { 110 return tools.ErrorMustPtr 111 } 112 dstT, srcT = dstT.Elem(), srcT.Elem() 113 if dstT.Kind() != reflect.Struct || srcT.Kind() != reflect.Struct { 114 return tools.ErrorMustStructPtr 115 } 116 dstV, srcV := reflect.ValueOf(dst).Elem(), reflect.ValueOf(src).Elem() 117 118 if model.Model&TagBind == TagBind && len(model.Tag) == 0 { 119 model.Tag = "json" 120 } 121 if model.Model&TagBind == TagBind && len(model.TagSqlite) == 0 { 122 model.TagSqlite = "," 123 } 124 if model.Model&TagBind == TagBind && len(model.FilterTag) == 0 { 125 model.FilterTag = []string{"omitempty"} 126 } 127 filterTag := make(map[string]struct{}) 128 for _, s := range model.FilterTag { 129 filterTag[s] = struct{}{} 130 } 131 132 if model.Model&FieldBind == FieldBind { 133 for i := 0; i < dstT.NumField(); i++ { 134 field := dstT.Field(i) 135 if !field.IsExported() { 136 continue 137 } 138 d := dstV.Field(i) 139 if _, ok := srcT.FieldByName(field.Name); !ok { 140 continue 141 } 142 143 s := srcV.FieldByName(field.Name) 144 for s.Kind() == reflect.Ptr && d.Kind() != s.Kind() { 145 s = s.Elem() 146 } 147 if d.Kind() != s.Kind() && !d.CanConvert(s.Type()) { 148 continue 149 } 150 151 if d.Kind() != s.Kind() && d.Kind() == reflect.Struct { 152 err := VoToDoPlus(d.Addr().Interface(), s.Addr().Interface(), model) 153 if err != nil { 154 return err 155 } 156 continue 157 } 158 159 if !s.IsZero() { 160 if d.Type() == s.Type() { 161 d.Set(s) 162 } else if s.CanConvert(d.Type()) { 163 d.Set(reflect.ValueOf(s.Interface()).Convert(d.Type())) 164 } 165 } 166 } 167 } 168 169 if model.Model&TagBind == TagBind { 170 171 srcMapping := make(map[string]reflect.StructField) 172 for i := 0; i < srcT.NumField(); i++ { 173 srcField := srcT.Field(i) 174 if !srcField.IsExported() { 175 continue 176 } 177 tag := srcField.Tag.Get(model.Tag) 178 if tag == "" || tag == "-" { 179 continue 180 } 181 for _, s := range strings.Split(tag, model.TagSqlite) { 182 if _, ok := filterTag[s]; ok { 183 continue 184 } 185 srcMapping[s] = srcField 186 } 187 } 188 189 for i := 0; i < dstT.NumField(); i++ { 190 field := dstT.Field(i) 191 if !field.IsExported() { 192 continue 193 } 194 d := dstV.Field(i) 195 196 if !d.IsZero() && !(model.Model&OverlayBind == OverlayBind) { 197 continue 198 } 199 200 currentFieldTag := field.Tag.Get(model.Tag) 201 if currentFieldTag == "" || currentFieldTag == "-" { 202 continue 203 } 204 for _, s := range strings.Split(currentFieldTag, model.TagSqlite) { 205 if _, ok := filterTag[s]; ok { 206 continue 207 } 208 srcField, ok := srcMapping[s] 209 if !ok { 210 continue 211 } 212 213 ss := srcV.FieldByName(srcField.Name) 214 for ss.Kind() == reflect.Ptr && d.Kind() != ss.Kind() { 215 ss = ss.Elem() 216 } 217 if d.Kind() != ss.Kind() { 218 continue 219 } 220 if d.Type() != ss.Type() && d.Kind() == reflect.Struct { 221 err := VoToDoPlus(d.Addr().Interface(), ss.Addr().Interface(), model) 222 if err != nil { 223 return err 224 } 225 continue 226 } 227 228 if !ss.IsZero() { 229 if d.Type() == ss.Type() { 230 d.Set(ss) 231 } else if d.CanConvert(ss.Type()) { 232 d.Set(reflect.ValueOf(ss.Interface()).Convert(d.Type())) 233 } 234 } 235 break 236 } 237 } 238 } 239 240 if model.Model&DefaultValueBind == DefaultValueBind { 241 for i := 0; i < dstT.NumField(); i++ { 242 field := dstT.Field(i) 243 if !field.IsExported() { 244 continue 245 } 246 defaultTag := field.Tag.Get("default") 247 if len(defaultTag) == 0 || defaultTag == "-" { 248 continue 249 } 250 d := dstV.Field(i) 251 // 如果源位置的内容为空,并且默认值不为0 252 if d.IsZero() && len(defaultTag) > 0 { 253 if d.Kind() == reflect.Ptr { 254 s := reflect.New(d.Type().Elem()) 255 err := bindDefault(s.Elem(), defaultTag, field) 256 if err != nil { 257 return err 258 } 259 d.Set(s) 260 } else { 261 err := bindDefault(d, defaultTag, field) 262 if err != nil { 263 return err 264 } 265 } 266 } 267 } 268 } 269 270 return nil 271 } 272 273 func bindDefault(value reflect.Value, val string, field reflect.StructField) error { 274 return bind.SetWithProperType(val, value, field) 275 }