10 Star 35 Fork 8

bigpigeon / toyorm

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
record_struct.go 7.46 KB
一键复制 编辑 原始数据 按行查看 历史
/*
* Copyright 2018. bigpigeon. All rights reserved.
* Use of this source code is governed by a MIT style
* license that can be found in the LICENSE file.
*/
package toyorm
import (
"fmt"
"reflect"
)
type ModelStructRecords struct {
model *Model
Type reflect.Type
source reflect.Value
RelationFieldPos map[string]int
FieldTypes map[string]reflect.Type
FieldValuesList []map[string]reflect.Value
VirtualFieldValuesList []map[string]reflect.Value
}
func NewStructRecords(model *Model, value reflect.Value) *ModelStructRecords {
vElemType := value.Type().Elem()
records := &ModelStructRecords{
model,
vElemType,
value,
map[string]int{},
map[string]reflect.Type{},
[]map[string]reflect.Value{},
[]map[string]reflect.Value{},
}
vIndirectElemType := LoopTypeIndirectSliceAndPtr(vElemType)
if vIndirectElemType == model.ReflectType {
for i := 0; i < len(model.AllFields); i++ {
f := model.GetPosField(i)
records.FieldTypes[f.Name()] = f.StructField().Type
records.RelationFieldPos[f.Name()] = i
}
} else {
structFieldList := GetStructFields(vIndirectElemType)
repeatName := map[string]struct{}{}
// RelationFieldPos[model_field]->struct_field_pos
for si, field := range structFieldList {
if _, ok := repeatName[field.Name]; ok {
}
if mField := model.GetFieldWithName(field.Name); mField != nil {
records.FieldTypes[field.Name] = field.Type
records.RelationFieldPos[field.Name] = si
}
}
}
records.sync()
return records
}
func NewStructRecord(model *Model, value reflect.Value) ModelRecord {
vtype := value.Type()
fieldValueList := GetStructValueFields(value)
structFieldList := GetStructFields(vtype)
record := map[string]reflect.Value{}
if vtype == model.ReflectType {
for i := 0; i < len(model.AllFields); i++ {
record[model.GetPosField(i).Name()] = fieldValueList[i]
}
} else {
for i, field := range structFieldList {
if mField := model.GetFieldWithName(field.Name); mField != nil {
record[field.Name] = fieldValueList[i]
}
}
}
return &ModelStructRecord{
FieldValues: record,
VirtualFieldValues: map[string]reflect.Value{},
source: value,
model: model,
}
}
func (m *ModelStructRecords) GetFieldType(field string) reflect.Type {
return m.FieldTypes[field]
}
func (m *ModelStructRecords) GetFieldAddressType(field string) reflect.Type {
return reflect.PtrTo(m.FieldTypes[field])
}
func (m *ModelStructRecords) GroupBy(key string) ModelGroupBy {
field := m.model.GetFieldWithName(key)
if field.StructField().Type.Comparable() == false {
panic(fmt.Sprintf("%s is not compareable field", field.Name()))
}
result := ModelGroupBy{}
for i := 0; i < len(m.FieldValuesList); i++ {
keyValue := m.FieldValuesList[i][key].Interface()
result[keyValue] = append(result[keyValue], ModelIndexRecord{&ModelStructRecord{
FieldValues: m.FieldValuesList[i],
VirtualFieldValues: m.VirtualFieldValuesList[i],
source: LoopIndirect(m.source.Index(i)),
model: m.model,
}, i})
}
return result
}
func (m *ModelStructRecords) GetRecords() []ModelRecord {
var records []ModelRecord
for i := 0; i < len(m.FieldValuesList); i++ {
records = append(records, &ModelStructRecord{
FieldValues: m.FieldValuesList[i],
VirtualFieldValues: m.VirtualFieldValuesList[i],
source: LoopIndirect(m.source.Index(i)),
model: m.model,
})
}
return records
}
func (m *ModelStructRecords) GetRecord(i int) ModelRecord {
return &ModelStructRecord{
FieldValues: m.FieldValuesList[i],
VirtualFieldValues: m.VirtualFieldValuesList[i],
source: LoopIndirect(m.source.Index(i)),
model: m.model,
}
}
func (m *ModelStructRecords) reallocate() {
m.FieldValuesList = nil
for i := 0; i < m.source.Len(); i++ {
// why need loop indirect? because data type can be []*ModelData{} or []**ModelData{}
c := make(map[string]reflect.Value, len(m.RelationFieldPos))
fieldList := GetStructValueFields(LoopIndirectAndNew(m.source.Index(i)))
for name, si := range m.RelationFieldPos {
c[name] = fieldList[si]
}
m.FieldValuesList = append(m.FieldValuesList, c)
}
}
func (m *ModelStructRecords) Add(v reflect.Value) ModelRecord {
if m.source.CanSet() == false {
panic("Add need can set permission")
}
if v.Type() != m.Type {
panic(fmt.Sprintf("add data type(%s) must be type(%s)", v.Type(), m.Type))
}
last := m.source.Len()
oldSource := m.source.Pointer()
m.source.Set(reflect.Append(m.source, v))
m.sync()
// if list trigger the reallocate , reallocate
if m.source.Pointer() != oldSource {
m.reallocate()
}
return &ModelStructRecord{
FieldValues: m.FieldValuesList[last],
VirtualFieldValues: m.VirtualFieldValuesList[last],
source: m.source.Index(last),
model: m.model,
}
}
func (m *ModelStructRecords) sync() {
for i := len(m.FieldValuesList); i < m.source.Len(); i++ {
c := make(map[string]reflect.Value, len(m.RelationFieldPos))
fieldList := GetStructValueFields(LoopIndirectAndNew(m.source.Index(i)))
for name, si := range m.RelationFieldPos {
c[name] = fieldList[si]
}
vc := map[string]reflect.Value{}
m.FieldValuesList = append(m.FieldValuesList, c)
m.VirtualFieldValuesList = append(m.VirtualFieldValuesList, vc)
}
}
func (m *ModelStructRecords) IsVariableContainer() bool {
return false
}
func (m *ModelStructRecords) ElemType() reflect.Type {
return m.Type
}
func (m *ModelStructRecords) Len() int {
return len(m.FieldValuesList)
}
func (m *ModelStructRecords) Source() reflect.Value {
return m.source
}
type ModelStructRecord struct {
FieldValues map[string]reflect.Value
VirtualFieldValues map[string]reflect.Value
source reflect.Value
model *Model
}
// set field to field value map or virtual field value map
// but if value is invalid delete it on map
func (m *ModelStructRecord) SetField(name string, value reflect.Value) {
if name == "" {
return
}
fieldValue := m.FieldValues[name]
//if value.Kind() == reflect.Ptr {
// panic("RecordFieldSetError: value cannot be a ptr")
//}
if fieldValue.IsValid() == false {
m.VirtualFieldValues[name] = reflect.New(m.model.GetFieldWithName(name).StructField().Type).Elem()
fieldValue = m.VirtualFieldValues[name]
}
//fieldValue = LoopIndirectAndNew(fieldValue)
safeSet(fieldValue, value)
}
func (m *ModelStructRecord) DeleteField(name string) {
if name == "" {
return
}
delete(m.VirtualFieldValues, name)
delete(m.FieldValues, name)
}
func (m *ModelStructRecord) Field(name string) reflect.Value {
if v := m.FieldValues[name]; v.IsValid() {
return v
}
return m.VirtualFieldValues[name]
}
func (m *ModelStructRecord) FieldAddress(name string) reflect.Value {
if v := m.FieldValues[name]; v.IsValid() {
return v.Addr()
}
return m.VirtualFieldValues[name].Addr()
}
func (m *ModelStructRecord) AllField() map[string]reflect.Value {
fieldValues := map[string]reflect.Value{}
for name, fieldValue := range m.FieldValues {
fieldValues[name] = fieldValue
}
for name, fieldValue := range m.VirtualFieldValues {
fieldValues[name] = fieldValue
}
return fieldValues
}
func (m *ModelStructRecord) IsVariableContainer() bool {
return false
}
func (m *ModelStructRecord) Source() reflect.Value {
return m.source
}
func (m *ModelStructRecord) GetFieldType(name string) reflect.Type {
if fieldValue := m.FieldValues[name]; fieldValue.IsValid() {
return fieldValue.Type()
}
return nil
}
Go
1
https://gitee.com/bigpigeon/toyorm.git
git@gitee.com:bigpigeon/toyorm.git
bigpigeon
toyorm
toyorm
master

搜索帮助