gitee.com/zhongguo168a/gocodes@v0.0.0-20230609140523-e1828349603f/datax/coderx/MapToRef.go (about)

     1  package coderx
     2  
     3  import (
     4  	"gitee.com/zhongguo168a/gocodes/datax/mapx"
     5  	"gitee.com/zhongguo168a/gocodes/datax/reflectx"
     6  	"gitee.com/zhongguo168a/gocodes/datax/schemax"
     7  	"gitee.com/zhongguo168a/gocodes/datax/schemax/basickind"
     8  	"gitee.com/zhongguo168a/gocodes/myx/errorx"
     9  	"strconv"
    10  )
    11  
    12  func NewMapToRef() (obj *MapToRef) {
    13  	obj = &MapToRef{}
    14  	return
    15  }
    16  
    17  type MapToRef struct {
    18  	//
    19  	source map[string]interface{}
    20  
    21  	// 忽视空值
    22  	// 空值不会输出到map中
    23  	ignoreNil bool
    24  }
    25  
    26  func (coder *MapToRef) Reset() {
    27  	coder.source = nil
    28  	coder.ignoreNil = false
    29  }
    30  
    31  func (coder *MapToRef) SetSource(source map[string]interface{}) *MapToRef {
    32  	coder.source = source
    33  	return coder
    34  }
    35  
    36  // Create 通过map创建一个对象
    37  // map必须设置 key=_type value=string, value指向schemax注册的声明
    38  func (coder *MapToRef) Create() (obj reflectx.IRefObject, err error) {
    39  	_type := mapx.String(coder.source, "_type")
    40  	if _type == "" {
    41  		err = errorx.New("_type not found")
    42  		return
    43  	}
    44  	schema := schemax.GetDeclByKey(_type)
    45  	if schema == nil {
    46  		err = errorx.New("schema not found: " + _type)
    47  		return
    48  	}
    49  
    50  	decl, ok := schema.(*schemax.ClassDecl)
    51  	if !ok {
    52  		err = errorx.New("decl not schemax.ClassDecl: " + _type)
    53  		return
    54  	}
    55  
    56  	reftype := reflectx.GetType(_type)
    57  	if reftype == nil {
    58  		err = errorx.New("reftype not found: " + decl.RefType())
    59  		return
    60  	}
    61  	obj = reftype.RefNew()
    62  	err = coder.fromMapObj(reftype, obj, coder.source, schema, "")
    63  	if err != nil {
    64  		err = errorx.Wrap(err, _type)
    65  		return
    66  	}
    67  	return
    68  }
    69  
    70  func (coder *MapToRef) Write(obj reflectx.IRefObject) (err error) {
    71  	schema := schemax.GetDeclByKey(obj.RefType())
    72  	if schema == nil {
    73  		return errorx.New("schema not found: " + obj.RefType())
    74  	}
    75  	reftype := reflectx.GetType(obj.RefType())
    76  	if reftype == nil {
    77  		err = errorx.New("reftype not found: " + obj.RefType())
    78  		return
    79  	}
    80  	return coder.fromMapObj(reftype, obj, coder.source, schema, "")
    81  }
    82  
    83  // keyMode 0-source的字段, 1-所有字段
    84  func (coder *MapToRef) fromMapObj(reftype reflectx.IRefType, obj reflectx.IRefObject, smap map[string]interface{}, schema schemax.IDecl, paths string) (err error) {
    85  	var (
    86  		decl = schema.(*schemax.ClassDecl)
    87  	)
    88  
    89  	allfields := decl.GetAllField()
    90  	for _, field := range allfields {
    91  		fname := field.Name
    92  		alias := field.Alias()
    93  
    94  		mval, mhas := smap[alias]
    95  		if !mhas {
    96  			continue
    97  		}
    98  		fname = alias
    99  
   100  		switch ftyp := field.Type.(type) {
   101  		case *schemax.ClassType:
   102  			oval, isNil := reftype.(reflectx.IRefField).RefGet(obj, alias)
   103  			st, classerr := coder.fromMapClass(reftype, oval.(reflectx.IRefObject), isNil, mval, ftyp.Decl, paths+"/"+fname)
   104  			if classerr != nil {
   105  				return classerr
   106  			}
   107  			reftype.(reflectx.IRefField).RefSet(obj, alias, st)
   108  		case *schemax.ArrayType:
   109  			err = coder.fromMapSlice(reftype.(reflectx.IRefSlice), obj, mval, fname, ftyp, paths+"/"+fname)
   110  			if err != nil {
   111  				return
   112  			}
   113  		case *schemax.MapType:
   114  			err = coder.fromMapMap(reftype.(reflectx.IRefMap), obj, fname, mval, ftyp, paths+"/"+fname)
   115  			if err != nil {
   116  				return
   117  			}
   118  		case *schemax.EnumType:
   119  			st, classerr := coder.fromMapEnum(mval, ftyp.Decl, paths+"/"+fname)
   120  			if classerr != nil {
   121  				return classerr
   122  			}
   123  			reftype.(reflectx.IRefField).RefSet(obj, field.Name, st)
   124  		case *schemax.BasicType:
   125  			reftype.(reflectx.IRefField).RefSet(obj, field.Name, coder.fromMapBasic(mval, ftyp))
   126  		case *schemax.AnyType:
   127  			oval, isNil := reftype.(reflectx.IRefField).RefGet(obj, fname)
   128  			st, classerr := coder.fromMapAny(reftype, oval, isNil, mval, paths+"/"+fname)
   129  			if classerr != nil {
   130  				return classerr
   131  			}
   132  			reftype.(reflectx.IRefField).RefSet(obj, fname, st)
   133  		default:
   134  		}
   135  	}
   136  	return
   137  }
   138  
   139  func (coder *MapToRef) fromMapAny(reftype reflectx.IRefType, oany interface{}, isNil bool, sany interface{}, paths string) (st interface{}, err error) {
   140  	var (
   141  		decl  string
   142  		smap  map[string]interface{}
   143  		ismap bool
   144  		oval  reflectx.IRefObject
   145  	)
   146  	if sany == nil { // 返回,并设置obj为nil
   147  		return
   148  	}
   149  
   150  	if oany == nil {
   151  		smap, ismap = sany.(map[string]interface{})
   152  		if ismap == false {
   153  			return
   154  		}
   155  		decl = mapx.String(smap, "_type")
   156  		if decl == "" {
   157  			st = sany
   158  			return
   159  		}
   160  	} else {
   161  		oval = oany.(reflectx.IRefObject)
   162  		decl = oval.RefType()
   163  	}
   164  
   165  	st, err = coder.fromMapClass(reftype, oval, isNil, sany.(map[string]interface{}), decl, paths)
   166  	if err != nil {
   167  		return
   168  	}
   169  	return
   170  }
   171  
   172  type TestClass1 struct {
   173  }
   174  
   175  func (t *TestClass1) RefType() string {
   176  	panic("implement me")
   177  }
   178  
   179  func (coder *MapToRef) fromMapClass(reftype reflectx.IRefType, oval reflectx.IRefObject, isNil bool, many interface{}, decl string, paths string) (rval reflectx.IRefObject, err error) {
   180  	if many == nil { // 设置为nil
   181  		return nil, nil
   182  	}
   183  
   184  	if isNil {
   185  		rval, err = reflectx.NewObject(decl)
   186  		if err != nil {
   187  			err = errorx.New(paths + ": new object " + decl + " : " + err.Error())
   188  			return
   189  		}
   190  	} else {
   191  		rval = oval
   192  	}
   193  	maptype := reflectx.GetType(decl)
   194  	if maptype == nil {
   195  		err = errorx.New(paths + ": reftype not found: " + oval.RefType())
   196  		return
   197  	}
   198  
   199  	stdesc := schemax.GetDeclByKey(decl)
   200  	err = coder.fromMapObj(maptype, rval, many.(map[string]interface{}), stdesc, paths)
   201  	return
   202  }
   203  func (coder *MapToRef) fromMapEnum(mval interface{}, decl string, paths string) (st interface{}, err error) {
   204  	idesc := schemax.GetDeclByKey(decl)
   205  	if idesc == nil {
   206  		err = errorx.New(paths + ": enum schema not found: " + decl)
   207  		return
   208  	}
   209  
   210  	enumdesc := idesc.(*schemax.EnumDecl)
   211  	st = enumdesc.ConvertToValue(mval)
   212  	return
   213  }
   214  
   215  func (coder *MapToRef) fromMapSlice(reftype reflectx.IRefSlice, obj reflectx.IRefObject, many interface{}, fname string, ftyp *schemax.ArrayType, paths string) (err error) {
   216  	if many == nil {
   217  		reftype.RefSet(obj, fname, reftype.RefSliceNew(fname, 0, 0))
   218  		return
   219  	}
   220  
   221  	marr := many.([]interface{})
   222  	mlen := len(marr)
   223  	mcap := cap(marr)
   224  	reftype.RefSet(obj, fname, reftype.RefSliceNew(fname, mlen, mcap))
   225  	if mlen == 0 {
   226  		return
   227  	}
   228  	switch etyp := ftyp.Elem.(type) {
   229  	case *schemax.ClassType:
   230  		for i := 0; i < len(marr); i++ {
   231  			mval := marr[i]
   232  			oval, isNil := reftype.RefSliceGet(obj, fname, i)
   233  			st, classerr := coder.fromMapClass(reftype, oval.(reflectx.IRefObject), isNil, mval, etyp.Decl, paths+"/"+strconv.Itoa(i))
   234  			if classerr != nil {
   235  				return classerr
   236  			}
   237  			reftype.RefSliceSet(obj, fname, i, st)
   238  		}
   239  	case *schemax.BasicType:
   240  		for i := 0; i < len(marr); i++ {
   241  			reftype.RefSliceSet(obj, fname, i, coder.fromMapBasic(marr[i], etyp))
   242  		}
   243  	case *schemax.EnumType:
   244  		for i := 0; i < len(marr); i++ {
   245  			mval := marr[i]
   246  			rval, classerr := coder.fromMapEnum(mval, etyp.Decl, paths+"/"+strconv.Itoa(i))
   247  			if classerr != nil {
   248  				return classerr
   249  			}
   250  			reftype.RefSliceSet(obj, fname, i, rval)
   251  		}
   252  	case *schemax.AnyType:
   253  
   254  	default:
   255  		err = errorx.New("decode array: not support type: " + etyp.String())
   256  		return
   257  
   258  	}
   259  
   260  	return
   261  }
   262  
   263  func (coder *MapToRef) fromMapMap(reftype reflectx.IRefMap, obj reflectx.IRefObject, fname string, many interface{}, ftyp *schemax.MapType, paths string) (err error) {
   264  	if many == nil { // 如果设置了nil
   265  		reftype.RefSet(obj, fname, nil)
   266  		return
   267  	}
   268  
   269  	mmap := many.(map[string]interface{})
   270  
   271  	_, isNil := reftype.RefGet(obj, fname)
   272  	if isNil {
   273  		// 创建
   274  		reftype.RefSet(obj, fname, reftype.RefMapNew(fname))
   275  	}
   276  	//
   277  	switch etyp := ftyp.Value.(type) {
   278  	case *schemax.ClassType:
   279  		for mkey, mval := range mmap {
   280  			oval, onil := reftype.RefMapGet(obj, fname, mkey)
   281  			st, classerr := coder.fromMapClass(reftype, oval.(reflectx.IRefObject), onil, mval, etyp.Decl, paths+"/"+mkey)
   282  			if classerr != nil {
   283  				return classerr
   284  			}
   285  			reftype.RefMapSet(obj, fname, mkey, st)
   286  		}
   287  	case *schemax.BasicType:
   288  		for mkey, mval := range mmap {
   289  			reftype.RefMapSet(obj, fname, mkey, coder.fromMapBasic(mval, etyp))
   290  		}
   291  	case *schemax.EnumType:
   292  		for mkey, mval := range mmap {
   293  			rval, classerr := coder.fromMapEnum(mval, etyp.Decl, paths+"/"+mkey)
   294  			if classerr != nil {
   295  				return classerr
   296  			}
   297  			reftype.RefMapSet(obj, fname, mkey, rval)
   298  		}
   299  	default:
   300  		err = errorx.New(paths + ": decode array: not support type: " + etyp.String())
   301  		return
   302  
   303  	}
   304  
   305  	return
   306  }
   307  
   308  func (coder *MapToRef) fromMapBasic(mval interface{}, ftyp *schemax.BasicType) interface{} {
   309  	return basickind.ConvertKindToStruct(ftyp.Kind, mval)
   310  }