Compare commits
63 Commits
020ba99fe8
...
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 | |||
270c4fcfd4 | |||
75fd00c4cf | |||
5a53679400 | |||
448b472c53 | |||
6da972b112 | |||
d7e591277a | |||
88d3066307 | |||
d9aed3d800 | |||
a427bc63c5 | |||
1dd7ccf026 | |||
e7417048fb | |||
1b71c40d14 | |||
31780bd924 | |||
91eca55f87 | |||
0a9175daa8 | |||
3432f85c3d | |||
160f464d15 | |||
8b1a515cb9 | |||
c641e6003b | |||
9f0b7008a4 | |||
faafa8ee2a | |||
2886126ae7 | |||
8308761f72 | |||
14bc4c2c9d | |||
cfc46e8d82 | |||
bff3fa8566 | |||
65186fe23b | |||
1e901000e9 | |||
824c098481 | |||
5c6053d86c | |||
b92b8dbf25 | |||
803cf00bd1 | |||
e9749e4844 | |||
b333760272 | |||
94c86f913f | |||
d8ff56b87d | |||
5e4a884374 | |||
d64bcfbfd8 | |||
685dec4f39 | |||
9d8c708852 | |||
ac0d81e47c |
74
any.go
74
any.go
@ -7,17 +7,24 @@
|
||||
// Date : 2023-06-01 18:18
|
||||
package wrapper
|
||||
|
||||
import "reflect"
|
||||
import (
|
||||
"fmt"
|
||||
"git.zhangdeman.cn/zhangdeman/consts"
|
||||
"git.zhangdeman.cn/zhangdeman/serialize"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// AnyDataType ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 18:19 2023/6/1
|
||||
func AnyDataType(data interface{}) *AnyType {
|
||||
return &AnyType{
|
||||
func AnyDataType(data any) *AnyType {
|
||||
at := &AnyType{
|
||||
data: data,
|
||||
}
|
||||
at.dataType = at.Type()
|
||||
return at
|
||||
}
|
||||
|
||||
// AnyType ...
|
||||
@ -26,7 +33,8 @@ func AnyDataType(data interface{}) *AnyType {
|
||||
//
|
||||
// Date : 18:19 2023/6/1
|
||||
type AnyType struct {
|
||||
data interface{}
|
||||
data any
|
||||
dataType string
|
||||
}
|
||||
|
||||
// IsNil 是否为 nil
|
||||
@ -44,23 +52,33 @@ func (at *AnyType) IsNil() bool {
|
||||
//
|
||||
// Date : 18:22 2023/6/1
|
||||
func (at *AnyType) Type() string {
|
||||
if len(at.dataType) > 0 {
|
||||
// 已经处理过的,无需在处理
|
||||
return at.dataType
|
||||
}
|
||||
if at.IsNil() {
|
||||
return DataTypeNil
|
||||
return consts.DataTypeNil
|
||||
}
|
||||
reflectType := reflect.TypeOf(at.data)
|
||||
switch reflectType.Kind() {
|
||||
case reflect.Slice:
|
||||
return DataTypeAnySlice
|
||||
case reflect.Array:
|
||||
return DataTypeAnySlice
|
||||
case reflect.Map:
|
||||
return DataTypeAnyObject
|
||||
case reflect.Struct:
|
||||
return DataTypeAnyObject
|
||||
case reflect.String:
|
||||
return consts.DataTypeString
|
||||
case reflect.Slice, reflect.Array:
|
||||
return consts.DataTypeSliceAny
|
||||
case reflect.Map, reflect.Struct:
|
||||
return consts.DataTypeMapAnyAny
|
||||
case reflect.Pointer:
|
||||
return DataTypePtr
|
||||
return consts.DataTypePtr
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return consts.DataTypeInt
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return consts.DataTypeUint
|
||||
case reflect.Bool:
|
||||
return consts.DataTypeBool
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return consts.DataTypeFloat
|
||||
default:
|
||||
return reflectType.Kind().String()
|
||||
return consts.DataTypeUnknown
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,6 +87,28 @@ func (at *AnyType) Type() string {
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 18:32 2023/6/1
|
||||
func (at *AnyType) ToString() string {
|
||||
return ""
|
||||
func (at *AnyType) ToString() String {
|
||||
dataType := at.Type()
|
||||
switch dataType {
|
||||
case consts.DataTypeUnknown, consts.DataTypeNil:
|
||||
return String("")
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
323
array.go
323
array.go
@ -10,35 +10,33 @@ package wrapper
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.zhangdeman.cn/zhangdeman/op_type"
|
||||
"github.com/tidwall/gjson"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Array 数组实例
|
||||
// ArrayType 数组实例
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 21:03 2023/6/11
|
||||
func Array(value interface{}) *ArrayType {
|
||||
at := &ArrayType{
|
||||
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
|
||||
}
|
||||
|
||||
// ArrayType ...
|
||||
// Array ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 21:05 2023/6/11
|
||||
type ArrayType 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,175 +44,22 @@ type ArrayType struct {
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 21:11 2023/6/11
|
||||
func (at *ArrayType) 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 *ArrayType) 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 *ArrayType) 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 *ArrayType) 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))
|
||||
for i := 0; i < len(val); i++ {
|
||||
at.convertResult[i] = val[i]
|
||||
}
|
||||
}
|
||||
return at.convertResult, nil
|
||||
}
|
||||
|
||||
// ConvertIgnoreError 类型转换并忽略异常
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 18:07 2023/6/26
|
||||
func (at *ArrayType) ConvertIgnoreError() []interface{} {
|
||||
res, _ := at.Convert()
|
||||
return res
|
||||
return list
|
||||
}
|
||||
|
||||
// Unique 对数据结果进行去重
|
||||
@ -222,45 +67,38 @@ func (at *ArrayType) ConvertIgnoreError() []interface{} {
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 17:43 2023/6/12
|
||||
func (at *ArrayType) 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
|
||||
|
||||
}
|
||||
|
||||
// In 查询一个值是否在列表里, 在的话, 返回首次出现的索引, 不在返回-1
|
||||
// Has 查询一个值是否在列表里, 在的话, 返回首次出现的索引, 不在返回-1
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:28 2023/7/31
|
||||
func (at *ArrayType) In(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
|
||||
@ -269,3 +107,84 @@ func (at *ArrayType) In(input interface{}) int {
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// ToString ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:57 2023/9/28
|
||||
func (at *Array[Bt, ExtractDataType]) ToString() StringResult {
|
||||
if at.IsNil() {
|
||||
return StringResult{
|
||||
Value: "",
|
||||
Err: nil,
|
||||
}
|
||||
}
|
||||
byteData, err := json.Marshal(at.value)
|
||||
return StringResult{
|
||||
Value: string(byteData),
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
|
||||
// ToStringWithSplit 数组按照指定分隔符转为字符串
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 17:42 2023/10/25
|
||||
func (at *Array[Bt, ExtractDataType]) ToStringWithSplit(split string) StringResult {
|
||||
if at.IsNil() {
|
||||
return StringResult{
|
||||
Value: "",
|
||||
Err: nil,
|
||||
}
|
||||
}
|
||||
return StringResult{
|
||||
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
|
||||
}
|
||||
|
@ -4,29 +4,33 @@
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2023-06-11 21:12
|
||||
// Date : 2024-05-06 下午2:48
|
||||
package wrapper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestArray(t *testing.T) {
|
||||
val := []interface{}{1, 2, 3}
|
||||
fmt.Println(Array(val).IsValid())
|
||||
fmt.Println(Array(val).ItemIsInterface())
|
||||
valInt := []int{1, 2, 3, 1, 4, 5, 6, 7, 7, 6, 9}
|
||||
fmt.Println(Array(valInt).Unique())
|
||||
a := map[string]interface{}{"name": "zhang"}
|
||||
b := a
|
||||
c := map[string]interface{}{"name": "de"}
|
||||
fmt.Println(reflect.DeepEqual(b, c))
|
||||
fmt.Println(reflect.DeepEqual(a, b))
|
||||
fmt.Println(Array(valInt).In("1"))
|
||||
fmt.Println(Array(valInt).In(1))
|
||||
fmt.Println(Array(valInt).In(2))
|
||||
fmt.Println(Array(valInt).In(7))
|
||||
fmt.Println(Array(valInt).In(20))
|
||||
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"))
|
||||
}
|
||||
|
394
convert.go
Normal file
394
convert.go
Normal file
@ -0,0 +1,394 @@
|
||||
// Package wrapper ...
|
||||
//
|
||||
// Description : 任意类型之间的相互转换
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2021-02-23 10:23 下午
|
||||
package wrapper
|
||||
|
||||
/*
|
||||
Desc : 在处理一些参数的时候,可能需要将参数转换为各种类型,这里实现一个通用的转换函数,实现各种类型之间的相互转换。
|
||||
|
||||
当然,如果源数据格式和目标数据类型不一致,是会返回错误的。例如将字符串“一二三”转换为数值类型则会报错,而将字符串“123”转换为数值类型则OK。
|
||||
|
||||
这段代码实际抄自go自带的“database/sql”库,只是源代码作为内部函数无法在外面调用,可以单独把需要的功能拎出来使用:
|
||||
|
||||
代码中有一个Scaner接口,可以自行实现,然后通过"convertAssign()"函数,作为dst参数传入。
|
||||
|
||||
Author : zhangdeman001@ke.com<白茶清欢>
|
||||
|
||||
*/
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// RawBytes is a byte slice that holds a reference to memory owned by
|
||||
// the database itself. After a Scan into a RawBytes, the slice is only
|
||||
// valid until the next call to Next, Scan, or Close.
|
||||
type RawBytes []byte
|
||||
|
||||
var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error
|
||||
|
||||
// ConvertAssign ...
|
||||
// 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 any) error {
|
||||
// Common cases, without reflect.
|
||||
switch s := src.(type) {
|
||||
case string:
|
||||
switch d := dest.(type) {
|
||||
case *string:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = s
|
||||
return nil
|
||||
case *[]byte:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = []byte(s)
|
||||
return nil
|
||||
case *RawBytes:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = append((*d)[:0], s...)
|
||||
return nil
|
||||
}
|
||||
case []byte:
|
||||
switch d := dest.(type) {
|
||||
case *string:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = string(s)
|
||||
return nil
|
||||
case *any:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = cloneBytes(s)
|
||||
return nil
|
||||
case *[]byte:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = cloneBytes(s)
|
||||
return nil
|
||||
case *RawBytes:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = s
|
||||
return nil
|
||||
}
|
||||
case time.Time:
|
||||
switch d := dest.(type) {
|
||||
case *time.Time:
|
||||
*d = s
|
||||
return nil
|
||||
case *string:
|
||||
*d = s.Format(time.RFC3339Nano)
|
||||
return nil
|
||||
case *[]byte:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = []byte(s.Format(time.RFC3339Nano))
|
||||
return nil
|
||||
case *RawBytes:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = s.AppendFormat((*d)[:0], time.RFC3339Nano)
|
||||
return nil
|
||||
}
|
||||
case nil:
|
||||
switch d := dest.(type) {
|
||||
case *any:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = nil
|
||||
return nil
|
||||
case *[]byte:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = nil
|
||||
return nil
|
||||
case *RawBytes:
|
||||
if d == nil {
|
||||
return errNilPtr
|
||||
}
|
||||
*d = nil
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var sv reflect.Value
|
||||
|
||||
switch d := dest.(type) {
|
||||
case *string:
|
||||
sv = reflect.ValueOf(src)
|
||||
switch sv.Kind() {
|
||||
case reflect.Bool,
|
||||
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||
reflect.Float32, reflect.Float64:
|
||||
*d = asString(src)
|
||||
return nil
|
||||
}
|
||||
case *[]byte:
|
||||
sv = reflect.ValueOf(src)
|
||||
if b, ok := asBytes(nil, sv); ok {
|
||||
*d = b
|
||||
return nil
|
||||
}
|
||||
case *RawBytes:
|
||||
sv = reflect.ValueOf(src)
|
||||
if b, ok := asBytes([]byte(*d)[:0], sv); ok {
|
||||
*d = RawBytes(b)
|
||||
return nil
|
||||
}
|
||||
case *bool:
|
||||
bv, err := Bool.ConvertValue(src)
|
||||
if err == nil {
|
||||
*d = bv.(bool)
|
||||
}
|
||||
return err
|
||||
case *any:
|
||||
*d = src
|
||||
return nil
|
||||
}
|
||||
|
||||
if scanner, ok := dest.(Scanner); ok {
|
||||
return scanner.Scan(src)
|
||||
}
|
||||
|
||||
dpv := reflect.ValueOf(dest)
|
||||
if dpv.Kind() != reflect.Ptr {
|
||||
return errors.New("destination not a pointer")
|
||||
}
|
||||
if dpv.IsNil() {
|
||||
return errNilPtr
|
||||
}
|
||||
|
||||
if !sv.IsValid() {
|
||||
sv = reflect.ValueOf(src)
|
||||
}
|
||||
|
||||
dv := reflect.Indirect(dpv)
|
||||
if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) {
|
||||
switch b := src.(type) {
|
||||
case []byte:
|
||||
dv.Set(reflect.ValueOf(cloneBytes(b)))
|
||||
default:
|
||||
dv.Set(sv)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) {
|
||||
dv.Set(sv.Convert(dv.Type()))
|
||||
return nil
|
||||
}
|
||||
|
||||
// The following conversions use a string value as an intermediate representation
|
||||
// to convert between various numeric types.
|
||||
//
|
||||
// This also allows scanning into user defined types such as "type Int int64".
|
||||
// For symmetry, also check for string destination types.
|
||||
switch dv.Kind() {
|
||||
case reflect.Ptr:
|
||||
if src == nil {
|
||||
dv.Set(reflect.Zero(dv.Type()))
|
||||
return nil
|
||||
}
|
||||
dv.Set(reflect.New(dv.Type().Elem()))
|
||||
return ConvertAssign(dv.Interface(), src)
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
s := asString(src)
|
||||
i64, err := strconv.ParseInt(s, 10, dv.Type().Bits())
|
||||
if err != nil {
|
||||
err = strconvErr(err)
|
||||
return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
|
||||
}
|
||||
dv.SetInt(i64)
|
||||
return nil
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
s := asString(src)
|
||||
u64, err := strconv.ParseUint(s, 10, dv.Type().Bits())
|
||||
if err != nil {
|
||||
err = strconvErr(err)
|
||||
return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
|
||||
}
|
||||
dv.SetUint(u64)
|
||||
return nil
|
||||
case reflect.Float32, reflect.Float64:
|
||||
s := asString(src)
|
||||
f64, err := strconv.ParseFloat(s, dv.Type().Bits())
|
||||
if err != nil {
|
||||
err = strconvErr(err)
|
||||
return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
|
||||
}
|
||||
dv.SetFloat(f64)
|
||||
return nil
|
||||
case reflect.String:
|
||||
switch v := src.(type) {
|
||||
case string:
|
||||
dv.SetString(v)
|
||||
return nil
|
||||
case []byte:
|
||||
dv.SetString(string(v))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest)
|
||||
}
|
||||
|
||||
func strconvErr(err error) error {
|
||||
if ne, ok := err.(*strconv.NumError); ok {
|
||||
return ne.Err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func cloneBytes(b []byte) []byte {
|
||||
if b == nil {
|
||||
return nil
|
||||
}
|
||||
c := make([]byte, len(b))
|
||||
copy(c, b)
|
||||
return c
|
||||
}
|
||||
|
||||
func ToString(src any) string {
|
||||
return asString(src)
|
||||
}
|
||||
|
||||
func asString(src any) string {
|
||||
switch v := src.(type) {
|
||||
case string:
|
||||
return v
|
||||
case []byte:
|
||||
return string(v)
|
||||
}
|
||||
rv := reflect.ValueOf(src)
|
||||
switch rv.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return strconv.FormatInt(rv.Int(), 10)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return strconv.FormatUint(rv.Uint(), 10)
|
||||
case reflect.Float64:
|
||||
return strconv.FormatFloat(rv.Float(), 'g', -1, 64)
|
||||
case reflect.Float32:
|
||||
return strconv.FormatFloat(rv.Float(), 'g', -1, 32)
|
||||
case reflect.Bool:
|
||||
return strconv.FormatBool(rv.Bool())
|
||||
}
|
||||
return fmt.Sprintf("%v", src)
|
||||
}
|
||||
|
||||
func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) {
|
||||
switch rv.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return strconv.AppendInt(buf, rv.Int(), 10), true
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return strconv.AppendUint(buf, rv.Uint(), 10), true
|
||||
case reflect.Float32:
|
||||
return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true
|
||||
case reflect.Float64:
|
||||
return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true
|
||||
case reflect.Bool:
|
||||
return strconv.AppendBool(buf, rv.Bool()), true
|
||||
case reflect.String:
|
||||
s := rv.String()
|
||||
return append(buf, s...), true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Value is a value that drivers must be able to handle.
|
||||
// It is either nil, a type handled by a database driver's NamedValueChecker
|
||||
// interface, or an instance of one of these types:
|
||||
//
|
||||
// int64
|
||||
// float64
|
||||
// bool
|
||||
// []byte
|
||||
// string
|
||||
// time.Time
|
||||
type Value any
|
||||
|
||||
type boolType struct{}
|
||||
|
||||
var Bool boolType
|
||||
|
||||
func (boolType) String() string { return "Bool" }
|
||||
func (boolType) ConvertValue(src any) (Value, error) {
|
||||
switch s := src.(type) {
|
||||
case bool:
|
||||
return s, nil
|
||||
case string:
|
||||
b, err := strconv.ParseBool(s)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("sql/driver: couldn't convert %q into type bool", s)
|
||||
}
|
||||
return b, nil
|
||||
case []byte:
|
||||
b, err := strconv.ParseBool(string(s))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("sql/driver: couldn't convert %q into type bool", s)
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
sv := reflect.ValueOf(src)
|
||||
switch sv.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
iv := sv.Int()
|
||||
if iv == 1 || iv == 0 {
|
||||
return iv == 1, nil
|
||||
}
|
||||
return nil, fmt.Errorf("sql/driver: couldn't convert %d into type bool", iv)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
uv := sv.Uint()
|
||||
if uv == 1 || uv == 0 {
|
||||
return uv == 1, nil
|
||||
}
|
||||
return nil, fmt.Errorf("sql/driver: couldn't convert %d into type bool", uv)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("sql/driver: couldn't convert %v (%T) into type bool", src, src)
|
||||
}
|
||||
|
||||
type Scanner interface {
|
||||
// Scan assigns a value from a database driver.
|
||||
//
|
||||
// The src value will be of one of the following types:
|
||||
//
|
||||
// int64
|
||||
// float64
|
||||
// bool
|
||||
// []byte
|
||||
// string
|
||||
// time.Time
|
||||
// nil - for NULL values
|
||||
//
|
||||
// An error should be returned if the value cannot be stored
|
||||
// without loss of information.
|
||||
//
|
||||
// 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 any) error
|
||||
}
|
66
define.go
66
define.go
@ -7,45 +7,7 @@
|
||||
// Date : 2023-05-05 14:44
|
||||
package wrapper
|
||||
|
||||
const (
|
||||
DataTypeUnknown = "unknown"
|
||||
DataTypeNil = "nil"
|
||||
DataTypeAny = "interface"
|
||||
DataTypePtr = "ptr"
|
||||
|
||||
DataTypeString = "string"
|
||||
|
||||
DataTypeInt8 = "int8"
|
||||
DataTypeInt16 = "int16"
|
||||
DataTypeInt32 = "int32"
|
||||
DataTypeInt64 = "int64"
|
||||
DataTypeInt = "int"
|
||||
|
||||
DataTypeUint8 = "uint8"
|
||||
DataTypeUint16 = "uint16"
|
||||
DataTypeUint32 = "uint32"
|
||||
DataTypeUint64 = "uint64"
|
||||
DataTypeUint = "uint"
|
||||
|
||||
DataTypeBool = "bool"
|
||||
|
||||
DataTypeNumber = "number"
|
||||
|
||||
DataTypeFloat32 = "float32"
|
||||
DataTypeFloat64 = "float64"
|
||||
DataTypeDouble = "double"
|
||||
DataTypeFloat = "float"
|
||||
|
||||
DataTypeIntSlice = "[]int"
|
||||
DataTypeUntSlice = "[]uint"
|
||||
DataTypeNumberSlice = "[]number"
|
||||
DataTypeFloatSlice = "[]float"
|
||||
DataTypeBoolSlice = "[]bool"
|
||||
DataTypeAnySlice = "[]interface"
|
||||
|
||||
DataTypeObject = "map[string]interface"
|
||||
DataTypeAnyObject = "map[interface]interface"
|
||||
)
|
||||
import "time"
|
||||
|
||||
// Int8Result ...
|
||||
//
|
||||
@ -293,7 +255,7 @@ type Float64PtrResult struct {
|
||||
//
|
||||
// Date : 16:40 2023/5/8
|
||||
type Any struct {
|
||||
Value interface{}
|
||||
Value any
|
||||
Err error
|
||||
}
|
||||
|
||||
@ -323,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
|
||||
}
|
||||
|
||||
@ -477,6 +439,16 @@ type Float64SliceResult struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
// DurationResult 时间转换结果
|
||||
//
|
||||
// Author : zhangdeman001@ke.com<张德满>
|
||||
//
|
||||
// Date : 20:32 2023/9/4
|
||||
type DurationResult struct {
|
||||
Value time.Duration
|
||||
Err error
|
||||
}
|
||||
|
||||
// StringSliceResult ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
@ -487,12 +459,22 @@ type StringSliceResult struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
// MapResult 转map的结果
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:05 2023/8/10
|
||||
type MapResult struct {
|
||||
Value Map
|
||||
Err error
|
||||
}
|
||||
|
||||
// AnySliceResult ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 18:28 2023/5/8
|
||||
type AnySliceResult struct {
|
||||
Value []interface{}
|
||||
Value []any
|
||||
Err error
|
||||
}
|
||||
|
27
go.mod
27
go.mod
@ -1,19 +1,28 @@
|
||||
module git.zhangdeman.cn/zhangdeman/wrapper
|
||||
|
||||
go 1.20
|
||||
go 1.21
|
||||
|
||||
require git.zhangdeman.cn/zhangdeman/util v0.0.0-20230505025924-96532aff0019
|
||||
toolchain go1.21.4
|
||||
|
||||
require (
|
||||
github.com/Jeffail/gabs v1.4.0 // indirect
|
||||
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 // indirect
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
|
||||
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/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/mssola/user_agent v0.6.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/tidwall/gjson v1.14.4 // indirect
|
||||
github.com/mozillazg/go-pinyin v0.20.0 // 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
|
||||
|
53
go.sum
53
go.sum
@ -1,26 +1,53 @@
|
||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20230505025924-96532aff0019 h1:eJ/9rEj2iI8P9I1DfCmMUvsV+n2EiAWCXnI9yVVDHO0=
|
||||
git.zhangdeman.cn/zhangdeman/util v0.0.0-20230505025924-96532aff0019/go.mod h1:z2bP5LIwRVpWSQV0/a3WIFaoarJUP8kA/0Clv0bP+8I=
|
||||
github.com/Jeffail/gabs v1.4.0 h1://5fYRRTq1edjfIrQGvdkcd22pkYUrHZ5YC/H2GJVAo=
|
||||
github.com/Jeffail/gabs v1.4.0/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc=
|
||||
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-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/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=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
|
||||
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mssola/user_agent v0.6.0 h1:uwPR4rtWlCHRFyyP9u2KOV0u8iQXmS7Z7feTrstQwk4=
|
||||
github.com/mssola/user_agent v0.6.0/go.mod h1:TTPno8LPY3wAIEKRpAtkdMT0f8SE24pLRGPahjCH4uw=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/mozillazg/go-pinyin v0.20.0 h1:BtR3DsxpApHfKReaPO1fCqF4pThRwH9uwvXzm+GnMFQ=
|
||||
github.com/mozillazg/go-pinyin v0.20.0/go.mod h1:iR4EnMMRXkfpFVV5FMi4FNB6wGq9NV6uDWbUuPhP4Yc=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
|
||||
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
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=
|
||||
|
13
int.go
13
int.go
@ -10,6 +10,7 @@ package wrapper
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Int int类型
|
||||
@ -19,6 +20,18 @@ import (
|
||||
// Date : 13:57 2023/5/5
|
||||
type Int int64
|
||||
|
||||
// ToDuration ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 20:33 2023/9/4
|
||||
func (i Int) ToDuration(timeUnit time.Duration) DurationResult {
|
||||
return DurationResult{
|
||||
Value: time.Duration(i.ToInt64().Value) * timeUnit,
|
||||
Err: nil,
|
||||
}
|
||||
}
|
||||
|
||||
// ToInt8 ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
|
95
map.go
Normal file
95
map.go
Normal file
@ -0,0 +1,95 @@
|
||||
// Package wrapper ...
|
||||
//
|
||||
// Description : wrapper ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2023-08-10 15:01
|
||||
package wrapper
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"git.zhangdeman.cn/zhangdeman/easymap"
|
||||
"git.zhangdeman.cn/zhangdeman/serialize"
|
||||
"github.com/tidwall/gjson"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// EasyMap ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 15:02 2023/8/10
|
||||
func EasyMap(mapData any) Map {
|
||||
m, _ := EasyMapWithError(mapData)
|
||||
return m
|
||||
}
|
||||
|
||||
// EasyMapWithError 转换map,并带上转换的异常
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 15:06 2023/8/10
|
||||
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]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")
|
||||
}
|
||||
mapData = mapFormatData
|
||||
}
|
||||
|
||||
reflectValue := reflect.ValueOf(mapData).MapRange()
|
||||
for reflectValue.Next() {
|
||||
// 循环提取相关值
|
||||
m.Set(reflectValue.Key().Interface(), reflectValue.Value().Interface())
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// EasyMapFromStruct 从struct转map
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:11 2023/8/10
|
||||
func EasyMapFromStruct(data any) Map {
|
||||
byteData, _ := json.Marshal(data)
|
||||
return EasyMapFromByte(byteData)
|
||||
}
|
||||
|
||||
// EasyMapFromString 从string转为Map
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:12 2023/8/10
|
||||
func EasyMapFromString(data string) Map {
|
||||
return EasyMapFromByte([]byte(data))
|
||||
}
|
||||
|
||||
// EasyMapFromByte 从字节数组转为Map
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:12 2023/8/10
|
||||
func EasyMapFromByte(data []byte) Map {
|
||||
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 ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 15:14 2023/8/10
|
||||
type Map easymap.EasyMap
|
24
object.go
24
object.go
@ -10,7 +10,7 @@ package wrapper
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"git.zhangdeman.cn/zhangdeman/util"
|
||||
"git.zhangdeman.cn/zhangdeman/serialize"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
@ -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"),
|
||||
@ -37,7 +37,7 @@ func ObjectData(data interface{}) *ObjectType {
|
||||
case reflect.Struct:
|
||||
ot.byteData, _ = json.Marshal(ot.source)
|
||||
default:
|
||||
// 数据类型不是 nil / map / struct 质疑
|
||||
// 数据类型不是 nil / map / struct 之一
|
||||
ot.isValid = false
|
||||
}
|
||||
return ot
|
||||
@ -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,13 +106,13 @@ 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() {
|
||||
return res
|
||||
}
|
||||
res.Err = util.JSON.UnmarshalWithNumber(ot.byteData, &res.Value)
|
||||
res.Err = serialize.JSON.UnmarshalWithNumber(ot.byteData, &res.Value)
|
||||
return res
|
||||
}
|
||||
|
||||
@ -121,14 +121,14 @@ 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")
|
||||
}
|
||||
if ot.IsNil() {
|
||||
return errors.New("data is nil")
|
||||
}
|
||||
return util.JSON.UnmarshalWithNumber(ot.byteData, receiver)
|
||||
return serialize.JSON.UnmarshalWithNumber(ot.byteData, receiver)
|
||||
}
|
||||
|
||||
// ToStructIgnoreErr ...
|
||||
@ -136,12 +136,12 @@ 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
|
||||
}
|
||||
if ot.IsNil() {
|
||||
return
|
||||
}
|
||||
_ = util.JSON.UnmarshalWithNumber(ot.byteData, receiver)
|
||||
_ = serialize.JSON.UnmarshalWithNumber(ot.byteData, receiver)
|
||||
}
|
||||
|
274
string.go
274
string.go
@ -9,12 +9,39 @@ package wrapper
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"git.zhangdeman.cn/zhangdeman/util"
|
||||
"git.zhangdeman.cn/zhangdeman/serialize"
|
||||
"github.com/axgle/mahonia"
|
||||
"github.com/spaolacci/murmur3"
|
||||
"io"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// StringFromRandom 从随机字符串生成String
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 14:50 2023/8/11
|
||||
func StringFromRandom(length int, sourceCharList string) String {
|
||||
if length == 0 {
|
||||
return ""
|
||||
}
|
||||
if len(sourceCharList) == 0 {
|
||||
//字符串为空,默认字符源为如下(去除易混淆的i/l):
|
||||
sourceCharList = "0123456789abcdefghjkmnopqrstuvwxyzABCDEFGHJKMNOPQRSTUVWXYZ"
|
||||
}
|
||||
strByte := []byte(sourceCharList)
|
||||
var genStrByte = make([]byte, 0)
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
for i := 0; i < int(length); i++ {
|
||||
genStrByte = append(genStrByte, strByte[r.Intn(len(strByte))])
|
||||
}
|
||||
return String(string(genStrByte))
|
||||
}
|
||||
|
||||
// String 字符串类型包装
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
@ -31,7 +58,7 @@ func (str String) ToFloat32() Float32Result {
|
||||
var (
|
||||
res Float32Result
|
||||
)
|
||||
res.Err = util.ConvertAssign(&res.Value, str)
|
||||
res.Err = ConvertAssign(&res.Value, str)
|
||||
return res
|
||||
}
|
||||
|
||||
@ -63,7 +90,7 @@ func (str String) ToFloat64() Float64Result {
|
||||
var (
|
||||
res Float64Result
|
||||
)
|
||||
res.Err = util.ConvertAssign(&res.Value, str)
|
||||
res.Err = ConvertAssign(&res.Value, str)
|
||||
return res
|
||||
}
|
||||
|
||||
@ -131,7 +158,7 @@ func (str String) ToInt8() Int8Result {
|
||||
var (
|
||||
res Int8Result
|
||||
)
|
||||
res.Err = util.ConvertAssign(&res.Value, str)
|
||||
res.Err = ConvertAssign(&res.Value, str)
|
||||
return res
|
||||
}
|
||||
|
||||
@ -163,7 +190,7 @@ func (str String) ToInt16() Int16Result {
|
||||
var (
|
||||
res Int16Result
|
||||
)
|
||||
res.Err = util.ConvertAssign(&res.Value, str)
|
||||
res.Err = ConvertAssign(&res.Value, str)
|
||||
return res
|
||||
}
|
||||
|
||||
@ -195,7 +222,7 @@ func (str String) ToInt32() Int32Result {
|
||||
var (
|
||||
res Int32Result
|
||||
)
|
||||
res.Err = util.ConvertAssign(&res.Value, str)
|
||||
res.Err = ConvertAssign(&res.Value, str)
|
||||
return res
|
||||
}
|
||||
|
||||
@ -227,7 +254,7 @@ func (str String) ToInt64() Int64Result {
|
||||
var (
|
||||
res Int64Result
|
||||
)
|
||||
res.Err = util.ConvertAssign(&res.Value, str)
|
||||
res.Err = ConvertAssign(&res.Value, str)
|
||||
return res
|
||||
}
|
||||
|
||||
@ -259,7 +286,7 @@ func (str String) ToInt() IntResult {
|
||||
var (
|
||||
res IntResult
|
||||
)
|
||||
res.Err = util.ConvertAssign(&res.Value, str)
|
||||
res.Err = ConvertAssign(&res.Value, str)
|
||||
return res
|
||||
}
|
||||
|
||||
@ -291,7 +318,7 @@ func (str String) ToUint8() Uint8Result {
|
||||
var (
|
||||
res Uint8Result
|
||||
)
|
||||
res.Err = util.ConvertAssign(&res.Value, str)
|
||||
res.Err = ConvertAssign(&res.Value, str)
|
||||
return res
|
||||
}
|
||||
|
||||
@ -323,7 +350,7 @@ func (str String) ToUint16() Uint16Result {
|
||||
var (
|
||||
res Uint16Result
|
||||
)
|
||||
res.Err = util.ConvertAssign(&res.Value, str)
|
||||
res.Err = ConvertAssign(&res.Value, str)
|
||||
return res
|
||||
}
|
||||
|
||||
@ -355,7 +382,7 @@ func (str String) ToUint32() Uint32Result {
|
||||
var (
|
||||
res Uint32Result
|
||||
)
|
||||
res.Err = util.ConvertAssign(&res.Value, str)
|
||||
res.Err = ConvertAssign(&res.Value, str)
|
||||
return res
|
||||
}
|
||||
|
||||
@ -387,7 +414,7 @@ func (str String) ToUint64() Uint64Result {
|
||||
var (
|
||||
res Uint64Result
|
||||
)
|
||||
res.Err = util.ConvertAssign(&res.Value, str)
|
||||
res.Err = ConvertAssign(&res.Value, str)
|
||||
return res
|
||||
}
|
||||
|
||||
@ -419,7 +446,7 @@ func (str String) ToUint() UintResult {
|
||||
var (
|
||||
res UintResult
|
||||
)
|
||||
res.Err = util.ConvertAssign(&res.Value, str)
|
||||
res.Err = ConvertAssign(&res.Value, str)
|
||||
return res
|
||||
}
|
||||
|
||||
@ -451,7 +478,7 @@ func (str String) ToBool() BoolResult {
|
||||
var (
|
||||
res BoolResult
|
||||
)
|
||||
res.Err = util.ConvertAssign(&res.Value, str)
|
||||
res.Err = ConvertAssign(&res.Value, str)
|
||||
return res
|
||||
}
|
||||
|
||||
@ -495,11 +522,11 @@ func (str String) ToStringPtr() StringPtrResult {
|
||||
func (str String) ToObject() ObjectResult {
|
||||
var (
|
||||
res = ObjectResult{
|
||||
Value: map[string]interface{}{},
|
||||
Value: map[string]any{},
|
||||
Err: nil,
|
||||
}
|
||||
)
|
||||
res.Err = util.JSON.UnmarshalWithNumber([]byte(str), &res.Value)
|
||||
res.Err = serialize.JSON.UnmarshalWithNumber([]byte(str), &res.Value)
|
||||
return res
|
||||
}
|
||||
|
||||
@ -508,11 +535,11 @@ 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")
|
||||
}
|
||||
return util.JSON.UnmarshalWithNumber([]byte(str), receiver)
|
||||
return serialize.JSON.UnmarshalWithNumber([]byte(str), receiver)
|
||||
}
|
||||
|
||||
// ToInt8Slice ...
|
||||
@ -527,7 +554,7 @@ func (str String) ToInt8Slice(splitChar ...string) Int8SliceResult {
|
||||
}
|
||||
isSplit := len(splitChar) > 0
|
||||
if !isSplit {
|
||||
result.Err = util.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
result.Err = serialize.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
return result
|
||||
}
|
||||
var (
|
||||
@ -561,7 +588,7 @@ func (str String) ToInt16Slice(splitChar ...string) Int16SliceResult {
|
||||
|
||||
isSplit := len(splitChar) > 0
|
||||
if !isSplit {
|
||||
result.Err = util.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
result.Err = serialize.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
return result
|
||||
}
|
||||
res := make([]int16, 0)
|
||||
@ -591,7 +618,7 @@ func (str String) ToInt32Slice(splitChar ...string) Int32SliceResult {
|
||||
|
||||
isSplit := len(splitChar) > 0
|
||||
if !isSplit {
|
||||
result.Err = util.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
result.Err = serialize.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
return result
|
||||
}
|
||||
res := make([]int32, 0)
|
||||
@ -621,7 +648,7 @@ func (str String) ToInt64Slice(splitChar ...string) Int64SliceResult {
|
||||
|
||||
isSplit := len(splitChar) > 0
|
||||
if !isSplit {
|
||||
result.Err = util.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
result.Err = serialize.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
return result
|
||||
}
|
||||
res := make([]int64, 0)
|
||||
@ -650,7 +677,7 @@ func (str String) ToIntSlice(splitChar ...string) IntSliceResult {
|
||||
|
||||
isSplit := len(splitChar) > 0
|
||||
if !isSplit {
|
||||
result.Err = util.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
result.Err = serialize.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
return result
|
||||
}
|
||||
res := make([]int, 0)
|
||||
@ -680,7 +707,7 @@ func (str String) ToUint8Slice(splitChar ...string) Uint8SliceResult {
|
||||
|
||||
isSplit := len(splitChar) > 0
|
||||
if !isSplit {
|
||||
result.Err = util.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
result.Err = serialize.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
return result
|
||||
}
|
||||
res := make([]uint8, 0)
|
||||
@ -710,7 +737,7 @@ func (str String) ToUint16Slice(splitChar ...string) Uint16SliceResult {
|
||||
|
||||
isSplit := len(splitChar) > 0
|
||||
if !isSplit {
|
||||
result.Err = util.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
result.Err = serialize.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
return result
|
||||
}
|
||||
res := make([]uint16, 0)
|
||||
@ -740,7 +767,7 @@ func (str String) ToUint32Slice(splitChar ...string) Uint32SliceResult {
|
||||
|
||||
isSplit := len(splitChar) > 0
|
||||
if !isSplit {
|
||||
result.Err = util.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
result.Err = serialize.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
return result
|
||||
}
|
||||
res := make([]uint32, 0)
|
||||
@ -770,7 +797,7 @@ func (str String) ToUint64Slice(splitChar ...string) Uint64SliceResult {
|
||||
|
||||
isSplit := len(splitChar) > 0
|
||||
if !isSplit {
|
||||
result.Err = util.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
result.Err = serialize.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
return result
|
||||
}
|
||||
res := make([]uint64, 0)
|
||||
@ -799,7 +826,7 @@ func (str String) ToUintSlice(splitChar ...string) UintSliceResult {
|
||||
|
||||
isSplit := len(splitChar) > 0
|
||||
if !isSplit {
|
||||
result.Err = util.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
result.Err = serialize.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
return result
|
||||
}
|
||||
res := make([]uint, 0)
|
||||
@ -829,7 +856,7 @@ func (str String) ToBoolSlice(splitChar ...string) BoolSliceResult {
|
||||
|
||||
isSplit := len(splitChar) > 0
|
||||
if !isSplit {
|
||||
result.Err = util.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
result.Err = serialize.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
return result
|
||||
}
|
||||
res := make([]bool, 0)
|
||||
@ -859,7 +886,7 @@ func (str String) ToFloat32Slice(splitChar ...string) Float32SliceResult {
|
||||
|
||||
isSplit := len(splitChar) > 0
|
||||
if !isSplit {
|
||||
result.Err = util.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
result.Err = serialize.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
return result
|
||||
}
|
||||
res := make([]float32, 0)
|
||||
@ -888,7 +915,7 @@ func (str String) ToFloat64Slice(splitChar ...string) Float64SliceResult {
|
||||
|
||||
isSplit := len(splitChar) > 0
|
||||
if !isSplit {
|
||||
result.Err = util.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
result.Err = serialize.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
return result
|
||||
}
|
||||
res := make([]float64, 0)
|
||||
@ -923,6 +950,22 @@ func (str String) ToNumberSlice(splitChar ...string) Float64SliceResult {
|
||||
return str.ToFloat64Slice(splitChar...)
|
||||
}
|
||||
|
||||
// ToDuration 转换为时间格式
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 20:31 2023/9/4
|
||||
func (str String) ToDuration(timeUnit time.Duration) DurationResult {
|
||||
int64Val := str.ToInt64()
|
||||
if nil != int64Val.Err {
|
||||
return DurationResult{
|
||||
Value: 0,
|
||||
Err: int64Val.Err,
|
||||
}
|
||||
}
|
||||
return Int(int64Val.Value).ToDuration(timeUnit)
|
||||
}
|
||||
|
||||
// ToStringSlice ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
@ -936,7 +979,7 @@ func (str String) ToStringSlice(splitChar ...string) StringSliceResult {
|
||||
|
||||
isSplit := len(splitChar) > 0
|
||||
if !isSplit {
|
||||
result.Err = util.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
result.Err = serialize.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
return result
|
||||
}
|
||||
result.Value = strings.Split(string(str), splitChar[0])
|
||||
@ -948,13 +991,34 @@ func (str String) ToStringSlice(splitChar ...string) StringSliceResult {
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 15:01 2023/5/5
|
||||
func (str String) ToAnySlice() AnySliceResult {
|
||||
func (str String) ToAnySlice(splitCharList ...string) AnySliceResult {
|
||||
result := AnySliceResult{
|
||||
Value: []interface{}{},
|
||||
Value: []any{},
|
||||
Err: nil,
|
||||
}
|
||||
|
||||
result.Err = util.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
if len(splitCharList) == 0 {
|
||||
result.Err = serialize.JSON.UnmarshalWithNumber([]byte(str), &result.Value)
|
||||
return result
|
||||
}
|
||||
|
||||
valArr := strings.Split(str.Value(), splitCharList[0])
|
||||
valList := make([]any, 0)
|
||||
for _, item := range valArr {
|
||||
v := String(item)
|
||||
if res := v.ToInt64(); nil == res.Err {
|
||||
valList = append(valList, res.Value)
|
||||
} else if res := v.ToUint64(); nil == res.Err {
|
||||
valList = append(valList, res.Value)
|
||||
} else if res := v.ToFloat64(); nil == res.Err {
|
||||
valList = append(valList, res.Value)
|
||||
} else if res := v.ToBool(); nil == res.Err {
|
||||
valList = append(valList, res.Value)
|
||||
} else {
|
||||
valList = append(valList, item)
|
||||
}
|
||||
}
|
||||
result.Value = valList
|
||||
return result
|
||||
}
|
||||
|
||||
@ -973,7 +1037,7 @@ func (str String) Md5() StringResult {
|
||||
}
|
||||
}
|
||||
return StringResult{
|
||||
Value: string(h.Sum(nil)),
|
||||
Value: hex.EncodeToString(h.Sum(nil)),
|
||||
Err: nil,
|
||||
}
|
||||
}
|
||||
@ -986,3 +1050,141 @@ func (str String) Md5() StringResult {
|
||||
func (str String) Value() string {
|
||||
return string(str)
|
||||
}
|
||||
|
||||
// GetLetterList 获取字母列表
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 14:53 2023/8/11
|
||||
func (str String) GetLetterList() []string {
|
||||
return []string{
|
||||
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
|
||||
"o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
|
||||
}
|
||||
}
|
||||
|
||||
// SnakeCaseToCamel 蛇形字符串转换为驼峰
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 4:58 下午 2021/10/25
|
||||
func (str String) SnakeCaseToCamel() string {
|
||||
if len(str) == 0 {
|
||||
return ""
|
||||
}
|
||||
builder := strings.Builder{}
|
||||
index := 0
|
||||
if str[0] >= 'a' && str[0] <= 'z' {
|
||||
builder.WriteByte(str[0] - ('a' - 'A'))
|
||||
index = 1
|
||||
}
|
||||
for i := index; i < len(str); i++ {
|
||||
if str[i] == '_' && i+1 < len(str) {
|
||||
if str[i+1] >= 'a' && str[i+1] <= 'z' {
|
||||
builder.WriteByte(str[i+1] - ('a' - 'A'))
|
||||
i++
|
||||
continue
|
||||
}
|
||||
}
|
||||
// 将ID转为大写
|
||||
if str[i] == 'd' && i-1 >= 0 && (str[i-1] == 'i' || str[i-1] == 'I') && (i+1 == len(str) || i+1 < len(str) && str[i+1] == '_') {
|
||||
builder.WriteByte('d' - ('a' - 'A'))
|
||||
continue
|
||||
}
|
||||
builder.WriteByte(str[i])
|
||||
}
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
// Convert 字符串编码转换
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 14:38 2022/7/9
|
||||
func (str String) Convert(sourceCode string, targetCode string) String {
|
||||
sourceCoder := mahonia.NewDecoder(sourceCode)
|
||||
sourceResult := sourceCoder.ConvertString(str.Value())
|
||||
targetCoder := mahonia.NewDecoder(targetCode)
|
||||
_, cdata, _ := targetCoder.Translate([]byte(sourceResult), true)
|
||||
return String(string(cdata))
|
||||
}
|
||||
|
||||
// ClearChar 清理指定字符
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 14:59 2023/8/11
|
||||
func (str String) ClearChar(charList ...string) String {
|
||||
if len(charList) == 0 {
|
||||
return str
|
||||
}
|
||||
formatStr := str.Value()
|
||||
for _, item := range charList {
|
||||
formatStr = strings.ReplaceAll(formatStr, item, "")
|
||||
}
|
||||
return String(formatStr)
|
||||
}
|
||||
|
||||
// ReplaceChineseChar 替换常见的中文符号
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:59 2023/4/4
|
||||
func (str String) ReplaceChineseChar() String {
|
||||
charTable := map[string]string{
|
||||
"(": "(",
|
||||
")": ")",
|
||||
":": ":",
|
||||
",": ",",
|
||||
"。": ".",
|
||||
"【": "]",
|
||||
"】": "]",
|
||||
}
|
||||
return str.ReplaceChar(charTable)
|
||||
}
|
||||
|
||||
// ReplaceChar 替换指定字符
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 15:01 2023/8/11
|
||||
func (str String) ReplaceChar(charTable map[string]string) String {
|
||||
if len(charTable) == 0 {
|
||||
return str
|
||||
}
|
||||
formatStr := str.Value()
|
||||
for k, v := range charTable {
|
||||
formatStr = strings.ReplaceAll(formatStr, k, v)
|
||||
}
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
@ -23,3 +23,9 @@ func TestString_ToFloat32(t *testing.T) {
|
||||
fmt.Println(str.ToInt())
|
||||
fmt.Println(str.ToUint())
|
||||
}
|
||||
|
||||
func TestString_ToAnySlice(t *testing.T) {
|
||||
str := "1,2,3"
|
||||
r := String(str).ToAnySlice(",")
|
||||
fmt.Println(r)
|
||||
}
|
||||
|
69
struct.go
Normal file
69
struct.go
Normal file
@ -0,0 +1,69 @@
|
||||
// Package wrapper ...
|
||||
//
|
||||
// Description : wrapper ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2023-08-10 16:05
|
||||
package wrapper
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// NewStruct 包装的数据类型
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:07 2023/8/10
|
||||
func NewStruct(data any) *Struct {
|
||||
s, _ := NewStructWithError(data)
|
||||
return s
|
||||
}
|
||||
|
||||
// NewStructWithError ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:17 2023/8/10
|
||||
func NewStructWithError(data any) (*Struct, error) {
|
||||
if data == nil {
|
||||
return nil, errors.New("input data is nil")
|
||||
}
|
||||
reflectType := reflect.TypeOf(data)
|
||||
if reflectType.Kind() == reflect.Ptr {
|
||||
reflectType = reflectType.Elem()
|
||||
if reflectType.Kind() != reflect.Struct {
|
||||
return nil, errors.New("input data type is " + reflectType.Elem().Kind().String())
|
||||
}
|
||||
}
|
||||
return &Struct{data: data}, nil
|
||||
}
|
||||
|
||||
// Struct 结构体类型
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:05 2023/8/10
|
||||
type Struct struct {
|
||||
data any
|
||||
}
|
||||
|
||||
// ToMap 转为Map
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:08 2023/8/10
|
||||
func (s *Struct) ToMap() MapResult {
|
||||
if nil == s.data {
|
||||
return MapResult{
|
||||
Value: EasyMap(map[any]any{}),
|
||||
Err: nil,
|
||||
}
|
||||
}
|
||||
return MapResult{
|
||||
Value: EasyMapFromStruct(s.data),
|
||||
Err: nil,
|
||||
}
|
||||
}
|
157
ternary_operator.go
Normal file
157
ternary_operator.go
Normal file
@ -0,0 +1,157 @@
|
||||
// Package wrapper ...
|
||||
//
|
||||
// Description : wrapper ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2023-11-28 16:05
|
||||
package wrapper
|
||||
|
||||
var (
|
||||
// TernaryOperator 三元运算符操作实例
|
||||
TernaryOperator = &ternaryOperator{}
|
||||
)
|
||||
|
||||
// ternaryOperator ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:06 2023/11/28
|
||||
type ternaryOperator struct {
|
||||
}
|
||||
|
||||
// CondFunc ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:10 2023/11/28
|
||||
type CondFunc func() bool
|
||||
|
||||
// defaultCondFunc ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:11 2023/11/28
|
||||
func defaultCondFunc() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Int ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:10 2023/11/28
|
||||
func (to *ternaryOperator) Int(cond bool, trueVal Int, falseVal Int) Int {
|
||||
if cond {
|
||||
return trueVal
|
||||
}
|
||||
return falseVal
|
||||
}
|
||||
|
||||
// IntWithFunc ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:11 2023/11/28
|
||||
func (to *ternaryOperator) IntWithFunc(condFunc CondFunc, trueVal Int, falseVal Int) Int {
|
||||
if nil == condFunc {
|
||||
condFunc = defaultCondFunc
|
||||
}
|
||||
return to.Int(condFunc(), trueVal, falseVal)
|
||||
}
|
||||
|
||||
// Float ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:10 2023/11/28
|
||||
func (to *ternaryOperator) Float(cond bool, trueVal Float, falseVal Float) Float {
|
||||
if cond {
|
||||
return trueVal
|
||||
}
|
||||
return falseVal
|
||||
}
|
||||
|
||||
// FloatWithFunc ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:13 2023/11/28
|
||||
func (to *ternaryOperator) FloatWithFunc(condFunc CondFunc, trueVal Float, falseVal Float) Float {
|
||||
if nil == condFunc {
|
||||
condFunc = defaultCondFunc
|
||||
}
|
||||
return to.Float(condFunc(), trueVal, falseVal)
|
||||
}
|
||||
|
||||
// String ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:15 2023/11/28
|
||||
func (to *ternaryOperator) String(cond bool, trueVal String, falseVal String) String {
|
||||
if cond {
|
||||
return trueVal
|
||||
}
|
||||
return falseVal
|
||||
}
|
||||
|
||||
// StringWithFunc ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:15 2023/11/28
|
||||
func (to *ternaryOperator) StringWithFunc(condFunc CondFunc, trueVal String, falseVal String) String {
|
||||
if nil == condFunc {
|
||||
condFunc = defaultCondFunc
|
||||
}
|
||||
return to.String(condFunc(), trueVal, falseVal)
|
||||
}
|
||||
|
||||
// Map ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:25 2023/11/28
|
||||
func (to *ternaryOperator) Map(cond bool, trueVal Map, falseVal Map) Map {
|
||||
if cond {
|
||||
return trueVal
|
||||
}
|
||||
return falseVal
|
||||
}
|
||||
|
||||
// MapWithFunc ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:24 2023/11/28
|
||||
func (to *ternaryOperator) MapWithFunc(condFunc CondFunc, trueVal Map, falseVal Map) Map {
|
||||
if nil == condFunc {
|
||||
condFunc = defaultCondFunc
|
||||
}
|
||||
return falseVal
|
||||
}
|
||||
|
||||
// Any ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:26 2023/11/28
|
||||
func (to *ternaryOperator) Any(cond bool, trueVal *AnyType, falseVal *AnyType) *AnyType {
|
||||
if cond {
|
||||
return trueVal
|
||||
}
|
||||
return falseVal
|
||||
}
|
||||
|
||||
// AnyWithFunc ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 16:24 2023/11/28
|
||||
func (to *ternaryOperator) AnyWithFunc(condFunc CondFunc, trueVal *AnyType, falseVal *AnyType) *AnyType {
|
||||
if nil == condFunc {
|
||||
condFunc = defaultCondFunc
|
||||
}
|
||||
return to.Any(condFunc(), trueVal, falseVal)
|
||||
}
|
166
time.go
Normal file
166
time.go
Normal file
@ -0,0 +1,166 @@
|
||||
// Package wrapper ...
|
||||
//
|
||||
// Description : wrapper ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2023-08-09 18:22
|
||||
package wrapper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// StandTimeFormat 标准时间格式
|
||||
StandTimeFormat = "2006-01-02 15:04:05"
|
||||
// StandISO8601Time 标准ISO时间格式
|
||||
StandISO8601Time = "2006-01-02T15:04:05+08:00"
|
||||
)
|
||||
|
||||
// OwnTime ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 18:28 2023/8/9
|
||||
func OwnTime(inputTime time.Time) *Time {
|
||||
instance := &Time{}
|
||||
instance.Time = inputTime
|
||||
return instance
|
||||
}
|
||||
|
||||
// OwnTimeFromNow 从当前时间获取实例
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 12:44 2023/8/10
|
||||
func OwnTimeFromNow() *Time {
|
||||
return OwnTime(time.Now())
|
||||
}
|
||||
|
||||
// OwnTimeFromSecond 从秒获取实例
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 18:47 2023/8/9
|
||||
func OwnTimeFromSecond(second int64) *Time {
|
||||
t := time.UnixMilli(second * 1000)
|
||||
return OwnTime(t)
|
||||
}
|
||||
|
||||
// OwnTimeFromMilli 从ms获取实例
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 18:56 2023/8/9
|
||||
func OwnTimeFromMilli(milli int64) *Time {
|
||||
t := time.UnixMilli(milli)
|
||||
return OwnTime(t)
|
||||
}
|
||||
|
||||
// OwnTimeFromMicro 从微秒获取实例
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 19:00 2023/8/9
|
||||
func OwnTimeFromMicro(micro int64) *Time {
|
||||
t := time.UnixMicro(micro)
|
||||
return OwnTime(t)
|
||||
}
|
||||
|
||||
// OwnTimeFromNano 从纳秒获取实例
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 19:00 2023/8/9
|
||||
func OwnTimeFromNano(nano int64) *Time {
|
||||
t := time.Unix(nano/1e9, nano%1e9)
|
||||
return OwnTime(t)
|
||||
}
|
||||
|
||||
// OwnTimeFromISO8601Time ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 11:02 2023/8/10
|
||||
func OwnTimeFromISO8601Time(parseTime string, layout ...string) *Time {
|
||||
var (
|
||||
err error
|
||||
)
|
||||
|
||||
ownTime := &Time{}
|
||||
|
||||
if ownTime.Time, err = time.Parse(ownTime.getTimeFormat(StandISO8601Time, layout...), parseTime); nil != err {
|
||||
return ownTime
|
||||
}
|
||||
return ownTime
|
||||
}
|
||||
|
||||
// Time 时间类型
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 18:23 2023/8/9
|
||||
type Time struct {
|
||||
time.Time
|
||||
}
|
||||
|
||||
// GetCurrentFormatTime 获取当前时间的格式化时间(秒)
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 1:34 上午 2021/10/7
|
||||
func (t *Time) GetCurrentFormatTime(layout ...string) string {
|
||||
return time.Now().In(time.Local).Format(t.getTimeFormat(StandTimeFormat, layout...))
|
||||
}
|
||||
|
||||
// FormatUnixNano 格式化纳秒时间戳
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 11:54 2022/7/14
|
||||
func (t *Time) FormatUnixNano(layout ...string) string {
|
||||
nano := t.UnixNano() % 1e6
|
||||
return t.FormatUnixMilli(layout...) + fmt.Sprintf(" %v", nano)
|
||||
}
|
||||
|
||||
// FormatUnixMilli 格式化毫秒时间戳
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 11:55 2022/7/14
|
||||
func (t *Time) FormatUnixMilli(layout ...string) string {
|
||||
return time.UnixMilli(t.UnixMilli()).In(time.Local).
|
||||
Format(t.getTimeFormat(StandTimeFormat, layout...)) + fmt.Sprintf(".%v", t.UnixMilli()%1000)
|
||||
}
|
||||
|
||||
// FormatUnixSec 格式化秒级时间戳
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 12:06 2022/7/14
|
||||
func (t *Time) FormatUnixSec(layout ...string) string {
|
||||
return time.Unix(t.Unix(), 0).In(time.Local).Format(t.getTimeFormat(StandTimeFormat, layout...))
|
||||
}
|
||||
|
||||
// ToString 转字符串
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 12:16 2023/8/10
|
||||
func (t *Time) ToString(layout ...string) string {
|
||||
return t.FormatUnixSec(layout...)
|
||||
}
|
||||
|
||||
// getTimeFormat 获取时间格式
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 18:37 2023/8/9
|
||||
func (t *Time) getTimeFormat(defaultFormat string, layout ...string) string {
|
||||
if len(layout) > 0 && len(layout[0]) > 0 {
|
||||
return layout[0]
|
||||
}
|
||||
return defaultFormat
|
||||
}
|
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相等")
|
||||
}
|
15
tool/define/version.go
Normal file
15
tool/define/version.go
Normal file
@ -0,0 +1,15 @@
|
||||
// Package define ...
|
||||
//
|
||||
// Description : define ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2023-12-27 17:08
|
||||
package define
|
||||
|
||||
const (
|
||||
VersionCompareFail = -2 // 版本比较失败
|
||||
VersionOneMax = -1 // 第一个版本号大
|
||||
VersionEqual = 0 // 两个版本号相等
|
||||
VersionTwoMax = 1 // 第二个版本号大
|
||||
)
|
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
|
||||
}
|
98
tool/version.go
Normal file
98
tool/version.go
Normal file
@ -0,0 +1,98 @@
|
||||
// Package tool ...
|
||||
//
|
||||
// Description : util ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2023-12-27 17:06
|
||||
package tool
|
||||
|
||||
import (
|
||||
"git.zhangdeman.cn/zhangdeman/wrapper"
|
||||
"git.zhangdeman.cn/zhangdeman/wrapper/tool/define"
|
||||
)
|
||||
|
||||
var (
|
||||
Version = &version{}
|
||||
)
|
||||
|
||||
type version struct {
|
||||
}
|
||||
|
||||
// getVersionArr 解析版本号
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 17:42 2023/12/27
|
||||
func (v *version) getVersionArr(versionOne string, versionTwo string) ([]int64, []int64, error) {
|
||||
oneWrapper := wrapper.String(versionOne).ToInt64Slice(".")
|
||||
twoWrapper := wrapper.String(versionTwo).ToInt64Slice(".")
|
||||
if oneWrapper.Err != nil {
|
||||
return nil, nil, oneWrapper.Err
|
||||
}
|
||||
if twoWrapper.Err != nil {
|
||||
return nil, nil, twoWrapper.Err
|
||||
}
|
||||
return oneWrapper.Value, twoWrapper.Value, nil
|
||||
}
|
||||
|
||||
// Compare 比较版本号的大小, 版本号格式必须是 x.y.z 的形式,几个 . 不限制, x、y、z 必须是是数字
|
||||
//
|
||||
// strictMode 严格模式, 非严格模式下, 2.4 == 2.4.0 , 开启严格模式, 则认为 2.4 < 2.4.0 , 因为 2.4 没有小版本号
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 17:07 2023/12/27
|
||||
func (v *version) Compare(versionOne string, versionTwo string, strictMode bool) (int, error) {
|
||||
oneVersionArr, twoVersionArr, err := v.getVersionArr(versionOne, versionTwo)
|
||||
if nil != err {
|
||||
return define.VersionCompareFail, err
|
||||
}
|
||||
oneVersionLength := len(oneVersionArr)
|
||||
twoVersionLength := len(twoVersionArr)
|
||||
// 版本号长度不一致补位
|
||||
if oneVersionLength > twoVersionLength {
|
||||
for fill := 0; fill < oneVersionLength-twoVersionLength; fill++ {
|
||||
twoVersionArr = append(twoVersionArr, 0)
|
||||
}
|
||||
}
|
||||
if oneVersionLength < twoVersionLength {
|
||||
for fill := 0; fill < twoVersionLength-oneVersionLength; fill++ {
|
||||
oneVersionArr = append(oneVersionArr, 0)
|
||||
}
|
||||
}
|
||||
|
||||
// 开始比较
|
||||
for offset := 0; offset < len(oneVersionArr); offset++ {
|
||||
if oneVersionArr[offset] == twoVersionArr[offset] {
|
||||
// 当前位版本相等
|
||||
continue
|
||||
}
|
||||
if oneVersionArr[offset] > twoVersionArr[offset] {
|
||||
// 第一个版本号大
|
||||
return define.VersionOneMax, nil
|
||||
} else {
|
||||
// 第二个版本号大
|
||||
return define.VersionTwoMax, nil
|
||||
}
|
||||
}
|
||||
// 版本号一致, 判断严格模式与非严格模式
|
||||
if !strictMode || oneVersionLength == twoVersionLength {
|
||||
return define.VersionEqual, nil
|
||||
}
|
||||
return wrapper.TernaryOperator.Int(
|
||||
oneVersionLength > twoVersionLength,
|
||||
wrapper.Int(define.VersionOneMax),
|
||||
wrapper.Int(define.VersionTwoMax),
|
||||
).ToInt().Value, nil
|
||||
}
|
||||
|
||||
// CompareIgnoreError 忽略error
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 18:20 2023/12/27
|
||||
func (v *version) CompareIgnoreError(versionOne string, versionTwo string, strictMode bool) int {
|
||||
res, _ := v.Compare(versionOne, versionTwo, strictMode)
|
||||
return res
|
||||
}
|
22
tool/version_test.go
Normal file
22
tool/version_test.go
Normal file
@ -0,0 +1,22 @@
|
||||
// Package tool ...
|
||||
//
|
||||
// Description : tool ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2023-12-27 17:51
|
||||
package tool
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_version_Compare(t *testing.T) {
|
||||
fmt.Println(Version.Compare("2.4.1", "2.4.1.0", true))
|
||||
fmt.Println(Version.Compare("2.4.1", "2.4.1.0", false))
|
||||
fmt.Println(Version.Compare("2.4.0", "2.4.1", true))
|
||||
fmt.Println(Version.Compare("2.4.2", "2.4.1", true))
|
||||
fmt.Println(Version.Compare("2.4", "2.4.1", true))
|
||||
fmt.Println(Version.Compare("2.4.2", "2.4", true))
|
||||
}
|
35
try/abstract.go
Normal file
35
try/abstract.go
Normal file
@ -0,0 +1,35 @@
|
||||
// Package try ...
|
||||
//
|
||||
// Description : try ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2023-07-20 11:26
|
||||
package try
|
||||
|
||||
// ICatchHandler 异常处理器接口约束
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 11:26 2023/7/20
|
||||
type ICatchHandler interface {
|
||||
Catch(errCode string, handler func(errCode string, data map[string]any)) ICatchHandler
|
||||
CatchAll(handler func(errCode string, data map[string]any)) IFinalHandler
|
||||
IFinalHandler
|
||||
}
|
||||
|
||||
// IFinalHandler 所有异常 / 逻辑执行成功之后的逻辑
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 11:27 2023/7/20
|
||||
type IFinalHandler interface {
|
||||
Finally(data map[string]any, handlers ...func(data map[string]any))
|
||||
}
|
||||
|
||||
// ILogicFunction 逻辑函数约束
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 11:29 2023/7/20
|
||||
type ILogicFunction func(input *LogicFuncInput) LogicFuncOutput
|
95
try/default.go
Normal file
95
try/default.go
Normal file
@ -0,0 +1,95 @@
|
||||
// Package try ...
|
||||
//
|
||||
// Description : try ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2023-07-20 12:13
|
||||
package try
|
||||
|
||||
// DefaultCatchHandler catch handler默认实现
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 12:14 2023/7/20
|
||||
type DefaultCatchHandler struct {
|
||||
hasDeal bool // 异常是否已被处理
|
||||
errCode string
|
||||
data map[string]any
|
||||
}
|
||||
|
||||
// hasDealError 判断异常是否已经被处理
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 12:46 2023/7/20
|
||||
func (d *DefaultCatchHandler) hasDealError() bool {
|
||||
if d.hasDeal {
|
||||
return true
|
||||
}
|
||||
if d.errCode == "" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Catch 处理指定errorCode
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 17:19 2023/7/20
|
||||
func (d *DefaultCatchHandler) Catch(errCode string, handler func(errCode string, data map[string]any)) ICatchHandler {
|
||||
if d.hasDealError() {
|
||||
return d
|
||||
}
|
||||
if errCode != d.errCode {
|
||||
return d
|
||||
}
|
||||
d.hasDeal = true
|
||||
defer func() {
|
||||
if r := recover(); nil != r {
|
||||
d.hasDeal = false
|
||||
d.data[errCode+"_handler_error"] = r.(error).Error()
|
||||
}
|
||||
}()
|
||||
handler(d.errCode, d.data)
|
||||
return d
|
||||
}
|
||||
|
||||
// CatchAll 捕捉任意一场
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 17:47 2023/7/20
|
||||
func (d *DefaultCatchHandler) CatchAll(handler func(errCode string, data map[string]any)) IFinalHandler {
|
||||
if d.hasDealError() {
|
||||
return d
|
||||
}
|
||||
defer func() {
|
||||
if r := recover(); nil != r {
|
||||
d.data[d.errCode+"_handler_error"] = r.(error).Error()
|
||||
}
|
||||
}()
|
||||
d.hasDeal = true
|
||||
handler(d.errCode, d.data)
|
||||
return d
|
||||
}
|
||||
|
||||
// Finally 最终逻辑
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 17:48 2023/7/20
|
||||
func (d *DefaultCatchHandler) Finally(data map[string]any, handlers ...func(data map[string]any)) {
|
||||
if data == nil {
|
||||
data = map[string]any{}
|
||||
}
|
||||
defer func() {
|
||||
if r := recover(); nil != r {
|
||||
|
||||
}
|
||||
}()
|
||||
for _, itemHandler := range handlers {
|
||||
itemHandler(data)
|
||||
}
|
||||
}
|
50
try/define.go
Normal file
50
try/define.go
Normal file
@ -0,0 +1,50 @@
|
||||
// Package try ...
|
||||
//
|
||||
// Description : try ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2023-07-20 11:29
|
||||
package try
|
||||
|
||||
// LogicFuncInput 逻辑函数输入参数
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 11:30 2023/7/20
|
||||
type LogicFuncInput struct {
|
||||
Parameter map[string]any
|
||||
}
|
||||
|
||||
// LogicFuncOutput ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 11:30 2023/7/20
|
||||
type LogicFuncOutput struct {
|
||||
ErrCode string // 错误标识码
|
||||
Data map[string]any // 错误时返回的数据
|
||||
}
|
||||
|
||||
// NewLogicFuncOutput 获取逻辑函数输出数据
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 11:33 2023/7/20
|
||||
func NewLogicFuncOutput(code string, data map[string]any) LogicFuncOutput {
|
||||
if data == nil {
|
||||
data = map[string]any{}
|
||||
}
|
||||
r := LogicFuncOutput{
|
||||
ErrCode: code,
|
||||
Data: data,
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
const (
|
||||
// NilLogicFunc 。。。
|
||||
NilLogicFunc = "NIL_LOGIC_FUNC"
|
||||
// LogicFuncPanic ...
|
||||
LogicFuncPanic = "LOGIC_FUNC_PANIC"
|
||||
)
|
41
try/try.go
Normal file
41
try/try.go
Normal file
@ -0,0 +1,41 @@
|
||||
// Package try ...
|
||||
//
|
||||
// Description : try ...
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 2023-07-20 11:36
|
||||
package try
|
||||
|
||||
// Try try入口函数
|
||||
//
|
||||
// Author : go_developer@163.com<白茶清欢>
|
||||
//
|
||||
// Date : 11:37 2023/7/20
|
||||
func Try(fn ILogicFunction, input *LogicFuncInput) ICatchHandler {
|
||||
catchHandler := &DefaultCatchHandler{}
|
||||
if nil == fn {
|
||||
// 逻辑函数空指针
|
||||
catchHandler.errCode = NilLogicFunc
|
||||
return catchHandler
|
||||
}
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
catchHandler.errCode = LogicFuncPanic
|
||||
catchHandler.data = map[string]any{
|
||||
"message": r.(error).Error(),
|
||||
}
|
||||
}
|
||||
}()
|
||||
if nil == input {
|
||||
input = &LogicFuncInput{
|
||||
Parameter: map[string]any{},
|
||||
}
|
||||
}
|
||||
|
||||
result := fn(input)
|
||||
catchHandler.errCode = result.ErrCode
|
||||
catchHandler.data = result.Data
|
||||
|
||||
return catchHandler
|
||||
}
|
Reference in New Issue
Block a user