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  }