pbmo

package
v0.19.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 1, 2026 License: Apache-2.0, Apache-2.0 Imports: 17 Imported by: 0

README

🔄 Go-PBMO

高性能 Protocol Buffer ↔ Model 双向转换库

为 gRPC/REST 网关场景精心打造的 PB-Model 转换引擎,热路径零分配,批量/map 字段场景反超原生代码,分配次数普遍低于原生手写


稳定版本 许可协议 Go 版本 Go 报告卡 文档


📖 快速开始 · 📚 详细文档 · 📊 性能基准


✨ 特性亮点

  • 🪶 核心零三方依赖 - 主模块只依赖 protobuf 本身,go.mod 不再出现任何其它第三方库
  • 🚀 高性能转换 - 稳态热路径零分配,unsafe 零拷贝 + 反射缓存 + 类型特化三引擎,批量与 map 字段场景反超原生,分配次数普遍低于原生手写
  • 🎯 泛型便捷函数 - ToPB / FromPB / ToPBs / FromPBs 一行搞定,类型安全无需 reflect
  • 🔄 双向转换 - PB → Model 和 Model → PB 一致性保证
  • 🗺️ 字段映射 - 支持 struct tag 和手动映射两种方式
  • ⚡ 字段转换器 - 自定义字段级别转换逻辑
  • ⏰ 自动时间转换 - time.Time ↔ *timestamppb.Timestamp 自动处理
  • 📦 批量转换 - 泛型批量 ToPBs / FromPBs,安全批量 SafeToPBs / SafeFromPBs 支持值切片与指针切片自动适配
  • 🗂️ 注册中心 - Register[M, P]() 一行注册,ConverterFor[M, P]() 按需获取
  • 🔢 枚举映射 - 支持 int32 和泛型枚举映射
  • 🎭 单遍脱敏 - 编织进拷贝计划,WithDesensitize(true) 开启(默认关闭),无 tag 的类型零代价
  • 🛡️ 安全转换 - SafeConverter 拦截 nil 与 typed-nil 指针,避免 panic
  • 🧩 更新构建器 - NewUpdates() 链式构建局部更新,PBToUpdates / ModelToUpdates 一行输出 GORM Updates 字典
  • 🎁 WKT 包装类型 - wrapperspb 包装类型与原生值/指针双向互转工具
  • ⚙️ 选项模式 - Functional Options + 链式调用灵活配置

🏗️ 架构概览

graph TB
    A["🔄 go-toolbox/pkg/pbmo"] --> B["🎯 泛型 API"]
    A --> C["🚀 核心转换"]
    A --> D["⚡ 扩展能力"]
    A --> E["🏗️ 基础设施"]
    A --> F["🧩 可选子包"]

    B --> B1["Register[M, P]<br/>一行注册"]
    B --> B2["ToPB / FromPB<br/>单条转换"]
    B --> B3["ToPBs / FromPBs<br/>批量转换"]
    B --> B4["SafeToPBs / SafeFromPBs<br/>安全批量"]
    B --> B5["PBToUpdates / ModelToUpdates<br/>更新字典直转"]

    C --> C1["📦 BidiConverter<br/>双向转换器"]
    C --> C2["📚 Batch<br/>批量转换"]
    C --> C3["🏛️ Registry<br/>注册中心"]

    D --> D1["🔧 Transformer<br/>字段转换器"]
    D --> D3["🔢 EnumMapper<br/>枚举映射"]
    D --> D4["🛡️ SafeConverter<br/>安全转换"]
    D --> D5["🎁 Wrapper 工具<br/>WKT 包装类型互转"]

    E --> E1["❌ Errors<br/>类型化错误"]
    E --> E2["⚙️ Options<br/>选项模式"]
    E --> E3["🔍 Helpers<br/>反射工具"]
    E --> E4["⏰ Time<br/>时间转换"]
    E --> E5["🗂️ syncMap<br/>并发安全缓存"]

    F --> F1["🎭 Desensitize<br/>单遍脱敏<br/>WithDesensitize 开关"]

    style A fill:#4CAF50,color:#fff
    style B fill:#E91E63,color:#fff
    style C fill:#2196F3,color:#fff
    style D fill:#FF9800,color:#fff
    style E fill:#9C27B0,color:#fff
    style F fill:#607D8B,color:#fff

🚀 快速开始

安装
go get github.com/HitGameAI/apex-toolbox/pkg/pbmo

第三方依赖只有两个模块、34 个包:

模块 包数 为什么需要
google.golang.org/protobuf 33 本库的主题,无法也不该去掉
go-toolbox/pkg/desensitize 1 单遍脱敏的规则与脱敏器,本身零第三方依赖

💡 脱敏一度被放在独立嵌套模块 desensitizex 里,为的是隔离当时位于 go-toolbox 的脱敏实现(它会拖进 go-toolbox/pkg/argus 等十余个包) 脱敏迁到零依赖的 go-desensitize 之后,隔离已经没有对象可隔离,而独立模块 要单独打 tag、单独维护 go.mod 与 replace,代价高于收益,因此合回主模块 现在脱敏编织进拷贝计划,由 WithDesensitize 开关控制,默认关闭, 无 desensitize tag 的类型拷贝计划与引入脱敏前逐字节相同

泛型 API(推荐)

泛型 API 是最简洁的使用方式,利用 reflect.Type 做 key + sync.Map 缓存,消除样板代码:

package main

import (
    "fmt"
    pbmo "github.com/HitGameAI/apex-toolbox/pkg/pbmo"
)

type UserPB struct {
    Id    uint64
    Name  string
    Email string
    Age   int32
}

type UserModel struct {
    ID    uint64 `pbmo:"Id"`
    Name  string
    Email string
    Age   int
}

func main() {
    // 一行注册(自动缓存,无需重复调用)
    pbmo.Register[UserModel, UserPB]()

    // 单条转换
    pb, _ := pbmo.ToPB[UserModel, UserPB](&UserModel{ID: 1, Name: "张三", Age: 25})
    model, _ := pbmo.FromPB[UserPB, UserModel](&UserPB{Id: 2, Name: "李四", Age: 30})

    // 批量转换
    models := []*UserModel{{ID: 1, Name: "a"}, {ID: 2, Name: "b"}}
    pbs, _ := pbmo.ToPBs[UserModel, UserPB](models)

    // 安全批量转换(不因单个失败中断,支持 []M 值切片与 []*M 指针切片)
    pbs2, result := pbmo.SafeToPBs[UserModel, UserPB](models)
    fmt.Printf("成功: %d, 失败: %d\n", result.SuccessCount, result.FailureCount)
}
非泛型 API(仍受支持)

BidiConverter 的方法没有废弃,需要在运行时才知道类型时仍然用它 批量方法与包级便捷函数已删除,对照关系见文末

// 手动创建转换器
converter := pbmo.NewBidiConverter(UserPB{}, UserModel{})

// PB -> Model
var model UserModel
converter.ConvertPBToModel(pb, &model)

// Model -> PB
var pb2 UserPB
converter.ConvertModelToPB(model2, &pb2)

// 批量转换
models, err := pbmo.FromPBs[UserPB, UserModel](pbs)
带选项配置
// 泛型方式
pbmo.RegisterWith[UserModel, UserPB](
    pbmo.WithAutoTimeConversion(true),
    pbmo.WithFieldMapping("ID", "Id"),
    pbmo.WithDesensitize(true),
)

// 传统方式
converter := pbmo.NewBidiConverter(PB{}, Model{},
    pbmo.WithAutoTimeConversion(true),
)
链式调用
converter := pbmo.NewBidiConverter(UserPB{}, UserModel{}).
    WithAutoTimeConversion(true).
    WithFieldMapping("ID", "Id").
    WithDesensitize(true)
更新字段构建器

NewUpdates() 用于构建 map[string]interface{},适合传给 GORM Updates 或仓储层局部更新方法 JSON 数组字段请使用 SetJSONSlice,避免把 Go slice 作为标量值写入 JSON 列

updates := pbmo.NewUpdates().
    SetStringVal("url", req.Url).
    SetInt32Val("sort_order", wrapperspb.Int32(req.SortOrder)).
    SetJSONSlice("display_pages", req.DisplayPages).
    Build()

SetJSONSlice 仅处理 slice/array,nil slice 会被跳过,非 nil 空切片会写入 []

更新字典直转

PBToUpdates / ModelToUpdates 一行将消息或结构体转为更新字典,自动跳过零值,适合直接传给 GORM Updates 字段 key 与偏移按类型缓存于更新计划,热路径零 tag 解析:

// PB 按 protobuf json tag 名(snake_case)输出,自动解包 wrapper 类型
updates := pbmo.PBToUpdates(req)

// Model 按 gorm column tag 或 json tag 输出,跳过零值与不可导出字段
updates := pbmo.ModelToUpdates(&user)

db.Model(&User{}).Where("id = ?", 1).Updates(updates)

📋 泛型 API 速查表

函数 签名 说明
Register Register[M, P]() *BidiConverter 注册转换对(默认配置)
RegisterWith RegisterWith[M, P](opts...) *BidiConverter 注册转换对(自定义配置)
ToPB ToPB[M, P](m *M) (*P, error) Model → PB
FromPB FromPB[P, M](pb *P) (*M, error) PB → Model
ToPBs ToPBs[M, P](models []*M) ([]*P, error) 批量 Model → PB,遇错即停
FromPBs FromPBs[P, M](pbs []*P) ([]*M, error) 批量 PB → Model,遇错即停
SafeToPBs SafeToPBs[M, P](models []M) ([]*P, *BatchResult) 安全批量 Model → PB,支持 []M 与 []*M 自动适配
SafeFromPBs SafeFromPBs[P, M](pbs []*P) ([]*M, *BatchResult) 安全批量 PB → Model
ConverterFor ConverterFor[M, P]() *BidiConverter 获取已注册的转换器
PBToUpdates PBToUpdates[P](pb *P) map[string]interface{} PB → 更新字典,protobuf json tag 作 key,跳过零值并解包 wrapper
ModelToUpdates ModelToUpdates[M](m *M) map[string]interface{} Model → 更新字典,gorm column/json tag 作 key,跳过零值

🔄 迁移指南

v0.3.0 破坏性变更:核心模块去三方依赖

主模块原先依赖 go-toolbox 与 go-toolbox/pkg/argus,使用者无论用不用脱敏,都要把整套工具包 拉进构建图,依赖闭包 53 个包、5 个模块 现在只剩 protobuf 与零依赖的 go-toolbox/pkg/desensitize,34 个包、2 个模块; 受影响的公开 API 如下:

原 API 现在怎么写 为什么
pbmo.DesensitizeConverter NewBidiConverter(..., WithDesensitize(true)) 脱敏编织进拷贝计划,不再需要专门的转换器类型
pbmo.NewDesensitizeConverter(...) 同上 同上
dc.ConvertPBToModelWithDesensitize(...) c.ConvertPBToModel(...) 开关决定是否脱敏,不再有带后缀的方法
dc.ConvertModelToPBWithDesensitize(...) c.ConvertModelToPB(...) 同上
pbmo.ApplyDesensitization(obj) desensitize.Desensitization(obj) 整对象脱敏属于输出层,直接用上游
pbmo.RegisterDesensitizer(t, d) desensitize.RegisterDesensitizer(t, d) 同上
pbmo.DesensitizeField(v, t) desensitize.Desensitize(v, t) 同上
pbmo.SafeGetField(obj, "F") safe.New(obj).Field("F") 原本只是一行转发,没有自己的语义
pbmo.SafeGetNestedField(obj, p) safe.New(obj).At(p) 同上
sc.SafeFieldAccess(obj, f...) 逐级 safe.New(obj).Field(f) 同上

上表里 desensitize 指 go-toolbox/pkg/desensitize, safe 指 go-toolbox/pkg/safe,两者都零第三方依赖

一度存在的 desensitizex 子模块已经取消:脱敏现在直接在主模块里完成, 由 WithDesensitize 开关控制,无 tag 的类型零代价,不必再为它单开一个模块

未受影响的部分:

  • 八个 ErrType* 错误码数值不变(20000 ~ 20007),错误消息前缀逐字不变
  • 预定义错误变量、New*Error 构造函数、Is*Error 判断签名不变
  • 错误类型由 errorx.ErrorType / errorx.BaseError 换成本包的 ErrorType / Error, errors.Is 与 errors.As 用法不变,新增导出的 ClassifyError 可直接取分类
  • SetJSON / SetJSONVal / SetJSONSlice 的输出逐字节不变
  • PBToUpdates / ModelToUpdates 的字段 key 解析与零值跳过规则不变
  • SafeConverter 及其 SafeConvert* 方法留在主模块,没有依赖
已删除的 API 替代品
NewBidiConverter(PB{}, Model{}) + RegisterConverter(c)(已删除) Register[Model, PB]()
converter.ConvertModelToPB(m, &pb) ToPB[Model, PB](m)
converter.ConvertPBToModel(pb, &model) FromPB[PB, Model](pb)
converter.BatchConvertModelToPB(models, &pbs)(已删除) ToPBs[Model, PB](models)
converter.BatchConvertPBToModel(pbs, &models)(已删除) FromPBs[PB, Model](pbs)
converter.SafeBatchConvertModelToPB(models, &pbs)(已删除) SafeToPBs[Model, PB](models)
converter.SafeBatchConvertPBToModel(pbs, &models)(已删除) SafeFromPBs[PB, Model](pbs)
GetConverter(pbType, modelType)(已删除) ConverterFor[Model, PB]()
ConvertPBToModel(pb, &model) FromPB[PB, Model](pb)
ConvertModelToPB(model, &pb) ToPB[Model, PB](model)

🧰 模块一览

模块 文件 功能描述 使用场景
🎯 泛型 API generic.go 一行注册、一行转换 推荐首选
🔄 核心转换 converter.go BidiConverter 双向转换 PB ↔ Model 转换
📦 批量转换 batch.go 批量转换、安全批量 列表数据转换
🗂️ 注册中心 registry.go 转换器统一管理 多类型转换场景
⚡ 字段转换 transform.go 字段级自定义转换 数据格式化、类型适配
🔢 枚举映射 enum.go int32/泛型枚举映射 枚举类型转换
🎭 单遍脱敏 desensitize.go 编织进拷贝计划的字段脱敏 隐私保护
🛡️ 安全转换 safe.go nil 安全转换 防止 panic
⏰ 时间转换 time.go Time ↔ Timestamp 时间字段处理
🧩 更新构建器 updates.go 链式构建局部更新字段 GORM Updates、JSON 字段更新
📋 更新计划 updates_plan.go 更新字典字段计划缓存 PBToUpdates / ModelToUpdates 热路径
🎁 包装类型 wrappers.go WKT 包装类型互转工具 wrapperspb ↔ 原生值/指针
🔧 辅助函数 helpers.go 反射工具、类型判断 内部使用
🗂️ 并发映射 syncmap.go 字段缓存、计划缓存、注册中心的并发容器 内部使用
🏷️ 字段 key fieldkey.go gorm / protobuf / json tag 解析 内部使用
🧮 空值判断 empty.go 更新字典跳过零值字段 内部使用
🧾 JSON 辅助 jsonx.go JSON 列规范化与切片编码 内部使用
❌ 错误定义 errors.go 类型化错误体系 错误处理
⚙️ 选项模式 option.go Functional Options 配置管理

📊 性能基准

基于 go test -bench=. -benchmem -count=3 实测,与手写原生转换代码对比,完整数据见 go-pbmo-benchmark:

单位说明: ns = 纳秒(10⁻⁹秒),µs = 微秒(10⁻⁶秒,1µs = 1000ns);对比列 PBMO/Native,< 1 表示 PBMO 反超 测试环境: Linux AMD64 · Go 1.25 · AMD EPYC 9V45(GitHub Actions CI),更新字典与注册中心为本机补充实测

核心转换(PBMO vs Native)
模型(结构特征) 场景 PBMO Native 对比 胜出 内存 分配
Simple(8 字段平铺) PB→Model 26.1 ns 20.1 ns 1.30x Native 48 B 1
Simple(8 字段平铺) Model→PB 25.4 ns 22.0 ns 1.15x Native 48 B 1
Mapped(字段映射) PB→Model 25.9 ns 20.3 ns 1.28x Native 48 B 1
Mapped(字段映射) Model→PB 25.5 ns 20.5 ns 1.24x Native 48 B 1
Medium(含切片/时间) PB→Model 37.4 ns 28.2 ns 1.33x Native 96 B 1
Full(多类型混合) PB→Model 87.1 ns 70.5 ns 1.24x Native 184 B 2
Full(多类型混合) Model→PB 120.2 ns 135.0 ns 0.89x PBMO 416 B 2
Large(大结构) PB→Model 104.9 ns 76.3 ns 1.38x Native 296 B 2
Large(大结构) Model→PB 126.9 ns 133.4 ns 0.95x PBMO 432 B 2
Huge30(30 字段) PB→Model 100.6 ns 100.9 ns 1.00x 持平 448 B 1
Huge100(100 字段) PB→Model 325.5 ns 321.1 ns 1.01x 持平 1344 B 2
Huge100(100 字段) Model→PB 383.4 ns 387.6 ns 0.99x PBMO 1728 B 2
DeepNested4(4 层嵌套) PB→Model 146.8 ns 84.9 ns 1.73x Native 224 B 4
Enterprise(多层聚合) PB→Model 152.8 ns 121.0 ns 1.26x Native 368 B 3
Comprehensive(sqlbuilder) Model→PB 193.2 ns 296.8 ns 0.65x PBMO 392 B 5

💡 分配列为 PBMO 数据;Native 同场景分配普遍更高:Full Model→PB 6 次、Large Model→PB 5 次、Huge100 Model→PB 10 次、Comprehensive 11 次、Enterprise 6 次;复合分配组将 wrapper/时间戳/指针字段的 N 次子对象分配聚合为单次复合分配,ModelToPB 方向大结构场景全面反超 Native

类型特征场景(PBMO vs Native)
场景 PBMO Native 对比 说明
Config Model→PB 36.9 ns 169.3 ns 0.22x map 字段转换 PBMO 快 4.6x
Config PB→Model 44.2 ns 37.5 ns 1.18x map[string]any 写入
ScoreBoard Model→PB 107.5 ns 86.4 ns 1.25x 计分板切片聚合
Wrapper Model→PB 102.0 ns 104.0 ns 0.98x WKT 包装类型 PBMO 持平反超,分配 2 vs 5
Wrapper PB→Model 62.5 ns 54.1 ns 1.15x wrapper 解包,分配 2 vs 5
Huge50 Model→PB 218.0 ns 242.1 ns 0.90x 50 字段混合,分配 2 vs 5
TimePtr Model→PB 66.7 ns 39.1 ns 1.71x *time.Time 转时间戳
TimeZero PB→Model 32.2 ns 25.3 ns 1.27x 零值时间自动归零
NamedSlice PB→Model 28.7 ns 24.4 ns 1.18x 类型别名切片
Metadata PB→Model 21.3 ns 16.9 ns 1.26x 极小结构(24 B/1 alloc)
更新字典(PBMO vs Native,本机实测)
场景 PBMO Native 对比 内存 分配
PBToUpdates 1.87 µs 973 ns 1.92x 744 B 8
ModelToUpdates 1.47 µs 1.06 µs 1.39x 840 B 11
UpdatesBuilder 链式构建 2.26 µs 3.34 µs 0.68x 480 B 11

💡 更新字典直转按类型缓存字段计划,热路径零 tag 解析、零 reflect.Value 构造;wrapper 解包与 nil 指针跳过按字段种类特化为直读比较

注册中心(本机实测)
场景 PBMO 对比 内存 分配
Register 热路径(重复注册命中槽位) 21.2 ns - 0 B 0
ConverterFor 23.0 ns - 0 B 0
批量注册 6 类型对轮换 151 ns 0.27x vs 手写 map 0 B 0
Registry.Lookup 74.1 ns 2.11x vs 手写 map 0 B 0

💡 Register/ConverterFor 命中 32 槽热路径缓存零分配,黄金比例散列保证多类型对不互相驱逐;批量注册场景比手写 map 反超 3.7x

并发与批量转换(PBMO vs Native)
场景 PBMO Native 对比
Simple 并发 PB→Model 19.4 ns 17.4 ns 1.11x
Wrapper 并发 PB→Model 40.5 ns 38.9 ns 1.04x
Outer 并发 PB→Model 47.3 ns 32.2 ns 1.47x
DeepNested4 并发 PB→Model 91.2 ns 73.4 ns 1.24x
Simple 批量 100 条 PB→Model 1.56 µs 2.39 µs 0.65x
Simple 批量 1000 条 PB→Model 16.09 µs 24.49 µs 0.66x
Large 批量 100 条 PB→Model 8.27 µs 8.38 µs 0.99x
Simple BatchConvert 100 条 1.68 µs 1.25 µs 1.34x
DeepNested4 批量 100 条 12.95 µs 8.84 µs 1.46x
SafeBatchConvert 100 条 2.84 µs 2.20 µs 1.29x

💡 批量转换采用预分配 + unsafe 批量拷贝:Simple 批量 1000 条仅 2 次分配而 Native 需 1001 次,Large 批量 102 次而 Native 301 次,SafeBatch 4 次而 Native 101 次,分配与 GC 压力优势随规模扩大

内部组件
场景 耗时 内存 分配
EnumMapper.Map 4.8 ns 0 B 0
GenericEnumMapper.Map 4.6 ns 0 B 0
AutoEnumConverter.Convert 5.0 ns 0 B 0
TransformerRegistry.Apply 78.8 ns 48 B 3
NewBidiConverter(构建期一次) 79.3 ns 256 B 3

💡 平铺字段单对象场景 Native 手写赋值更快属物理极限(零反射零间接调用);PBMO 的价值在批量/并发/map 字段/字段映射/更新字典场景的反超与全场景零样板代码

🧪 测试

# 运行单元测试
go test ./...

# 运行指定模块测试
go test -run TestConverter -v

📚 详细文档

编号 文档 说明
01 快速开始 安装、泛型 API、核心 API
02 字段映射 struct tag、手动映射、优先级
03 字段转换器 TransformerFunc、注册、常见场景
05 批量转换 泛型批量、安全批量、BatchResult
06 注册中心 Registry、泛型注册、多类型管理
07 枚举映射 EnumMapper、GenericEnumMapper、AutoEnumConverter
08 脱敏转换 WithDesensitize 开关、脱敏 Tag、作用范围
09 安全转换 SafeConverter、安全字段访问、safe 的 Access
10 时间转换 自动时间转换、手动转换函数
11 选项模式 Functional Options、链式调用、常见组合
12 错误处理 类型化错误体系、错误判断、最佳实践

📄 许可证

Copyright (c) 2026 kamalyes. All Rights Reserved.

Documentation

Overview

Package pbmo 在 protobuf 生成结构体与领域/GORM 模型之间做字段映射转换

本包不参与 protobuf 线格式编解码:不调用 proto.Marshal/Unmarshal/Clone, 也不走 protojson对 google.golang.org/protobuf 的依赖仅用于 WKT 类型 (timestamppb / wrapperspb / structpb)与一次 proto.Message 接口判定

性能模型

转换计划按 reflect.Type 编译一次后缓存,热路径只做一次原子读 + 一次闭包调用, 稳态零反射字段按偏移合并为连续 memmove 段,WKT 子对象的多次分配被合并为 单次复合分配——因此 Model→PB 的 wrapper 路径可以比手写代码更快(分配更少)

字段别名语义(重要)

为保持热路径零拷贝,标量与切片类字段**不做防御性复制**:

  • 标量、定长数组:按值 memmove 到目标,相互独立
  • []byte 与其他切片字段:**只拷贝切片头(指针 + 长度 + 容量)**, 源与目标因此共享同一底层数组修改 src[0] 会改变 dst[0],反之亦然
  • map 字段:拷贝 map 头,源与目标指向同一个 map
  • 指针字段:拷贝指针值,源与目标指向同一对象

这是有意的设计(跨节点扇出等场景据此省掉整份载荷复制),但调用方必须知道: 若转换后仍会改写源对象,且目标的生命周期更长,则需要自行深拷贝相关字段

PBToUpdates / ModelToUpdates 输出的 map 值是**值快照**(标量经值拷贝后装箱), 不随源结构体后续改动而变化;但指针类字段的值仍是共享指针

目标归属与 Into 变体

ToPB / FromPB 必须为结果分配目标并返回,该分配必然逃逸,是这两条路径 100% 的垃圾来源与并行扩展的实际天花板需要稳态零分配时改用 ToPBInto / FromPBInto 写入调用方持有的目标,但要遵守其文档中的清零契约: 拷贝计划只写有映射关系的字段,复用脏目标会残留上一轮的值

Index

Constants

PtrSize 是 unsafe.Sizeof(unsafe.Pointer(nil)) 的常量,用于指针算术

Variables

View Source
var (
	ErrPBMessageNil      = Error{Msg: "PB消息不能为空", Type: ErrTypeNilValue}
	ErrModelNil          = Error{Msg: "Model不能为空", Type: ErrTypeNilValue}
	ErrMustBePointer     = Error{Msg: "目标必须是指针类型", Type: ErrTypeTypeMismatch}
	ErrMustBeSlice       = Error{Msg: "源必须是切片类型", Type: ErrTypeTypeMismatch}
	ErrMustBeStruct      = Error{Msg: "目标必须是结构体类型", Type: ErrTypeTypeMismatch}
	ErrConverterExists   = Error{Msg: "转换器已存在", Type: ErrTypeRegistry}
	ErrConverterNotFound = Error{Msg: "转换器未找到", Type: ErrTypeRegistry}
)

Functions

func BoolValueToPtr

func BoolValueToPtr(v *wrapperspb.BoolValue) *bool

BoolValueToPtr 将 *wrapperspb.BoolValue 转换为 *bool 当源值为 nil 指针时,BoolValueToPtr 返回 nil 指针

func ConvertEnum

func ConvertEnum[S, T any](mapper *EnumMapper, source S, defaultValue T) T

ConvertEnum 便捷方法:转换枚举(自动推断类型)

func DerefBoolVal

func DerefBoolVal(v *wrapperspb.BoolValue) bool

DerefBoolVal 从 *wrapperspb.BoolValue 中提取布尔值 当源值为 nil 指针时,DerefBoolVal 返回 false

func DerefDoubleVal

func DerefDoubleVal(v *wrapperspb.DoubleValue) float64

DerefDoubleVal 从 *wrapperspb.DoubleValue 中提取浮点数值 当源值为 nil 指针时,DerefDoubleVal 返回 0.0

func DerefFloatVal

func DerefFloatVal(v *wrapperspb.FloatValue) float32

DerefFloatVal 从 *wrapperspb.FloatValue 中提取浮点数值 当源值为 nil 指针时,DerefFloatVal 返回 0.0

func DerefInt32Val

func DerefInt32Val(v *wrapperspb.Int32Value) int32

DerefInt32Val 从 *wrapperspb.Int32Value 中提取整数值 当源值为 nil 指针时,DerefInt32Val 返回 0

func DerefInt64Val

func DerefInt64Val(v *wrapperspb.Int64Value) int64

DerefInt64Val 从 *wrapperspb.Int64Value 中提取整数值 当源值为 nil 指针时,DerefInt64Val 返回 0

func DerefSlice

func DerefSlice[T any](ptrs []*T) []T

DerefSlice 将 []*T 转换为 []T,nil 元素转为零值

func DerefStringVal

func DerefStringVal(v *wrapperspb.StringValue) string

DerefStringVal 从 *wrapperspb.StringValue 中提取字符串值 当源值为 nil 指针时,DerefStringVal 返回空字符串 ""

func DerefUInt32Val

func DerefUInt32Val(v *wrapperspb.UInt32Value) uint32

DerefUInt32Val 从 *wrapperspb.UInt32Value 中提取无符号整数值 当源值为 nil 指针时,DerefUInt32Val 返回 0

func DerefUInt64Val

func DerefUInt64Val(v *wrapperspb.UInt64Value) uint64

DerefUInt64Val 从 *wrapperspb.UInt64Value 中提取无符号整数值 当源值为 nil 指针时,DerefUInt64Val 返回 0

func DereferenceType

func DereferenceType(t reflect.Type) reflect.Type

DereferenceType 解引用指针类型,返回实际类型

func DoubleValueToPtr

func DoubleValueToPtr(v *wrapperspb.DoubleValue) *float64

DoubleValueToPtr 将 *wrapperspb.DoubleValue 转换为 *float64 当源值为 nil 指针时,DoubleValueToPtr 返回 nil 指针

func FloatValueToPtr

func FloatValueToPtr(v *wrapperspb.FloatValue) *float32

FloatValueToPtr 将 *wrapperspb.FloatValue 转换为 *float32 当源值为 nil 指针时,FloatValueToPtr 返回 nil 指针

func FromPB

func FromPB[P any, M any](pb *P) (*M, error)

FromPB 将 PB 消息转换为 Model,nil 输入返回 nil 类型字静态提取一次原子读命中即分发,纯拷贝直达合并闭包,稳态零反射

目标由本函数分配并返回,该分配必然逃逸;需要稳态零分配时改用 FromPBInto 切片/map/指针类字段与源共享底层数据,不做防御性复制(见包文档「字段别名语义」)

func FromPBInto

func FromPBInto[P any, M any](pb *P, dst *M) error

FromPBInto 将 PB 消息转换到调用方提供的 Model 目标,免去 FromPB 的目标堆分配

与 ToPBInto 对偶,动机、契约与别名语义同上:dst 清零责任在调用方, 未映射字段保持原值;pb 为 nil 时不触碰 dst 并返回 nil;dst 为 nil 返回 ErrModelNil

func FromPBs

func FromPBs[P any, M any](pbs []*P) ([]*M, error)

FromPBs 批量将 PB 切片转换为 Model 指针切片 nil 元素会被跳过,对应的 model 保持零值

func GetTypeName

func GetTypeName(t reflect.Type) string

GetTypeName 获取类型名称

func Int32ValueToPtr

func Int32ValueToPtr(v *wrapperspb.Int32Value) *int32

Int32ValueToPtr 将 *wrapperspb.Int32Value 转换为 *int32 当源值为 nil 指针时,Int32ValueToPtr 返回 nil 指针

func Int64ValueToPtr

func Int64ValueToPtr(v *wrapperspb.Int64Value) *int64

Int64ValueToPtr 将 *wrapperspb.Int64Value 转换为 *int64 当源值为 nil 指针时,Int64ValueToPtr 返回 nil 指针

func IsConversionError

func IsConversionError(err error) bool

IsConversionError 判断是否为转换错误

func IsIntegerType

func IsIntegerType(t reflect.Type) bool

IsIntegerType 判断是否为整数类型 对应 go-toolbox/types.Integer + types.Unsigned

func IsNilValueError

func IsNilValueError(err error) bool

IsNilValueError 判断是否为空值错误

func IsSignedInt

func IsSignedInt(kind reflect.Kind) bool

IsSignedInt 判断是否为有符号整数 对应 go-toolbox/types.Integer 约束

func IsStructPtrType

func IsStructPtrType(t reflect.Type) bool

IsStructPtrType 判断是否为 *structpb.Struct 类型

func IsTimeType

func IsTimeType(t reflect.Type) bool

IsTimeType 判断是否为 time.Time 类型

func IsTimestampPtrType

func IsTimestampPtrType(t reflect.Type) bool

IsTimestampPtrType 判断是否为 *timestamppb.Timestamp 类型

func IsTypeMismatchError

func IsTypeMismatchError(err error) bool

IsTypeMismatchError 判断是否为类型不匹配错误

func IsUnsignedInt

func IsUnsignedInt(kind reflect.Kind) bool

IsUnsignedInt 判断是否为无符号整数 对应 go-toolbox/types.Unsigned 约束

func IsValidationError

func IsValidationError(err error) bool

IsValidationError 判断是否为校验错误

func ModelToUpdates

func ModelToUpdates[M any](m *M) map[string]interface{}

ModelToUpdates 将 Model 结构体转换为 map[string]interface{} 使用 gorm column tag 或 json tag 作为 key,跳过零值字段和不可导出字段 字段 key 与偏移按类型缓存于更新计划,热路径零 tag 解析

func NewBatchError

func NewBatchError(format string, args ...interface{}) error

NewBatchError 创建批量操作错误

func NewConversionError

func NewConversionError(format string, args ...interface{}) error

NewConversionError 创建转换错误

func NewDesensitizeError

func NewDesensitizeError(format string, args ...interface{}) error

NewDesensitizeError 创建脱敏错误

func NewFieldMappingError

func NewFieldMappingError(format string, args ...interface{}) error

NewFieldMappingError 创建字段映射错误

func NewNilValueError

func NewNilValueError(format string, args ...interface{}) error

NewNilValueError 创建空值错误

func NewTypeMismatchError

func NewTypeMismatchError(format string, args ...interface{}) error

NewTypeMismatchError 创建类型不匹配错误

func NewValidationError

func NewValidationError(format string, args ...interface{}) error

NewValidationError 创建校验错误

func PBToUpdates

func PBToUpdates[P any](pb *P) map[string]interface{}

PBToUpdates 将 PB 消息转换为 map[string]interface{} 遍历 proto 字段,使用 protobuf json tag 名作为 key(snake_case) 自动跳过零值、protobuf 内部字段,自动解包 wrapper 类型 字段 key 与偏移按类型缓存于更新计划,热路径零 tag 解析

func ProtoTimestampToTime

func ProtoTimestampToTime(ts *timestamppb.Timestamp) time.Time

ProtoTimestampToTime 将 *timestamppb.Timestamp 转换为 time.Time 如果输入为 nil,返回零值时间

func ProtoTimestampToTimePointer

func ProtoTimestampToTimePointer(ts *timestamppb.Timestamp) *time.Time

ProtoTimestampToTimePointer 将 *timestamppb.Timestamp 转换为 *time.Time 如果输入为 nil,返回 nil

func PtrToBoolValue

func PtrToBoolValue(v *bool) *wrapperspb.BoolValue

PtrToBoolValue 将 *bool 转换为 *wrapperspb.BoolValue 当源值为 nil 指针时,PtrToBoolValue 返回 nil 指针

func PtrToDoubleValue

func PtrToDoubleValue(v *float64) *wrapperspb.DoubleValue

PtrToDoubleValue 将 *float64 转换为 *wrapperspb.DoubleValue 当源值为 nil 指针时,PtrToDoubleValue 返回 nil 指针

func PtrToFloatValue

func PtrToFloatValue(v *float32) *wrapperspb.FloatValue

PtrToFloatValue 将 *float32 转换为 *wrapperspb.FloatValue 当源值为 nil 指针时,PtrToFloatValue 返回 nil 指针

func PtrToInt32Value

func PtrToInt32Value(v *int32) *wrapperspb.Int32Value

PtrToInt32Value 将 *int32 转换为 *wrapperspb.Int32Value 当源值为 nil 指针时,PtrToInt32Value 返回 nil 指针

func PtrToInt64Value

func PtrToInt64Value(v *int64) *wrapperspb.Int64Value

PtrToInt64Value 将 *int64 转换为 *wrapperspb.Int64Value 当源值为 nil 指针时,PtrToInt64Value 返回 nil 指针

func PtrToStringValue

func PtrToStringValue(v *string) *wrapperspb.StringValue

PtrToStringValue 将 *string 转换为 *wrapperspb.StringValue 当源值为 nil 指针时,PtrToStringValue 返回 nil 指针

func PtrToUInt32Value

func PtrToUInt32Value(v *uint32) *wrapperspb.UInt32Value

PtrToUInt32Value 将 *uint32 转换为 *wrapperspb.UInt32Value 当源值为 nil 指针时,PtrToUInt32Value 返回 nil 指针

func PtrToUInt64Value

func PtrToUInt64Value(v *uint64) *wrapperspb.UInt64Value

PtrToUInt64Value 将 *uint64 转换为 *wrapperspb.UInt64Value 当源值为 nil 指针时,PtrToUInt64Value 返回 nil 指针

func StringValueToPtr

func StringValueToPtr(v *wrapperspb.StringValue) *string

StringValueToPtr 将 *wrapperspb.StringValue 转换为 *string 当源值为 nil 指针时,StringValueToPtr 返回 nil 指针

func TimePointerToProtoTimestamp

func TimePointerToProtoTimestamp(t *time.Time) *timestamppb.Timestamp

TimePointerToProtoTimestamp 将 *time.Time 转换为 *timestamppb.Timestamp 如果输入为 nil 或零值时间,返回 nil

func TimeToProtoTimestamp

func TimeToProtoTimestamp(t time.Time) *timestamppb.Timestamp

TimeToProtoTimestamp 将 time.Time 转换为 *timestamppb.Timestamp 如果输入为零值时间,返回 nil

func ToPB

func ToPB[M any, P any](m *M) (*P, error)

ToPB 将 Model 转换为 PB 消息,nil 输入返回 nil 类型字静态提取一次原子读命中即分发,纯拷贝直达合并闭包,稳态零反射

目标由本函数分配并返回,该分配必然逃逸;需要稳态零分配时改用 ToPBInto 切片/map/指针类字段与源共享底层数据,不做防御性复制(见包文档「字段别名语义」)

func ToPBInto

func ToPBInto[M any, P any](m *M, dst *P) error

ToPBInto 将 Model 转换到调用方提供的 PB 目标,免去 ToPB 的目标堆分配

与 ToPB 的唯一差异是目标归属ToPB 必须 new(P) 后返回,该返回值必然逃逸—— 它是该路径 100% 的垃圾与约 47% 的单次耗时,也是并行扩展的真实天花板 (无锁竞争,纯分配/GC 压力:同一基准关掉 GC 后 1→10 核扩展比从 1.31× 升到 2.80×) 本函数写入调用方持有的 dst,配合对象池复用即稳态零分配

⚠️ 调用方契约:dst 的清零责任在调用方 拷贝计划只写「存在映射关系的字段」,未映射字段保持 dst 原有值不变—— 复用一个脏目标会残留上一轮的数据复用前请显式置零(*dst = P{}), 或确认该类型对的全部字段均被映射覆盖

m 为 nil 时不触碰 dst 并返回 nil(与 ToPB 的 nil→nil 语义一致); dst 为 nil 返回 ErrPBMessageNil

字段别名语义与 ToPB 完全一致:标量与 []byte/切片头经合并 memmove 直拷, 切片类字段与源共享底层数组,不做防御性复制(见包文档「字段别名语义」)

func ToPBs

func ToPBs[M any, P any](models []*M) ([]*P, error)

ToPBs 批量将 Model 指针切片转换为 PB 切片

func UInt32ValueToPtr

func UInt32ValueToPtr(v *wrapperspb.UInt32Value) *uint32

UInt32ValueToPtr 将 *wrapperspb.UInt32Value 转换为 *uint32 当源值为 nil 指针时,UInt32ValueToPtr 返回 nil 指针

func UInt64ValueToPtr

func UInt64ValueToPtr(v *wrapperspb.UInt64Value) *uint64

UInt64ValueToPtr 将 *wrapperspb.UInt64Value 转换为 *uint64 当源值为 nil 指针时,UInt64ValueToPtr 返回 nil 指针

Types

type AutoEnumConverter

type AutoEnumConverter[S comparable, T comparable] struct {
	// contains filtered or unexported fields
}

AutoEnumConverter 自动枚举转换器

func NewAutoEnumConverter

func NewAutoEnumConverter[S comparable, T comparable](defaultValue T) *AutoEnumConverter[S, T]

NewAutoEnumConverter 创建自动枚举转换器

func (*AutoEnumConverter[S, T]) AutoRegister

func (ac *AutoEnumConverter[S, T]) AutoRegister(mappings map[S]T) *AutoEnumConverter[S, T]

AutoRegister 自动批量注册映射关系

func (*AutoEnumConverter[S, T]) Convert

func (ac *AutoEnumConverter[S, T]) Convert(source S) T

Convert 自动转换

func (*AutoEnumConverter[S, T]) ConvertBack

func (ac *AutoEnumConverter[S, T]) ConvertBack(target T) (S, bool)

ConvertBack 反向转换

func (*AutoEnumConverter[S, T]) ConvertSlice

func (ac *AutoEnumConverter[S, T]) ConvertSlice(sources []S) []T

ConvertSlice 批量转换

func (*AutoEnumConverter[S, T]) ConvertWithDefault

func (ac *AutoEnumConverter[S, T]) ConvertWithDefault(source S, defaultValue T) T

ConvertWithDefault 带默认值转换

type BatchItem

type BatchItem struct {
	Index   int         // 索引
	Success bool        // 是否成功
	Value   interface{} // 转换后的值
	Error   error       // 错误信息
}

BatchItem 单个转换结果

type BatchResult

type BatchResult struct {
	SuccessCount int         // 成功数量
	FailureCount int         // 失败数量
	Results      []BatchItem // 每个元素的转换结果
}

BatchResult 批量转换结果

func SafeFromPBs

func SafeFromPBs[P any, M any](pbs []*P) ([]*M, *BatchResult)

SafeFromPBs 安全批量将 PB 切片转换为 Model 切片,不因单个失败而中断 接受 []*P(指针切片),nil 元素标记为失败

func SafeToPBs

func SafeToPBs[M any, P any](models []M) ([]*P, *BatchResult)

SafeToPBs 安全批量将 Model 切片转换为 PB 切片,不因单个失败而中断 自动支持 []M(值切片)和 []*M(指针切片),nil 指针元素标记为失败

type BidiConverter

type BidiConverter struct {
	// contains filtered or unexported fields
}

BidiConverter 双向转换器

func ConverterFor

func ConverterFor[M any, P any]() *BidiConverter

ConverterFor 获取已注册的转换器

func NewBidiConverter

func NewBidiConverter(pbType, modelType interface{}, opts ...Option) *BidiConverter

NewBidiConverter 创建双向转换器 FieldMapping 惰性初始化:无映射配置时不分配 map

func Register

func Register[M any, P any]() *BidiConverter

Register[M, P] 注册 Model-PB 转换对(使用默认配置)

func RegisterWith

func RegisterWith[M any, P any](opts ...Option) *BidiConverter

RegisterWith[M, P] 注册 Model-PB 转换对(自定义配置)

func (*BidiConverter) ConvertModelToPB

func (bc *BidiConverter) ConvertModelToPB(model, pbPtr interface{}) error

ConvertModelToPB 将 Model 转换为 PB 消息(核心热路径) 与 ConvertPBToModel 对称,方向为 Model → PB,委托给 convertWithCache

func (*BidiConverter) ConvertPBToModel

func (bc *BidiConverter) ConvertPBToModel(pb, modelPtr interface{}) error

ConvertPBToModel 将 PB 消息转换为 Model(核心热路径) 入参校验后委托给 convertWithCache,三层加速策略详见 convertWithCache 注释

func (*BidiConverter) GetModelType

func (bc *BidiConverter) GetModelType() reflect.Type

GetModelType 获取 Model 类型

func (*BidiConverter) GetPBType

func (bc *BidiConverter) GetPBType() reflect.Type

GetPBType 获取 PB 类型

func (*BidiConverter) GetTransformers

func (bc *BidiConverter) GetTransformers() *TransformerRegistry

GetTransformers 获取转换器注册表

func (*BidiConverter) RegisterFieldMapping

func (bc *BidiConverter) RegisterFieldMapping(mappings map[string]string) *BidiConverter

RegisterFieldMapping 注册字段映射

func (*BidiConverter) RegisterTransformer

func (bc *BidiConverter) RegisterTransformer(field string, fn TransformerFunc) *BidiConverter

RegisterTransformer 注册字段转换器

func (*BidiConverter) Warmup

func (bc *BidiConverter) Warmup() *BidiConverter

Warmup 预热缓存,在注册完成后调用确保所有映射就绪

func (*BidiConverter) WithAutoTimeConversion

func (bc *BidiConverter) WithAutoTimeConversion(enabled bool) *BidiConverter

WithAutoTimeConversion 设置自动时间转换

func (*BidiConverter) WithBatchSize

func (bc *BidiConverter) WithBatchSize(size int) *BidiConverter

WithBatchSize 设置批处理大小

func (*BidiConverter) WithConcurrency

func (bc *BidiConverter) WithConcurrency(n int) *BidiConverter

WithConcurrency 设置并发数

func (*BidiConverter) WithDesensitize

func (bc *BidiConverter) WithDesensitize(enabled bool) *BidiConverter

WithDesensitize 设置是否启用脱敏,默认关闭 开关影响拷贝计划的构建结果,必须让已建好的计划失效后重建

func (*BidiConverter) WithFieldMapping

func (bc *BidiConverter) WithFieldMapping(modelField, pbField string) *BidiConverter

WithFieldMapping 设置字段映射

func (*BidiConverter) WithFieldMappings

func (bc *BidiConverter) WithFieldMappings(mappings map[string]string) *BidiConverter

WithFieldMappings 批量设置字段映射

func (*BidiConverter) WithSafeMode

func (bc *BidiConverter) WithSafeMode(enabled bool) *BidiConverter

WithSafeMode 设置是否启用安全模式

func (*BidiConverter) WithTagMapping

func (bc *BidiConverter) WithTagMapping(enabled bool) *BidiConverter

WithTagMapping 设置是否启用 struct tag 映射

func (*BidiConverter) WithTagName

func (bc *BidiConverter) WithTagName(name string) *BidiConverter

WithTagName 设置 struct tag 名称

func (*BidiConverter) WithTimeout

func (bc *BidiConverter) WithTimeout(timeout time.Duration) *BidiConverter

WithTimeout 设置超时时间

type Converter

type Converter interface {
	ConvertPBToModel(pb, modelPtr interface{}) error
	ConvertModelToPB(model, pbPtr interface{}) error
	GetPBType() reflect.Type
	GetModelType() reflect.Type
}

Converter 双向转换器接口

type EnumMapper

type EnumMapper struct {
	// contains filtered or unexported fields
}

EnumMapper int32 枚举映射器(兼容旧代码)

func NewEnumMapper

func NewEnumMapper() *EnumMapper

NewEnumMapper 创建枚举映射器

func (*EnumMapper) AddMapping

func (em *EnumMapper) AddMapping(source, target int32) *EnumMapper

AddMapping 添加映射关系(链式调用)

func (*EnumMapper) AddMappings

func (em *EnumMapper) AddMappings(pairs [][2]int32) *EnumMapper

AddMappings 批量添加映射关系

func (*EnumMapper) Map

func (em *EnumMapper) Map(source int32, defaultValue int32) int32

Map 映射源枚举值到目标枚举值

func (*EnumMapper) MapEnum

func (em *EnumMapper) MapEnum(sourceEnum interface{}, targetEnumType reflect.Type, defaultValue interface{}) (interface{}, error)

MapEnum 通用枚举映射方法(使用反射)

func (*EnumMapper) ReverseMap

func (em *EnumMapper) ReverseMap(target int32, defaultValue int32) int32

ReverseMap 反向映射

type Error

type Error struct {
	Msg  string
	Type ErrorType
}

Error 带分类的错误值 值类型实现 error,可直接用 errors.Is 比较预定义变量, 也可用 errors.As 在包装链中取回分类 [EN] A value type implementing error, so predefined vars compare with errors.Is and the category survives wrapping via errors.As

func (Error) Error

func (e Error) Error() string

Error 实现 error 接口

func (Error) GetType

func (e Error) GetType() ErrorType

GetType 获取错误分类

type ErrorType

type ErrorType int

ErrorType 错误分类标识 数值区间 20000+ 为本库私有,与其它库的错误码空间互不干扰 [EN] Error category id; the 20000+ range is private to this library and never collides with another library's code space

const (
	ErrTypeConversion   ErrorType = iota + 20000 // 转换错误
	ErrTypeValidation                            // 校验错误
	ErrTypeNilValue                              // 空值错误
	ErrTypeTypeMismatch                          // 类型不匹配
	ErrTypeFieldMapping                          // 字段映射错误
	ErrTypeBatch                                 // 批量操作错误
	ErrTypeDesensitize                           // 脱敏错误
	ErrTypeRegistry                              // 注册中心错误
)

错误类型常量

const ErrTypeUnknown ErrorType = 0

ErrTypeUnknown 未知错误,ClassifyError 对非本库错误的返回值 单独声明而不并入下方 iota 块,否则 iota 从 1 起算会把整段错误码整体后移一位 [EN] Declared separately: folding it into the iota block below would start iota at 1 and shift every code by one

func ClassifyError

func ClassifyError(err error) ErrorType

ClassifyError 取出错误的分类,非本库错误返回 ErrTypeUnknown 穿透 fmt.Errorf("%w") 包装链

type GenericEnumMapper

type GenericEnumMapper[S comparable, T comparable] struct {
	// contains filtered or unexported fields
}

GenericEnumMapper 泛型枚举映射器

func NewGenericEnumMapper

func NewGenericEnumMapper[S comparable, T comparable](defaultValue T) *GenericEnumMapper[S, T]

NewGenericEnumMapper 创建泛型枚举映射器

func (*GenericEnumMapper[S, T]) Map

func (m *GenericEnumMapper[S, T]) Map(source S) T

Map 映射源枚举到目标枚举

func (*GenericEnumMapper[S, T]) MapSlice

func (m *GenericEnumMapper[S, T]) MapSlice(sources []S) []T

MapSlice 批量映射切片

func (*GenericEnumMapper[S, T]) MapWithDefault

func (m *GenericEnumMapper[S, T]) MapWithDefault(source S, defaultValue T) T

MapWithDefault 映射源枚举到目标枚举(指定默认值)

func (*GenericEnumMapper[S, T]) Register

func (m *GenericEnumMapper[S, T]) Register(source S, target T) *GenericEnumMapper[S, T]

Register 注册映射关系(链式调用)

func (*GenericEnumMapper[S, T]) RegisterBatch

func (m *GenericEnumMapper[S, T]) RegisterBatch(pairs map[S]T) *GenericEnumMapper[S, T]

RegisterBatch 批量注册映射关系

func (*GenericEnumMapper[S, T]) ReverseMap

func (m *GenericEnumMapper[S, T]) ReverseMap(target T) (S, bool)

ReverseMap 反向映射

type IntWrapper

type IntWrapper struct {
	Data int
}

IntWrapper DataWrapper[T] 模式:struct{Data T} 用于触发 convertDataWrapper 慢路径(makeDataWrapperCopyFunc 对非指针 inner 返回 nil)

type Option

type Option func(*Options)

Option 转换器配置选项函数

func WithAutoTimeConversion

func WithAutoTimeConversion(enabled bool) Option

WithAutoTimeConversion 设置自动时间转换

func WithBatchSize

func WithBatchSize(size int) Option

WithBatchSize 设置批处理大小

func WithConcurrency

func WithConcurrency(n int) Option

WithConcurrency 设置并发数

func WithDesensitize

func WithDesensitize(enabled bool) Option

WithDesensitize 启用/禁用脱敏,默认关闭

开启后也不是所有字段都脱敏:只处理带 desensitize tag 的字符串字段, 无 tag 的类型拷贝计划与关闭时逐字节相同,不付任何代价

作用范围是本转换器自己的顶层字段,嵌套结构体不参与 嵌套结构体的拷贝计划按「源类型+目标类型」全进程共享,承载不了 per-converter 的开关——这与 AutoTimeConversion 对嵌套同样不生效是一致的 嵌套字段需要脱敏时在输出层调 desensitize.Desensitization

[EN] Off by default. Enabling it does not mask everything: only string fields carrying a desensitize tag are touched, and a type with no tags gets byte-for-byte the same copy plan as with masking off, at no cost. The scope is this converter's own top-level fields; nested structs are excluded because their copy plans are shared process-wide by source and destination type and cannot carry a per-converter switch, exactly as AutoTimeConversion does not reach nested plans either. Mask nested fields at the output layer with desensitize.Desensitization

func WithFieldMapping

func WithFieldMapping(modelField, pbField string) Option

WithFieldMapping 设置字段映射

func WithFieldMappings

func WithFieldMappings(mappings map[string]string) Option

WithFieldMappings 批量设置字段映射

func WithSafeMode

func WithSafeMode(enabled bool) Option

WithSafeMode 启用/禁用安全模式

func WithTagMapping

func WithTagMapping(enabled bool) Option

WithTagMapping 启用/禁用 struct tag 映射

func WithTagName

func WithTagName(name string) Option

WithTagName 设置 struct tag 名称

func WithTimeout

func WithTimeout(timeout time.Duration) Option

WithTimeout 设置超时时间

type Options

type Options struct {
	AutoTimeConversion bool              // 自动时间转换开关
	FieldMapping       map[string]string // 字段名映射: Model字段名 -> PB字段名
	TagMappingEnabled  bool              // 是否启用 struct tag 自动映射
	TagName            string            // struct tag 名称(默认 pbmo)
	DesensitizeEnabled bool              // 是否启用脱敏(默认关闭,开启后按字段 desensitize tag 生效)
	SafeMode           bool              // 是否启用安全模式
	Concurrency        int               // 并发数(批量转换时使用)
	BatchSize          int               // 批处理大小
	Timeout            time.Duration     // 超时时间
}

Options 转换器配置项

func ApplyOptions

func ApplyOptions(opts ...Option) *Options

ApplyOptions 应用选项到默认配置

func DefaultOptions

func DefaultOptions() *Options

DefaultOptions 默认配置 FieldMapping 惰性初始化:无映射配置时不分配 map

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry 转换器注册中心 使用 syncMap 统一管理 PB ↔ Model 转换器,天然并发安全 key 为类型对结构体,热路径零字符串分配

func GlobalRegistry

func GlobalRegistry() *Registry

GlobalRegistry 获取全局注册中心

func NewRegistry

func NewRegistry() *Registry

NewRegistry 创建转换器注册中心

func (*Registry) Clear

func (r *Registry) Clear()

Clear 清空所有转换器

func (*Registry) ConvertModelToPB

func (r *Registry) ConvertModelToPB(model, pb interface{}) error

ConvertModelToPB 通过注册中心执行 Model -> PB 转换

func (*Registry) ConvertPBToModel

func (r *Registry) ConvertPBToModel(pb, model interface{}) error

ConvertPBToModel 通过注册中心执行 PB -> Model 转换

func (*Registry) Count

func (r *Registry) Count() int

Count 获取已注册的转换器数量

func (*Registry) Has

func (r *Registry) Has(pbType, modelType reflect.Type) bool

Has 检查转换器是否已注册

func (*Registry) Keys

func (r *Registry) Keys() []string

Keys 获取所有已注册的可读 key

func (*Registry) Lookup

func (r *Registry) Lookup(pbType, modelType reflect.Type) (*BidiConverter, error)

Lookup 查找转换器

func (*Registry) LookupByInstance

func (r *Registry) LookupByInstance(pb, model interface{}) (*BidiConverter, error)

LookupByInstance 通过实例查找转换器

func (*Registry) MustLookup

func (r *Registry) MustLookup(pbType, modelType reflect.Type) *BidiConverter

MustLookup 查找转换器,如果不存在则 panic

func (*Registry) MustRegister

func (r *Registry) MustRegister(converter *BidiConverter)

MustRegister 注册转换器,如果已存在则 panic

func (*Registry) Register

func (r *Registry) Register(converter *BidiConverter) error

Register 注册转换器

func (*Registry) Unregister

func (r *Registry) Unregister(pbType, modelType reflect.Type)

Unregister 移除转换器

type SafeConverter

type SafeConverter struct {
	*BidiConverter
}

SafeConverter 安全转换器 在转换前拦截 nil 与 typed-nil 指针,避免转换引擎 panic

func NewSafeConverter

func NewSafeConverter(pbType, modelType interface{}, opts ...Option) *SafeConverter

NewSafeConverter 创建安全转换器

func (*SafeConverter) SafeConvertModelToPB

func (sc *SafeConverter) SafeConvertModelToPB(model interface{}, pbPtr interface{}) error

SafeConvertModelToPB 安全的 Model -> PB 转换 自动处理 nil 与 typed-nil 指针,避免 panic

func (*SafeConverter) SafeConvertPBToModel

func (sc *SafeConverter) SafeConvertPBToModel(pb interface{}, modelPtr interface{}) error

SafeConvertPBToModel 安全的 PB -> Model 转换 自动处理 nil 与 typed-nil 指针,避免 panic typed-nil 检查已覆盖 safe Access 的 IsValid 语义,不再重复构造反射包装

type TestAllSlowInnerModel

type TestAllSlowInnerModel struct {
	Params map[string]interface{}
}

TestAllSlowInnerModel 与 TestAllSlowInnerPB 对应的 Model

type TestAllSlowInnerPB

type TestAllSlowInnerPB struct {
	Params *structpb.Struct
}

TestAllSlowInnerPB 全 slow 字段嵌套 PB(仅含 *structpb.Struct 字段) 用于触发 convertStructPtr:makeStructPtrCopyFunc 因无 fast 字段返回 nil,该字段成为 slowEntry

type TestAllTypesModel

type TestAllTypesModel struct {
	IntVal    int32
	Int64Val  int64
	UintVal   uint32
	Uint64Val uint64
	FloatVal  float32
	DoubleVal float64
	BoolVal   bool
	StrVal    string
	BytesVal  []byte
}

TestAllTypesModel 全类型测试 Model

type TestAllTypesPB

type TestAllTypesPB struct {
	IntVal    int32
	Int64Val  int64
	UintVal   uint32
	Uint64Val uint64
	FloatVal  float32
	DoubleVal float64
	BoolVal   bool
	StrVal    string
	BytesVal  []byte
}

TestAllTypesPB 全类型测试 PB

type TestDataWrapperModel

type TestDataWrapperModel struct {
	Name  string
	Count int
}

TestDataWrapperModel 与 TestDataWrapperPB 对应的 Model(Count 为 int 值类型)

type TestDataWrapperPB

type TestDataWrapperPB struct {
	Name  string
	Count IntWrapper
}

TestDataWrapperPB DataWrapper 测试 PB(Count 字段为 IntWrapper 值类型)

type TestEmptyModel

type TestEmptyModel struct{}

TestEmptyModel 空结构体 Model

type TestEmptyPB

type TestEmptyPB struct{}

TestEmptyPB 空结构体 PB

type TestInnerModel

type TestInnerModel struct {
	Label string
	Count int32
}

TestInnerModel 内嵌结构体 Model

type TestInnerPB

type TestInnerPB struct {
	Label string
	Count int32
}

TestInnerPB 内嵌结构体 PB

type TestMapModel

type TestMapModel struct {
	Name     string
	Metadata map[string]interface{}
}

type TestMapPB

type TestMapPB struct {
	Name     string            `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
	Metadata map[string]string `` /* 143-byte string literal not displayed */
	// contains filtered or unexported fields
}

type TestMapStringSliceModel

type TestMapStringSliceModel struct {
	Name   string
	Params map[string][]string
}

TestMapStringSliceModel 与 TestMapStringSlicePB 对应的 Model(Params 为 map[string][]string)

type TestMapStringSlicePB

type TestMapStringSlicePB struct {
	Name   string
	Params *structpb.Struct
}

TestMapStringSlicePB 测试 map[string][]string ↔ *structpb.Struct 快路径 触发 buildStructFromMapStringSlice

type TestMapStructModel

type TestMapStructModel struct {
	Name   string                 `json:"name"`
	Params map[string]interface{} `json:"params"`
}

TestMapStructModel 测试 map[string]any ↔ *structpb.Struct 的 Model 模拟 sqltypes.MapAny 字段场景

type TestMapStructPB

type TestMapStructPB struct {
	Name   string           `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
	Params *structpb.Struct `protobuf:"bytes,2,opt,name=params,proto3" json:"params,omitempty"`
	// contains filtered or unexported fields
}

TestMapStructPB 测试 map[string]any ↔ *structpb.Struct 的 PB Params 对应 google.protobuf.Struct 类型字段

type TestMixedInnerModel

type TestMixedInnerModel struct {
	Name   string
	Params map[string]interface{}
}

TestMixedInnerModel 与 TestMixedInnerPB 对应的 Model

type TestMixedInnerPB

type TestMixedInnerPB struct {
	Name   string
	Params *structpb.Struct
}

TestMixedInnerPB 混合字段嵌套 PB:Name(fast) + Params(slow in PB→Model) 在 PB→Model 方向,Params 为 slow(makeMapStructCopyFunc 对 *structpb.Struct→map 返回 nil), 从而触发外层 makeStructPtrCopyFunc 闭包中的 applyStructSlowEntriesUnsafe

type TestModel

type TestModel struct {
	ID     uint64 `pbmo:"Id"`
	Name   string
	Email  string `desensitize:"email"`
	Age    int
	Score  float64
	Active bool
	Tags   []string
}

TestModel 测试用 Model 结构体

type TestModelAllTypes

type TestModelAllTypes struct {
	Int       int     `gorm:"column:int" json:"int"`
	Int8      int8    `gorm:"column:int8" json:"int8"`
	Int16     int16   `gorm:"column:int16" json:"int16"`
	Int32     int32   `gorm:"column:int32" json:"int32"`
	Int64     int64   `gorm:"column:int64" json:"int64"`
	Uint      uint    `gorm:"column:uint" json:"uint"`
	Uint8     uint8   `gorm:"column:uint8" json:"uint8"`
	Uint16    uint16  `gorm:"column:uint16" json:"uint16"`
	Uint32    uint32  `gorm:"column:uint32" json:"uint32"`
	Uint64    uint64  `gorm:"column:uint64" json:"uint64"`
	Float32   float32 `gorm:"column:float32" json:"float32"`
	Float64   float64 `gorm:"column:float64" json:"float64"`
	Bool      bool    `gorm:"column:bool" json:"bool"`
	String    string  `gorm:"column:string" json:"string"`
	ByteSlice []byte  `gorm:"column:byte_slice" json:"byte_slice"`
	PtrInt    *int    `gorm:"column:ptr_int" json:"ptr_int"`
	PtrString *string `gorm:"column:ptr_string" json:"ptr_string"`
	PtrBool   *bool   `gorm:"column:ptr_bool" json:"ptr_bool"`
}

type TestModelForUpdates

type TestModelForUpdates struct {
	Name   string  `gorm:"column:name;type:varchar(255)" json:"name"`
	Status int     `gorm:"column:status;type:int" json:"status"`
	Score  float64 `gorm:"column:score;type:float" json:"score"`
	Active bool    `gorm:"column:active;type:boolean" json:"active"`
}

type TestModelJsonTag

type TestModelJsonTag struct {
	Label  string `json:"label,omitempty"`
	Count  int    `json:"count,omitempty"`
	Secret string `json:"-"`
}

type TestModelNoPbmoTag

type TestModelNoPbmoTag struct {
	ConfigKey int    `gorm:"column:config_key" json:"config_key"`
	Name      string `gorm:"column:name" json:"name"`
}

TestModelNoPbmoTag 无 pbmo tag 的 Model(仅 gorm/json tag), 用于测试 WithFieldMapping 在无 pbmo tag 时是否生效

type TestModelUnexported

type TestModelUnexported struct {
	Name string `gorm:"column:name" json:"name"`
	// contains filtered or unexported fields
}

type TestModelWithMapping

type TestModelWithMapping struct {
	ID    uint64 `pbmo:"ClientId"`
	Name  string `pbmo:"UserName"`
	Email string `pbmo:"UserEmail"`
}

TestModelWithMapping 测试用 Model 结构体(需要字段映射)

type TestNamedSliceModel

type TestNamedSliceModel struct {
	Name  string
	Tags  TestStringSlice
	Items TestStringSlice
}

TestNamedSliceModel 命名切片测试 Model(使用命名切片类型)

type TestNamedSlicePB

type TestNamedSlicePB struct {
	Name  string
	Tags  []string
	Items []string
}

TestNamedSlicePB 命名切片测试 PB(使用 []string)

type TestNestModel

type TestNestModel struct {
	Name   string
	Detail *TestSimpleModel
}

TestNestModel 嵌套测试 Model

type TestNestPB

type TestNestPB struct {
	Name   string
	Detail *TestSimplePB
}

TestNestPB 嵌套测试 PB

type TestNestedAutoModel

type TestNestedAutoModel struct {
	Name  string
	Inner *TestInnerModel
}

TestNestedAutoModel 嵌套自动转换 Model

type TestNestedAutoPB

type TestNestedAutoPB struct {
	Name  string
	Inner *TestInnerPB
}

TestNestedAutoPB 嵌套自动转换 PB

type TestOuterAllSlowModel

type TestOuterAllSlowModel struct {
	Name  string
	Inner *TestAllSlowInnerModel
}

TestOuterAllSlowModel 与 TestOuterAllSlowPB 对应的 Model

type TestOuterAllSlowPB

type TestOuterAllSlowPB struct {
	Name  string
	Inner *TestAllSlowInnerPB
}

TestOuterAllSlowPB 外层包含全 slow 嵌套指针(触发 convertStructPtr)

type TestOuterMixedModel

type TestOuterMixedModel struct {
	Name  string
	Inner *TestMixedInnerModel
}

TestOuterMixedModel 与 TestOuterMixedPB 对应的 Model

type TestOuterMixedPB

type TestOuterMixedPB struct {
	Name  string
	Inner *TestMixedInnerPB
}

TestOuterMixedPB 外层包含混合嵌套指针(触发 applyStructSlowEntriesUnsafe)

type TestOuterValueStructModel

type TestOuterValueStructModel struct {
	Name  string
	Inner TestAllSlowInnerModel
}

TestOuterValueStructModel 与 TestOuterValueStructPB 对应的 Model

type TestOuterValueStructPB

type TestOuterValueStructPB struct {
	Name  string
	Inner TestAllSlowInnerPB
}

TestOuterValueStructPB 外层包含值类型嵌套结构体(触发 convertStruct,非指针)

type TestPB

type TestPB struct {
	Id     uint64
	Name   string
	Email  string
	Age    int32
	Score  float64
	Active bool
	Tags   []string
}

TestPB 测试用 PB 结构体

type TestPBNoPbmoTag

type TestPBNoPbmoTag struct {
	Key  int32
	Name string
}

TestPBNoPbmoTag 对应的 PB,字段名与 Model 不同,需要 FieldMapping

type TestPBUpdatesEmpty

type TestPBUpdatesEmpty struct {
	// contains filtered or unexported fields
}

type TestPBUpdatesMsg

type TestPBUpdatesMsg struct {
	Status      int32                   `protobuf:"varint,1,opt,name=status,proto3" json:"status,omitempty"`
	HostStatus  int32                   `protobuf:"varint,2,opt,name=host_status,json=hostStatus,proto3" json:"host_status,omitempty"`
	TenantId    string                  `protobuf:"bytes,3,opt,name=tenant_id,json=tenantId,proto3" json:"tenant_id,omitempty"`
	RegionCode  string                  `protobuf:"bytes,4,opt,name=region_code,json=regionCode,proto3" json:"region_code,omitempty"`
	IsProxied   *wrapperspb.BoolValue   `protobuf:"varint,5,opt,name=is_proxied,json=isProxied,proto3" json:"is_proxied,omitempty"`
	DisplayName *wrapperspb.StringValue `protobuf:"bytes,6,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"`
	Priority    *wrapperspb.Int32Value  `protobuf:"varint,7,opt,name=priority,json=priority,proto3" json:"priority,omitempty"`
	Score       *wrapperspb.DoubleValue `protobuf:"varint,8,opt,name=score,json=score,proto3" json:"score,omitempty"`
	Metadata    map[string]string       `` /* 143-byte string literal not displayed */
	// contains filtered or unexported fields
}

type TestPBUpdatesNoTag

type TestPBUpdatesNoTag struct {
	Name    string
	Count   int32
	Ignored string `json:"-"`
	// contains filtered or unexported fields
}

type TestPBWithMapping

type TestPBWithMapping struct {
	ClientId  uint64
	UserName  string
	UserEmail string
}

TestPBWithMapping 测试用 PB 结构体(需要字段映射)

type TestSimpleModel

type TestSimpleModel struct {
	Value string
	Count int32
}

TestSimpleModel 简单测试 Model

type TestSimplePB

type TestSimplePB struct {
	Value string
	Count int32
}

TestSimplePB 简单测试 PB

type TestSingleFieldModel

type TestSingleFieldModel struct {
	Name string
}

TestSingleFieldModel 单字段 Model

type TestSingleFieldPB

type TestSingleFieldPB struct {
	Name string
}

TestSingleFieldPB 单字段 PB

type TestSliceStructModel

type TestSliceStructModel struct {
	Name  string
	Items []*TestAllSlowInnerModel
}

TestSliceStructModel 与 TestSliceStructPB 对应的 Model

type TestSliceStructPB

type TestSliceStructPB struct {
	Name  string
	Items []*TestAllSlowInnerPB
}

TestSliceStructPB 切片元素为不同结构体指针(触发 convertSlice/convertElement) 元素类型 *TestAllSlowInnerPB → *TestAllSlowInnerModel 不 ConvertibleTo, 且元素结构体全 slow,使 makeSliceCopyFunc 返回 nil

type TestSliceValueStructModel

type TestSliceValueStructModel struct {
	Name  string
	Items []TestAllSlowInnerModel
}

TestSliceValueStructModel 与 TestSliceValueStructPB 对应的 Model

type TestSliceValueStructPB

type TestSliceValueStructPB struct {
	Name  string
	Items []TestAllSlowInnerPB
}

TestSliceValueStructPB 切片元素为值结构体(覆盖 convertSlice 元素为值类型的分支)

type TestStringSlice

type TestStringSlice []string

TestStringSlice 命名字符串切片类型

type TestTimePtrModel

type TestTimePtrModel struct {
	Name        string
	ScheduledAt *time.Time
	ReleasedAt  *time.Time
}

TestTimePtrModel 时间指针测试 Model

type TestTimePtrPB

type TestTimePtrPB struct {
	Name        string
	ScheduledAt *timestamppb.Timestamp
	ReleasedAt  *timestamppb.Timestamp
}

TestTimePtrPB 时间指针测试 PB

type TestTimeZeroModel

type TestTimeZeroModel struct {
	Name      string
	CreatedAt time.Time
	UpdatedAt time.Time
}

TestTimeZeroModel 时间零值测试 Model

type TestTimeZeroPB

type TestTimeZeroPB struct {
	Name      string
	CreatedAt *timestamppb.Timestamp
	UpdatedAt *timestamppb.Timestamp
}

TestTimeZeroPB 时间零值测试 PB

type TestWrapperFieldModel

type TestWrapperFieldModel struct {
	Name   string
	MinVal *int32
	MaxVal *int32
}

TestWrapperFieldModel Wrapper 字段测试 Model

type TestWrapperFieldPB

type TestWrapperFieldPB struct {
	Name   string
	MinVal *wrapperspb.Int32Value
	MaxVal *wrapperspb.Int32Value
}

TestWrapperFieldPB Wrapper 字段测试 PB

type TestWrapperValueModel

type TestWrapperValueModel struct {
	Name     string
	IsActive bool
	Count    int32
	Score    float64
	Label    string
}

type TestWrapperValuePB

type TestWrapperValuePB struct {
	Name     string                  `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
	IsActive *wrapperspb.BoolValue   `protobuf:"varint,2,opt,name=is_active,json=isActive,proto3" json:"is_active,omitempty"`
	Count    *wrapperspb.Int32Value  `protobuf:"varint,3,opt,name=count,proto3" json:"count,omitempty"`
	Score    *wrapperspb.DoubleValue `protobuf:"varint,4,opt,name=score,proto3" json:"score,omitempty"`
	Label    *wrapperspb.StringValue `protobuf:"bytes,5,opt,name=label,proto3" json:"label,omitempty"`
	// contains filtered or unexported fields
}

type TransformerFunc

type TransformerFunc func(interface{}) interface{}

TransformerFunc 字段转换函数类型 输入原始字段值,输出转换后的值

type TransformerRegistry

type TransformerRegistry struct {
	// contains filtered or unexported fields
}

TransformerRegistry 字段转换器注册表 封装 sync.Map 提供类型安全的字段转换器管理,天然并发安全 count: 原子计数器,避免 Count() 使用 sync.Map.Range() 的 O(n) 开销

func NewTransformerRegistry

func NewTransformerRegistry() *TransformerRegistry

NewTransformerRegistry 创建字段转换器注册表

func (*TransformerRegistry) Apply

func (tr *TransformerRegistry) Apply(field string, value reflect.Value) reflect.Value

Apply 应用字段转换器 如果字段有注册的转换器,则应用转换;否则返回原始值

func (*TransformerRegistry) Clear

func (tr *TransformerRegistry) Clear()

Clear 清空所有转换器

func (*TransformerRegistry) Clone

Clone 克隆转换器注册表

func (*TransformerRegistry) Count

func (tr *TransformerRegistry) Count() int

Count 获取已注册的转换器数量

func (*TransformerRegistry) Fields

func (tr *TransformerRegistry) Fields() []string

Fields 获取所有已注册的字段名

func (*TransformerRegistry) Has

func (tr *TransformerRegistry) Has(field string) bool

Has 检查字段是否有注册的转换器

func (*TransformerRegistry) Lookup

func (tr *TransformerRegistry) Lookup(field string) (TransformerFunc, bool)

Lookup 查找字段转换器

func (*TransformerRegistry) Register

func (tr *TransformerRegistry) Register(field string, fn TransformerFunc)

Register 注册字段转换器

func (*TransformerRegistry) RegisterBatch

func (tr *TransformerRegistry) RegisterBatch(transformers map[string]TransformerFunc)

RegisterBatch 批量注册字段转换器

func (*TransformerRegistry) Remove

func (tr *TransformerRegistry) Remove(field string)

Remove 移除字段转换器

type UpdatesBuilder

type UpdatesBuilder struct {
	// contains filtered or unexported fields
}

UpdatesBuilder 更新字段构建器

func NewUpdates

func NewUpdates() *UpdatesBuilder

NewUpdates 初始化字段构建器

func (*UpdatesBuilder) Build

func (b *UpdatesBuilder) Build() map[string]interface{}

func (*UpdatesBuilder) Clear

func (b *UpdatesBuilder) Clear() *UpdatesBuilder

func (*UpdatesBuilder) Delete

func (b *UpdatesBuilder) Delete(key string) *UpdatesBuilder

func (*UpdatesBuilder) Has

func (b *UpdatesBuilder) Has(key string) bool

func (*UpdatesBuilder) IsEmpty

func (b *UpdatesBuilder) IsEmpty() bool

func (*UpdatesBuilder) Len

func (b *UpdatesBuilder) Len() int

func (*UpdatesBuilder) Merge

func (b *UpdatesBuilder) Merge(other *UpdatesBuilder) *UpdatesBuilder

func (*UpdatesBuilder) Set

func (b *UpdatesBuilder) Set(key string, value interface{}) *UpdatesBuilder

func (*UpdatesBuilder) SetBoolVal

func (b *UpdatesBuilder) SetBoolVal(key string, val *wrapperspb.BoolValue) *UpdatesBuilder

func (*UpdatesBuilder) SetDoubleVal

func (b *UpdatesBuilder) SetDoubleVal(key string, val *wrapperspb.DoubleValue) *UpdatesBuilder

func (*UpdatesBuilder) SetFloatVal

func (b *UpdatesBuilder) SetFloatVal(key string, val *wrapperspb.FloatValue) *UpdatesBuilder

func (*UpdatesBuilder) SetIf

func (b *UpdatesBuilder) SetIf(condition bool, key string, value interface{}) *UpdatesBuilder

func (*UpdatesBuilder) SetIfNotEmpty

func (b *UpdatesBuilder) SetIfNotEmpty(key string, value interface{}) *UpdatesBuilder

SetIfNotEmpty 设置字符串字段(非空时) 支持 string 和 *wrapperspb.StringValue 类型 使用 IsEmptyValue 进行严格的空值判断:

  • 过滤空字符串、空白字符(空格、tab、换行等)
  • 过滤 "null"、"undefined" 字符串(不区分大小写)
  • 过滤 nil 值

func (*UpdatesBuilder) SetIfNotNil

func (b *UpdatesBuilder) SetIfNotNil(key string, value interface{}) *UpdatesBuilder

func (*UpdatesBuilder) SetIfNotZero

func (b *UpdatesBuilder) SetIfNotZero(key string, value interface{}) *UpdatesBuilder

func (*UpdatesBuilder) SetInt32Val

func (b *UpdatesBuilder) SetInt32Val(key string, val *wrapperspb.Int32Value) *UpdatesBuilder

func (*UpdatesBuilder) SetInt64Val

func (b *UpdatesBuilder) SetInt64Val(key string, val *wrapperspb.Int64Value) *UpdatesBuilder

func (*UpdatesBuilder) SetJSON

func (b *UpdatesBuilder) SetJSON(key string, value string, defaultJSON ...string) *UpdatesBuilder

func (*UpdatesBuilder) SetJSONSlice

func (b *UpdatesBuilder) SetJSONSlice(key string, value interface{}) *UpdatesBuilder

func (*UpdatesBuilder) SetJSONVal

func (b *UpdatesBuilder) SetJSONVal(key string, val *wrapperspb.StringValue, defaultJSON ...string) *UpdatesBuilder

func (*UpdatesBuilder) SetNull

func (b *UpdatesBuilder) SetNull(key string) *UpdatesBuilder

SetNull 将字段设置为 NULL(等价于 Set(key, nil)) 用于将数据库字段清空的语义化写法,如 SetNull("callback_at") 替代 Set("callback_at", time.Time{})

func (*UpdatesBuilder) SetString

func (b *UpdatesBuilder) SetString(key string, val string) *UpdatesBuilder

SetString 设置 plain string 字段(空字符串/空白时跳过) 用于 proto3 非 wrapper 的 string 字段,区分"未发送(默认空字符串)"和"有值"

func (*UpdatesBuilder) SetStringVal

func (b *UpdatesBuilder) SetStringVal(key string, val *wrapperspb.StringValue) *UpdatesBuilder

func (*UpdatesBuilder) SetStringValAny

func (b *UpdatesBuilder) SetStringValAny(key string, val *wrapperspb.StringValue) *UpdatesBuilder

func (*UpdatesBuilder) SetStringValOrEmpty

func (b *UpdatesBuilder) SetStringValOrEmpty(key string, val *wrapperspb.StringValue) *UpdatesBuilder

SetStringValOrEmpty 设置字段(nil 也写入空字符串,用于全量覆盖场景) 与 SetStringValAny 的区别:nil 不跳过,而是写入 ""

func (*UpdatesBuilder) String

func (b *UpdatesBuilder) String() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL