1 Star 1 Fork 0

听见安静 / vds

加入 Gitee
与超过 1400万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
json_funcs.go 3.61 KB
一键复制 编辑 原始数据 按行查看 历史
// json_funcs.go JSON 类型辅助函数:序列化、路径提取、类型判断
package executor
import (
"encoding/json"
"fmt"
"strconv"
"strings"
)
// jsonMarshal 将任意 Go 值序列化为 JSON 字节。
var jsonMarshal = json.Marshal
// jsonUnmarshal 将 JSON 字节反序列化到目标指针。
var jsonUnmarshal = json.Unmarshal
// jsonIsValid 报告字节切片是否为合法 JSON。
var jsonIsValid = json.Valid
// jsonExtract 按 MySQL 风格路径($.key, $.arr[0], $.a.b)从 JSON 字符串中提取值。
// 返回值类型:string(标量序列化为 JSON 字符串)或 nil。
func jsonExtract(doc, path string) (interface{}, error) {
// 解析整个 JSON 文档
var root interface{}
if err := json.Unmarshal([]byte(doc), &root); err != nil {
return nil, fmt.Errorf("json_extract: 无效 JSON: %w", err)
}
if path == "$" {
return doc, nil
}
// 路径必须以 "$" 开头
if !strings.HasPrefix(path, "$") {
return nil, fmt.Errorf("json_extract: 路径必须以 $ 开头,got %q", path)
}
// 去掉 "$" 前缀,剩余为 ".key", "[0]", ".key[0].sub" 等片段
rest := path[1:]
val, err := jsonWalk(root, rest)
if err != nil {
return nil, err
}
if val == nil {
return nil, nil
}
// 标量直接返回相应 Go 类型(调用方会在比较时使用);
// 对象/数组序列化为 JSON 字符串。
switch v := val.(type) {
case string:
// 返回带引号的 JSON 字符串字面量,与 MySQL 行为一致
b, _ := json.Marshal(v)
return string(b), nil
case float64:
// 尝试整数化
if v == float64(int64(v)) {
return int64(v), nil
}
return v, nil
case bool:
if v {
return int64(1), nil
}
return int64(0), nil
case nil:
return nil, nil
default:
// map / slice → 序列化为 JSON 字符串
b, err := json.Marshal(val)
if err != nil {
return nil, err
}
return string(b), nil
}
}
// jsonWalk 沿路径片段递归遍历 JSON 值。
// path 是去掉 "$" 之后的剩余字符串,如 ".name", "[0]", ".arr[1].val"。
func jsonWalk(val interface{}, path string) (interface{}, error) {
if path == "" {
return val, nil
}
if strings.HasPrefix(path, ".") {
// 对象键访问:.key 或 .key[idx]
rest := path[1:]
// 找到下一个 '.' 或 '[' 作为键结束位置
end := strings.IndexAny(rest, ".[")
var key string
if end < 0 {
key = rest
rest = ""
} else {
key = rest[:end]
rest = rest[end:]
}
m, ok := val.(map[string]interface{})
if !ok {
return nil, nil // 类型不匹配,返回 NULL
}
child, exists := m[key]
if !exists {
return nil, nil
}
return jsonWalk(child, rest)
}
if strings.HasPrefix(path, "[") {
// 数组下标访问:[n]
end := strings.Index(path, "]")
if end < 0 {
return nil, fmt.Errorf("json_extract: 未闭合的 [")
}
idxStr := path[1:end]
rest := path[end+1:]
idx, err := strconv.Atoi(idxStr)
if err != nil {
return nil, fmt.Errorf("json_extract: 无效下标 %q", idxStr)
}
arr, ok := val.([]interface{})
if !ok {
return nil, nil
}
if idx < 0 || idx >= len(arr) {
return nil, nil
}
return jsonWalk(arr[idx], rest)
}
return nil, fmt.Errorf("json_extract: 无法解析路径片段 %q", path)
}
// jsonTypeName 返回 JSON 值的 MySQL 类型名称字符串。
func jsonTypeName(s string) string {
s = strings.TrimSpace(s)
if len(s) == 0 {
return "NULL"
}
switch s[0] {
case '{':
return "OBJECT"
case '[':
return "ARRAY"
case '"':
return "STRING"
case 't', 'f':
return "BOOLEAN"
case 'n':
return "NULL"
default:
// 数字:区分整数和浮点
if strings.ContainsAny(s, ".eE") {
return "DOUBLE"
}
return "INTEGER"
}
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/bigant/vds.git
git@gitee.com:bigant/vds.git
bigant
vds
vds
v1.2.7

搜索帮助