1 Star 0 Fork 0

笑看风云/gocodes

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
RefToMap.go 7.92 KB
一键复制 编辑 原始数据 按行查看 历史
笑看风云 提交于 2022-06-28 13:09 +08:00 . 更新
package coderx
import (
"errors"
"gitee.com/zhongguo168a/gocodes/datax/jsonmap"
"gitee.com/zhongguo168a/gocodes/datax/reflectx"
"gitee.com/zhongguo168a/gocodes/datax/schemax"
)
func NewRefToMap() (obj *RefToMap) {
obj = &RefToMap{
replaceStringToAlias: map[string]string{},
}
return
}
type RefToMap struct {
// 忽视空值
// 空值不会输出到map中
ignoreNil bool
// _type字符串使用枚举 schemax.SCHEMA_TYPE 代替
replaceMapTypeToSchemaEnum bool
// 字符串使用别名代替
replaceStringToAlias map[string]string
// map存在的键值才会输出
// map中
exportByMapKey bool
//
source reflectx.IRefObject
}
func (coder *RefToMap) Reset() {
coder.source = nil
coder.ignoreNil = false
coder.replaceStringToAlias = map[string]string{}
coder.exportByMapKey = false
}
func (coder *RefToMap) SetSource(source reflectx.IRefObject) *RefToMap {
coder.source = source
return coder
}
func (coder *RefToMap) ReplaceMapTypeToSchemaEnum() *RefToMap {
coder.replaceMapTypeToSchemaEnum = true
return coder
}
func (coder *RefToMap) ReplaceStringToAlias(from, to string) *RefToMap {
coder.replaceStringToAlias[from] = to
return coder
}
func (coder *RefToMap) ExportByMapKey() *RefToMap {
coder.exportByMapKey = true
return coder
}
func (coder *RefToMap) Create() (r map[string]interface{}, err error) {
r = map[string]interface{}{}
err = coder.Write(r)
return
}
func (coder *RefToMap) Write(target map[string]interface{}) (err error) {
if target == nil {
err = errors.New("target is nil")
return
}
source := coder.source
description := schemax.GetDeclByKey(source.RefType())
if description == nil {
err = errors.New("description not found: " + source.RefType())
return
}
reftype := reflectx.GetType(source.RefType())
if reftype == nil {
err = errors.New("reftype not found: " + source.RefType())
return
}
err = coder.toMapObj(reftype, source, target, description, 1)
return
}
// keyMode 0-source的字段, 1-所有字段
func (coder *RefToMap) toMapObj(reftype reflectx.IRefType, obj reflectx.IRefObject, smap map[string]interface{}, description schemax.IDecl, exportAllKey int) (err error) {
decl := description.(*schemax.ClassDecl)
var (
keyModeChild = 1 // 默认子属性默认遍历所有字段
)
// 注:如果采用遍历source的方式,因为需要取field,所以还是需要对decl.Fields进行遍历,遍历次数可能更多
allfields := decl.GetAllField()
for _, field := range allfields {
fname := field.Name
alias := field.Alias()
mval, mhas := smap[alias]
if coder.exportByMapKey { // 需要指定字段
if !mhas { // 没有字段,跳过
continue
}
if mval == 1 { // 需要处理
keyModeChild = 1
mval = nil // 设置为nil
} else {
keyModeChild = exportAllKey
}
}
switch ftyp := field.Type.(type) {
case *schemax.ClassType:
st, isNil := reftype.(reflectx.IRefField).RefGet(obj, field.Name)
if isNil {
continue
}
rval, classerr := coder.toMapClass(st.(reflectx.IRefObject), mval, keyModeChild)
if classerr != nil {
err = classerr
return
}
if rval == nil {
continue
}
smap[alias] = rval
case *schemax.ArrayType:
rval, sliceerr := coder.toMapSlice(reftype.(reflectx.IRefSlice), obj, fname, ftyp, keyModeChild)
if sliceerr != nil {
err = sliceerr
return
}
if rval == nil {
continue
}
smap[alias] = rval
case *schemax.MapType:
rmap, maperr := coder.toMapMap(reftype.(reflectx.IRefMap), obj, mval, fname, ftyp, keyModeChild)
if maperr != nil {
err = maperr
return
}
if rmap == nil {
continue
}
smap[alias] = rmap
case *schemax.EnumType:
smap[alias], _ = reftype.(reflectx.IRefField).RefGet(obj, field.Name)
case *schemax.BasicType:
oval, _ := reftype.(reflectx.IRefField).RefGet(obj, field.Name)
smap[alias] = coder.toMapConvert(ftyp, oval)
case *schemax.AnyType:
st, isNil := reftype.(reflectx.IRefField).RefGet(obj, field.Name)
if isNil {
continue
}
rmap, anyerr := coder.toMapAny(st, mval, keyModeChild)
if anyerr != nil {
err = anyerr
return
}
if rmap == nil {
continue
}
smap[alias] = rmap
default:
}
}
return
}
func (coder *RefToMap) toMapFunc(ist interface{}, mval interface{}, keyMode int) (interface{}, error) {
st, ok := ist.(reflectx.IRefObject)
if ok {
rval, classerr := coder.toMapClass(st, mval, keyMode)
if classerr != nil {
return nil, classerr
}
if rval == nil {
return nil, nil
}
return rval, nil
} else {
return ist, nil
}
}
func (coder *RefToMap) toMapAny(ist interface{}, mval interface{}, keyMode int) (interface{}, error) {
st, ok := ist.(reflectx.IRefObject)
if ok {
rval, classerr := coder.toMapClass(st, mval, keyMode)
if classerr != nil {
return nil, classerr
}
if rval == nil {
return nil, nil
}
rval["_type"] = st.RefType()
return rval, nil
} else {
return ist, nil
}
}
func (coder *RefToMap) toMapConvert(basic *schemax.BasicType, val interface{}) (r interface{}) {
return jsonmap.ConvertBasicToJsonValue(basic.Kind, val)
}
func (coder *RefToMap) toMapClass(st reflectx.IRefObject, sany interface{}, keyMode int) (m map[string]interface{}, err error) {
if st == nil {
return
}
stdesc := schemax.GetDeclByKey(st.RefType())
if stdesc == nil {
err = errors.New("map description not found: " + st.RefType())
return
}
reftype := reflectx.GetType(st.RefType())
if reftype == nil {
err = errors.New("map reftype not found: " + st.RefType())
return
}
if sany == nil {
m = map[string]interface{}{}
} else {
m = sany.(map[string]interface{})
}
err = coder.toMapObj(reftype, st, m, stdesc, keyMode)
return
}
func (coder *RefToMap) toMapSlice(reftype reflectx.IRefSlice, obj reflectx.IRefObject, fname string, ftyp *schemax.ArrayType, keyMode int) (marr []interface{}, err error) {
objlen := reftype.RefSliceLength(obj, fname)
if objlen == 0 {
return
}
marr = make([]interface{}, objlen, objlen)
//
for i := 0; i < objlen; i++ {
switch etyp := ftyp.Elem.(type) {
case *schemax.ClassType:
st, _ := reftype.RefSliceGet(obj, fname, i)
mval, classerr := coder.toMapClass(st.(reflectx.IRefObject), nil, 1)
if classerr != nil {
err = classerr
return
}
marr[i] = mval
case *schemax.BasicType:
oval, _ := reftype.RefSliceGet(obj, fname, i)
marr[i] = coder.toMapConvert(etyp, oval)
case *schemax.EnumType:
marr[i], _ = reftype.RefSliceGet(obj, fname, i)
case *schemax.AnyType:
st, _ := reftype.RefSliceGet(obj, fname, i)
rmap, anyerr := coder.toMapAny(st, nil, 1)
if anyerr != nil {
err = anyerr
return
}
if rmap == nil {
continue
}
marr[i] = rmap
default:
err = errors.New("RefToMap array: not support type: " + etyp.String())
return
}
}
return
}
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) {
_, isNil := reftype.RefGet(obj, fname)
if isNil {
return
}
if sany == nil {
rmap = map[string]interface{}{}
} else {
rmap = sany.(map[string]interface{})
}
keyModeChild := keyMode
keys := reftype.RefMapKeys(obj, fname)
for _, key := range keys {
mval, ok := rmap[key]
if keyMode == 0 {
if !ok {
continue
}
if mval == 1 { // 需要处理
keyModeChild = 1
mval = nil // 设置为nil
} else {
keyModeChild = keyMode
}
}
switch etyp := ftyp.Value.(type) {
case *schemax.ClassType:
st, _ := reftype.RefMapGet(obj, fname, key)
rval, classerr := coder.toMapClass(st.(reflectx.IRefObject), mval, keyModeChild)
if classerr != nil {
err = classerr
return
}
rmap[key] = rval
case *schemax.BasicType:
oval, _ := reftype.RefMapGet(obj, fname, key)
rmap[key] = coder.toMapConvert(etyp, oval)
case *schemax.EnumType:
rmap[key], _ = reftype.RefMapGet(obj, fname, key)
default:
err = errors.New("RefToMap array: not support type: " + etyp.String())
return
}
}
return
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/zhongguo168a/gocodes.git
git@gitee.com:zhongguo168a/gocodes.git
zhongguo168a
gocodes
gocodes
4da1013f7e88

搜索帮助