106 lines
2.5 KiB
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()
|
|
}
|
|
}
|