| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500 | 
							- package ii
 
- import (
 
- 	"errors"
 
- 	"fmt"
 
- 	"reflect"
 
- 	"strconv"
 
- 	"strings"
 
- 	"time"
 
- 	"golib/v3/features/mo"
 
- 	"golib/v3/gnet"
 
- 	"golib/v3/pkg/tuid"
 
- )
 
- var (
 
- 	errCovertReturn = func(f *FieldInfo, v any) error {
 
- 		return fmt.Errorf("%s: %v not covert name: %s valueType: %v", getCallerName(), v, f.Name, valueType(v))
 
- 	}
 
- 	errCovertRetErr = func(f *FieldInfo, v any, err error) error {
 
- 		return fmt.Errorf("%s: %v not covert name: %s valueType: %s err: %s", getCallerName(), v, f.Name, valueType(v), err)
 
- 	}
 
- )
 
- // Convert 将 value 转换为 Type 类型. 遇到任何错误时返回
 
- // value 被设计为传入非指针类型参数. 当前除 mo.TypeBinary 支持传入指针类型(用作反射代码示例), 其他 Type 都会返回错误
 
- // 详情见 field_covert_test.go
 
- func (f *FieldInfo) Convert(value any) (any, error) {
 
- 	switch f.Type {
 
- 	case mo.TypeDouble:
 
- 		return f.convertDouble(value)
 
- 	case mo.TypeString:
 
- 		return f.convertString(value)
 
- 	case mo.TypeObject:
 
- 		return f.convertObject(value)
 
- 	case mo.TypeArray:
 
- 		return f.convertArray(value)
 
- 	case mo.TypeBinary:
 
- 		return f.convertBinary(value)
 
- 	case mo.TypeObjectID:
 
- 		return f.convertObjectID(value)
 
- 	case mo.TypeBoolean:
 
- 		return f.convertBoolean(value)
 
- 	case mo.TypeDateTime:
 
- 		return f.convertDate(value)
 
- 	case mo.TypeInt32:
 
- 		return f.convertInt32(value)
 
- 	case mo.TypeInt64:
 
- 		return f.convertInt64(value)
 
- 	default:
 
- 		return nil, errCovertReturn(f, value)
 
- 	}
 
- }
 
- func (f *FieldInfo) convertDouble(value any) (float64, error) {
 
- 	switch v := value.(type) {
 
- 	case float64, float32, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
 
- 		val := reflect.ValueOf(v).Convert(reflect.TypeOf(float64(0)))
 
- 		return toFloat64Decimal(val.Float(), f.Decimal), nil
 
- 	case string:
 
- 		if v == "" {
 
- 			return 0, nil
 
- 		}
 
- 		val, err := strconv.ParseFloat(v, 64)
 
- 		if err != nil {
 
- 			return 0, errCovertRetErr(f, value, err)
 
- 		}
 
- 		return toFloat64Decimal(val, f.Decimal), nil
 
- 	default:
 
- 		return 0, errCovertReturn(f, value)
 
- 	}
 
- }
 
- func (f *FieldInfo) convertString(value any) (string, error) {
 
- 	if value == nil {
 
- 		return "", errors.New("value is nil")
 
- 	}
 
- 	rv := reflect.ValueOf(value)
 
- 	switch rv.Type().Kind() {
 
- 	case reflect.String:
 
- 		if value == "new" {
 
- 			return tuid.New(), nil
 
- 		}
 
- 		return rv.String(), nil
 
- 	case reflect.Bool:
 
- 		return strconv.FormatBool(rv.Bool()), nil
 
- 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 
- 		return strconv.FormatInt(rv.Int(), 10), nil
 
- 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 
- 		return strconv.FormatUint(rv.Uint(), 10), nil
 
- 	case reflect.Float64, reflect.Float32:
 
- 		return strconv.FormatFloat(rv.Float(), 'g', -1, 64), nil
 
- 	case reflect.Map:
 
- 		val, _ := f.convertObject(value)
 
- 		bv, err := mo.MarshalExtJSON(val, false, true)
 
- 		if err != nil {
 
- 			return "", err
 
- 		}
 
- 		return string(bv), nil
 
- 	case reflect.Array, reflect.Slice:
 
- 		length := rv.Len()
 
- 		val := make([]string, length)
 
- 		for i := 0; i < length; i++ {
 
- 			sv, err := f.convertString(rv.Index(i).Interface())
 
- 			if err != nil {
 
- 				return "", err
 
- 			}
 
- 			val[i] = sv
 
- 		}
 
- 		return strings.Join(val, ","), nil
 
- 	default:
 
- 		return "", errCovertReturn(f, value)
 
- 	}
 
- }
 
- // convertObject 将 value 转换为 mo.M 类型
 
- // 对于已经是 map 类型的 value, 则需要深度 copy 后返回.
 
- // 当大量转换时可能会出现性能影响
 
- // 2023/01/28: from eric: object/map 类型的数据不允许 value 再次作为 map, 即只能存在一层 map // 移动至 ItemInfo 的 initFieldMap 中实现
 
- func (f *FieldInfo) convertObject(value any) (mo.M, error) {
 
- 	if f.NoField {
 
- 		return mo.M{}, nil
 
- 	}
 
- 	var (
 
- 		m   mo.M
 
- 		err error
 
- 	)
 
- 	switch val := value.(type) {
 
- 	case mo.D:
 
- 		m, err = mo.ToM(val)
 
- 	case mo.M:
 
- 		m, err = mo.DeepCopy(val)
 
- 	default:
 
- 		var b []byte
 
- 		b, err = mo.MarshalExtJSON(val, true, true)
 
- 		if err != nil {
 
- 			return nil, errCovertRetErr(f, value, err)
 
- 		}
 
- 		err = mo.UnmarshalExtJSON(b, true, &m)
 
- 	}
 
- 	if err != nil {
 
- 		return nil, errCovertRetErr(f, value, err)
 
- 	}
 
- 	fm := make(mo.M)
 
- 	for _, sf := range f.Fields {
 
- 		sv, ok := m[sf.Name]
 
- 		if !ok {
 
- 			continue // 如果字段不存 SubField 内则跳过解析
 
- 		}
 
- 		sfv, err := sf.Convert(sv)
 
- 		if err != nil {
 
- 			return nil, errCovertRetErr(f, value, err)
 
- 		}
 
- 		fm[sf.Name] = sfv
 
- 	}
 
- 	return fm, nil
 
- }
 
- func (f *FieldInfo) convertObjectWith(value, t any) error {
 
- 	m, err := f.convertObject(value)
 
- 	if err != nil {
 
- 		return err
 
- 	}
 
- 	b, err := mo.Marshal(m)
 
- 	if err != nil {
 
- 		return errCovertRetErr(f, value, err)
 
- 	}
 
- 	return mo.Unmarshal(b, t)
 
- }
 
- func (f *FieldInfo) convertArray(value any) (mo.A, error) {
 
- 	if value == nil {
 
- 		return nil, errors.New("value is nil")
 
- 	}
 
- 	rv := reflect.ValueOf(value)
 
- 	switch rv.Type().Kind() {
 
- 	case reflect.Slice, reflect.Array:
 
- 		length := rv.Len()
 
- 		n := make(mo.A, length)
 
- 		for i := 0; i < length; i++ {
 
- 			rvi := rv.Index(i).Interface()
 
- 			if err := covertArray(f, rvi, &n, i); err != nil {
 
- 				return nil, err
 
- 			}
 
- 		}
 
- 		return n, nil
 
- 	case reflect.String:
 
- 		v := rv.String()
 
- 		if strings.TrimSpace(v) == "" {
 
- 			return mo.A{}, nil
 
- 		}
 
- 		if indexEqual(v, "{", "}") {
 
- 			n := make(mo.A, 1)
 
- 			if err := covertArray(f, v, &n, 0); err != nil {
 
- 				return nil, err
 
- 			}
 
- 			return n, nil
 
- 		}
 
- 		if indexEqual(v, "[", "]") {
 
- 			// 移除括号
 
- 			v = strings.TrimPrefix(v, "[")
 
- 			v = strings.TrimSuffix(v, "]")
 
- 			// 如果包含 , 表示数组内有多个元素
 
- 			if strings.Contains(v, ",") {
 
- 				str := strings.Split(v, ",")
 
- 				n := make(mo.A, len(str))
 
- 				for i, s := range str {
 
- 					if err := covertArray(f, s, &n, i); err != nil {
 
- 						return nil, err
 
- 					}
 
- 				}
 
- 				return n, nil
 
- 			} else {
 
- 				// 否则表示只有一个元素
 
- 				n := make(mo.A, 1)
 
- 				if err := covertArray(f, v, &n, 0); err != nil {
 
- 					return nil, err
 
- 				}
 
- 				return n, nil
 
- 			}
 
- 		} else {
 
- 			n := make(mo.A, 1)
 
- 			if err := covertArray(f, v, &n, 0); err == nil {
 
- 				return n, nil
 
- 			}
 
- 		}
 
- 		return nil, errCovertReturn(f, v)
 
- 	case reflect.Float32, reflect.Float64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
 
- 		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 
- 		return mo.A{value}, nil
 
- 	case reflect.Map:
 
- 		// 兼容 javaScript 传入空数组时会被 Go 语言解析为 (interface{}|map[string]interface{}) 的问题
 
- 		return mo.A{}, nil
 
- 	default:
 
- 		return nil, errCovertReturn(f, value)
 
- 	}
 
- }
 
- // convertBinary
 
- func (f *FieldInfo) convertBinary(value any) (mo.Binary, error) {
 
- 	if value == nil {
 
- 		return mo.Binary{}, errors.New("value is nil")
 
- 	}
 
- 	rv := reflect.ValueOf(value)
 
- 	// 获取 value 的类型, 例如 pointer, int64, float64, map, slice, array
 
- 	switch rv.Type().Kind() {
 
- 	case reflect.Pointer:
 
- 		// 由于首先确认 value 是指针, 因此此处无需再次判断 CanSet
 
- 		// if rv.Elem().CanSet() {
 
- 		//
 
- 		// }
 
- 		// 当类型为 Pointer 时则需要使用 Elem() 函数操作
 
- 		rvp := rv.Type().Elem()
 
- 		// 所以 value 作为一个指针传入时, 先判断指针的类型是否为 Array 或 Slice
 
- 		if rvp.Kind() != reflect.Array && rvp.Kind() != reflect.Slice {
 
- 			return mo.Binary{}, errCovertReturn(f, value)
 
- 		}
 
- 		// 由于已知 rvp 为 Array 或 Slice 类型, 则再次调用 Elem() 函数表示获取其元素类型
 
- 		// 备忘录: 若数组内的元素数据类型不一致时则 Kind() 会返回 interface
 
- 		// uint8: [1,2,3,4,5]
 
- 		// interface: ["1", 3.14, []byte{0x01, 0x02}]
 
- 		if rvp.Elem().Kind() != reflect.Uint8 {
 
- 			return mo.Binary{}, errCovertReturn(f, value)
 
- 		}
 
- 		// 检查完毕指针内部的类型后, 应继续调用 rv 表示使用指针操作
 
- 		// 因此通过 rv.Elem() 调用 Bytes()
 
- 		return mo.Binary{Data: rv.Elem().Bytes()}, nil
 
- 	case reflect.Uint8:
 
- 		return mo.Binary{Data: []byte{uint8(rv.Uint())}}, nil
 
- 	case reflect.Slice, reflect.Array:
 
- 		if rv.Type().Elem().Kind() != reflect.Uint8 {
 
- 			return mo.Binary{}, errCovertReturn(f, value)
 
- 		}
 
- 		length := rv.Len()
 
- 		val := make([]byte, length)
 
- 		for i := 0; i < length; i++ {
 
- 			val[i] = rv.Index(i).Interface().(byte)
 
- 		}
 
- 		return mo.Binary{Data: val}, nil
 
- 	case reflect.String:
 
- 		val := gnet.String(rv.String()).Hex()
 
- 		if val == nil {
 
- 			return mo.Binary{}, errCovertReturn(f, value)
 
- 		}
 
- 		return mo.Binary{Data: val}, nil
 
- 	case reflect.Struct:
 
- 		val, ok := rv.Interface().(mo.Binary)
 
- 		if ok {
 
- 			if val.IsZero() {
 
- 				return mo.Binary{}, errCovertReturn(f, value)
 
- 			}
 
- 			return val, nil
 
- 		}
 
- 		fallthrough
 
- 	default:
 
- 		return mo.Binary{}, errCovertReturn(f, value)
 
- 	}
 
- }
 
- func (f *FieldInfo) convertObjectID(value any) (mo.ObjectID, error) {
 
- 	switch v := value.(type) {
 
- 	case mo.ObjectID:
 
- 		if v.IsZero() && f.Required {
 
- 			return mo.NilObjectID, errCovertReturn(f, value)
 
- 		}
 
- 		return v, nil
 
- 	case string:
 
- 		if v == "new" {
 
- 			return mo.ID.New(), nil
 
- 		}
 
- 		// 当 v 不等于空, 则不关心 Required 是否为 true
 
- 		if v != "" {
 
- 			val, err := mo.ID.From(v)
 
- 			if err != nil {
 
- 				return mo.NilObjectID, errCovertRetErr(f, val, err)
 
- 			}
 
- 			return val, nil
 
- 		} else {
 
- 			if f.Required {
 
- 				return mo.NilObjectID, errCovertReturn(f, value)
 
- 			}
 
- 			return mo.NilObjectID, nil
 
- 		}
 
- 	default:
 
- 		return mo.NilObjectID, errCovertReturn(f, value)
 
- 	}
 
- }
 
- func (f *FieldInfo) convertBoolean(value any) (bool, error) {
 
- 	switch v := value.(type) {
 
- 	case bool:
 
- 		return v, nil
 
- 	case string:
 
- 		if v == "" {
 
- 			return false, nil
 
- 		}
 
- 		val, err := strconv.ParseBool(v)
 
- 		if err != nil {
 
- 			return false, errCovertRetErr(f, value, err)
 
- 		}
 
- 		return val, nil
 
- 	case uint, uint8, uint16, uint32, uint64, int, int8, int16, int32, int64, float32, float64:
 
- 		val := reflect.ValueOf(v).Convert(reflect.TypeOf(int64(0)))
 
- 		return val.Int() == 1, nil
 
- 	default:
 
- 		return false, errCovertReturn(f, value)
 
- 	}
 
- }
 
- // convertDate 将 value 转换为 mo.DateTime 类型
 
- // convertDate 函数会将 value 用做 毫秒 进行解析
 
- func (f *FieldInfo) convertDate(value any) (mo.DateTime, error) {
 
- 	switch v := value.(type) {
 
- 	case mo.DateTime:
 
- 		return mo.NewDateTimeFromTime(v.Time()), nil
 
- 	case time.Time:
 
- 		if v.IsZero() {
 
- 			return 0, errCovertReturn(f, value)
 
- 		}
 
- 		return mo.NewDateTimeFromTime(v), nil
 
- 	case time.Duration:
 
- 		return mo.NewDateTimeFromTime(time.UnixMilli(v.Milliseconds())), nil
 
- 	case uint, uint8, uint16, uint32, uint64, int, int8, int16, int32, int64, float32, float64:
 
- 		val := reflect.ValueOf(v).Convert(reflect.TypeOf(int64(0)))
 
- 		return mo.NewDateTimeFromTime(time.UnixMilli(val.Int())), nil
 
- 	case string:
 
- 		if v == "" {
 
- 			return 0, nil
 
- 		}
 
- 		if v == "now" {
 
- 			return mo.NewDateTime(), nil
 
- 		}
 
- 		if strings.Contains(v, "-") || strings.Contains(v, ":") {
 
- 			tim, err := mo.ResolveDateTime(v)
 
- 			if err != nil {
 
- 				return 0, errCovertRetErr(f, value, err)
 
- 			}
 
- 			return tim, nil
 
- 		}
 
- 		val, err := strconv.ParseInt(v, 10, 64)
 
- 		if err != nil {
 
- 			return 0, errCovertRetErr(f, value, err)
 
- 		}
 
- 		return mo.NewDateTimeFromTime(time.UnixMilli(val)), nil
 
- 	case []byte:
 
- 		if val := gnet.BigEndian.Int64(v); val > 0 {
 
- 			return mo.NewDateTimeFromTime(time.UnixMilli(val)), nil
 
- 		}
 
- 		return 0, errCovertReturn(f, value)
 
- 	default:
 
- 		return 0, errCovertReturn(f, value)
 
- 	}
 
- }
 
- func (f *FieldInfo) convertInt32(value any) (int32, error) {
 
- 	switch v := value.(type) {
 
- 	case int32:
 
- 		return v, nil
 
- 	case int64:
 
- 		return int32(v), nil
 
- 	case float64:
 
- 		return int32(v), nil
 
- 	case uint64:
 
- 		return int32(v), nil
 
- 	case int:
 
- 		return int32(v), nil
 
- 	case uint:
 
- 		return int32(v), nil
 
- 	case uint8:
 
- 		return int32(v), nil
 
- 	case uint16:
 
- 		return int32(v), nil
 
- 	case uint32:
 
- 		return int32(v), nil
 
- 	case int8:
 
- 		return int32(v), nil
 
- 	case int16:
 
- 		return int32(v), nil
 
- 	case float32:
 
- 		return int32(v), nil
 
- 	case string:
 
- 		if v == "" {
 
- 			return 0, nil
 
- 		}
 
- 		val, err := strconv.ParseInt(v, 10, 32)
 
- 		if err != nil {
 
- 			return 0, errCovertRetErr(f, val, err)
 
- 		}
 
- 		return int32(val), nil
 
- 	case []byte:
 
- 		if val := gnet.BigEndian.Int32(v); val > 0 {
 
- 			return val, nil
 
- 		}
 
- 		return 0, errCovertReturn(f, value)
 
- 	case time.Duration:
 
- 		return int32(v.Milliseconds()), nil
 
- 	case time.Time:
 
- 		return int32(v.UnixMilli()), nil
 
- 	case mo.DateTime:
 
- 		return int32(v.Time().UnixMilli()), nil
 
- 	default:
 
- 		return 0, errCovertReturn(f, value)
 
- 	}
 
- }
 
- func (f *FieldInfo) convertInt64(value any) (int64, error) {
 
- 	switch v := value.(type) {
 
- 	case int64:
 
- 		return v, nil
 
- 	case float64:
 
- 		return int64(v), nil
 
- 	case uint64:
 
- 		return int64(v), nil
 
- 	case int:
 
- 		return int64(v), nil
 
- 	case uint:
 
- 		return int64(v), nil
 
- 	case uint8:
 
- 		return int64(v), nil
 
- 	case uint16:
 
- 		return int64(v), nil
 
- 	case uint32:
 
- 		return int64(v), nil
 
- 	case int8:
 
- 		return int64(v), nil
 
- 	case int16:
 
- 		return int64(v), nil
 
- 	case int32:
 
- 		return int64(v), nil
 
- 	case float32:
 
- 		return int64(v), nil
 
- 	case string:
 
- 		if v == "" {
 
- 			return 0, nil
 
- 		}
 
- 		val, err := strconv.ParseInt(v, 10, 64)
 
- 		if err != nil {
 
- 			return 0, errCovertRetErr(f, val, err)
 
- 		}
 
- 		return val, nil
 
- 	case []byte:
 
- 		if val := gnet.BigEndian.Int64(v); val > 0 {
 
- 			return val, nil
 
- 		}
 
- 		return 0, errCovertReturn(f, value)
 
- 	case time.Duration:
 
- 		return v.Milliseconds(), nil
 
- 	case time.Time:
 
- 		return v.UnixMilli(), nil
 
- 	case mo.DateTime:
 
- 		return v.Time().UnixMilli(), nil
 
- 	default:
 
- 		return 0, errCovertReturn(f, value)
 
- 	}
 
- }
 
 
  |