22 Commits

Author SHA1 Message Date
50aa5ae7f8 数组支持提取指定路径字段, 转换成list 2024-08-06 16:03:12 +08:00
3533617196 update go mod 2024-08-06 15:23:20 +08:00
9ff1c213bb 计算字符串hash nimber 2024-06-27 11:17:06 +08:00
8d056baada Merge branch 'master' of git.zhangdeman.cn:zhangdeman/wrapper 2024-06-12 16:38:58 +08:00
ed0c57913a 完善any2string 2024-06-12 16:38:51 +08:00
588df729e0 变更 interface{} => any 2024-06-08 20:06:35 +08:00
3faebb9145 Merge branch 'master' of git.zhangdeman.cn:zhangdeman/wrapper 2024-05-20 20:47:54 +08:00
5163fd6f49 修复EasyMapFromByte的BUG 2024-05-20 20:47:44 +08:00
e228983e73 优化uniqueue返回值 2024-05-06 15:00:32 +08:00
3caad964bc 升级数组操作 2024-05-06 14:56:35 +08:00
9ae0c8f4be 增加数组去重 2024-05-06 14:29:33 +08:00
d1b9779946 update go mod 2024-05-06 14:19:37 +08:00
8c922be06d array 增加 to string slice 2024-04-22 11:44:17 +08:00
ee726ea6bc 增加判断字符串是否包含子串方法 2024-04-19 18:39:25 +08:00
e125c7e75d update go mod 2024-03-20 12:07:04 +08:00
1e1db09499 增加包装的IsSame方法 2024-03-11 11:18:25 +08:00
65107176f4 Merge pull request '增加比较两个map某一个字段值是否相等的能力' (#4) from feature/diff into master
Reviewed-on: #4
2024-03-08 16:00:00 +08:00
c07adaf249 增加仅比较一个字段方法 2024-03-08 15:58:58 +08:00
4d25a2a650 对外暴露compare方法 2024-03-08 15:56:53 +08:00
ab1f877b3c 优化字符串数字的处理 2024-03-08 15:51:38 +08:00
e8fc0addfc 增加判断字段是否相等的默认实现 2024-03-08 15:46:14 +08:00
9b469e0ac2 增加diff基础信息的结构定义 2024-03-08 11:33:54 +08:00
19 changed files with 643 additions and 381 deletions

89
any.go
View File

@ -9,6 +9,7 @@ package wrapper
import (
"fmt"
"git.zhangdeman.cn/zhangdeman/consts"
"git.zhangdeman.cn/zhangdeman/serialize"
"reflect"
)
@ -18,7 +19,7 @@ import (
// Author : go_developer@163.com<白茶清欢>
//
// Date : 18:19 2023/6/1
func AnyDataType(data interface{}) *AnyType {
func AnyDataType(data any) *AnyType {
at := &AnyType{
data: data,
}
@ -32,7 +33,7 @@ func AnyDataType(data interface{}) *AnyType {
//
// Date : 18:19 2023/6/1
type AnyType struct {
data interface{}
data any
dataType string
}
@ -56,28 +57,28 @@ func (at *AnyType) Type() string {
return at.dataType
}
if at.IsNil() {
return DataTypeNil
return consts.DataTypeNil
}
reflectType := reflect.TypeOf(at.data)
switch reflectType.Kind() {
case reflect.String:
return DataTypeString
return consts.DataTypeString
case reflect.Slice, reflect.Array:
return DataTypeSlice
return consts.DataTypeSliceAny
case reflect.Map, reflect.Struct:
return DataTypeObject
return consts.DataTypeMapAnyAny
case reflect.Pointer:
return DataTypePtr
return consts.DataTypePtr
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:
return DataTypeUint
return consts.DataTypeUint
case reflect.Bool:
return DataTypeBool
return consts.DataTypeBool
case reflect.Float32, reflect.Float64:
return DataTypeFloat
return consts.DataTypeFloat
default:
return DataTypeUnknown
return consts.DataTypeUnknown
}
}
@ -87,51 +88,27 @@ func (at *AnyType) Type() string {
//
// Date : 18:32 2023/6/1
func (at *AnyType) ToString() String {
switch at.dataType {
case DataTypeNil:
dataType := at.Type()
switch dataType {
case consts.DataTypeUnknown, consts.DataTypeNil:
return String("")
case DataTypeObject:
fallthrough
case DataTypeSlice:
fallthrough
case DataTypePtr:
case consts.DataTypeString:
return String(fmt.Sprintf("%v", at.data))
case consts.DataTypeSliceAny:
var val []any
_ = 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(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
View File

@ -10,7 +10,8 @@ package wrapper
import (
"encoding/json"
"errors"
"fmt"
"git.zhangdeman.cn/zhangdeman/op_type"
"github.com/tidwall/gjson"
"reflect"
"strings"
)
@ -20,11 +21,10 @@ import (
// Author : go_developer@163.com<白茶清欢>
//
// Date : 21:03 2023/6/11
func ArrayType(value interface{}) *Array {
at := &Array{
func ArrayType[Bt op_type.BaseType, ExtractDataType op_type.BaseType](value []Bt) *Array[Bt, ExtractDataType] {
at := &Array[Bt, ExtractDataType]{
value: value,
}
_, _ = at.Convert()
return at
}
@ -33,12 +33,10 @@ func ArrayType(value interface{}) *Array {
// Author : go_developer@163.com<白茶清欢>
//
// Date : 21:05 2023/6/11
type Array struct {
value interface{}
convertResult []interface{}
convertErr error
isSimpleSlice bool // 是否简单list, 即数据的每一项类型相同, 且都是基础内置数据类型
itemType reflect.Kind // 简单list场景下, 每一项的数据类型
type Array[Bt op_type.BaseType, ExtractDataType op_type.BaseType] struct {
value []Bt
convertErr error
itemType reflect.Kind // 简单list场景下, 每一项的数据类型
}
// IsNil 输入是否为nil
@ -46,189 +44,22 @@ type Array struct {
// Author : go_developer@163.com<白茶清欢>
//
// Date : 21:11 2023/6/11
func (at *Array) IsNil() bool {
func (at *Array[Bt, ExtractDataType]) IsNil() bool {
return at.value == nil
}
// IsValid 检测是否为数组类型
// ToStringSlice ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 21:06 2023/6/11
func (at *Array) IsValid() bool {
if at.IsNil() {
return false
// Date : 11:42 2024/4/22
func (at *Array[Bt, ExtractDataType]) ToStringSlice() []string {
list := make([]string, 0)
for _, item := range at.value {
byteData, _ := json.Marshal(item)
list = append(list, strings.Trim(string(byteData), "\""))
}
byteData, err := json.Marshal(at.value)
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
return list
}
// Unique 对数据结果进行去重
@ -236,22 +67,24 @@ func (at *Array) ConvertIgnoreError() []interface{} {
// Author : go_developer@163.com<白茶清欢>
//
// Date : 17:43 2023/6/12
func (at *Array) Unique() []interface{} {
result := make([]interface{}, 0)
if at.isSimpleSlice {
// 简单数据类型
dataTable := make(map[string]bool)
for _, item := range at.convertResult {
k := fmt.Sprintf("%v", item)
if _, exist := dataTable[k]; exist {
continue
}
dataTable[k] = true
result = append(result, item)
func (at *Array[Bt, ExtractDataType]) Unique() []Bt {
result := make([]Bt, 0)
dataTable := make(map[string]bool)
for _, item := range at.value {
byteData, _ := json.Marshal(item)
k := string(byteData)
if strings.HasPrefix(k, "\"\"") && strings.HasSuffix(k, "\"\"") {
k = string(byteData[1 : len(byteData)-1])
}
return result
if _, exist := dataTable[k]; exist {
continue
}
dataTable[k] = true
result = append(result, item)
}
return []interface{}{}
return result
}
// Has 查询一个值是否在列表里, 在的话, 返回首次出现的索引, 不在返回-1
@ -259,22 +92,13 @@ func (at *Array) Unique() []interface{} {
// Author : go_developer@163.com<白茶清欢>
//
// Date : 16:28 2023/7/31
func (at *Array) Has(input interface{}) int {
for idx := 0; idx < len(at.convertResult); idx++ {
if nil == input {
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() {
func (at *Array[Bt, ExtractDataType]) Has(input Bt) int {
for idx := 0; idx < len(at.value); idx++ {
if reflect.TypeOf(at.value[idx]).String() != reflect.TypeOf(input).String() {
// 类型不同
continue
}
sourceByte, _ := json.Marshal(at.convertResult[idx])
sourceByte, _ := json.Marshal(at.value[idx])
inputByte, _ := json.Marshal(input)
if string(sourceByte) != string(inputByte) {
continue
@ -289,14 +113,14 @@ func (at *Array) Has(input interface{}) int {
// Author : go_developer@163.com<白茶清欢>
//
// Date : 16:57 2023/9/28
func (at *Array) ToString() StringResult {
func (at *Array[Bt, ExtractDataType]) ToString() StringResult {
if at.IsNil() {
return StringResult{
Value: "",
Err: nil,
}
}
byteData, err := json.Marshal(at.convertResult)
byteData, err := json.Marshal(at.value)
return StringResult{
Value: string(byteData),
Err: err,
@ -308,19 +132,59 @@ func (at *Array) ToString() StringResult {
// Author : go_developer@163.com<白茶清欢>
//
// 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() {
return StringResult{
Value: "",
Err: nil,
}
}
strList := make([]string, 0)
for _, item := range at.convertResult {
strList = append(strList, fmt.Sprintf("%v", item))
}
return StringResult{
Value: strings.Join(strList, split),
Value: strings.Join(at.ToStringSlice(), split),
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
View 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"))
}

View File

@ -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.
// An error is returned if the copy would result in loss of information.
// dest should be a pointer type.
func ConvertAssign(dest, src interface{}) error {
func ConvertAssign(dest, src any) error {
// Common cases, without reflect.
switch s := src.(type) {
case string:
@ -70,7 +70,7 @@ func ConvertAssign(dest, src interface{}) error {
}
*d = string(s)
return nil
case *interface{}:
case *any:
if d == nil {
return errNilPtr
}
@ -112,7 +112,7 @@ func ConvertAssign(dest, src interface{}) error {
}
case nil:
switch d := dest.(type) {
case *interface{}:
case *any:
if d == nil {
return errNilPtr
}
@ -164,7 +164,7 @@ func ConvertAssign(dest, src interface{}) error {
*d = bv.(bool)
}
return err
case *interface{}:
case *any:
*d = src
return nil
}
@ -271,11 +271,11 @@ func cloneBytes(b []byte) []byte {
return c
}
func ToString(src interface{}) string {
func ToString(src any) string {
return asString(src)
}
func asString(src interface{}) string {
func asString(src any) string {
switch v := src.(type) {
case string:
return v
@ -327,14 +327,14 @@ func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) {
// []byte
// string
// time.Time
type Value interface{}
type Value any
type boolType struct{}
var Bool boolType
func (boolType) String() string { return "Bool" }
func (boolType) ConvertValue(src interface{}) (Value, error) {
func (boolType) ConvertValue(src any) (Value, error) {
switch s := src.(type) {
case bool:
return s, nil
@ -390,5 +390,5 @@ type Scanner interface {
// 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.
// If retention is necessary, copy their values before the next call to Scan.
Scan(src interface{}) error
Scan(src any) error
}

View File

@ -9,19 +9,6 @@ package wrapper
import "time"
const (
DataTypeUnknown = "unknown"
DataTypeNil = "nil"
DataTypePtr = "ptr"
DataTypeString = "string"
DataTypeInt = "int"
DataTypeUint = "uint"
DataTypeBool = "bool"
DataTypeFloat = "float"
DataTypeSlice = "slice"
DataTypeObject = "object"
)
// Int8Result ...
//
// Author : go_developer@163.com<白茶清欢>
@ -268,7 +255,7 @@ type Float64PtrResult struct {
//
// Date : 16:40 2023/5/8
type Any struct {
Value interface{}
Value any
Err error
}
@ -298,7 +285,7 @@ type BoolPtrResult struct {
//
// Date : 16:38 2023/5/8
type ObjectResult struct {
Value map[string]interface{}
Value map[string]any
Err error
}
@ -488,6 +475,6 @@ type MapResult struct {
//
// Date : 18:28 2023/5/8
type AnySliceResult struct {
Value []interface{}
Value []any
Err error
}

20
go.mod
View File

@ -5,19 +5,25 @@ go 1.21
toolchain go1.21.4
require (
git.zhangdeman.cn/zhangdeman/easymap v0.0.0-20240130062251-a87a97b0e8d4
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20240110090803-399e964daa0c
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20240726024939-e424db29c5c4
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/spaolacci/murmur3 v1.1.0
github.com/stretchr/testify v1.8.4
github.com/tidwall/gjson v1.17.3
)
require (
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20240104123641-b3f23974e5d6 // indirect
git.zhangdeman.cn/zhangdeman/util v0.0.0-20231227095334-7eb5cdbf9253 // indirect
github.com/BurntSushi/toml v1.3.2 // indirect
git.zhangdeman.cn/zhangdeman/util v0.0.0-20240618042405-6ee2c904644e // indirect
github.com/BurntSushi/toml v1.4.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-ini/ini v1.67.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mozillazg/go-pinyin v0.20.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/stretchr/testify v1.8.4 // indirect
github.com/pmezard/go-difflib v1.0.0 // 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
)

37
go.sum
View File

@ -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/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k=
git.zhangdeman.cn/zhangdeman/easymap v0.0.0-20231224145141-489e31b07a71 h1:nvVSH+Ju8EmoPiPHTae5lxHo4kDjROYChs19Yayz+NY=
git.zhangdeman.cn/zhangdeman/easymap v0.0.0-20231224145141-489e31b07a71/go.mod h1:SrtvrQRdzt+8KfYzvosH++gWxo2ShPTzR1m3VQ6uX7U=
git.zhangdeman.cn/zhangdeman/easymap v0.0.0-20231229032122-804bc9822704 h1:y/hXa0Ez+u0ka+QLv1abiCRy+rlJlnNdaH4H/eI6ZJ0=
git.zhangdeman.cn/zhangdeman/easymap v0.0.0-20231229032122-804bc9822704/go.mod h1:SrtvrQRdzt+8KfYzvosH++gWxo2ShPTzR1m3VQ6uX7U=
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20240419080457-9d9562469008 h1:6z99+X/B/G9sCZ+aTLYGWk3YLVVODzevA4wjWj9jvq0=
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20240419080457-9d9562469008/go.mod h1:IXXaZkb7vGzGnGM5RRWrASAuwrVSNxuoe0DmeXx5g6k=
git.zhangdeman.cn/zhangdeman/consts v0.0.0-20240501142503-e31a270e50cc h1:kPz9xiUVruM8kwbUUVpxyCTX8pGgyKt60K5zX77oyC4=
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/go.mod h1:SrtvrQRdzt+8KfYzvosH++gWxo2ShPTzR1m3VQ6uX7U=
git.zhangdeman.cn/zhangdeman/serialize v0.0.0-20231224125439-01f39b6ea08d h1:TV0BCQQewBEtLsv3i9gXkxLFd5A5bWBTiNd3D/I5o4Q=
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 h1:I/wOsRpCSRkU9vo1u703slQsmK0wnNeZzsWQOGtIAG0=
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/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/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/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/go.mod h1:Q8n74mJTIgjX4RBBcHnJ05h//6/k6foqmgE45jTQtxg=
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/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

22
map.go
View File

@ -8,11 +8,11 @@
package wrapper
import (
"bytes"
"encoding/json"
"errors"
"git.zhangdeman.cn/zhangdeman/easymap"
"git.zhangdeman.cn/zhangdeman/serialize"
"github.com/tidwall/gjson"
"reflect"
)
@ -21,7 +21,7 @@ import (
// Author : go_developer@163.com<白茶清欢>
//
// Date : 15:02 2023/8/10
func EasyMap(mapData interface{}) Map {
func EasyMap(mapData any) Map {
m, _ := EasyMapWithError(mapData)
return m
}
@ -31,14 +31,14 @@ func EasyMap(mapData interface{}) Map {
// Author : go_developer@163.com<白茶清欢>
//
// Date : 15:06 2023/8/10
func EasyMapWithError(mapData interface{}) (Map, error) {
func EasyMapWithError(mapData any) (Map, error) {
if nil == mapData {
return easymap.NewNormal(), nil
}
m := easymap.NewNormal()
reflectType := reflect.TypeOf(mapData)
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 {
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<白茶清欢>
//
// Date : 16:11 2023/8/10
func EasyMapFromStruct(data interface{}) Map {
func EasyMapFromStruct(data any) Map {
byteData, _ := json.Marshal(data)
return EasyMapFromByte(byteData)
}
@ -78,11 +78,13 @@ func EasyMapFromString(data string) Map {
//
// Date : 16:12 2023/8/10
func EasyMapFromByte(data []byte) Map {
var tmpMap map[interface{}]interface{}
decoder := json.NewDecoder(bytes.NewReader(data))
decoder.UseNumber()
_ = decoder.Decode(&tmpMap)
return EasyMap(tmpMap)
res := easymap.NewNormal()
jsonRes := gjson.Parse(string(data))
jsonRes.ForEach(func(key, value gjson.Result) bool {
res.Set(key.Value(), value.Value())
return true
})
return res
}
// Map ...

View File

@ -19,10 +19,10 @@ import (
// Author : go_developer@163.com<白茶清欢>
//
// Date : 18:36 2023/6/1
func ObjectData(data interface{}) *ObjectType {
func ObjectData(data any) *ObjectType {
ot := &ObjectType{
source: data,
data: map[interface{}]interface{}{},
data: map[any]any{},
byteData: []byte{},
isValid: true,
invalidErr: errors.New("data is invalid"),
@ -49,8 +49,8 @@ func ObjectData(data interface{}) *ObjectType {
//
// Date : 18:38 2023/6/1
type ObjectType struct {
source interface{}
data map[interface{}]interface{}
source any
data map[any]any
byteData []byte
isValid bool
invalidErr error
@ -106,7 +106,7 @@ func (ot *ObjectType) ToString() StringResult {
// Date : 16:17 2023/6/2
func (ot *ObjectType) ToMapStringAny() ObjectResult {
res := ObjectResult{
Value: map[string]interface{}{},
Value: map[string]any{},
Err: nil,
}
if ot.IsNil() {
@ -121,7 +121,7 @@ func (ot *ObjectType) ToMapStringAny() ObjectResult {
// Author : go_developer@163.com<白茶清欢>
//
// Date : 16:41 2023/6/2
func (ot *ObjectType) ToStruct(receiver interface{}) error {
func (ot *ObjectType) ToStruct(receiver any) error {
if nil == receiver {
return errors.New("receiver is nil")
}
@ -136,7 +136,7 @@ func (ot *ObjectType) ToStruct(receiver interface{}) error {
// Author : go_developer@163.com<白茶清欢>
//
// Date : 16:42 2023/6/2
func (ot *ObjectType) ToStructIgnoreErr(receiver interface{}) {
func (ot *ObjectType) ToStructIgnoreErr(receiver any) {
if nil == receiver {
return
}

View File

@ -13,6 +13,7 @@ import (
"errors"
"git.zhangdeman.cn/zhangdeman/serialize"
"github.com/axgle/mahonia"
"github.com/spaolacci/murmur3"
"io"
"math/rand"
"strings"
@ -521,7 +522,7 @@ func (str String) ToStringPtr() StringPtrResult {
func (str String) ToObject() ObjectResult {
var (
res = ObjectResult{
Value: map[string]interface{}{},
Value: map[string]any{},
Err: nil,
}
)
@ -534,7 +535,7 @@ func (str String) ToObject() ObjectResult {
// Author : go_developer@163.com<白茶清欢>
//
// Date : 18:38 2023/5/4
func (str String) ToStruct(receiver interface{}) error {
func (str String) ToStruct(receiver any) error {
if nil == receiver {
return errors.New("receiver is nil")
}
@ -992,7 +993,7 @@ func (str String) ToStringSlice(splitChar ...string) StringSliceResult {
// Date : 15:01 2023/5/5
func (str String) ToAnySlice(splitCharList ...string) AnySliceResult {
result := AnySliceResult{
Value: []interface{}{},
Value: []any{},
Err: nil,
}
@ -1002,7 +1003,7 @@ func (str String) ToAnySlice(splitCharList ...string) AnySliceResult {
}
valArr := strings.Split(str.Value(), splitCharList[0])
valList := make([]interface{}, 0)
valList := make([]any, 0)
for _, item := range valArr {
v := String(item)
if res := v.ToInt64(); nil == res.Err {
@ -1157,3 +1158,33 @@ func (str String) ReplaceChar(charTable map[string]string) String {
}
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,
}
}

View File

@ -17,7 +17,7 @@ import (
// Author : go_developer@163.com<白茶清欢>
//
// Date : 16:07 2023/8/10
func NewStruct(data interface{}) *Struct {
func NewStruct(data any) *Struct {
s, _ := NewStructWithError(data)
return s
}
@ -27,7 +27,7 @@ func NewStruct(data interface{}) *Struct {
// Author : go_developer@163.com<白茶清欢>
//
// Date : 16:17 2023/8/10
func NewStructWithError(data interface{}) (*Struct, error) {
func NewStructWithError(data any) (*Struct, error) {
if data == 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
type Struct struct {
data interface{}
data any
}
// ToMap 转为Map
@ -58,7 +58,7 @@ type Struct struct {
func (s *Struct) ToMap() MapResult {
if nil == s.data {
return MapResult{
Value: EasyMap(map[interface{}]interface{}{}),
Value: EasyMap(map[any]any{}),
Err: nil,
}
}

View File

@ -108,30 +108,6 @@ func (to *ternaryOperator) StringWithFunc(condFunc CondFunc, trueVal String, fal
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 ...
//
// Author : go_developer@163.com<白茶清欢>

245
tool/define/diff.go Normal file
View 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
View 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
View 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
}

View File

@ -13,8 +13,8 @@ package try
//
// Date : 11:26 2023/7/20
type ICatchHandler interface {
Catch(errCode string, handler func(errCode string, data map[string]interface{})) ICatchHandler
CatchAll(handler func(errCode string, data map[string]interface{})) IFinalHandler
Catch(errCode string, handler func(errCode string, data map[string]any)) ICatchHandler
CatchAll(handler func(errCode string, data map[string]any)) IFinalHandler
IFinalHandler
}
@ -24,7 +24,7 @@ type ICatchHandler interface {
//
// Date : 11:27 2023/7/20
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 逻辑函数约束

View File

@ -15,7 +15,7 @@ package try
type DefaultCatchHandler struct {
hasDeal bool // 异常是否已被处理
errCode string
data map[string]interface{}
data map[string]any
}
// hasDealError 判断异常是否已经被处理
@ -38,7 +38,7 @@ func (d *DefaultCatchHandler) hasDealError() bool {
// Author : go_developer@163.com<白茶清欢>
//
// 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() {
return d
}
@ -61,7 +61,7 @@ func (d *DefaultCatchHandler) Catch(errCode string, handler func(errCode string,
// Author : go_developer@163.com<白茶清欢>
//
// 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() {
return d
}
@ -80,9 +80,9 @@ func (d *DefaultCatchHandler) CatchAll(handler func(errCode string, data map[str
// Author : go_developer@163.com<白茶清欢>
//
// 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 {
data = map[string]interface{}{}
data = map[string]any{}
}
defer func() {
if r := recover(); nil != r {

View File

@ -13,7 +13,7 @@ package try
//
// Date : 11:30 2023/7/20
type LogicFuncInput struct {
Parameter map[string]interface{}
Parameter map[string]any
}
// LogicFuncOutput ...
@ -22,8 +22,8 @@ type LogicFuncInput struct {
//
// Date : 11:30 2023/7/20
type LogicFuncOutput struct {
ErrCode string // 错误标识码
Data map[string]interface{} // 错误时返回的数据
ErrCode string // 错误标识码
Data map[string]any // 错误时返回的数据
}
// NewLogicFuncOutput 获取逻辑函数输出数据
@ -31,9 +31,9 @@ type LogicFuncOutput struct {
// Author : go_developer@163.com<白茶清欢>
//
// 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 {
data = map[string]interface{}{}
data = map[string]any{}
}
r := LogicFuncOutput{
ErrCode: code,

View File

@ -22,14 +22,14 @@ func Try(fn ILogicFunction, input *LogicFuncInput) ICatchHandler {
defer func() {
if r := recover(); r != nil {
catchHandler.errCode = LogicFuncPanic
catchHandler.data = map[string]interface{}{
catchHandler.data = map[string]any{
"message": r.(error).Error(),
}
}
}()
if nil == input {
input = &LogicFuncInput{
Parameter: map[string]interface{}{},
Parameter: map[string]any{},
}
}