json_filter/gjson_hack/precision.go

470 lines
13 KiB
Go

// Package gjson_hack 精确地类型转换
//
// Description : gjson_hack ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2024-11-27 10:47
package gjson_hack
import (
"errors"
"git.zhangdeman.cn/zhangdeman/consts"
"git.zhangdeman.cn/zhangdeman/exception"
"git.zhangdeman.cn/zhangdeman/serialize"
"git.zhangdeman.cn/zhangdeman/util"
"git.zhangdeman.cn/zhangdeman/wrapper"
"github.com/tidwall/gjson"
"strings"
)
// Number 结果转换为数字(int64 / uint64 / float64)
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 10:57 2024/11/27
func Number(gjsonResult gjson.Result, numberReceiver any) error {
if !gjsonResult.Exists() {
return errors.New("gjson result not found")
}
if gjsonResult.Type != gjson.Number {
return errors.New(gjsonResult.String() + " : value not a number")
}
if err := util.ConvertAssign(numberReceiver, gjsonResult.String()); nil != err {
return errors.New(gjsonResult.String() + " : convert to num fail -> " + err.Error())
}
return nil
}
// Int 转int
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 11:19 2024/11/27
func Int[T int8 | int16 | int32 | int64 | int](gjsonResult gjson.Result) (T, error) {
var intResult T
if err := Number(gjsonResult, &intResult); nil != err {
return 0, err
}
return intResult, nil
}
// Uint 转为uint64
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 11:21 2024/11/27
func Uint[T uint8 | uint16 | uint32 | uint64 | uint](gjsonResult gjson.Result) (T, error) {
var uintResult T
if err := Number(gjsonResult, &uintResult); nil != err {
return 0, err
}
return uintResult, nil
}
// Float 转为float64
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 11:24 2024/11/27
func Float[T float32 | float64](gjsonResult gjson.Result) (T, error) {
var floatResult T
if err := Number(gjsonResult, &floatResult); nil != err {
return 0, err
}
return floatResult, nil
}
// String 获取字符串值
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 10:55 2024/12/1
func String(sourceValue gjson.Result, defaultValue string) string {
sourceValueStr := defaultValue
if sourceValue.Exists() {
str := sourceValue.String()
if len(str) > 0 {
sourceValueStr = str
}
}
return sourceValueStr
}
// MapAnyAny ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 17:48 2024/12/1
func MapAnyAny(sourceValue gjson.Result) (map[string]any, error) {
if !sourceValue.Exists() {
return nil, exception.New(ErrDataPathNotFound, nil, "data path not found")
}
if !sourceValue.IsObject() {
return nil, exception.New(ErrDataIsNotObject, nil)
}
res := make(map[string]any)
sourceValue.ForEach(func(key, value gjson.Result) bool {
res[key.String()] = value
return true
})
return res, nil
}
// Any 获取任意类型的值
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 11:00 2024/12/1
func Any(sourceValue gjson.Result) (any, error) {
if !sourceValue.Exists() {
return nil, nil
}
// 可能存在精度丢失, 原因 : gjson.Value 内置的转换, int64 超过一定大小会存在丢失精度问题
if sourceValue.Type == gjson.Number {
// 说明是数字
if strings.Contains(sourceValue.String(), ".") {
// 小数
var res float64
if err := Number(sourceValue, &res); nil != err {
return nil, err
}
return res, nil
} else {
// 整数
if strings.HasPrefix(sourceValue.String(), "-") {
// 负数
var res int64
if err := Number(sourceValue, &res); nil != err {
return nil, err
}
return res, nil
} else {
// 正数
var res uint64
if err := Number(sourceValue, &res); nil != err {
return nil, err
}
return res, nil
}
}
}
if sourceValue.IsObject() {
return MapAnyAny(sourceValue)
}
if sourceValue.IsArray() {
return SliceAny(sourceValue)
}
return sourceValue.Value(), nil
}
// getRealDataType ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 14:28 2024/12/1
func getRealDataType(dataType consts.DataType, sourceValue gjson.Result) consts.DataType {
// 指针数据类型, 转换为普通数据类型处理
dataType = consts.DataType(strings.TrimLeft(dataType.String(), "*"))
// 没指定数据类型或者数据类型是any
if dataType == consts.DataTypeAny || dataType == "" {
if sourceValue.IsObject() {
dataType = consts.DataTypeMapAnyAny
} else if sourceValue.IsArray() {
dataType = consts.DataTypeSliceAny
} else if sourceValue.IsBool() {
dataType = consts.DataTypeBool
} else {
if sourceValue.Type == gjson.Number {
dataType = consts.DataTypeFloat64
} else if sourceValue.Type == gjson.String {
dataType = consts.DataTypeString
} else {
dataType = consts.DataTypeAny
}
}
}
return dataType
}
// SliceAny ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 17:53 2024/12/1
func SliceAny(gjsonResult gjson.Result) ([]any, error) {
if gjsonResult.Value() == nil {
return nil, nil
}
strVal := strings.TrimSpace(gjsonResult.String())
// 任意类型的list
if strings.HasPrefix(strVal, "[") && strings.HasSuffix(strVal, "]") {
// 序列化之后的数组
sliceVal := wrapper.String(strVal).ToAnySlice()
return sliceVal.Value, sliceVal.Err
}
// 分隔的数组
sliceVal := wrapper.String(strVal).ToAnySlice(",")
return sliceVal.Value, sliceVal.Err
}
// SliceInt 获取int list
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 14:43 2024/12/1
func SliceInt(gjsonResult gjson.Result) ([]int64, error) {
if gjsonResult.Value() == nil {
return nil, nil
}
strVal := strings.TrimSpace(gjsonResult.String())
// 任意类型的list
if strings.HasPrefix(strVal, "[") && strings.HasSuffix(strVal, "]") {
// 序列化之后的数组
sliceVal := wrapper.String(strVal).ToInt64Slice()
return sliceVal.Value, sliceVal.Err
}
// 分隔的数组
sliceVal := wrapper.String(strVal).ToInt64Slice(",")
return sliceVal.Value, sliceVal.Err
}
// SliceUint ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 14:58 2024/12/1
func SliceUint(gjsonResult gjson.Result) ([]uint64, error) {
if gjsonResult.Value() == nil {
return nil, nil
}
strVal := strings.TrimSpace(gjsonResult.String())
// 任意类型的list
if strings.HasPrefix(strVal, "[") && strings.HasSuffix(strVal, "]") {
// 序列化之后的数组
sliceVal := wrapper.String(strVal).ToUint64Slice()
return sliceVal.Value, sliceVal.Err
}
// 分隔的数组
sliceVal := wrapper.String(strVal).ToUint64Slice(",")
return sliceVal.Value, sliceVal.Err
}
// SliceFloat ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 14:59 2024/12/1
func SliceFloat(gjsonResult gjson.Result) ([]float64, error) {
if gjsonResult.Value() == nil {
return nil, nil
}
strVal := strings.TrimSpace(gjsonResult.String())
// 任意类型的list
if strings.HasPrefix(strVal, "[") && strings.HasSuffix(strVal, "]") {
// 序列化之后的数组
sliceVal := wrapper.String(strVal).ToFloat64Slice()
return sliceVal.Value, sliceVal.Err
}
// 分隔的数组
sliceVal := wrapper.String(strVal).ToFloat64Slice(",")
return sliceVal.Value, sliceVal.Err
}
// SliceBool ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 15:00 2024/12/1
func SliceBool(gjsonResult gjson.Result) ([]bool, error) {
if gjsonResult.Value() == nil {
return nil, nil
}
strVal := strings.TrimSpace(gjsonResult.String())
// 任意类型的list
if strings.HasPrefix(strVal, "[") && strings.HasSuffix(strVal, "]") {
// 序列化之后的数组
sliceVal := wrapper.String(strVal).ToBoolSlice()
return sliceVal.Value, sliceVal.Err
}
// 分隔的数组
sliceVal := wrapper.String(strVal).ToBoolSlice(",")
return sliceVal.Value, sliceVal.Err
}
// SliceString ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 15:03 2024/12/1
func SliceString(gjsonResult gjson.Result) ([]string, error) {
if gjsonResult.Value() == nil {
return nil, nil
}
strVal := strings.TrimSpace(gjsonResult.String())
// 任意类型的list
if strings.HasPrefix(strVal, "[") && strings.HasSuffix(strVal, "]") {
// 序列化之后的数组
sliceVal := wrapper.String(strVal).ToStringSlice()
return sliceVal.Value, sliceVal.Err
}
// 分隔的数组
sliceVal := wrapper.String(strVal).ToStringSlice(",")
return sliceVal.Value, sliceVal.Err
}
// SliceMapStringAny ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 15:41 2024/12/1
func SliceMapStringAny(gjsonResult gjson.Result) ([]map[string]any, error) {
if gjsonResult.Value() == nil {
return nil, nil
}
strVal := strings.TrimSpace(gjsonResult.String())
// 任意类型的list
if !gjsonResult.IsArray() {
return nil, exception.New(ErrDataIsNotArray, nil)
}
var res []map[string]any
if err := serialize.JSON.UnmarshalWithNumber([]byte(strVal), &res); nil != err {
return nil, err
}
return res, nil
}
// SliceSlice ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 17:44 2024/12/1
func SliceSlice(gjsonResult gjson.Result) ([][]any, error) {
if gjsonResult.Value() == nil {
return nil, nil
}
strVal := strings.TrimSpace(gjsonResult.String())
// 任意类型的list
if !gjsonResult.IsArray() {
return nil, exception.New(ErrDataIsNotArray, nil)
}
var res [][]any
if err := serialize.JSON.UnmarshalWithNumber([]byte(strVal), &res); nil != err {
return nil, err
}
return res, nil
}
// MapStrAny 获取任意map类型的结果
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 14:26 2024/12/2
func MapStrAny[T string | int64 | uint64 | bool | float64 | []any | map[string]any | any](gjsonResult gjson.Result) (map[string]T, error) {
if !gjsonResult.IsObject() {
return nil, exception.New(ErrDataIsNotArray, nil)
}
var res map[string]T
if err := serialize.JSON.UnmarshalWithNumber([]byte(gjsonResult.String()), &res); nil != err {
return nil, err
}
return res, nil
}
// Value 获取指定的值
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 10:52 2024/12/1
func Value(dataType consts.DataType, sourceValue gjson.Result, defaultValue any) (any, error) {
if !sourceValue.Exists() {
return defaultValue, nil
}
// 归一化处理对象、数组等
sourceValue = Result(sourceValue)
dataType = getRealDataType(dataType, sourceValue)
strVal := wrapper.String(sourceValue.String())
switch dataType {
case consts.DataTypeInt:
return Int[int](sourceValue)
case consts.DataTypeInt8:
return Int[int8](sourceValue)
case consts.DataTypeInt16:
return Int[int16](sourceValue)
case consts.DataTypeInt32:
return Int[int32](sourceValue)
case consts.DataTypeInt64:
return Int[int64](sourceValue)
case consts.DataTypeUint:
return Uint[uint](sourceValue)
case consts.DataTypeUint8:
return Uint[uint8](sourceValue)
case consts.DataTypeUint16:
return Uint[uint16](sourceValue)
case consts.DataTypeUint32:
return Uint[uint32](sourceValue)
case consts.DataTypeUint64:
return Uint[uint64](sourceValue)
case consts.DataTypeFloat64:
return Float[float64](sourceValue)
case consts.DataTypeFloat32:
return Float[float32](sourceValue)
case consts.DataTypeBool:
boolVal := strVal.ToBool()
return boolVal.Value, boolVal.Err
case consts.DataTypeString:
return sourceValue.String(), nil
case consts.DataTypeAny:
// 经过getRealDataType类型处理后依旧是any,不考虑精度问题
return sourceValue.Value(), nil
case consts.DataTypeSliceAny:
// 任意类型的list
sliceVal := strVal.ToAnySlice()
return sliceVal.Value, sliceVal.Err
case consts.DataTypeSliceInt, consts.DataTypeSliceIntWithChar:
// 任意类型的list
return SliceInt(sourceValue)
case consts.DataTypeSliceUint, consts.DataTypeSliceUintWithChar:
// 任意类型的list
return SliceUint(sourceValue)
case consts.DataTypeSliceFloat, consts.DataTypeSliceFloatWithChar:
// 任意类型的list
return SliceFloat(sourceValue)
case consts.DataTypeSliceBool, consts.DataTypeSliceBoolWithChar:
// 任意类型的list
return SliceBool(sourceValue)
case consts.DataTypeSliceString, consts.DataTypeSliceStringWithChar:
// 任意类型的list
return SliceString(sourceValue)
case consts.DataTypeSliceSlice:
return SliceSlice(sourceValue)
case consts.DataTypeMapAnyAny:
return MapAnyAny(sourceValue)
case consts.DataTypeSliceMapStringAny:
return SliceMapStringAny(sourceValue)
case consts.DataTypeMapStrInt:
return MapStrAny[int64](sourceValue)
case consts.DataTypeMapStrUint:
return MapStrAny[uint64](sourceValue)
case consts.DataTypeMapStrFloat:
return MapStrAny[float64](sourceValue)
case consts.DataTypeMapStrBool:
return MapStrAny[bool](sourceValue)
case consts.DataTypeMapStrAny:
return MapStrAny[any](sourceValue)
case consts.DataTypeMapStrStr:
return MapStrAny[string](sourceValue)
case consts.DataTypeMapStrSlice:
return MapStrAny[[]any](sourceValue)
default:
return nil, exception.New(ErrDataTypeIsNotSupport, map[string]any{"data_type": dataType.String()})
}
}