mirror of
https://github.com/astaxie/beego.git
synced 2024-11-29 14:01:29 +00:00
213 lines
5.1 KiB
Go
213 lines
5.1 KiB
Go
|
package orm
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"reflect"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
func RegisterModel(model Modeler) {
|
||
|
info := newModelInfo(model)
|
||
|
model.Init(model)
|
||
|
table := model.GetTableName()
|
||
|
if _, ok := modelCache.get(table); ok {
|
||
|
fmt.Printf("model <%T> redeclared, must be unique\n", model)
|
||
|
os.Exit(2)
|
||
|
}
|
||
|
if info.fields.pk == nil {
|
||
|
fmt.Printf("model <%T> need a primary key field\n", model)
|
||
|
os.Exit(2)
|
||
|
}
|
||
|
info.table = table
|
||
|
info.pkg = getPkgPath(model)
|
||
|
info.model = model
|
||
|
info.manual = true
|
||
|
modelCache.set(table, info)
|
||
|
}
|
||
|
|
||
|
func BootStrap() {
|
||
|
modelCache.Lock()
|
||
|
defer modelCache.Unlock()
|
||
|
|
||
|
var (
|
||
|
err error
|
||
|
models map[string]*modelInfo
|
||
|
)
|
||
|
|
||
|
if dataBaseCache.getDefault() == nil {
|
||
|
err = fmt.Errorf("must have one register alias named `default`")
|
||
|
goto end
|
||
|
}
|
||
|
|
||
|
models = modelCache.all()
|
||
|
for _, mi := range models {
|
||
|
for _, fi := range mi.fields.columns {
|
||
|
if fi.rel || fi.reverse {
|
||
|
elm := fi.addrValue.Type().Elem()
|
||
|
switch fi.fieldType {
|
||
|
case RelReverseMany, RelManyToMany:
|
||
|
elm = elm.Elem()
|
||
|
}
|
||
|
|
||
|
tn := getTableName(reflect.New(elm).Interface().(Modeler))
|
||
|
mii, ok := modelCache.get(tn)
|
||
|
if ok == false || mii.pkg != elm.PkgPath() {
|
||
|
err = fmt.Errorf("can not found rel in field `%s`, `%s` may be miss register", fi.fullName, elm.String())
|
||
|
goto end
|
||
|
}
|
||
|
fi.relModelInfo = mii
|
||
|
|
||
|
if fi.rel {
|
||
|
|
||
|
if mii.fields.pk.IsMulti() {
|
||
|
err = fmt.Errorf("field `%s` unsupport rel to multi primary key field", fi.fullName)
|
||
|
goto end
|
||
|
}
|
||
|
}
|
||
|
|
||
|
switch fi.fieldType {
|
||
|
case RelManyToMany:
|
||
|
if fi.relThrough != "" {
|
||
|
msg := fmt.Sprintf("filed `%s` wrong rel_through value `%s`", fi.fullName, fi.relThrough)
|
||
|
if i := strings.LastIndex(fi.relThrough, "."); i != -1 && len(fi.relThrough) > (i+1) {
|
||
|
pn := fi.relThrough[:i]
|
||
|
mn := fi.relThrough[i+1:]
|
||
|
tn := snakeString(mn)
|
||
|
rmi, ok := modelCache.get(tn)
|
||
|
if ok == false || pn != rmi.pkg {
|
||
|
err = errors.New(msg + " cannot find table")
|
||
|
goto end
|
||
|
}
|
||
|
|
||
|
fi.relThroughModelInfo = rmi
|
||
|
fi.relTable = rmi.table
|
||
|
|
||
|
} else {
|
||
|
err = errors.New(msg)
|
||
|
goto end
|
||
|
}
|
||
|
err = nil
|
||
|
} else {
|
||
|
i := newM2MModelInfo(mi, mii)
|
||
|
if fi.relTable != "" {
|
||
|
i.table = fi.relTable
|
||
|
}
|
||
|
|
||
|
if v := modelCache.set(i.table, i); v != nil {
|
||
|
err = fmt.Errorf("the rel table name `%s` already registered, cannot be use, please change one", fi.relTable)
|
||
|
goto end
|
||
|
}
|
||
|
fi.relTable = i.table
|
||
|
fi.relThroughModelInfo = i
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
models = modelCache.all()
|
||
|
for _, mi := range models {
|
||
|
for _, fi := range mi.fields.fieldsRel {
|
||
|
switch fi.fieldType {
|
||
|
case RelForeignKey, RelOneToOne, RelManyToMany:
|
||
|
inModel := false
|
||
|
for _, ffi := range fi.relModelInfo.fields.fieldsReverse {
|
||
|
if ffi.relModelInfo == mi {
|
||
|
inModel = true
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
if inModel == false {
|
||
|
rmi := fi.relModelInfo
|
||
|
ffi := new(fieldInfo)
|
||
|
ffi.name = mi.name
|
||
|
ffi.column = ffi.name
|
||
|
ffi.fullName = rmi.fullName + "." + ffi.name
|
||
|
ffi.reverse = true
|
||
|
ffi.relModelInfo = mi
|
||
|
ffi.mi = rmi
|
||
|
if fi.fieldType == RelOneToOne {
|
||
|
ffi.fieldType = RelReverseOne
|
||
|
} else {
|
||
|
ffi.fieldType = RelReverseMany
|
||
|
}
|
||
|
if rmi.fields.Add(ffi) == false {
|
||
|
added := false
|
||
|
for cnt := 0; cnt < 5; cnt++ {
|
||
|
ffi.name = fmt.Sprintf("%s%d", mi.name, cnt)
|
||
|
ffi.column = ffi.name
|
||
|
ffi.fullName = rmi.fullName + "." + ffi.name
|
||
|
if added = rmi.fields.Add(ffi); added {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
if added == false {
|
||
|
panic(fmt.Sprintf("cannot generate auto reverse field info `%s` to `%s`", fi.fullName, ffi.fullName))
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for _, mi := range models {
|
||
|
if fields, ok := mi.fields.fieldsByType[RelReverseOne]; ok {
|
||
|
for _, fi := range fields {
|
||
|
found := false
|
||
|
mForA:
|
||
|
for _, ffi := range fi.relModelInfo.fields.fieldsByType[RelOneToOne] {
|
||
|
if ffi.relModelInfo == mi {
|
||
|
found = true
|
||
|
fi.reverseField = ffi.name
|
||
|
fi.reverseFieldInfo = ffi
|
||
|
break mForA
|
||
|
}
|
||
|
}
|
||
|
if found == false {
|
||
|
err = fmt.Errorf("reverse field `%s` not found in model `%s`", fi.fullName, fi.relModelInfo.fullName)
|
||
|
goto end
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if fields, ok := mi.fields.fieldsByType[RelReverseMany]; ok {
|
||
|
for _, fi := range fields {
|
||
|
found := false
|
||
|
mForB:
|
||
|
for _, ffi := range fi.relModelInfo.fields.fieldsByType[RelForeignKey] {
|
||
|
if ffi.relModelInfo == mi {
|
||
|
found = true
|
||
|
fi.reverseField = ffi.name
|
||
|
fi.reverseFieldInfo = ffi
|
||
|
break mForB
|
||
|
}
|
||
|
}
|
||
|
if found == false {
|
||
|
mForC:
|
||
|
for _, ffi := range fi.relModelInfo.fields.fieldsByType[RelManyToMany] {
|
||
|
if ffi.relModelInfo == mi {
|
||
|
found = true
|
||
|
fi.reverseField = ffi.name
|
||
|
fi.reverseFieldInfo = ffi
|
||
|
break mForC
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if found == false {
|
||
|
err = fmt.Errorf("reverse field `%s` not found in model `%s`", fi.fullName, fi.relModelInfo.fullName)
|
||
|
goto end
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
end:
|
||
|
if err != nil {
|
||
|
fmt.Println(err)
|
||
|
os.Exit(2)
|
||
|
}
|
||
|
|
||
|
runCommand()
|
||
|
}
|