dynamic-struct/builder.go

328 lines
10 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
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
}
)
// NewStruct 获取builder实例
// 传入的tag映射表: 字段路径 => json tag最高优先级, 没传的时候会使用AddField的tag, 也为空使用手搓json tag
func NewStruct(structTagTable map[string]string) Builder {
return &builderImpl{
fields: []*fieldConfigImpl{},
nestedStructTable: make(map[string]nestedStruct),
structTagTable: structTagTable,
}
}
// ExtendStruct 基于已有结构体, 生成动态结构体(相当于继承指定的结构体属性)
func ExtendStruct(value ...any) Builder {
return MergeStructs(value...)
}
// MergeStructs 多个结构体合并成一个动态结构体
func MergeStructs(values ...any) Builder {
builder := NewStruct(map[string]string{})
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()
if cfgTag, exist := b.structTagTable[name]; exist && len(cfgTag) > 0 {
tag = cfgTag
} else {
if len(tag) == 0 {
tag = fmt.Sprintf(`json:"%s"`, name)
}
}
// 判断是否嵌套结构体
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()
fieldTag := fmt.Sprintf(`json:"%s"`, parentJsonTag)
if tagCfg, exist := b.structTagTable[parentName]; exist && len(tagCfg) > 0 {
fieldTag = tagCfg
}
if len(parentName) > 0 {
if _, exist := b.nestedStructTable[parentName]; !exist {
b.nestedStructTable[parentName] = nestedStruct{
Field: parentFieldName,
Builder: NewStruct(b.structTagTable),
Tag: fieldTag,
}
}
}
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 == 1 {
// 说明是顶层了
b.AddField(builderCfg.Field, "", builderCfg.Builder.Build().New(), builderCfg.Tag, false)
} else {
// 处理数组
arrDeep := 0
newParentNameArr := []string{}
for i := len(parentNameArr) - 1; i >= 0; i-- {
if parentNameArr[i] != ArraySplit {
newParentNameArr = parentNameArr[:i+1]
break
}
// 删除
delete(b.nestedStructTable, strings.Join(parentNameArr[:i+1], "."))
arrDeep++
}
if arrDeep > 0 {
// 数组嵌套数组配置
val := reflect.ValueOf(builderCfg.Builder.Build().New()).Elem().Interface()
for i := 0; i < arrDeep; i++ {
val = reflect.New(reflect.SliceOf(reflect.TypeOf(val))).Interface()
}
// 解除指针引用
val = reflect.ValueOf(val).Elem().Interface()
newParamIndex := strings.Join(newParentNameArr, ".")
isTopIndex := len(newParentNameArr) == 1
if isTopIndex {
// 顶层结构, 数组类型不存在还有其他属性情况, 直接追加字段, 并移除嵌套表里的定义
b.AddField(b.nestedStructTable[newParamIndex].Field, "", val, b.nestedStructTable[newParamIndex].Tag, false)
delete(b.nestedStructTable, newParamIndex)
// b.nestedStructTable[newParamIndex].Builder.AddField(b.nestedStructTable[newParamIndex].Field, "", val, b.nestedStructTable[newParamIndex].Tag, false)
} else {
// 非顶层结构, 再上探一级
b.nestedStructTable[strings.Join(newParentNameArr[:len(newParentNameArr)-1], ".")].Builder.AddField(b.nestedStructTable[newParamIndex].Field, "", val, b.nestedStructTable[newParamIndex].Tag, false)
}
} else {
// 非数组
// (非顶层) 父级结构存在, 将其追加到父级结构中即可, 向前看一步即为父级结构
b.nestedStructTable[strings.Join(parentNameArr[:len(parentNameArr)-1], ".")].Builder.AddField(builderCfg.Field, "", builderCfg.Builder.Build().New(), builderCfg.Tag, false)
}
}
}
}
// 一级字段属性
var structFields []reflect.StructField
for _, field := range b.fields {
if strings.Contains(field.name, ArraySplit) {
// TODO : 临时过滤, 后续需要在正确逻辑处正确移除
continue
}
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()
}