dynamic-struct/builder.go

282 lines
8.2 KiB
Go

package dynamicstruct
import (
"fmt"
"git.zhangdeman.cn/zhangdeman/wrapper"
"reflect"
"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
}
// 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
JsonTag string
}
builderImpl struct {
fields []*fieldConfigImpl
nestedStructTable map[string]nestedStruct // 嵌套结构体的定义, 父级路径 => 父级路径下挂接的子路径
maxFieldDeep int // 字段嵌套最大深度
}
fieldConfigImpl struct {
name string
pkg string
typ any
tag string
anonymous bool
}
dynamicStructImpl struct {
structFields []reflect.StructField
definition reflect.Type
}
)
// NewStruct 获取builder实例
func NewStruct() Builder {
return &builderImpl{
fields: []*fieldConfigImpl{},
nestedStructTable: make(map[string]nestedStruct),
}
}
// ExtendStruct 基于已有结构体, 生成动态结构体(相当于继承指定的结构体属性)
func ExtendStruct(value ...any) Builder {
return MergeStructs(value...)
}
// MergeStructs 多个结构体合并成一个动态结构体
func MergeStructs(values ...any) Builder {
builder := NewStruct()
for _, value := range values {
valueOf := reflect.Indirect(reflect.ValueOf(value))
typeOf := valueOf.Type()
for i := 0; i < valueOf.NumField(); i++ {
fVal := valueOf.Field(i)
fTyp := typeOf.Field(i)
builder.(*builderImpl).AddField(fTyp.Name, fTyp.PkgPath, fVal.Interface(), string(fTyp.Tag), fTyp.Anonymous)
}
}
return builder
}
// IsNestedField 判断是否是嵌套结构体
func (b *builderImpl) parseNestedField(fieldName string) ([]string, bool) {
fieldNameArr := strings.Split(strings.Trim(fieldName, "."), ".")
return fieldNameArr, len(fieldNameArr) > 1
}
// AddField 添加结构体字段
func (b *builderImpl) AddField(name string, pkg string, typ any, tag string, anonymous bool) Builder {
// 瞎话线转驼峰, 传入的name实际对应序列化时的json tag
// name = wrapper.String(name).SnakeCaseToCamel()
// 判断是否嵌套结构体
fieldNameArr, isNestedField := b.parseNestedField(name)
if !isNestedField {
// 普通字段
b.addNormalField(name, pkg, typ, tag, anonymous)
return b
}
// 添加嵌套的结构体
b.addNestedField(fieldNameArr, pkg, typ, tag, anonymous)
return b
}
// addNormalField 添加普通无嵌套的字段
func (b *builderImpl) addNormalField(name string, pkg string, typ any, tag string, anonymous bool) {
name = wrapper.String(name).SnakeCaseToCamel()
if existFieldCfg := b.GetField(name); nil != existFieldCfg {
// 说明已存在指定名称字段
// 重复添加, 则会议后面的标签以及类型, 覆盖前面的值
existFieldCfg.SetTag(tag)
existFieldCfg.SetType(typ)
return
}
b.fields = append(b.fields, &fieldConfigImpl{
name: name,
typ: typ,
tag: tag,
anonymous: anonymous,
pkg: pkg,
})
}
// addNestedField 添加嵌套字段
func (b *builderImpl) addNestedField(nameArr []string, pkg string, typ any, tag string, anonymous bool) {
if len(nameArr) == 1 {
// 说明已经是最顶层结构了
b.addNormalField(nameArr[0], pkg, typ, tag, anonymous)
return
}
if len(nameArr) > b.maxFieldDeep {
// 设置字段嵌套的最大深度, 由于生成结构体确认深度使用
b.maxFieldDeep = len(nameArr)
}
for i := len(nameArr) - 1; i > 0; i-- {
jsonTag := nameArr[i]
fieldName := wrapper.String(jsonTag).SnakeCaseToCamel()
parentName := strings.Join(nameArr[:i], ".")
parentJsonTag := nameArr[i-1]
parentFieldName := wrapper.String(parentJsonTag).SnakeCaseToCamel()
if len(parentName) > 0 {
if _, exist := b.nestedStructTable[parentName]; !exist {
b.nestedStructTable[parentName] = nestedStruct{
Field: parentFieldName,
Builder: NewStruct(),
JsonTag: parentJsonTag,
}
}
}
if i == len(nameArr)-1 {
// 最深层此字段, 直接追加到他的父级结构体中即可
b.nestedStructTable[parentName].Builder.AddField(fieldName, pkg, typ, tag, anonymous)
continue
}
}
}
// RemoveField 根据名称移除结构体字段
func (b *builderImpl) RemoveField(name string) Builder {
newFieldList := make([]*fieldConfigImpl, 0)
for i := range b.fields {
if b.fields[i].name == name {
continue
}
newFieldList = append(newFieldList, b.fields[i])
}
b.fields = newFieldList
return b
}
// HasField 是否存在指定字段
func (b *builderImpl) HasField(name string) bool {
for i := range b.fields {
if b.fields[i].name == name {
return true
}
}
return false
}
// GetField 根据名称获取字段配置, 不存在, 返回nil
func (b *builderImpl) GetField(name string) FieldConfig {
for i := range b.fields {
if b.fields[i].name == name {
return b.fields[i]
}
}
return nil
}
// Build 构建动态结构体
func (b *builderImpl) Build() DynamicStruct {
// 按照嵌套深度, 进行一次回溯处理
for deep := b.maxFieldDeep - 1; deep > 0; deep-- {
// 嵌套数据结构
for parentIndex, builderCfg := range b.nestedStructTable {
parentNameArr := strings.Split(parentIndex, ".")
if len(parentNameArr) != deep {
// 从深度最深处向上处理
continue
}
/*if deep == b.maxFieldDeep-1 {
// 说明最深层嵌套结构
parentJsonTag := parentNameArr[deep-1]
parentField := wrapper.String(parentJsonTag).SnakeCaseToCamel()
b.AddField(parentField, "", builderCfg.Builder.Build().New(), fmt.Sprintf(`json:"%v"`, parentJsonTag), false)
continue
}*/
if deep == 1 {
// 说明是顶层了
b.AddField(builderCfg.Field, "", builderCfg.Builder.Build().New(), fmt.Sprintf(`json:"%v"`, builderCfg.JsonTag), false)
} else {
// (非顶层) 父级结构存在, 将其追加到父级结构中即可, 向前看一步即为父级结构
b.nestedStructTable[strings.Join(parentNameArr[:len(parentNameArr)-1], ".")].Builder.AddField(builderCfg.Field, "", builderCfg.Builder.Build().New(), fmt.Sprintf(`json:"%v"`, builderCfg.JsonTag), false)
}
}
}
// 一级字段属性
var structFields []reflect.StructField
for _, field := range b.fields {
structFields = append(structFields, reflect.StructField{
Name: field.name,
PkgPath: field.pkg,
Type: reflect.TypeOf(field.typ),
Tag: reflect.StructTag(field.tag),
Anonymous: field.anonymous,
})
}
return &dynamicStructImpl{
structFields: structFields,
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()
}