代码拉取完成,页面将自动刷新
package schema
import (
"errors"
"fmt"
"go/ast"
"reflect"
"gitee.com/leminewx/wxorm/dialect"
"gitee.com/leminewx/wxorm/dialect/column"
)
const _TAG = "wxorm"
var (
ErrValueNil = errors.New("wxorm: value is nil")
ErrValueNotStruct = errors.New("wxorm: value is not Struct or *Struct")
ErrModelNotStruct = errors.New("wxorm: model is not Struct or *Struct")
ErrModelNilPointer = errors.New("wxorm: model pointer is nil")
ErrModelEmptyFields = errors.New("wxorm: model struct has no available field")
ErrValuesEmpty = errors.New("wxorm: values is empty")
)
type TableNameGetter interface {
GetTableName() string
}
// Schema 定义数据表的数据结构
type Schema struct {
TableName string // 数据表名
ModelName string // 数据模型名称
ModelType reflect.Type // 数据模型类型
Model any // 数据模型
Fields []*reflect.StructField // 数据模型字段
Methods []*reflect.Method // 数据模型方法
Columns []column.Column // 数据表字段列表
ColumnNames []string // 数据表字段名列表
ColumnIndexesInModel []int // 数据表字段索引列表(数据表字段在对应的数据模型中的索引)
InsertableColumnNames []string // 数据表可插入字段名列表
InsertableFieldIndexes []int // 数据模型可插入字段索引列表
}
/*
Parse 解析 Go 结构体数据模型与数据表的对应关系
- dial: 对应数据库的 dialect.Dialect
- model: 数据表对应的数据模型,推荐使用 *Struct 格式
*/
func Parse(dial dialect.Dialect, model any) (*Schema, error) {
// 获取数据模型
modelValue, err := GetModelStruct(model)
if err != nil {
return nil, err
}
modelType := modelValue.Type()
// 尝试从缓存中获取数据模型
cacheKey := modelType.String()
if tab, ok := schemaCache.Load(cacheKey); ok {
return tab.(*Schema), nil
}
// 获取数据表名
var tableName string
if tab, ok := model.(TableNameGetter); ok {
tableName = tab.GetTableName()
} else {
tableName = column.FormatHumpToUnderline([]byte(modelType.Name()))
}
// 初始化数据表
fieldNum := modelValue.NumField()
sch := &Schema{
TableName: tableName,
ModelName: modelType.Name(),
ModelType: modelType,
Model: model,
Fields: make([]*reflect.StructField, 0, fieldNum),
Columns: make([]column.Column, 0, fieldNum),
ColumnNames: make([]string, 0, fieldNum),
ColumnIndexesInModel: make([]int, 0, fieldNum),
InsertableColumnNames: make([]string, 0, fieldNum),
InsertableFieldIndexes: make([]int, 0, fieldNum),
}
// 遍历数据模型的所有字段
for i := range cap(sch.Fields) {
field := modelType.Field(i)
// 过滤掉匿名和不可导出字段
if field.Anonymous || !ast.IsExported(field.Name) {
continue
}
// 过滤掉非 orm 标签
tag := field.Tag.Get(_TAG)
if tag == "-" || tag == "" {
continue
}
// 解析标签,生成数据字段
col, err := dial.ParseColumn(tag)
if err != nil {
return nil, fmt.Errorf("wxorm: failed to parse column tag for field %s: %w", field.Name, err)
}
// 检查数据字段名
if col.GetName() == "" {
name := column.FormatHumpToUnderline([]byte(field.Name))
col.SetName(name)
}
// 检查数据字段类型
if col.GetDatatype() == "" {
col.SetDatatype(dial.ConvertDatatype(field.Type))
}
// 添加每一个数据表字段
sch.Fields = append(sch.Fields, &field)
sch.Columns = append(sch.Columns, col)
sch.ColumnNames = append(sch.ColumnNames, col.GetName())
sch.ColumnIndexesInModel = append(sch.ColumnIndexesInModel, i)
// 添加可写入的数据表字段
if !col.IsAutoInsert() {
sch.InsertableColumnNames = append(sch.InsertableColumnNames, col.GetName())
sch.InsertableFieldIndexes = append(sch.InsertableFieldIndexes, i)
}
}
// 检查数据表字段
if len(sch.Columns) == 0 {
return nil, ErrModelEmptyFields
}
// 遍历数据模型的所有方法
modelValue = reflect.ValueOf(model)
if modelValue.Kind() == reflect.Ptr {
modelType = modelValue.Type()
}
// 对于值类型,也可以获取方法,但只能获取值接收者的方法
sch.Methods = make([]*reflect.Method, 0, modelType.NumMethod())
for i := 0; i < modelType.NumMethod(); i++ {
method := modelType.Method(i)
sch.Methods = append(sch.Methods, &method)
}
// 缓存数据模型
PutToCache(cacheKey, sch)
return sch, nil
}
// GetColumnByName 根据字段名获取数据字段
func (own *Schema) GetColumnByName(name string) (column.Column, error) {
for _, col := range own.Columns {
if col.GetName() == name {
return col, nil
}
}
return nil, fmt.Errorf("wxorm: column '%s' not found in table '%s'", name, own.TableName)
}
/*
ExtractValue 从结构体中提取单个数据
- value:数据格式 Struct 或 *Struct
*/
func (own *Schema) ExtractValue(value any) ([]any, error) {
// 检查数据是否为空
if value == nil {
return nil, ErrValueNil
}
// 获取数据的反射值
val := reflect.ValueOf(value)
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
// 检查数据类型是否匹配
if val.Type() != own.ModelType {
return nil, fmt.Errorf("wxorm: value model '%s' is not match schema model '%s'", val.Type().Name(), own.ModelName)
}
// 按索引提取数据
dst := make([]any, len(own.InsertableFieldIndexes))
for i, idx := range own.InsertableFieldIndexes {
dst[i], _ = GetReflectFieldValue(val.Field(idx))
}
return dst, nil
}
// ExtractPrimaryKeyValues 提取数据主键数据
func (own *Schema) ExtractPrimaryKeyValues(value reflect.Value) (pkNames []string, pkValues []any, isZero bool) {
isZero = true
pkNames = make([]string, 0, len(own.ColumnIndexesInModel))
pkValues = make([]any, 0, len(own.ColumnIndexesInModel))
for colIdx, fieldIdx := range own.ColumnIndexesInModel {
col := own.Columns[colIdx]
if !col.IsPrimaryKey() {
continue
}
pkNames = append(pkNames, col.GetName())
pkValue, zero := GetReflectFieldValue(value.Field(fieldIdx))
if !zero {
isZero = false
}
pkValues = append(pkValues, pkValue)
}
return
}
// GetModelStruct 获取数据模型的数据结构
func GetModelStruct(model any) (reflect.Value, error) {
if model == nil {
return reflect.Value{}, ErrModelNilPointer
}
// 如果数据模型是指针类型,则获取底层类型
value := reflect.ValueOf(model)
if value.Kind() == reflect.Ptr {
if value.IsNil() {
return reflect.Value{}, ErrModelNilPointer
}
value = value.Elem()
}
// 检查数据模型是否为 Go 结构体
if value.Type().Kind() != reflect.Struct {
return reflect.Value{}, ErrModelNotStruct
}
return value, nil
}
// GetReflectFieldValue 获取反射字段的值
func GetReflectFieldValue(field reflect.Value) (value any, zero bool) {
switch field.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
value := field.Int()
return value, value == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
value := field.Uint()
return value, value == 0
case reflect.Float32, reflect.Float64:
value := field.Float()
return value, value == 0
case reflect.Bool:
value := field.Bool()
return value, !value
case reflect.String:
value := field.String()
return value, value == ""
default:
// 复杂类型使用 Interface()
value := field.Interface()
switch field.Kind() {
case reflect.Ptr, reflect.Interface, reflect.Slice, reflect.Map, reflect.Chan:
return value, field.IsNil()
default:
return value, reflect.DeepEqual(field.Interface(), reflect.Zero(field.Type()).Interface())
}
}
}
// IsZeroValue 判断是否为零值
func IsZeroValue(value reflect.Value) bool {
switch value.Kind() {
case reflect.String:
return value.String() == ""
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return value.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return value.Uint() == 0
case reflect.Float32, reflect.Float64:
return value.Float() == 0
case reflect.Bool:
return !value.Bool()
case reflect.Ptr, reflect.Interface, reflect.Slice, reflect.Map, reflect.Chan:
return value.IsNil()
default:
// 对于复杂类型,谨慎判断
return reflect.DeepEqual(value.Interface(), reflect.Zero(value.Type()).Interface())
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。