Compare commits
22 Commits
270c4fcfd4
...
feature/ge
Author | SHA1 | Date | |
---|---|---|---|
50aa5ae7f8 | |||
3533617196 | |||
9ff1c213bb | |||
8d056baada | |||
ed0c57913a | |||
588df729e0 | |||
3faebb9145 | |||
5163fd6f49 | |||
e228983e73 | |||
3caad964bc | |||
9ae0c8f4be | |||
d1b9779946 | |||
8c922be06d | |||
ee726ea6bc | |||
e125c7e75d | |||
1e1db09499 | |||
65107176f4 | |||
c07adaf249 | |||
4d25a2a650 | |||
ab1f877b3c | |||
e8fc0addfc | |||
9b469e0ac2 |
89
any.go
89
any.go
@ -9,6 +9,7 @@ package wrapper
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"git.zhangdeman.cn/zhangdeman/consts"
|
||||||
"git.zhangdeman.cn/zhangdeman/serialize"
|
"git.zhangdeman.cn/zhangdeman/serialize"
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
@ -18,7 +19,7 @@ import (
|
|||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 18:19 2023/6/1
|
// Date : 18:19 2023/6/1
|
||||||
func AnyDataType(data interface{}) *AnyType {
|
func AnyDataType(data any) *AnyType {
|
||||||
at := &AnyType{
|
at := &AnyType{
|
||||||
data: data,
|
data: data,
|
||||||
}
|
}
|
||||||
@ -32,7 +33,7 @@ func AnyDataType(data interface{}) *AnyType {
|
|||||||
//
|
//
|
||||||
// Date : 18:19 2023/6/1
|
// Date : 18:19 2023/6/1
|
||||||
type AnyType struct {
|
type AnyType struct {
|
||||||
data interface{}
|
data any
|
||||||
dataType string
|
dataType string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,28 +57,28 @@ func (at *AnyType) Type() string {
|
|||||||
return at.dataType
|
return at.dataType
|
||||||
}
|
}
|
||||||
if at.IsNil() {
|
if at.IsNil() {
|
||||||
return DataTypeNil
|
return consts.DataTypeNil
|
||||||
}
|
}
|
||||||
reflectType := reflect.TypeOf(at.data)
|
reflectType := reflect.TypeOf(at.data)
|
||||||
switch reflectType.Kind() {
|
switch reflectType.Kind() {
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
return DataTypeString
|
return consts.DataTypeString
|
||||||
case reflect.Slice, reflect.Array:
|
case reflect.Slice, reflect.Array:
|
||||||
return DataTypeSlice
|
return consts.DataTypeSliceAny
|
||||||
case reflect.Map, reflect.Struct:
|
case reflect.Map, reflect.Struct:
|
||||||
return DataTypeObject
|
return consts.DataTypeMapAnyAny
|
||||||
case reflect.Pointer:
|
case reflect.Pointer:
|
||||||
return DataTypePtr
|
return consts.DataTypePtr
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
return DataTypeInt
|
return consts.DataTypeInt
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
return DataTypeUint
|
return consts.DataTypeUint
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
return DataTypeBool
|
return consts.DataTypeBool
|
||||||
case reflect.Float32, reflect.Float64:
|
case reflect.Float32, reflect.Float64:
|
||||||
return DataTypeFloat
|
return consts.DataTypeFloat
|
||||||
default:
|
default:
|
||||||
return DataTypeUnknown
|
return consts.DataTypeUnknown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,51 +88,27 @@ func (at *AnyType) Type() string {
|
|||||||
//
|
//
|
||||||
// Date : 18:32 2023/6/1
|
// Date : 18:32 2023/6/1
|
||||||
func (at *AnyType) ToString() String {
|
func (at *AnyType) ToString() String {
|
||||||
switch at.dataType {
|
dataType := at.Type()
|
||||||
case DataTypeNil:
|
switch dataType {
|
||||||
|
case consts.DataTypeUnknown, consts.DataTypeNil:
|
||||||
return String("")
|
return String("")
|
||||||
case DataTypeObject:
|
case consts.DataTypeString:
|
||||||
fallthrough
|
return String(fmt.Sprintf("%v", at.data))
|
||||||
case DataTypeSlice:
|
case consts.DataTypeSliceAny:
|
||||||
fallthrough
|
var val []any
|
||||||
case DataTypePtr:
|
_ = serialize.JSON.Transition(at.data, &val)
|
||||||
|
return String(ArrayType[any, any](val).ToString().Value)
|
||||||
|
case consts.DataTypeMapAnyAny:
|
||||||
|
return String(EasyMap(at.data).ToString())
|
||||||
|
case consts.DataTypeInt:
|
||||||
|
return String(Int(at.data.(int64)).ToString().Value)
|
||||||
|
case consts.DataTypeUint:
|
||||||
|
return String(Int(at.data.(uint)).ToString().Value)
|
||||||
|
case consts.DataTypeFloat:
|
||||||
|
return String(Float(at.data.(float64)).ToString().Value)
|
||||||
|
case consts.DataTypeBool:
|
||||||
|
return String(fmt.Sprintf("%v", at.data))
|
||||||
|
default:
|
||||||
return String(serialize.JSON.MarshalForString(at.data))
|
return String(serialize.JSON.MarshalForString(at.data))
|
||||||
}
|
}
|
||||||
return String(fmt.Sprintf("%v", at.data))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToObject 任意类型转为对象
|
|
||||||
//
|
|
||||||
// Author : go_developer@163.com<白茶清欢>
|
|
||||||
//
|
|
||||||
// Date : 17:19 2023/10/11
|
|
||||||
func (at *AnyType) ToObject() MapResult {
|
|
||||||
return MapResult{
|
|
||||||
Value: EasyMapFromString(at.ToString().Value()),
|
|
||||||
Err: nil,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (at *AnyType) ToIntSlice() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (at *AnyType) ToUintSlice() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (at *AnyType) ToStringSlice() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (at *AnyType) ToFloatSlice() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (at *AnyType) ToBoolSlice() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (at *AnyType) ToAnySlice() {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
306
array.go
306
array.go
@ -10,7 +10,8 @@ package wrapper
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"git.zhangdeman.cn/zhangdeman/op_type"
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@ -20,11 +21,10 @@ import (
|
|||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 21:03 2023/6/11
|
// Date : 21:03 2023/6/11
|
||||||
func ArrayType(value interface{}) *Array {
|
func ArrayType[Bt op_type.BaseType, ExtractDataType op_type.BaseType](value []Bt) *Array[Bt, ExtractDataType] {
|
||||||
at := &Array{
|
at := &Array[Bt, ExtractDataType]{
|
||||||
value: value,
|
value: value,
|
||||||
}
|
}
|
||||||
_, _ = at.Convert()
|
|
||||||
return at
|
return at
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,12 +33,10 @@ func ArrayType(value interface{}) *Array {
|
|||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 21:05 2023/6/11
|
// Date : 21:05 2023/6/11
|
||||||
type Array struct {
|
type Array[Bt op_type.BaseType, ExtractDataType op_type.BaseType] struct {
|
||||||
value interface{}
|
value []Bt
|
||||||
convertResult []interface{}
|
convertErr error
|
||||||
convertErr error
|
itemType reflect.Kind // 简单list场景下, 每一项的数据类型
|
||||||
isSimpleSlice bool // 是否简单list, 即数据的每一项类型相同, 且都是基础内置数据类型
|
|
||||||
itemType reflect.Kind // 简单list场景下, 每一项的数据类型
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsNil 输入是否为nil
|
// IsNil 输入是否为nil
|
||||||
@ -46,189 +44,22 @@ type Array struct {
|
|||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 21:11 2023/6/11
|
// Date : 21:11 2023/6/11
|
||||||
func (at *Array) IsNil() bool {
|
func (at *Array[Bt, ExtractDataType]) IsNil() bool {
|
||||||
return at.value == nil
|
return at.value == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsValid 检测是否为数组类型
|
// ToStringSlice ...
|
||||||
//
|
//
|
||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 21:06 2023/6/11
|
// Date : 11:42 2024/4/22
|
||||||
func (at *Array) IsValid() bool {
|
func (at *Array[Bt, ExtractDataType]) ToStringSlice() []string {
|
||||||
if at.IsNil() {
|
list := make([]string, 0)
|
||||||
return false
|
for _, item := range at.value {
|
||||||
|
byteData, _ := json.Marshal(item)
|
||||||
|
list = append(list, strings.Trim(string(byteData), "\""))
|
||||||
}
|
}
|
||||||
byteData, err := json.Marshal(at.value)
|
return list
|
||||||
if nil != err {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return strings.HasPrefix(string(byteData), "[") && strings.HasSuffix(string(byteData), "]")
|
|
||||||
}
|
|
||||||
|
|
||||||
// ItemIsInterface 数组每一项是否为interface
|
|
||||||
//
|
|
||||||
// Author : go_developer@163.com<白茶清欢>
|
|
||||||
//
|
|
||||||
// Date : 21:20 2023/6/11
|
|
||||||
func (at *Array) ItemIsInterface() bool {
|
|
||||||
if !at.IsValid() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if _, ok := at.value.([]interface{}); ok {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert 类型转换
|
|
||||||
//
|
|
||||||
// Author : go_developer@163.com<白茶清欢>
|
|
||||||
//
|
|
||||||
// Date : 17:59 2023/6/12
|
|
||||||
func (at *Array) Convert() ([]interface{}, error) {
|
|
||||||
if at.IsNil() {
|
|
||||||
// 空指针
|
|
||||||
at.convertResult = make([]interface{}, 0)
|
|
||||||
return at.convertResult, nil
|
|
||||||
}
|
|
||||||
if !at.IsValid() {
|
|
||||||
// 无效slice
|
|
||||||
at.convertErr = errors.New("input slice is invalid")
|
|
||||||
return nil, at.convertErr
|
|
||||||
}
|
|
||||||
switch val := at.value.(type) {
|
|
||||||
case []int8:
|
|
||||||
at.isSimpleSlice = true
|
|
||||||
at.itemType = reflect.Int8
|
|
||||||
at.convertResult = make([]interface{}, len(val))
|
|
||||||
for i := 0; i < len(val); i++ {
|
|
||||||
at.convertResult[i] = val[i]
|
|
||||||
}
|
|
||||||
case []int16:
|
|
||||||
at.isSimpleSlice = true
|
|
||||||
at.itemType = reflect.Int16
|
|
||||||
at.convertResult = make([]interface{}, len(val))
|
|
||||||
for i := 0; i < len(val); i++ {
|
|
||||||
at.convertResult[i] = val[i]
|
|
||||||
}
|
|
||||||
case []int32:
|
|
||||||
at.isSimpleSlice = true
|
|
||||||
at.itemType = reflect.Int32
|
|
||||||
at.convertResult = make([]interface{}, len(val))
|
|
||||||
for i := 0; i < len(val); i++ {
|
|
||||||
at.convertResult[i] = val[i]
|
|
||||||
}
|
|
||||||
case []int64:
|
|
||||||
at.isSimpleSlice = true
|
|
||||||
at.itemType = reflect.Int64
|
|
||||||
at.convertResult = make([]interface{}, len(val))
|
|
||||||
for i := 0; i < len(val); i++ {
|
|
||||||
at.convertResult[i] = val[i]
|
|
||||||
}
|
|
||||||
case []int:
|
|
||||||
at.isSimpleSlice = true
|
|
||||||
at.itemType = reflect.Int
|
|
||||||
at.convertResult = make([]interface{}, len(val))
|
|
||||||
for i := 0; i < len(val); i++ {
|
|
||||||
at.convertResult[i] = val[i]
|
|
||||||
}
|
|
||||||
case []uint:
|
|
||||||
at.isSimpleSlice = true
|
|
||||||
at.itemType = reflect.Uint
|
|
||||||
at.convertResult = make([]interface{}, len(val))
|
|
||||||
for i := 0; i < len(val); i++ {
|
|
||||||
at.convertResult[i] = val[i]
|
|
||||||
}
|
|
||||||
case []uint8:
|
|
||||||
at.isSimpleSlice = true
|
|
||||||
at.itemType = reflect.Uint8
|
|
||||||
at.convertResult = make([]interface{}, len(val))
|
|
||||||
for i := 0; i < len(val); i++ {
|
|
||||||
at.convertResult[i] = val[i]
|
|
||||||
}
|
|
||||||
case []uint16:
|
|
||||||
at.isSimpleSlice = true
|
|
||||||
at.itemType = reflect.Uint16
|
|
||||||
at.convertResult = make([]interface{}, len(val))
|
|
||||||
for i := 0; i < len(val); i++ {
|
|
||||||
at.convertResult[i] = val[i]
|
|
||||||
}
|
|
||||||
case []uint32:
|
|
||||||
at.isSimpleSlice = true
|
|
||||||
at.itemType = reflect.Int32
|
|
||||||
at.convertResult = make([]interface{}, len(val))
|
|
||||||
for i := 0; i < len(val); i++ {
|
|
||||||
at.convertResult[i] = val[i]
|
|
||||||
}
|
|
||||||
case []uint64:
|
|
||||||
at.isSimpleSlice = true
|
|
||||||
at.itemType = reflect.Int64
|
|
||||||
at.convertResult = make([]interface{}, len(val))
|
|
||||||
for i := 0; i < len(val); i++ {
|
|
||||||
at.convertResult[i] = val[i]
|
|
||||||
}
|
|
||||||
case []float32:
|
|
||||||
at.isSimpleSlice = true
|
|
||||||
at.itemType = reflect.Float32
|
|
||||||
at.convertResult = make([]interface{}, len(val))
|
|
||||||
for i := 0; i < len(val); i++ {
|
|
||||||
at.convertResult[i] = val[i]
|
|
||||||
}
|
|
||||||
case []float64:
|
|
||||||
at.isSimpleSlice = true
|
|
||||||
at.itemType = reflect.Float64
|
|
||||||
at.convertResult = make([]interface{}, len(val))
|
|
||||||
for i := 0; i < len(val); i++ {
|
|
||||||
at.convertResult[i] = val[i]
|
|
||||||
}
|
|
||||||
case []bool:
|
|
||||||
at.isSimpleSlice = true
|
|
||||||
at.itemType = reflect.Bool
|
|
||||||
at.convertResult = make([]interface{}, len(val))
|
|
||||||
for i := 0; i < len(val); i++ {
|
|
||||||
at.convertResult[i] = val[i]
|
|
||||||
}
|
|
||||||
case []string:
|
|
||||||
at.isSimpleSlice = true
|
|
||||||
at.itemType = reflect.String
|
|
||||||
at.convertResult = make([]interface{}, len(val))
|
|
||||||
for i := 0; i < len(val); i++ {
|
|
||||||
at.convertResult[i] = val[i]
|
|
||||||
}
|
|
||||||
case []interface{}:
|
|
||||||
at.isSimpleSlice = false
|
|
||||||
at.itemType = reflect.Interface
|
|
||||||
at.convertResult = make([]interface{}, len(val))
|
|
||||||
copy(at.convertResult, val)
|
|
||||||
case []struct{}:
|
|
||||||
at.isSimpleSlice = false
|
|
||||||
at.itemType = reflect.Interface
|
|
||||||
at.convertResult = make([]interface{}, len(val))
|
|
||||||
for i := 0; i < len(val); i++ {
|
|
||||||
at.convertResult[i] = val[i]
|
|
||||||
}
|
|
||||||
case []map[string]interface{}:
|
|
||||||
at.isSimpleSlice = false
|
|
||||||
at.itemType = reflect.Interface
|
|
||||||
at.convertResult = make([]interface{}, len(val))
|
|
||||||
for i := 0; i < len(val); i++ {
|
|
||||||
at.convertResult[i] = val[i]
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
|
|
||||||
}
|
|
||||||
return at.convertResult, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConvertIgnoreError 类型转换并忽略异常
|
|
||||||
//
|
|
||||||
// Author : go_developer@163.com<白茶清欢>
|
|
||||||
//
|
|
||||||
// Date : 18:07 2023/6/26
|
|
||||||
func (at *Array) ConvertIgnoreError() []interface{} {
|
|
||||||
res, _ := at.Convert()
|
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unique 对数据结果进行去重
|
// Unique 对数据结果进行去重
|
||||||
@ -236,22 +67,24 @@ func (at *Array) ConvertIgnoreError() []interface{} {
|
|||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 17:43 2023/6/12
|
// Date : 17:43 2023/6/12
|
||||||
func (at *Array) Unique() []interface{} {
|
func (at *Array[Bt, ExtractDataType]) Unique() []Bt {
|
||||||
result := make([]interface{}, 0)
|
result := make([]Bt, 0)
|
||||||
if at.isSimpleSlice {
|
dataTable := make(map[string]bool)
|
||||||
// 简单数据类型
|
|
||||||
dataTable := make(map[string]bool)
|
for _, item := range at.value {
|
||||||
for _, item := range at.convertResult {
|
byteData, _ := json.Marshal(item)
|
||||||
k := fmt.Sprintf("%v", item)
|
k := string(byteData)
|
||||||
if _, exist := dataTable[k]; exist {
|
if strings.HasPrefix(k, "\"\"") && strings.HasSuffix(k, "\"\"") {
|
||||||
continue
|
k = string(byteData[1 : len(byteData)-1])
|
||||||
}
|
|
||||||
dataTable[k] = true
|
|
||||||
result = append(result, item)
|
|
||||||
}
|
}
|
||||||
return result
|
if _, exist := dataTable[k]; exist {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dataTable[k] = true
|
||||||
|
result = append(result, item)
|
||||||
}
|
}
|
||||||
return []interface{}{}
|
return result
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Has 查询一个值是否在列表里, 在的话, 返回首次出现的索引, 不在返回-1
|
// Has 查询一个值是否在列表里, 在的话, 返回首次出现的索引, 不在返回-1
|
||||||
@ -259,22 +92,13 @@ func (at *Array) Unique() []interface{} {
|
|||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 16:28 2023/7/31
|
// Date : 16:28 2023/7/31
|
||||||
func (at *Array) Has(input interface{}) int {
|
func (at *Array[Bt, ExtractDataType]) Has(input Bt) int {
|
||||||
for idx := 0; idx < len(at.convertResult); idx++ {
|
for idx := 0; idx < len(at.value); idx++ {
|
||||||
if nil == input {
|
if reflect.TypeOf(at.value[idx]).String() != reflect.TypeOf(input).String() {
|
||||||
if nil != at.convertResult[idx] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return idx
|
|
||||||
}
|
|
||||||
if at.convertResult[idx] == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if reflect.TypeOf(at.convertResult[idx]).String() != reflect.TypeOf(input).String() {
|
|
||||||
// 类型不同
|
// 类型不同
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
sourceByte, _ := json.Marshal(at.convertResult[idx])
|
sourceByte, _ := json.Marshal(at.value[idx])
|
||||||
inputByte, _ := json.Marshal(input)
|
inputByte, _ := json.Marshal(input)
|
||||||
if string(sourceByte) != string(inputByte) {
|
if string(sourceByte) != string(inputByte) {
|
||||||
continue
|
continue
|
||||||
@ -289,14 +113,14 @@ func (at *Array) Has(input interface{}) int {
|
|||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 16:57 2023/9/28
|
// Date : 16:57 2023/9/28
|
||||||
func (at *Array) ToString() StringResult {
|
func (at *Array[Bt, ExtractDataType]) ToString() StringResult {
|
||||||
if at.IsNil() {
|
if at.IsNil() {
|
||||||
return StringResult{
|
return StringResult{
|
||||||
Value: "",
|
Value: "",
|
||||||
Err: nil,
|
Err: nil,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
byteData, err := json.Marshal(at.convertResult)
|
byteData, err := json.Marshal(at.value)
|
||||||
return StringResult{
|
return StringResult{
|
||||||
Value: string(byteData),
|
Value: string(byteData),
|
||||||
Err: err,
|
Err: err,
|
||||||
@ -308,19 +132,59 @@ func (at *Array) ToString() StringResult {
|
|||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 17:42 2023/10/25
|
// Date : 17:42 2023/10/25
|
||||||
func (at *Array) ToStringWithSplit(split string) StringResult {
|
func (at *Array[Bt, ExtractDataType]) ToStringWithSplit(split string) StringResult {
|
||||||
if at.IsNil() {
|
if at.IsNil() {
|
||||||
return StringResult{
|
return StringResult{
|
||||||
Value: "",
|
Value: "",
|
||||||
Err: nil,
|
Err: nil,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
strList := make([]string, 0)
|
|
||||||
for _, item := range at.convertResult {
|
|
||||||
strList = append(strList, fmt.Sprintf("%v", item))
|
|
||||||
}
|
|
||||||
return StringResult{
|
return StringResult{
|
||||||
Value: strings.Join(strList, split),
|
Value: strings.Join(at.ToStringSlice(), split),
|
||||||
Err: nil,
|
Err: nil,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExtractField 提取指定字段, 转换成数组
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 15:24 2024/8/6
|
||||||
|
func (at *Array[Bt, ExtractDataType]) ExtractField(fieldPath string) ([]ExtractDataType, error) {
|
||||||
|
strValResult := at.ToString()
|
||||||
|
if nil != strValResult.Err {
|
||||||
|
return make([]ExtractDataType, 0), nil
|
||||||
|
}
|
||||||
|
gjsonResult := gjson.Parse(strValResult.Value)
|
||||||
|
if !gjsonResult.IsArray() {
|
||||||
|
return make([]ExtractDataType, 0), errors.New("input value is not slice")
|
||||||
|
}
|
||||||
|
arrList := gjsonResult.Array()
|
||||||
|
if len(arrList) == 0 {
|
||||||
|
return make([]ExtractDataType, 0), nil
|
||||||
|
}
|
||||||
|
res := make([]ExtractDataType, 0)
|
||||||
|
for _, item := range arrList {
|
||||||
|
valueResult := item.Get(fieldPath)
|
||||||
|
if !valueResult.Exists() {
|
||||||
|
// 不存在
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var val ExtractDataType
|
||||||
|
if err := ConvertAssign(&val, valueResult.String()); nil != err {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res = append(res, val)
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractFieldIgnoreError 提取指定字段并忽略异常
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 15:28 2024/8/6
|
||||||
|
func (at *Array[Bt, ExtractDataType]) ExtractFieldIgnoreError(field string) []ExtractDataType {
|
||||||
|
res, _ := at.ExtractField(field)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
36
array_test.go
Normal file
36
array_test.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// Package wrapper ...
|
||||||
|
//
|
||||||
|
// Description : wrapper ...
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 2024-05-06 下午2:48
|
||||||
|
package wrapper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestArray_Unique(t *testing.T) {
|
||||||
|
fmt.Println(ArrayType[any, any]([]any{"1", 1, 1, "1", 2, 3}).Unique())
|
||||||
|
fmt.Println(ArrayType[int, any]([]int{1, 1, 2, 3}).Unique())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestArray_ExtractField(t *testing.T) {
|
||||||
|
testMap := []any{
|
||||||
|
map[string]any{
|
||||||
|
"age": 18,
|
||||||
|
"name": "baicha",
|
||||||
|
},
|
||||||
|
map[string]any{
|
||||||
|
"age": 20,
|
||||||
|
"name": "qinghuan",
|
||||||
|
},
|
||||||
|
map[string]any{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
fmt.Println(ArrayType[any, int](testMap).ExtractField("age"))
|
||||||
|
fmt.Println(ArrayType[any, string](testMap).ExtractField("name"))
|
||||||
|
}
|
18
convert.go
18
convert.go
@ -38,7 +38,7 @@ var errNilPtr = errors.New("destination pointer is nil") // embedded in descript
|
|||||||
// convertAssign copies to dest the value in src, converting it if possible.
|
// convertAssign copies to dest the value in src, converting it if possible.
|
||||||
// An error is returned if the copy would result in loss of information.
|
// An error is returned if the copy would result in loss of information.
|
||||||
// dest should be a pointer type.
|
// dest should be a pointer type.
|
||||||
func ConvertAssign(dest, src interface{}) error {
|
func ConvertAssign(dest, src any) error {
|
||||||
// Common cases, without reflect.
|
// Common cases, without reflect.
|
||||||
switch s := src.(type) {
|
switch s := src.(type) {
|
||||||
case string:
|
case string:
|
||||||
@ -70,7 +70,7 @@ func ConvertAssign(dest, src interface{}) error {
|
|||||||
}
|
}
|
||||||
*d = string(s)
|
*d = string(s)
|
||||||
return nil
|
return nil
|
||||||
case *interface{}:
|
case *any:
|
||||||
if d == nil {
|
if d == nil {
|
||||||
return errNilPtr
|
return errNilPtr
|
||||||
}
|
}
|
||||||
@ -112,7 +112,7 @@ func ConvertAssign(dest, src interface{}) error {
|
|||||||
}
|
}
|
||||||
case nil:
|
case nil:
|
||||||
switch d := dest.(type) {
|
switch d := dest.(type) {
|
||||||
case *interface{}:
|
case *any:
|
||||||
if d == nil {
|
if d == nil {
|
||||||
return errNilPtr
|
return errNilPtr
|
||||||
}
|
}
|
||||||
@ -164,7 +164,7 @@ func ConvertAssign(dest, src interface{}) error {
|
|||||||
*d = bv.(bool)
|
*d = bv.(bool)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
case *interface{}:
|
case *any:
|
||||||
*d = src
|
*d = src
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -271,11 +271,11 @@ func cloneBytes(b []byte) []byte {
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func ToString(src interface{}) string {
|
func ToString(src any) string {
|
||||||
return asString(src)
|
return asString(src)
|
||||||
}
|
}
|
||||||
|
|
||||||
func asString(src interface{}) string {
|
func asString(src any) string {
|
||||||
switch v := src.(type) {
|
switch v := src.(type) {
|
||||||
case string:
|
case string:
|
||||||
return v
|
return v
|
||||||
@ -327,14 +327,14 @@ func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) {
|
|||||||
// []byte
|
// []byte
|
||||||
// string
|
// string
|
||||||
// time.Time
|
// time.Time
|
||||||
type Value interface{}
|
type Value any
|
||||||
|
|
||||||
type boolType struct{}
|
type boolType struct{}
|
||||||
|
|
||||||
var Bool boolType
|
var Bool boolType
|
||||||
|
|
||||||
func (boolType) String() string { return "Bool" }
|
func (boolType) String() string { return "Bool" }
|
||||||
func (boolType) ConvertValue(src interface{}) (Value, error) {
|
func (boolType) ConvertValue(src any) (Value, error) {
|
||||||
switch s := src.(type) {
|
switch s := src.(type) {
|
||||||
case bool:
|
case bool:
|
||||||
return s, nil
|
return s, nil
|
||||||
@ -390,5 +390,5 @@ type Scanner interface {
|
|||||||
// Reference types such as []byte are only valid until the next call to Scan
|
// Reference types such as []byte are only valid until the next call to Scan
|
||||||
// and should not be retained. Their underlying memory is owned by the driver.
|
// and should not be retained. Their underlying memory is owned by the driver.
|
||||||
// If retention is necessary, copy their values before the next call to Scan.
|
// If retention is necessary, copy their values before the next call to Scan.
|
||||||
Scan(src interface{}) error
|
Scan(src any) error
|
||||||
}
|
}
|
||||||
|
19
define.go
19
define.go
@ -9,19 +9,6 @@ package wrapper
|
|||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
const (
|
|
||||||
DataTypeUnknown = "unknown"
|
|
||||||
DataTypeNil = "nil"
|
|
||||||
DataTypePtr = "ptr"
|
|
||||||
DataTypeString = "string"
|
|
||||||
DataTypeInt = "int"
|
|
||||||
DataTypeUint = "uint"
|
|
||||||
DataTypeBool = "bool"
|
|
||||||
DataTypeFloat = "float"
|
|
||||||
DataTypeSlice = "slice"
|
|
||||||
DataTypeObject = "object"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Int8Result ...
|
// Int8Result ...
|
||||||
//
|
//
|
||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
@ -268,7 +255,7 @@ type Float64PtrResult struct {
|
|||||||
//
|
//
|
||||||
// Date : 16:40 2023/5/8
|
// Date : 16:40 2023/5/8
|
||||||
type Any struct {
|
type Any struct {
|
||||||
Value interface{}
|
Value any
|
||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,7 +285,7 @@ type BoolPtrResult struct {
|
|||||||
//
|
//
|
||||||
// Date : 16:38 2023/5/8
|
// Date : 16:38 2023/5/8
|
||||||
type ObjectResult struct {
|
type ObjectResult struct {
|
||||||
Value map[string]interface{}
|
Value map[string]any
|
||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -488,6 +475,6 @@ type MapResult struct {
|
|||||||
//
|
//
|
||||||
// Date : 18:28 2023/5/8
|
// Date : 18:28 2023/5/8
|
||||||
type AnySliceResult struct {
|
type AnySliceResult struct {
|
||||||
Value []interface{}
|
Value []any
|
||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
20
go.mod
20
go.mod
@ -5,19 +5,25 @@ go 1.21
|
|||||||
toolchain go1.21.4
|
toolchain go1.21.4
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.zhangdeman.cn/zhangdeman/easymap v0.0.0-20240130062251-a87a97b0e8d4
|
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20240726024939-e424db29c5c4
|
||||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20240110090803-399e964daa0c
|
git.zhangdeman.cn/zhangdeman/easymap v0.0.0-20240311030808-e2a2e6a3c211
|
||||||
|
git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20240122104027-4928421213c0
|
||||||
|
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20240618035451-8d48a6bd39dd
|
||||||
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394
|
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394
|
||||||
|
github.com/spaolacci/murmur3 v1.1.0
|
||||||
|
github.com/stretchr/testify v1.8.4
|
||||||
|
github.com/tidwall/gjson v1.17.3
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20240104123641-b3f23974e5d6 // indirect
|
git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e // indirect
|
||||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20231227095334-7eb5cdbf9253 // indirect
|
github.com/BurntSushi/toml v1.4.0 // indirect
|
||||||
github.com/BurntSushi/toml v1.3.2 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/go-ini/ini v1.67.0 // indirect
|
github.com/go-ini/ini v1.67.0 // indirect
|
||||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||||
github.com/mozillazg/go-pinyin v0.20.0 // indirect
|
github.com/mozillazg/go-pinyin v0.20.0 // indirect
|
||||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/stretchr/testify v1.8.4 // indirect
|
github.com/tidwall/match v1.1.1 // indirect
|
||||||
|
github.com/tidwall/pretty v1.2.1 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
37
go.sum
37
go.sum
@ -1,21 +1,35 @@
|
|||||||
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20230815040024-2b12dd51d19b h1:C7KftnLh7dOqzNRs5dn/9yqMDvuqMn5RCglvV6bY758=
|
|
||||||
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20230815040024-2b12dd51d19b/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k=
|
|
||||||
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20240104123641-b3f23974e5d6 h1:ytpXTP3oxp480BAZQoOzqlBP4XP73NcpMplZ1/fA1lQ=
|
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20240104123641-b3f23974e5d6 h1:ytpXTP3oxp480BAZQoOzqlBP4XP73NcpMplZ1/fA1lQ=
|
||||||
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20240104123641-b3f23974e5d6/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k=
|
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20240104123641-b3f23974e5d6/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k=
|
||||||
git.zhangdeman.cn/zhangdeman/easymap v0.0.0-20231224145141-489e31b07a71 h1:nvVSH+Ju8EmoPiPHTae5lxHo4kDjROYChs19Yayz+NY=
|
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20240419080457-9d9562469008 h1:6z99+X/B/G9sCZ+aTLYGWk3YLVVODzevA4wjWj9jvq0=
|
||||||
git.zhangdeman.cn/zhangdeman/easymap v0.0.0-20231224145141-489e31b07a71/go.mod h1:SrtvrQRdzt+8KfYzvosH++gWxo2ShPTzR1m3VQ6uX7U=
|
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20240419080457-9d9562469008/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k=
|
||||||
git.zhangdeman.cn/zhangdeman/easymap v0.0.0-20231229032122-804bc9822704 h1:y/hXa0Ez+u0ka+QLv1abiCRy+rlJlnNdaH4H/eI6ZJ0=
|
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20240501142503-e31a270e50cc h1:kPz9xiUVruM8kwbUUVpxyCTX8pGgyKt60K5zX77oyC4=
|
||||||
git.zhangdeman.cn/zhangdeman/easymap v0.0.0-20231229032122-804bc9822704/go.mod h1:SrtvrQRdzt+8KfYzvosH++gWxo2ShPTzR1m3VQ6uX7U=
|
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20240501142503-e31a270e50cc/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k=
|
||||||
|
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20240608124542-4d97bd80dc68 h1:AaWKU0bKHnNot24OMhaOCBKtpfhz4o05DKHrRFgYd8M=
|
||||||
|
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20240608124542-4d97bd80dc68/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k=
|
||||||
|
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20240612081722-31c64d4d4ce7 h1:QR8vMXOTy0NFKdodsGKA4gTNHJMfob3yRFYMXrZj7ek=
|
||||||
|
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20240612081722-31c64d4d4ce7/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k=
|
||||||
|
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20240726024939-e424db29c5c4 h1:mibnyzYbZullK0aTHVASHl3UeoVr8IgytQZsuyv+yEM=
|
||||||
|
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20240726024939-e424db29c5c4/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k=
|
||||||
git.zhangdeman.cn/zhangdeman/easymap v0.0.0-20240130062251-a87a97b0e8d4 h1:93JYY8JLbFcrlq37q/uKyxs2r2e3modsjvfSbnZQ/UI=
|
git.zhangdeman.cn/zhangdeman/easymap v0.0.0-20240130062251-a87a97b0e8d4 h1:93JYY8JLbFcrlq37q/uKyxs2r2e3modsjvfSbnZQ/UI=
|
||||||
git.zhangdeman.cn/zhangdeman/easymap v0.0.0-20240130062251-a87a97b0e8d4/go.mod h1:SrtvrQRdzt+8KfYzvosH++gWxo2ShPTzR1m3VQ6uX7U=
|
git.zhangdeman.cn/zhangdeman/easymap v0.0.0-20240130062251-a87a97b0e8d4/go.mod h1:SrtvrQRdzt+8KfYzvosH++gWxo2ShPTzR1m3VQ6uX7U=
|
||||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20231224125439-01f39b6ea08d h1:TV0BCQQewBEtLsv3i9gXkxLFd5A5bWBTiNd3D/I5o4Q=
|
git.zhangdeman.cn/zhangdeman/easymap v0.0.0-20240311030808-e2a2e6a3c211 h1:I/wOsRpCSRkU9vo1u703slQsmK0wnNeZzsWQOGtIAG0=
|
||||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20231224125439-01f39b6ea08d/go.mod h1:w7kG4zyTJ1uPFaTWhze+OQuaUBINT2XnDxpyiM6ctc0=
|
git.zhangdeman.cn/zhangdeman/easymap v0.0.0-20240311030808-e2a2e6a3c211/go.mod h1:SrtvrQRdzt+8KfYzvosH++gWxo2ShPTzR1m3VQ6uX7U=
|
||||||
|
git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20240122104027-4928421213c0 h1:gUDlQMuJ4xNfP2Abl1Msmpa3fASLWYkNlqDFF/6GN0Y=
|
||||||
|
git.zhangdeman.cn/zhangdeman/op_type v0.0.0-20240122104027-4928421213c0/go.mod h1:VHb9qmhaPDAQDcS6vUiDCamYjZ4R5lD1XtVsh55KsMI=
|
||||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20240110090803-399e964daa0c h1:k7VCn9GfRGTilvdF/TcTFVMDBfKLe3VeGAtMTiDSnS0=
|
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20240110090803-399e964daa0c h1:k7VCn9GfRGTilvdF/TcTFVMDBfKLe3VeGAtMTiDSnS0=
|
||||||
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20240110090803-399e964daa0c/go.mod h1:w7kG4zyTJ1uPFaTWhze+OQuaUBINT2XnDxpyiM6ctc0=
|
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20240110090803-399e964daa0c/go.mod h1:w7kG4zyTJ1uPFaTWhze+OQuaUBINT2XnDxpyiM6ctc0=
|
||||||
|
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20240325080031-1f58204e8687 h1:uQcGqdzi4UdpZlp4f4FUPeBqoygP58pEKJkmN3ROsE0=
|
||||||
|
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20240325080031-1f58204e8687/go.mod h1:gf7SW2TXATgux8pfdFedMkXWv2515OtIIM/5c4atkFw=
|
||||||
|
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20240618035451-8d48a6bd39dd h1:2Y37waOVCmVvx0Rp8VGEptE2/2JVMImtxB4dKKDk/3w=
|
||||||
|
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20240618035451-8d48a6bd39dd/go.mod h1:6+7whkCmb4sJDIfH3HxNuXRveaM0gCCNWd2uXZqNtIE=
|
||||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20231227095334-7eb5cdbf9253 h1:GO3oZa5a2sqwAzGcLDJtQzmshSWRmoP7IDS8bwFqvC4=
|
git.zhangdeman.cn/zhangdeman/util v0.0.0-20231227095334-7eb5cdbf9253 h1:GO3oZa5a2sqwAzGcLDJtQzmshSWRmoP7IDS8bwFqvC4=
|
||||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20231227095334-7eb5cdbf9253/go.mod h1:VpPjBlwz8U+OxZuxzHQBv1aEEZ3pStH6bZvT21ADEbI=
|
git.zhangdeman.cn/zhangdeman/util v0.0.0-20231227095334-7eb5cdbf9253/go.mod h1:VpPjBlwz8U+OxZuxzHQBv1aEEZ3pStH6bZvT21ADEbI=
|
||||||
|
git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e h1:Q973S6CcWr1ICZhFI1STFOJ+KUImCl2BaIXm6YppBqI=
|
||||||
|
git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e/go.mod h1:VpPjBlwz8U+OxZuxzHQBv1aEEZ3pStH6bZvT21ADEbI=
|
||||||
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
||||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||||
|
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
||||||
|
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 h1:OYA+5W64v3OgClL+IrOD63t4i/RW7RqrAVl9LTZ9UqQ=
|
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 h1:OYA+5W64v3OgClL+IrOD63t4i/RW7RqrAVl9LTZ9UqQ=
|
||||||
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394/go.mod h1:Q8n74mJTIgjX4RBBcHnJ05h//6/k6foqmgE45jTQtxg=
|
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394/go.mod h1:Q8n74mJTIgjX4RBBcHnJ05h//6/k6foqmgE45jTQtxg=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
@ -32,6 +46,13 @@ github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0b
|
|||||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94=
|
||||||
|
github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||||
|
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||||
|
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||||
|
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||||
|
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||||
|
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
22
map.go
22
map.go
@ -8,11 +8,11 @@
|
|||||||
package wrapper
|
package wrapper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"git.zhangdeman.cn/zhangdeman/easymap"
|
"git.zhangdeman.cn/zhangdeman/easymap"
|
||||||
"git.zhangdeman.cn/zhangdeman/serialize"
|
"git.zhangdeman.cn/zhangdeman/serialize"
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ import (
|
|||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 15:02 2023/8/10
|
// Date : 15:02 2023/8/10
|
||||||
func EasyMap(mapData interface{}) Map {
|
func EasyMap(mapData any) Map {
|
||||||
m, _ := EasyMapWithError(mapData)
|
m, _ := EasyMapWithError(mapData)
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
@ -31,14 +31,14 @@ func EasyMap(mapData interface{}) Map {
|
|||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 15:06 2023/8/10
|
// Date : 15:06 2023/8/10
|
||||||
func EasyMapWithError(mapData interface{}) (Map, error) {
|
func EasyMapWithError(mapData any) (Map, error) {
|
||||||
if nil == mapData {
|
if nil == mapData {
|
||||||
return easymap.NewNormal(), nil
|
return easymap.NewNormal(), nil
|
||||||
}
|
}
|
||||||
m := easymap.NewNormal()
|
m := easymap.NewNormal()
|
||||||
reflectType := reflect.TypeOf(mapData)
|
reflectType := reflect.TypeOf(mapData)
|
||||||
if reflectType.Kind() != reflect.Map {
|
if reflectType.Kind() != reflect.Map {
|
||||||
mapFormatData := make(map[string]interface{})
|
mapFormatData := make(map[string]any)
|
||||||
if err := serialize.JSON.UnmarshalWithNumber(serialize.JSON.MarshalForByte(mapData), &mapFormatData); nil != err {
|
if err := serialize.JSON.UnmarshalWithNumber(serialize.JSON.MarshalForByte(mapData), &mapFormatData); nil != err {
|
||||||
return m, errors.New("input data type is " + reflectType.String() + ", can not convert to map")
|
return m, errors.New("input data type is " + reflectType.String() + ", can not convert to map")
|
||||||
}
|
}
|
||||||
@ -58,7 +58,7 @@ func EasyMapWithError(mapData interface{}) (Map, error) {
|
|||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 16:11 2023/8/10
|
// Date : 16:11 2023/8/10
|
||||||
func EasyMapFromStruct(data interface{}) Map {
|
func EasyMapFromStruct(data any) Map {
|
||||||
byteData, _ := json.Marshal(data)
|
byteData, _ := json.Marshal(data)
|
||||||
return EasyMapFromByte(byteData)
|
return EasyMapFromByte(byteData)
|
||||||
}
|
}
|
||||||
@ -78,11 +78,13 @@ func EasyMapFromString(data string) Map {
|
|||||||
//
|
//
|
||||||
// Date : 16:12 2023/8/10
|
// Date : 16:12 2023/8/10
|
||||||
func EasyMapFromByte(data []byte) Map {
|
func EasyMapFromByte(data []byte) Map {
|
||||||
var tmpMap map[interface{}]interface{}
|
res := easymap.NewNormal()
|
||||||
decoder := json.NewDecoder(bytes.NewReader(data))
|
jsonRes := gjson.Parse(string(data))
|
||||||
decoder.UseNumber()
|
jsonRes.ForEach(func(key, value gjson.Result) bool {
|
||||||
_ = decoder.Decode(&tmpMap)
|
res.Set(key.Value(), value.Value())
|
||||||
return EasyMap(tmpMap)
|
return true
|
||||||
|
})
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map ...
|
// Map ...
|
||||||
|
14
object.go
14
object.go
@ -19,10 +19,10 @@ import (
|
|||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 18:36 2023/6/1
|
// Date : 18:36 2023/6/1
|
||||||
func ObjectData(data interface{}) *ObjectType {
|
func ObjectData(data any) *ObjectType {
|
||||||
ot := &ObjectType{
|
ot := &ObjectType{
|
||||||
source: data,
|
source: data,
|
||||||
data: map[interface{}]interface{}{},
|
data: map[any]any{},
|
||||||
byteData: []byte{},
|
byteData: []byte{},
|
||||||
isValid: true,
|
isValid: true,
|
||||||
invalidErr: errors.New("data is invalid"),
|
invalidErr: errors.New("data is invalid"),
|
||||||
@ -49,8 +49,8 @@ func ObjectData(data interface{}) *ObjectType {
|
|||||||
//
|
//
|
||||||
// Date : 18:38 2023/6/1
|
// Date : 18:38 2023/6/1
|
||||||
type ObjectType struct {
|
type ObjectType struct {
|
||||||
source interface{}
|
source any
|
||||||
data map[interface{}]interface{}
|
data map[any]any
|
||||||
byteData []byte
|
byteData []byte
|
||||||
isValid bool
|
isValid bool
|
||||||
invalidErr error
|
invalidErr error
|
||||||
@ -106,7 +106,7 @@ func (ot *ObjectType) ToString() StringResult {
|
|||||||
// Date : 16:17 2023/6/2
|
// Date : 16:17 2023/6/2
|
||||||
func (ot *ObjectType) ToMapStringAny() ObjectResult {
|
func (ot *ObjectType) ToMapStringAny() ObjectResult {
|
||||||
res := ObjectResult{
|
res := ObjectResult{
|
||||||
Value: map[string]interface{}{},
|
Value: map[string]any{},
|
||||||
Err: nil,
|
Err: nil,
|
||||||
}
|
}
|
||||||
if ot.IsNil() {
|
if ot.IsNil() {
|
||||||
@ -121,7 +121,7 @@ func (ot *ObjectType) ToMapStringAny() ObjectResult {
|
|||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 16:41 2023/6/2
|
// Date : 16:41 2023/6/2
|
||||||
func (ot *ObjectType) ToStruct(receiver interface{}) error {
|
func (ot *ObjectType) ToStruct(receiver any) error {
|
||||||
if nil == receiver {
|
if nil == receiver {
|
||||||
return errors.New("receiver is nil")
|
return errors.New("receiver is nil")
|
||||||
}
|
}
|
||||||
@ -136,7 +136,7 @@ func (ot *ObjectType) ToStruct(receiver interface{}) error {
|
|||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 16:42 2023/6/2
|
// Date : 16:42 2023/6/2
|
||||||
func (ot *ObjectType) ToStructIgnoreErr(receiver interface{}) {
|
func (ot *ObjectType) ToStructIgnoreErr(receiver any) {
|
||||||
if nil == receiver {
|
if nil == receiver {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
39
string.go
39
string.go
@ -13,6 +13,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"git.zhangdeman.cn/zhangdeman/serialize"
|
"git.zhangdeman.cn/zhangdeman/serialize"
|
||||||
"github.com/axgle/mahonia"
|
"github.com/axgle/mahonia"
|
||||||
|
"github.com/spaolacci/murmur3"
|
||||||
"io"
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"strings"
|
"strings"
|
||||||
@ -521,7 +522,7 @@ func (str String) ToStringPtr() StringPtrResult {
|
|||||||
func (str String) ToObject() ObjectResult {
|
func (str String) ToObject() ObjectResult {
|
||||||
var (
|
var (
|
||||||
res = ObjectResult{
|
res = ObjectResult{
|
||||||
Value: map[string]interface{}{},
|
Value: map[string]any{},
|
||||||
Err: nil,
|
Err: nil,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -534,7 +535,7 @@ func (str String) ToObject() ObjectResult {
|
|||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 18:38 2023/5/4
|
// Date : 18:38 2023/5/4
|
||||||
func (str String) ToStruct(receiver interface{}) error {
|
func (str String) ToStruct(receiver any) error {
|
||||||
if nil == receiver {
|
if nil == receiver {
|
||||||
return errors.New("receiver is nil")
|
return errors.New("receiver is nil")
|
||||||
}
|
}
|
||||||
@ -992,7 +993,7 @@ func (str String) ToStringSlice(splitChar ...string) StringSliceResult {
|
|||||||
// Date : 15:01 2023/5/5
|
// Date : 15:01 2023/5/5
|
||||||
func (str String) ToAnySlice(splitCharList ...string) AnySliceResult {
|
func (str String) ToAnySlice(splitCharList ...string) AnySliceResult {
|
||||||
result := AnySliceResult{
|
result := AnySliceResult{
|
||||||
Value: []interface{}{},
|
Value: []any{},
|
||||||
Err: nil,
|
Err: nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1002,7 +1003,7 @@ func (str String) ToAnySlice(splitCharList ...string) AnySliceResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
valArr := strings.Split(str.Value(), splitCharList[0])
|
valArr := strings.Split(str.Value(), splitCharList[0])
|
||||||
valList := make([]interface{}, 0)
|
valList := make([]any, 0)
|
||||||
for _, item := range valArr {
|
for _, item := range valArr {
|
||||||
v := String(item)
|
v := String(item)
|
||||||
if res := v.ToInt64(); nil == res.Err {
|
if res := v.ToInt64(); nil == res.Err {
|
||||||
@ -1157,3 +1158,33 @@ func (str String) ReplaceChar(charTable map[string]string) String {
|
|||||||
}
|
}
|
||||||
return String(formatStr)
|
return String(formatStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasSubStr 是否包含指定的子串
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 18:37 2024/4/19
|
||||||
|
func (str String) HasSubStr(subStrList []string) bool {
|
||||||
|
if len(subStrList) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
v := str.Value()
|
||||||
|
for _, item := range subStrList {
|
||||||
|
if strings.Contains(v, item) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// HashNumber ...
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 11:05 2024/6/27
|
||||||
|
func (str String) HashNumber() Uint64Result {
|
||||||
|
return Uint64Result{
|
||||||
|
Value: murmur3.Sum64([]byte(str.Value())),
|
||||||
|
Err: nil,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -17,7 +17,7 @@ import (
|
|||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 16:07 2023/8/10
|
// Date : 16:07 2023/8/10
|
||||||
func NewStruct(data interface{}) *Struct {
|
func NewStruct(data any) *Struct {
|
||||||
s, _ := NewStructWithError(data)
|
s, _ := NewStructWithError(data)
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
@ -27,7 +27,7 @@ func NewStruct(data interface{}) *Struct {
|
|||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 16:17 2023/8/10
|
// Date : 16:17 2023/8/10
|
||||||
func NewStructWithError(data interface{}) (*Struct, error) {
|
func NewStructWithError(data any) (*Struct, error) {
|
||||||
if data == nil {
|
if data == nil {
|
||||||
return nil, errors.New("input data is nil")
|
return nil, errors.New("input data is nil")
|
||||||
}
|
}
|
||||||
@ -47,7 +47,7 @@ func NewStructWithError(data interface{}) (*Struct, error) {
|
|||||||
//
|
//
|
||||||
// Date : 16:05 2023/8/10
|
// Date : 16:05 2023/8/10
|
||||||
type Struct struct {
|
type Struct struct {
|
||||||
data interface{}
|
data any
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToMap 转为Map
|
// ToMap 转为Map
|
||||||
@ -58,7 +58,7 @@ type Struct struct {
|
|||||||
func (s *Struct) ToMap() MapResult {
|
func (s *Struct) ToMap() MapResult {
|
||||||
if nil == s.data {
|
if nil == s.data {
|
||||||
return MapResult{
|
return MapResult{
|
||||||
Value: EasyMap(map[interface{}]interface{}{}),
|
Value: EasyMap(map[any]any{}),
|
||||||
Err: nil,
|
Err: nil,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,30 +108,6 @@ func (to *ternaryOperator) StringWithFunc(condFunc CondFunc, trueVal String, fal
|
|||||||
return to.String(condFunc(), trueVal, falseVal)
|
return to.String(condFunc(), trueVal, falseVal)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Array ...
|
|
||||||
//
|
|
||||||
// Author : go_developer@163.com<白茶清欢>
|
|
||||||
//
|
|
||||||
// Date : 16:22 2023/11/28
|
|
||||||
func (to *ternaryOperator) Array(cond bool, trueVal *Array, falseVal *Array) *Array {
|
|
||||||
if cond {
|
|
||||||
return trueVal
|
|
||||||
}
|
|
||||||
return falseVal
|
|
||||||
}
|
|
||||||
|
|
||||||
// ArrayWithFunc ...
|
|
||||||
//
|
|
||||||
// Author : go_developer@163.com<白茶清欢>
|
|
||||||
//
|
|
||||||
// Date : 16:22 2023/11/28
|
|
||||||
func (to *ternaryOperator) ArrayWithFunc(condFunc CondFunc, trueVal *Array, falseVal *Array) *Array {
|
|
||||||
if nil == condFunc {
|
|
||||||
condFunc = defaultCondFunc
|
|
||||||
}
|
|
||||||
return to.Array(condFunc(), trueVal, falseVal)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map ...
|
// Map ...
|
||||||
//
|
//
|
||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
245
tool/define/diff.go
Normal file
245
tool/define/diff.go
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
// Package define ...
|
||||||
|
//
|
||||||
|
// Description : define ...
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 2024-03-08 11:04
|
||||||
|
package define
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"git.zhangdeman.cn/zhangdeman/util"
|
||||||
|
"git.zhangdeman.cn/zhangdeman/wrapper"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DiffOption 做数据对比时的选项
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 11:12 2024/3/8
|
||||||
|
type DiffOption struct {
|
||||||
|
StrictMode bool `json:"strict_mode"` // 采用严格模式: 1 != 1.0 , 采用非严格模式 1 == 1.0
|
||||||
|
AllowStringNumber bool `json:"allow_string_number"` // 是否允许字符串数字, 在非严格模式下, 若允许, 则 1 == "1" , 不允许, 则 1 != "1"
|
||||||
|
IgnoreNotFoundField bool `json:"ignore_not_found_field"` // 忽略不存在的字段
|
||||||
|
IgnoreEmptyString bool `json:"ignore_empty_string"` // 忽略空字符串, 若输入值为空字符串, 则不做比较, 认为两个值相同
|
||||||
|
IgnoreZeroNumber bool `json:"ignore_zero_number"` // 忽略置为0的数字, 若输入的数据为数字类型, 则不做比较, 认为两个值相同
|
||||||
|
IgnoreNil bool `json:"ignore_nil"` // 忽略 nil 值, 若输入值为NIL , 则不做比较, 认为两个值相同
|
||||||
|
CustomDiffFuncTable map[string]CustomDiffFunc `json:"-"` // 外部自定义的字段是否相同的比较函数, 会优先使用外部输入的比较函数
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDiffOption ...
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 12:06 2024/3/8
|
||||||
|
func NewDiffOption() *DiffOption {
|
||||||
|
return &DiffOption{
|
||||||
|
StrictMode: false,
|
||||||
|
IgnoreNotFoundField: false,
|
||||||
|
IgnoreEmptyString: false,
|
||||||
|
IgnoreZeroNumber: false,
|
||||||
|
IgnoreNil: false,
|
||||||
|
CustomDiffFuncTable: make(map[string]CustomDiffFunc),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CustomDiffFunc 自定义字段对比方法
|
||||||
|
//
|
||||||
|
// 输入分别如下:
|
||||||
|
//
|
||||||
|
// field : 要对比的字段
|
||||||
|
//
|
||||||
|
// inputVal : 输入的原始数据
|
||||||
|
//
|
||||||
|
// storageVal : 当前存储的数据
|
||||||
|
//
|
||||||
|
// option : 对比时的额外选项
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 11:06 2024/3/8
|
||||||
|
type CustomDiffFunc func(field string, inputVal wrapper.Map, storageVal wrapper.Map, option *DiffOption) *DiffResult
|
||||||
|
|
||||||
|
// DiffResult 对比结果
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 11:10 2024/3/8
|
||||||
|
type DiffResult struct {
|
||||||
|
Field string `json:"field"` // 字段名
|
||||||
|
OldVal any `json:"old_val"` // 当前field在storageVal中的值
|
||||||
|
NewVal any `json:"new_val"` // 当前field在inputVal中的值
|
||||||
|
IsSame bool `json:"is_same"` // 两个值是否相同
|
||||||
|
DiffReason string `json:"diff_reason"` // 两个值不同的原因
|
||||||
|
Err error `json:"err"` // 对比过程中是否出现异常
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
DiffReasonTypeNotMatch = "TYPE_NOT_MATCH" // 类型不匹配
|
||||||
|
DiffReasonValueNotMatch = "VALUE_NOT_MATCH" // 数据值不匹配
|
||||||
|
DiffReasonInputFieldNotFound = "INPUT_FIELD_NOT_FOUND" // 输入数据中不存在相关字段
|
||||||
|
DiffReasonStorageFieldNotFound = "STORAGE_FIELD_NOT_FOUND" // 存储数据中不存在相关字段
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// 当前仅支持基础类型的比较,不支持slice/map/struct等复杂类型的比较
|
||||||
|
supportValueTypeTable = map[reflect.Kind]any{
|
||||||
|
reflect.Bool: true,
|
||||||
|
reflect.Int: true,
|
||||||
|
reflect.Int8: true,
|
||||||
|
reflect.Int16: true,
|
||||||
|
reflect.Int32: true,
|
||||||
|
reflect.Int64: true,
|
||||||
|
reflect.Uint: true,
|
||||||
|
reflect.Uint8: true,
|
||||||
|
reflect.Uint16: true,
|
||||||
|
reflect.Uint32: true,
|
||||||
|
reflect.Uint64: true,
|
||||||
|
reflect.Float32: true,
|
||||||
|
reflect.Float64: true,
|
||||||
|
reflect.String: true,
|
||||||
|
// reflect.Ptr: true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsSupportValueType ...
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 11:23 2024/3/8
|
||||||
|
func IsSupportValueType(kind reflect.Kind) bool {
|
||||||
|
if _, exist := supportValueTypeTable[kind]; exist {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultDiffFunc 默认的diff函数
|
||||||
|
//
|
||||||
|
// Author : zhangdeman001@ke.com<张德满>
|
||||||
|
//
|
||||||
|
// Date : 12:05 2024/3/8
|
||||||
|
func DefaultDiffFunc(field string, inputVal wrapper.Map, storageVal wrapper.Map, option *DiffOption) *DiffResult {
|
||||||
|
if nil == option {
|
||||||
|
option = NewDiffOption()
|
||||||
|
}
|
||||||
|
result := &DiffResult{
|
||||||
|
Field: field,
|
||||||
|
OldVal: nil,
|
||||||
|
NewVal: nil,
|
||||||
|
IsSame: true,
|
||||||
|
DiffReason: "",
|
||||||
|
Err: nil,
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
inputFieldVal any
|
||||||
|
inputFieldValExist bool
|
||||||
|
storageFieldVal any
|
||||||
|
storageFieldValExist bool
|
||||||
|
)
|
||||||
|
|
||||||
|
inputFieldVal, inputFieldValExist = inputVal.Get(field)
|
||||||
|
storageFieldVal, storageFieldValExist = storageVal.Get(field)
|
||||||
|
// 字段在输入数据和存储数据中均不存在
|
||||||
|
if !inputFieldValExist && !storageFieldValExist {
|
||||||
|
// 输入和存储都没这个字段
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断输入字段是否存在
|
||||||
|
if !inputFieldValExist {
|
||||||
|
if option.IgnoreNotFoundField {
|
||||||
|
// 忽略不存在的字段
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
// 由于前置逻辑保证了, 输入不存在相关字段, 则现存数据一定存在相关字段
|
||||||
|
result.IsSame = false
|
||||||
|
result.DiffReason = DiffReasonInputFieldNotFound
|
||||||
|
result.OldVal = storageFieldVal
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
// 判断存储字段是否存在
|
||||||
|
if !storageFieldValExist {
|
||||||
|
result.IsSame = false
|
||||||
|
result.DiffReason = DiffReasonStorageFieldNotFound
|
||||||
|
result.NewVal = inputFieldVal
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
// 校验类型
|
||||||
|
inputFieldValType := reflect.TypeOf(inputFieldVal)
|
||||||
|
storageFieldValType := reflect.TypeOf(storageFieldVal)
|
||||||
|
if inputFieldValType.Kind() == reflect.Ptr {
|
||||||
|
inputReflect := reflect.ValueOf(inputFieldVal)
|
||||||
|
inputFieldValType = inputReflect.Type()
|
||||||
|
inputFieldVal = inputReflect.Interface()
|
||||||
|
}
|
||||||
|
if storageFieldValType.Kind() == reflect.Ptr {
|
||||||
|
storageReflect := reflect.ValueOf(storageFieldValType)
|
||||||
|
storageFieldValType = storageReflect.Type()
|
||||||
|
storageFieldVal = storageReflect.Interface()
|
||||||
|
}
|
||||||
|
result.NewVal = inputFieldVal
|
||||||
|
result.OldVal = storageFieldVal
|
||||||
|
if inputFieldValType.Kind() != storageFieldValType.Kind() && option.StrictMode {
|
||||||
|
// 严格模式下, 类型不相同
|
||||||
|
result.IsSame = false
|
||||||
|
result.DiffReason = DiffReasonTypeNotMatch
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
// 类型相同, 或者非严格模式下不校验类型
|
||||||
|
if option.StrictMode {
|
||||||
|
// 严格模式
|
||||||
|
if inputFieldVal != storageFieldVal {
|
||||||
|
result.IsSame = false
|
||||||
|
result.DiffReason = DiffReasonValueNotMatch
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
// return result
|
||||||
|
}
|
||||||
|
// 非严格模式
|
||||||
|
// 存储值尝试转 float64
|
||||||
|
inputValStr := fmt.Sprintf("%v", inputFieldVal)
|
||||||
|
storageValStr := fmt.Sprintf("%v", storageFieldVal)
|
||||||
|
if inputValStr == storageValStr {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
if option.AllowStringNumber {
|
||||||
|
// 允许字符串数字
|
||||||
|
var (
|
||||||
|
storageFloat64 float64
|
||||||
|
inputFloat64 float64
|
||||||
|
)
|
||||||
|
if err := util.ConvertAssign(&storageFloat64, storageValStr); nil == err {
|
||||||
|
if err := util.ConvertAssign(&inputFloat64, inputValStr); nil == err {
|
||||||
|
if storageFloat64 == inputFloat64 {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 浮点型数字. 去小数部分最右侧的0
|
||||||
|
if inputFieldValType.Kind() == reflect.Float64 || inputFieldValType.Kind() == reflect.Float32 {
|
||||||
|
inputValStrArr := strings.Split(inputValStr, ".")
|
||||||
|
if len(inputValStrArr) == 2 {
|
||||||
|
inputValStrArr[1] = strings.TrimRight(inputValStrArr[1], "0")
|
||||||
|
inputValStr = strings.Join(inputValStrArr, ".")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if storageFieldValType.Kind() == reflect.Float64 || storageFieldValType.Kind() == reflect.Float32 {
|
||||||
|
storageValStrArr := strings.Split(storageValStr, ".")
|
||||||
|
if len(storageValStrArr) == 2 {
|
||||||
|
storageValStrArr[1] = strings.TrimRight(storageValStrArr[1], "0")
|
||||||
|
storageValStr = strings.Join(storageValStrArr, ".")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if inputValStr != storageValStr {
|
||||||
|
result.IsSame = false
|
||||||
|
result.DiffReason = DiffReasonValueNotMatch
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
49
tool/define/diff_test.go
Normal file
49
tool/define/diff_test.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// Package define ...
|
||||||
|
//
|
||||||
|
// Description : define ...
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 2024-03-08 15:24
|
||||||
|
package define
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.zhangdeman.cn/zhangdeman/wrapper"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDefaultDiffFunc(t *testing.T) {
|
||||||
|
var (
|
||||||
|
num1 float64 = 1.0
|
||||||
|
num2 float32 = 1.00
|
||||||
|
num3 string = "1"
|
||||||
|
num4 string = "1.00"
|
||||||
|
)
|
||||||
|
input := wrapper.EasyMap(map[string]any{
|
||||||
|
"num": num1,
|
||||||
|
"num3": num3,
|
||||||
|
"num4": num4,
|
||||||
|
"num5": num1,
|
||||||
|
})
|
||||||
|
storage := wrapper.EasyMap(map[string]any{
|
||||||
|
"num": num2,
|
||||||
|
"num3": num2,
|
||||||
|
"num4": num2,
|
||||||
|
"num5": num1,
|
||||||
|
})
|
||||||
|
diffOption := NewDiffOption()
|
||||||
|
diffOption.StrictMode = true
|
||||||
|
res := DefaultDiffFunc("num", input, storage, diffOption)
|
||||||
|
assert.EqualValues(t, false, res.IsSame, "严格模式下, float32与float64不相等")
|
||||||
|
res = DefaultDiffFunc("num5", input, storage, diffOption)
|
||||||
|
assert.EqualValues(t, true, res.IsSame, "严格模式下, float32与float32相等")
|
||||||
|
diffOption.StrictMode = false
|
||||||
|
res = DefaultDiffFunc("num", input, storage, diffOption)
|
||||||
|
assert.EqualValues(t, true, res.IsSame, "非严格模式下, float32与float64相等")
|
||||||
|
res = DefaultDiffFunc("num3", input, storage, diffOption)
|
||||||
|
assert.EqualValues(t, true, res.IsSame, "非严格模式下, float32与string相等")
|
||||||
|
diffOption.AllowStringNumber = true
|
||||||
|
res = DefaultDiffFunc("num4", input, storage, diffOption)
|
||||||
|
assert.EqualValues(t, true, res.IsSame, "非严格模式下, float32与string相等")
|
||||||
|
}
|
68
tool/diff.go
Normal file
68
tool/diff.go
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// Package tool ...
|
||||||
|
//
|
||||||
|
// Description : 对比两个数据是否相同 + 构建不同数据的前后值
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 2024-03-08 11:03
|
||||||
|
package tool
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.zhangdeman.cn/zhangdeman/wrapper"
|
||||||
|
"git.zhangdeman.cn/zhangdeman/wrapper/tool/define"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
Diff = &diff{}
|
||||||
|
)
|
||||||
|
|
||||||
|
type diff struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare 比较两个数据源的指定字段
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 15:53 2024/3/8
|
||||||
|
func (d *diff) Compare(fieldList []string, input wrapper.Map, storage wrapper.Map, option *define.DiffOption) map[string]*define.DiffResult {
|
||||||
|
if nil == option {
|
||||||
|
option = define.NewDiffOption()
|
||||||
|
}
|
||||||
|
res := make(map[string]*define.DiffResult)
|
||||||
|
for _, itemField := range fieldList {
|
||||||
|
res[itemField] = d.CompareSingle(itemField, input, storage, option)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// CompareSingle 比较一个字段
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 15:57 2024/3/8
|
||||||
|
func (d *diff) CompareSingle(field string, input wrapper.Map, storage wrapper.Map, option *define.DiffOption) *define.DiffResult {
|
||||||
|
if nil == option {
|
||||||
|
option = define.NewDiffOption()
|
||||||
|
}
|
||||||
|
if compareFunc, exist := option.CustomDiffFuncTable[field]; exist && nil != compareFunc {
|
||||||
|
return compareFunc(field, input, storage, option)
|
||||||
|
} else {
|
||||||
|
return define.DefaultDiffFunc(field, input, storage, option)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSame 判断连个数据是否一致
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 11:16 2024/3/11
|
||||||
|
func (d *diff) IsSame(fieldList []string, input wrapper.Map, storage wrapper.Map, option *define.DiffOption) bool {
|
||||||
|
res := d.Compare(fieldList, input, storage, option)
|
||||||
|
for _, item := range res {
|
||||||
|
if item.IsSame {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
@ -13,8 +13,8 @@ package try
|
|||||||
//
|
//
|
||||||
// Date : 11:26 2023/7/20
|
// Date : 11:26 2023/7/20
|
||||||
type ICatchHandler interface {
|
type ICatchHandler interface {
|
||||||
Catch(errCode string, handler func(errCode string, data map[string]interface{})) ICatchHandler
|
Catch(errCode string, handler func(errCode string, data map[string]any)) ICatchHandler
|
||||||
CatchAll(handler func(errCode string, data map[string]interface{})) IFinalHandler
|
CatchAll(handler func(errCode string, data map[string]any)) IFinalHandler
|
||||||
IFinalHandler
|
IFinalHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ type ICatchHandler interface {
|
|||||||
//
|
//
|
||||||
// Date : 11:27 2023/7/20
|
// Date : 11:27 2023/7/20
|
||||||
type IFinalHandler interface {
|
type IFinalHandler interface {
|
||||||
Finally(data map[string]interface{}, handlers ...func(data map[string]interface{}))
|
Finally(data map[string]any, handlers ...func(data map[string]any))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ILogicFunction 逻辑函数约束
|
// ILogicFunction 逻辑函数约束
|
||||||
|
@ -15,7 +15,7 @@ package try
|
|||||||
type DefaultCatchHandler struct {
|
type DefaultCatchHandler struct {
|
||||||
hasDeal bool // 异常是否已被处理
|
hasDeal bool // 异常是否已被处理
|
||||||
errCode string
|
errCode string
|
||||||
data map[string]interface{}
|
data map[string]any
|
||||||
}
|
}
|
||||||
|
|
||||||
// hasDealError 判断异常是否已经被处理
|
// hasDealError 判断异常是否已经被处理
|
||||||
@ -38,7 +38,7 @@ func (d *DefaultCatchHandler) hasDealError() bool {
|
|||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 17:19 2023/7/20
|
// Date : 17:19 2023/7/20
|
||||||
func (d *DefaultCatchHandler) Catch(errCode string, handler func(errCode string, data map[string]interface{})) ICatchHandler {
|
func (d *DefaultCatchHandler) Catch(errCode string, handler func(errCode string, data map[string]any)) ICatchHandler {
|
||||||
if d.hasDealError() {
|
if d.hasDealError() {
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
@ -61,7 +61,7 @@ func (d *DefaultCatchHandler) Catch(errCode string, handler func(errCode string,
|
|||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 17:47 2023/7/20
|
// Date : 17:47 2023/7/20
|
||||||
func (d *DefaultCatchHandler) CatchAll(handler func(errCode string, data map[string]interface{})) IFinalHandler {
|
func (d *DefaultCatchHandler) CatchAll(handler func(errCode string, data map[string]any)) IFinalHandler {
|
||||||
if d.hasDealError() {
|
if d.hasDealError() {
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
@ -80,9 +80,9 @@ func (d *DefaultCatchHandler) CatchAll(handler func(errCode string, data map[str
|
|||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 17:48 2023/7/20
|
// Date : 17:48 2023/7/20
|
||||||
func (d *DefaultCatchHandler) Finally(data map[string]interface{}, handlers ...func(data map[string]interface{})) {
|
func (d *DefaultCatchHandler) Finally(data map[string]any, handlers ...func(data map[string]any)) {
|
||||||
if data == nil {
|
if data == nil {
|
||||||
data = map[string]interface{}{}
|
data = map[string]any{}
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); nil != r {
|
if r := recover(); nil != r {
|
||||||
|
@ -13,7 +13,7 @@ package try
|
|||||||
//
|
//
|
||||||
// Date : 11:30 2023/7/20
|
// Date : 11:30 2023/7/20
|
||||||
type LogicFuncInput struct {
|
type LogicFuncInput struct {
|
||||||
Parameter map[string]interface{}
|
Parameter map[string]any
|
||||||
}
|
}
|
||||||
|
|
||||||
// LogicFuncOutput ...
|
// LogicFuncOutput ...
|
||||||
@ -22,8 +22,8 @@ type LogicFuncInput struct {
|
|||||||
//
|
//
|
||||||
// Date : 11:30 2023/7/20
|
// Date : 11:30 2023/7/20
|
||||||
type LogicFuncOutput struct {
|
type LogicFuncOutput struct {
|
||||||
ErrCode string // 错误标识码
|
ErrCode string // 错误标识码
|
||||||
Data map[string]interface{} // 错误时返回的数据
|
Data map[string]any // 错误时返回的数据
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLogicFuncOutput 获取逻辑函数输出数据
|
// NewLogicFuncOutput 获取逻辑函数输出数据
|
||||||
@ -31,9 +31,9 @@ type LogicFuncOutput struct {
|
|||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 11:33 2023/7/20
|
// Date : 11:33 2023/7/20
|
||||||
func NewLogicFuncOutput(code string, data map[string]interface{}) LogicFuncOutput {
|
func NewLogicFuncOutput(code string, data map[string]any) LogicFuncOutput {
|
||||||
if data == nil {
|
if data == nil {
|
||||||
data = map[string]interface{}{}
|
data = map[string]any{}
|
||||||
}
|
}
|
||||||
r := LogicFuncOutput{
|
r := LogicFuncOutput{
|
||||||
ErrCode: code,
|
ErrCode: code,
|
||||||
|
@ -22,14 +22,14 @@ func Try(fn ILogicFunction, input *LogicFuncInput) ICatchHandler {
|
|||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
catchHandler.errCode = LogicFuncPanic
|
catchHandler.errCode = LogicFuncPanic
|
||||||
catchHandler.data = map[string]interface{}{
|
catchHandler.data = map[string]any{
|
||||||
"message": r.(error).Error(),
|
"message": r.(error).Error(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
if nil == input {
|
if nil == input {
|
||||||
input = &LogicFuncInput{
|
input = &LogicFuncInput{
|
||||||
Parameter: map[string]interface{}{},
|
Parameter: map[string]any{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user