diamond-orm/model_internals.go

106 lines
2.5 KiB
Go

package orm
import (
"reflect"
"strings"
)
func parseModel(model any) *Model {
t := reflect.TypeOf(model)
for t.Kind() == reflect.Ptr {
t = t.Elem()
}
minfo := &Model{
Name: t.Name(),
Relationships: make(map[string]*Relationship),
Fields: make(map[string]*Field),
FieldsByColumnName: make(map[string]*Field),
Type: t,
}
for i := range t.NumField() {
f := t.Field(i)
if !f.IsExported() {
continue
}
}
if minfo.TableName == "" {
minfo.TableName = pascalToSnakeCase(t.Name())
}
return minfo
}
func parseModelFields(model *Model, modelMap map[string]*Model) {
t := model.Type
for i := range t.NumField() {
f := t.Field(i)
fi := parseField(f, model, modelMap, i)
if fi != nil && (fi.ColumnType != "" || fi.isAnonymous()) {
model.addField(fi)
}
}
}
func makeModelMap(models ...any) *internalModelMap {
modelMap := &internalModelMap{
Map: make(map[string]*Model),
}
//internalModelMap := make(map[string]*Model)
for _, model := range models {
minfo := parseModel(model)
modelMap.Mux.Lock()
modelMap.Map[minfo.Name] = minfo
modelMap.Mux.Unlock()
}
for _, model := range modelMap.Map {
modelMap.Mux.Lock()
parseModelFields(model, modelMap.Map)
modelMap.Mux.Unlock()
}
tagManyToMany(modelMap)
for _, model := range modelMap.Map {
for _, ref := range model.Relationships {
if ref.Type != ManyToMany && ref.Idx != -1 {
modelMap.Mux.Lock()
addForeignKeyFields(ref)
modelMap.Mux.Unlock()
}
}
}
return modelMap
}
func tagManyToMany(models *internalModelMap) {
hasManys := make(map[string]*Relationship)
for _, model := range models.Map {
for relName := range model.Relationships {
hasManys[model.Name+"."+relName] = model.Relationships[relName]
}
}
for _, model := range models.Map {
models.Mux.Lock()
for relName := range model.Relationships {
mb := model.Relationships[relName].RelatedModel
var name string
for n, reltmp := range hasManys {
if !strings.HasPrefix(n, mb.Name) || reltmp.Type != HasMany {
continue
}
if reltmp.RelatedType == model.Type {
name = reltmp.FieldName
break
}
}
if rel2, ok := mb.Relationships[name]; ok {
if name < relName &&
rel2.Type == HasMany && model.Relationships[relName].Type == HasMany {
mb.Relationships[name].Type = ManyToMany
mb.Relationships[name].m2mInverse = model.Relationships[relName]
model.Relationships[relName].Type = ManyToMany
model.Relationships[relName].m2mInverse = mb.Relationships[name]
}
}
}
models.Mux.Unlock()
}
}