代码拉取完成,页面将自动刷新
同步操作将从 K./go-adm 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
package adm
import (
"reflect"
"git.oschina.net/janpoem/go-agi"
"time"
)
type ModelMapping struct {
// 主键的字段,实际上指向的是一个ModelColumn
Pk *ModelColumn
// 主键的模式
PkMode PkMode
// 映射的字段
Columns []*ModelColumn
// 字段的总数
Size int
}
type ModelColumn struct {
// 结构的属性名
Name string
// 数据库存储的字段名
Column string
// 该字段在Model的属性集合中的Index,用于从一个Model实例中快速获取该字段
Index int
}
// 预定32个mapping缓冲
var models = make(map[reflect.Type]*ModelMapping, 32)
func GetModelMapping(obj Model) *ModelMapping {
tp := reflect.TypeOf(obj)
tpEl := tp.Elem()
m, exists := models[tpEl]
if exists {
return m
}
pkHit := false
pkMode := PkNone
var pk *ModelColumn
columns := make([]*ModelColumn, 0)
for i := 0; i < tpEl.NumField(); i++ {
field := tpEl.Field(i)
tag := field.Tag
tagCol := tag.Get(TagColumn)
if tagCol == TagValNothing {
continue
}
col := &ModelColumn{Name: field.Name, Column: tagCol, Index: i }
pkSetting := tag.Get(TagPk)
if pkHit == false && pkSetting != TagValNothing {
pkHit = true
pkMode = detectPkMode(pkSetting)
pk = col
}
columns = append(columns, col)
}
m = &ModelMapping{Pk: pk, PkMode: pkMode, Columns: columns, Size: len(columns) }
models[tpEl] = m
return m
}
func AssignSlice(obj Model, values []interface {}) {
mapping := GetModelMapping(obj)
valRef := reflect.ValueOf(obj).Elem()
for i := 0; i < len(values); i++ {
col := mapping.Columns[i]
assignFieldValue(valRef.Field(col.Index), values[i])
}
}
func detectPkMode(mode string) PkMode {
if mode == TagValPkAi {
return PkAi
}
return PkNormal
}
// 基于数据库字段,来写入对象
// 从map -> column的匹配,需要两次,所以,还是从本地的字段长度来匹配
func assignMap(obj Model, m map[string]interface{}, useColumn bool) {
mapping := GetModelMapping(obj)
valRef := reflect.ValueOf(obj).Elem()
for i := 0; i < len(mapping.Columns); i++ {
col := mapping.Columns[i]
var val interface{}
var exists bool
if useColumn {
val, exists = m[col.Column]
} else {
val, exists = m[col.Name]
}
if exists {
assignFieldValue(valRef.Field(col.Index), val)
}
}
}
func AssignMap(obj Model, m map[string]interface{}) {
assignMap(obj, m, true)
}
func AssignMapByField(obj Model, m map[string]interface{}) {
assignMap(obj, m, false)
}
func AssignStruct(obj Model, target interface {}) {
if agi.KindOf(target) != reflect.Struct {
return
}
mapping := GetModelMapping(obj)
valRef := reflect.ValueOf(obj).Elem()
targetRef := agi.ValueOf(target)
for i := 0; i < len(mapping.Columns); i++ {
col := mapping.Columns[i]
targetField := targetRef.FieldByName(col.Name)
if targetField.IsValid() {
assignFieldValue(valRef.Field(col.Index), targetField.Interface())
}
}
}
func isSimpleNumber(field reflect.Value) bool {
switch field.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Float32, reflect.Float64:
return true
}
return false
}
func isExcept(field reflect.Value) bool {
kind := field.Kind()
return kind == reflect.Slice || kind == reflect.Array || kind == reflect.Map || kind == reflect.Struct
}
func assignFieldValue(field reflect.Value, value interface{}) {
// 跳过特定类型的字段
if !field.IsValid() {
return
}
valueOf := agi.ValueOf(value)
fieldType := field.Type()
fieldKind := field.Kind()
// 字段类型为数字的转换处理
if isSimpleNumber(field) {
// 跳过特定类型的值
if isExcept(valueOf) {
return
}
// 简单数字类型,直接使用反射的转换处理
if isSimpleNumber(valueOf) {
field.Set(valueOf.Convert(fieldType))
} else {
field.Set(agi.ValueOf(agi.AnyToFloat(value)).Convert(fieldType))
}
return
}
// 字段类型为字符的转换处理
if fieldKind == reflect.String {
field.SetString(agi.AnyToStr(value))
return
}
// 布尔类型转换
if fieldKind == reflect.Bool {
field.SetBool(agi.AnyToBool(value))
return
}
// 时间类型
if fieldType.String() == "time.Time" {
// 这里有一些问题,暂时先把值转为整型,而后直接调用time.Unix()转换为一个时间值
intTime := agi.AnyToInt64(value)
field.Set(reflect.ValueOf(time.Unix(intTime, 0)))
return
}
// @todo 这里应该还有一些类型要做转换处理的
}
// 判断是否有有效主键值
func PkValid(obj Model) bool {
mapping := GetModelMapping(obj)
// 无主键的话,就返回false
if mapping.PkMode == PkNone {
return false
}
valRef := reflect.ValueOf(obj).Elem()
field := valRef.Field(mapping.Pk.Index)
kind := valRef.Kind() // 取得主键的值类型,现在只判断两种,字符串和整型
val := field.Interface()
iVal := agi.AnyToInt64(val) // 整型需要两次被使用
// 自增的主键,默认认为主键必须为整型的数值,并且必须大于0,则认为是有效的主键
if mapping.PkMode == PkAi {
return iVal > 0
}
// 艾玛,整型也很多好不好
// 暂时将整型值的使用缩小在这几个范围内,uint16最大也就是65535,可能作为主键吗?
// 整型的话,大于0即可
switch kind {
case reflect.Int, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint32, reflect.Uint64 :
return iVal > 0
// 剩下的,就是正常模式下的主键,那我们就将他转为字符串,且字符串不为空为判断有效性
default :
return len(agi.AnyToStr(val)) > 0
}
return false
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。