整理代码结构, 增加普通结构体单元测试

This commit is contained in:
2025-03-23 14:20:49 +08:00
parent 7b830c8a9e
commit 9ef4123f38
7 changed files with 210 additions and 108 deletions

View File

@ -7,73 +7,22 @@ import (
"strings"
)
type (
// Builder 运行时动态生成结构体的接口约束
Builder interface {
// AddField 添加结构体字段
AddField(name string, pkg string, typ any, tag string, anonymous bool) Builder
// RemoveField 移除指定名称的结构体字段
RemoveField(name string) Builder
// HasField 检测指定名称的结构体字段是否存在
HasField(name string) bool
// GetField 根据名称获取结构体字段定义
GetField(name string) FieldConfig
// Build 返回动态定义的结构体.
Build() DynamicStruct
}
type nestedStruct struct {
Field string
Builder IBuilder
Tag string
}
// FieldConfig 结构体字段的定义.
FieldConfig interface {
// SetType 设置字段类型.
SetType(typ any) FieldConfig
// SetTag 设置字段 tag.
SetTag(tag string) FieldConfig
}
// DynamicStruct contains defined dynamic struct.
// This definition can't be changed anymore, once is built.
// It provides a method for creating new instances of same defintion.
DynamicStruct interface {
// New 获取结构体实例, 所有字段值均为对应类型的初始零值
New() any
// NewSliceOfStructs slice实例化
NewSliceOfStructs() any
// NewMapOfStructs map 或者 struct实例化
NewMapOfStructs(key any) any
}
nestedStruct struct {
Field string
Builder Builder
Tag string
}
builderImpl struct {
fields []*fieldConfigImpl
nestedStructTable map[string]nestedStruct // 嵌套结构体的定义, 父级路径 => 父级路径下挂接的子路径
maxFieldDeep int // 字段嵌套最大深度
structTagTable map[string]string // 字段路径 => json tag最高优先级, 没传的时候会使用AddField的tag, 也为空使用手搓json tag
}
fieldConfigImpl struct {
name string
pkg string
typ any
tag string
anonymous bool
}
dynamicStructImpl struct {
structFields []reflect.StructField
definition reflect.Type
}
)
type builderImpl struct {
fields []*fieldConfigImpl
nestedStructTable map[string]nestedStruct // 嵌套结构体的定义, 父级路径 => 父级路径下挂接的子路径
maxFieldDeep int // 字段嵌套最大深度
structTagTable map[string]string // 字段路径 => json tag最高优先级, 没传的时候会使用AddField的tag, 也为空使用手搓json tag
}
// NewStruct 获取builder实例
// 传入的tag映射表: 字段路径 => json tag最高优先级, 没传的时候会使用AddField的tag, 也为空使用手搓json tag
func NewStruct(structTagTable map[string]string) Builder {
func NewStruct(structTagTable map[string]string) IBuilder {
return &builderImpl{
fields: []*fieldConfigImpl{},
nestedStructTable: make(map[string]nestedStruct),
@ -82,12 +31,12 @@ func NewStruct(structTagTable map[string]string) Builder {
}
// ExtendStruct 基于已有结构体, 生成动态结构体(相当于继承指定的结构体属性)
func ExtendStruct(value ...any) Builder {
func ExtendStruct(value ...any) IBuilder {
return MergeStructs(value...)
}
// MergeStructs 多个结构体合并成一个动态结构体
func MergeStructs(values ...any) Builder {
func MergeStructs(values ...any) IBuilder {
builder := NewStruct(map[string]string{})
for _, value := range values {
@ -111,8 +60,8 @@ func (b *builderImpl) parseNestedField(fieldName string) ([]string, bool) {
}
// AddField 添加结构体字段
func (b *builderImpl) AddField(name string, pkg string, typ any, tag string, anonymous bool) Builder {
// 瞎话线转驼峰, 传入的name实际对应序列化时的json tag
func (b *builderImpl) AddField(name string, pkg string, typ any, tag string, anonymous bool) IBuilder {
// 下划线转驼峰, 传入的name实际对应序列化时的json tag
// name = wrapper.String(name).SnakeCaseToCamel()
if cfgTag, exist := b.structTagTable[name]; exist && len(cfgTag) > 0 {
tag = cfgTag
@ -191,7 +140,7 @@ func (b *builderImpl) addNestedField(nameArr []string, pkg string, typ any, tag
}
// RemoveField 根据名称移除结构体字段
func (b *builderImpl) RemoveField(name string) Builder {
func (b *builderImpl) RemoveField(name string) IBuilder {
newFieldList := make([]*fieldConfigImpl, 0)
for i := range b.fields {
if b.fields[i].name == name {
@ -214,7 +163,7 @@ func (b *builderImpl) HasField(name string) bool {
}
// GetField 根据名称获取字段配置, 不存在, 返回nil
func (b *builderImpl) GetField(name string) FieldConfig {
func (b *builderImpl) GetField(name string) IFieldConfig {
for i := range b.fields {
if b.fields[i].name == name {
return b.fields[i]
@ -224,7 +173,7 @@ func (b *builderImpl) GetField(name string) FieldConfig {
}
// Build 构建动态结构体
func (b *builderImpl) Build() DynamicStruct {
func (b *builderImpl) Build() IDynamicStruct {
// 按照嵌套深度, 进行一次回溯处理
for deep := b.maxFieldDeep - 1; deep > 0; deep-- {
// 嵌套数据结构
@ -281,7 +230,7 @@ func (b *builderImpl) Build() DynamicStruct {
var structFields []reflect.StructField
for _, field := range b.fields {
if strings.Contains(field.name, ArraySplit) {
// TODO : 临时过滤, 后续需要在正确逻辑处正确移除
// 去除数组路径
continue
}
structFields = append(structFields, reflect.StructField{
@ -297,31 +246,3 @@ func (b *builderImpl) Build() DynamicStruct {
definition: reflect.StructOf(structFields),
}
}
// SetType 设置字段类型
func (f *fieldConfigImpl) SetType(typ any) FieldConfig {
f.typ = typ
return f
}
// SetTag 设置字段标签
func (f *fieldConfigImpl) SetTag(tag string) FieldConfig {
f.tag = tag
return f
}
// New 创建动态结构体实例
func (ds *dynamicStructImpl) New() any {
// 不要指针,全部解引用
return reflect.New(ds.definition).Interface()
}
// NewSliceOfStructs 创建动态结构体切片实例
func (ds *dynamicStructImpl) NewSliceOfStructs() any {
return reflect.New(reflect.SliceOf(ds.definition)).Interface()
}
// NewMapOfStructs 创建动态结构体map实例
func (ds *dynamicStructImpl) NewMapOfStructs(key any) any {
return reflect.New(reflect.MapOf(reflect.Indirect(reflect.ValueOf(key)).Type(), ds.definition)).Interface()
}