gitee.com/zhongguo168a/gocodes@v0.0.0-20230609140523-e1828349603f/datax/coderx/RefToMap.go (about) 1 package coderx 2 3 import ( 4 "errors" 5 "gitee.com/zhongguo168a/gocodes/datax/jsonmap" 6 "gitee.com/zhongguo168a/gocodes/datax/reflectx" 7 "gitee.com/zhongguo168a/gocodes/datax/schemax" 8 ) 9 10 func NewRefToMap() (obj *RefToMap) { 11 obj = &RefToMap{ 12 replaceStringToAlias: map[string]string{}, 13 } 14 return 15 } 16 17 type RefToMap struct { 18 // 忽视空值 19 // 空值不会输出到map中 20 ignoreNil bool 21 // _type字符串使用枚举 schemax.SCHEMA_TYPE 代替 22 replaceMapTypeToSchemaEnum bool 23 // 字符串使用别名代替 24 replaceStringToAlias map[string]string 25 // map存在的键值才会输出 26 // map中 27 exportByMapKey bool 28 // 29 source reflectx.IRefObject 30 } 31 32 func (coder *RefToMap) Reset() { 33 coder.source = nil 34 coder.ignoreNil = false 35 coder.replaceStringToAlias = map[string]string{} 36 coder.exportByMapKey = false 37 } 38 39 func (coder *RefToMap) SetSource(source reflectx.IRefObject) *RefToMap { 40 coder.source = source 41 return coder 42 } 43 44 func (coder *RefToMap) ReplaceMapTypeToSchemaEnum() *RefToMap { 45 coder.replaceMapTypeToSchemaEnum = true 46 return coder 47 } 48 49 func (coder *RefToMap) ReplaceStringToAlias(from, to string) *RefToMap { 50 coder.replaceStringToAlias[from] = to 51 return coder 52 } 53 54 func (coder *RefToMap) ExportByMapKey() *RefToMap { 55 coder.exportByMapKey = true 56 return coder 57 } 58 59 func (coder *RefToMap) Create() (r map[string]interface{}, err error) { 60 r = map[string]interface{}{} 61 err = coder.Write(r) 62 return 63 } 64 65 func (coder *RefToMap) Write(target map[string]interface{}) (err error) { 66 if target == nil { 67 err = errors.New("target is nil") 68 return 69 } 70 71 source := coder.source 72 description := schemax.GetDeclByKey(source.RefType()) 73 if description == nil { 74 err = errors.New("description not found: " + source.RefType()) 75 return 76 } 77 reftype := reflectx.GetType(source.RefType()) 78 if reftype == nil { 79 err = errors.New("reftype not found: " + source.RefType()) 80 return 81 } 82 err = coder.toMapObj(reftype, source, target, description, 1) 83 return 84 } 85 86 // keyMode 0-source的字段, 1-所有字段 87 func (coder *RefToMap) toMapObj(reftype reflectx.IRefType, obj reflectx.IRefObject, smap map[string]interface{}, description schemax.IDecl, exportAllKey int) (err error) { 88 decl := description.(*schemax.ClassDecl) 89 var ( 90 keyModeChild = 1 // 默认子属性默认遍历所有字段 91 ) 92 93 // 注:如果采用遍历source的方式,因为需要取field,所以还是需要对decl.Fields进行遍历,遍历次数可能更多 94 allfields := decl.GetAllField() 95 for _, field := range allfields { 96 fname := field.Name 97 alias := field.Alias() 98 99 mval, mhas := smap[alias] 100 if coder.exportByMapKey { // 需要指定字段 101 if !mhas { // 没有字段,跳过 102 continue 103 } 104 if mval == 1 { // 需要处理 105 keyModeChild = 1 106 mval = nil // 设置为nil 107 } else { 108 keyModeChild = exportAllKey 109 } 110 } 111 switch ftyp := field.Type.(type) { 112 case *schemax.ClassType: 113 st, isNil := reftype.(reflectx.IRefField).RefGet(obj, field.Name) 114 if isNil { 115 continue 116 } 117 rval, classerr := coder.toMapClass(st.(reflectx.IRefObject), mval, keyModeChild) 118 if classerr != nil { 119 err = classerr 120 return 121 } 122 if rval == nil { 123 continue 124 } 125 126 smap[alias] = rval 127 case *schemax.ArrayType: 128 rval, sliceerr := coder.toMapSlice(reftype.(reflectx.IRefSlice), obj, fname, ftyp, keyModeChild) 129 if sliceerr != nil { 130 err = sliceerr 131 return 132 } 133 if rval == nil { 134 continue 135 } 136 smap[alias] = rval 137 case *schemax.MapType: 138 rmap, maperr := coder.toMapMap(reftype.(reflectx.IRefMap), obj, mval, fname, ftyp, keyModeChild) 139 if maperr != nil { 140 err = maperr 141 return 142 } 143 if rmap == nil { 144 continue 145 } 146 smap[alias] = rmap 147 case *schemax.EnumType: 148 smap[alias], _ = reftype.(reflectx.IRefField).RefGet(obj, field.Name) 149 case *schemax.BasicType: 150 oval, _ := reftype.(reflectx.IRefField).RefGet(obj, field.Name) 151 smap[alias] = coder.toMapConvert(ftyp, oval) 152 case *schemax.AnyType: 153 st, isNil := reftype.(reflectx.IRefField).RefGet(obj, field.Name) 154 if isNil { 155 continue 156 } 157 158 rmap, anyerr := coder.toMapAny(st, mval, keyModeChild) 159 if anyerr != nil { 160 err = anyerr 161 return 162 } 163 if rmap == nil { 164 continue 165 } 166 smap[alias] = rmap 167 default: 168 } 169 } 170 171 return 172 } 173 174 func (coder *RefToMap) toMapFunc(ist interface{}, mval interface{}, keyMode int) (interface{}, error) { 175 st, ok := ist.(reflectx.IRefObject) 176 if ok { 177 rval, classerr := coder.toMapClass(st, mval, keyMode) 178 if classerr != nil { 179 return nil, classerr 180 } 181 if rval == nil { 182 return nil, nil 183 } 184 return rval, nil 185 } else { 186 return ist, nil 187 } 188 } 189 190 func (coder *RefToMap) toMapAny(ist interface{}, mval interface{}, keyMode int) (interface{}, error) { 191 st, ok := ist.(reflectx.IRefObject) 192 if ok { 193 rval, classerr := coder.toMapClass(st, mval, keyMode) 194 if classerr != nil { 195 return nil, classerr 196 } 197 if rval == nil { 198 return nil, nil 199 } 200 rval["_type"] = st.RefType() 201 return rval, nil 202 } else { 203 return ist, nil 204 } 205 } 206 207 func (coder *RefToMap) toMapConvert(basic *schemax.BasicType, val interface{}) (r interface{}) { 208 return jsonmap.ConvertBasicToJsonValue(basic.Kind, val) 209 } 210 211 func (coder *RefToMap) toMapClass(st reflectx.IRefObject, sany interface{}, keyMode int) (m map[string]interface{}, err error) { 212 if st == nil { 213 return 214 } 215 stdesc := schemax.GetDeclByKey(st.RefType()) 216 if stdesc == nil { 217 err = errors.New("map description not found: " + st.RefType()) 218 return 219 } 220 reftype := reflectx.GetType(st.RefType()) 221 if reftype == nil { 222 err = errors.New("map reftype not found: " + st.RefType()) 223 return 224 } 225 226 if sany == nil { 227 m = map[string]interface{}{} 228 } else { 229 m = sany.(map[string]interface{}) 230 } 231 err = coder.toMapObj(reftype, st, m, stdesc, keyMode) 232 return 233 } 234 235 func (coder *RefToMap) toMapSlice(reftype reflectx.IRefSlice, obj reflectx.IRefObject, fname string, ftyp *schemax.ArrayType, keyMode int) (marr []interface{}, err error) { 236 objlen := reftype.RefSliceLength(obj, fname) 237 if objlen == 0 { 238 return 239 } 240 marr = make([]interface{}, objlen, objlen) 241 // 242 for i := 0; i < objlen; i++ { 243 switch etyp := ftyp.Elem.(type) { 244 case *schemax.ClassType: 245 st, _ := reftype.RefSliceGet(obj, fname, i) 246 mval, classerr := coder.toMapClass(st.(reflectx.IRefObject), nil, 1) 247 if classerr != nil { 248 err = classerr 249 return 250 } 251 marr[i] = mval 252 case *schemax.BasicType: 253 oval, _ := reftype.RefSliceGet(obj, fname, i) 254 marr[i] = coder.toMapConvert(etyp, oval) 255 case *schemax.EnumType: 256 marr[i], _ = reftype.RefSliceGet(obj, fname, i) 257 case *schemax.AnyType: 258 st, _ := reftype.RefSliceGet(obj, fname, i) 259 rmap, anyerr := coder.toMapAny(st, nil, 1) 260 if anyerr != nil { 261 err = anyerr 262 return 263 } 264 if rmap == nil { 265 continue 266 } 267 marr[i] = rmap 268 default: 269 err = errors.New("RefToMap array: not support type: " + etyp.String()) 270 return 271 } 272 } 273 274 return 275 } 276 277 func (coder *RefToMap) toMapMap(reftype reflectx.IRefMap, obj reflectx.IRefObject, sany interface{}, fname string, ftyp *schemax.MapType, keyMode int) (rmap map[string]interface{}, err error) { 278 _, isNil := reftype.RefGet(obj, fname) 279 if isNil { 280 return 281 } 282 283 if sany == nil { 284 rmap = map[string]interface{}{} 285 } else { 286 rmap = sany.(map[string]interface{}) 287 } 288 keyModeChild := keyMode 289 keys := reftype.RefMapKeys(obj, fname) 290 for _, key := range keys { 291 mval, ok := rmap[key] 292 if keyMode == 0 { 293 if !ok { 294 continue 295 } 296 if mval == 1 { // 需要处理 297 keyModeChild = 1 298 mval = nil // 设置为nil 299 } else { 300 keyModeChild = keyMode 301 } 302 } 303 304 switch etyp := ftyp.Value.(type) { 305 case *schemax.ClassType: 306 st, _ := reftype.RefMapGet(obj, fname, key) 307 rval, classerr := coder.toMapClass(st.(reflectx.IRefObject), mval, keyModeChild) 308 if classerr != nil { 309 err = classerr 310 return 311 } 312 rmap[key] = rval 313 case *schemax.BasicType: 314 oval, _ := reftype.RefMapGet(obj, fname, key) 315 rmap[key] = coder.toMapConvert(etyp, oval) 316 case *schemax.EnumType: 317 rmap[key], _ = reftype.RefMapGet(obj, fname, key) 318 default: 319 err = errors.New("RefToMap array: not support type: " + etyp.String()) 320 return 321 322 } 323 } 324 325 return 326 }