1
0

models_boot.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. // Copyright 2014 beego Author. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package orm
  15. import (
  16. "fmt"
  17. "os"
  18. "reflect"
  19. "strings"
  20. )
  21. // register models.
  22. // PrefixOrSuffix means table name prefix or suffix.
  23. // isPrefix whether the prefix is prefix or suffix
  24. func registerModel(PrefixOrSuffix string, model interface{}, isPrefix bool) {
  25. val := reflect.ValueOf(model)
  26. typ := reflect.Indirect(val).Type()
  27. if val.Kind() != reflect.Ptr {
  28. panic(fmt.Errorf("<orm.RegisterModel> cannot use non-ptr model struct `%s`", getFullName(typ)))
  29. }
  30. // For this case:
  31. // u := &User{}
  32. // registerModel(&u)
  33. if typ.Kind() == reflect.Ptr {
  34. panic(fmt.Errorf("<orm.RegisterModel> only allow ptr model struct, it looks you use two reference to the struct `%s`", typ))
  35. }
  36. table := getTableName(val)
  37. if PrefixOrSuffix != "" {
  38. if isPrefix {
  39. table = PrefixOrSuffix + table
  40. } else {
  41. table = table + PrefixOrSuffix
  42. }
  43. }
  44. // models's fullname is pkgpath + struct name
  45. name := getFullName(typ)
  46. if _, ok := modelCache.getByFullName(name); ok {
  47. fmt.Printf("<orm.RegisterModel> model `%s` repeat register, must be unique\n", name)
  48. os.Exit(2)
  49. }
  50. if _, ok := modelCache.get(table); ok {
  51. fmt.Printf("<orm.RegisterModel> table name `%s` repeat register, must be unique\n", table)
  52. os.Exit(2)
  53. }
  54. mi := newModelInfo(val)
  55. if mi.fields.pk == nil {
  56. outFor:
  57. for _, fi := range mi.fields.fieldsDB {
  58. if strings.ToLower(fi.name) == "id" {
  59. switch fi.addrValue.Elem().Kind() {
  60. case reflect.Int, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint32, reflect.Uint64:
  61. fi.auto = true
  62. fi.pk = true
  63. mi.fields.pk = fi
  64. break outFor
  65. }
  66. }
  67. }
  68. if mi.fields.pk == nil {
  69. fmt.Printf("<orm.RegisterModel> `%s` need a primary key field, default use 'id' if not set\n", name)
  70. os.Exit(2)
  71. }
  72. }
  73. mi.table = table
  74. mi.pkg = typ.PkgPath()
  75. mi.model = model
  76. mi.manual = true
  77. modelCache.set(table, mi)
  78. }
  79. // boostrap models
  80. func bootStrap() {
  81. if modelCache.done {
  82. return
  83. }
  84. var (
  85. err error
  86. models map[string]*modelInfo
  87. )
  88. if dataBaseCache.getDefault() == nil {
  89. err = fmt.Errorf("must have one register DataBase alias named `default`")
  90. goto end
  91. }
  92. // set rel and reverse model
  93. // RelManyToMany set the relTable
  94. models = modelCache.all()
  95. for _, mi := range models {
  96. for _, fi := range mi.fields.columns {
  97. if fi.rel || fi.reverse {
  98. elm := fi.addrValue.Type().Elem()
  99. if fi.fieldType == RelReverseMany || fi.fieldType == RelManyToMany {
  100. elm = elm.Elem()
  101. }
  102. // check the rel or reverse model already register
  103. name := getFullName(elm)
  104. mii, ok := modelCache.getByFullName(name)
  105. if !ok || mii.pkg != elm.PkgPath() {
  106. err = fmt.Errorf("can not find rel in field `%s`, `%s` may be miss register", fi.fullName, elm.String())
  107. goto end
  108. }
  109. fi.relModelInfo = mii
  110. switch fi.fieldType {
  111. case RelManyToMany:
  112. if fi.relThrough != "" {
  113. if i := strings.LastIndex(fi.relThrough, "."); i != -1 && len(fi.relThrough) > (i+1) {
  114. pn := fi.relThrough[:i]
  115. rmi, ok := modelCache.getByFullName(fi.relThrough)
  116. if ok == false || pn != rmi.pkg {
  117. err = fmt.Errorf("field `%s` wrong rel_through value `%s` cannot find table", fi.fullName, fi.relThrough)
  118. goto end
  119. }
  120. fi.relThroughModelInfo = rmi
  121. fi.relTable = rmi.table
  122. } else {
  123. err = fmt.Errorf("field `%s` wrong rel_through value `%s`", fi.fullName, fi.relThrough)
  124. goto end
  125. }
  126. } else {
  127. i := newM2MModelInfo(mi, mii)
  128. if fi.relTable != "" {
  129. i.table = fi.relTable
  130. }
  131. if v := modelCache.set(i.table, i); v != nil {
  132. err = fmt.Errorf("the rel table name `%s` already registered, cannot be use, please change one", fi.relTable)
  133. goto end
  134. }
  135. fi.relTable = i.table
  136. fi.relThroughModelInfo = i
  137. }
  138. fi.relThroughModelInfo.isThrough = true
  139. }
  140. }
  141. }
  142. }
  143. // check the rel filed while the relModelInfo also has filed point to current model
  144. // if not exist, add a new field to the relModelInfo
  145. models = modelCache.all()
  146. for _, mi := range models {
  147. for _, fi := range mi.fields.fieldsRel {
  148. switch fi.fieldType {
  149. case RelForeignKey, RelOneToOne, RelManyToMany:
  150. inModel := false
  151. for _, ffi := range fi.relModelInfo.fields.fieldsReverse {
  152. if ffi.relModelInfo == mi {
  153. inModel = true
  154. break
  155. }
  156. }
  157. if inModel == false {
  158. rmi := fi.relModelInfo
  159. ffi := new(fieldInfo)
  160. ffi.name = mi.name
  161. ffi.column = ffi.name
  162. ffi.fullName = rmi.fullName + "." + ffi.name
  163. ffi.reverse = true
  164. ffi.relModelInfo = mi
  165. ffi.mi = rmi
  166. if fi.fieldType == RelOneToOne {
  167. ffi.fieldType = RelReverseOne
  168. } else {
  169. ffi.fieldType = RelReverseMany
  170. }
  171. if rmi.fields.Add(ffi) == false {
  172. added := false
  173. for cnt := 0; cnt < 5; cnt++ {
  174. ffi.name = fmt.Sprintf("%s%d", mi.name, cnt)
  175. ffi.column = ffi.name
  176. ffi.fullName = rmi.fullName + "." + ffi.name
  177. if added = rmi.fields.Add(ffi); added {
  178. break
  179. }
  180. }
  181. if added == false {
  182. panic(fmt.Errorf("cannot generate auto reverse field info `%s` to `%s`", fi.fullName, ffi.fullName))
  183. }
  184. }
  185. }
  186. }
  187. }
  188. }
  189. models = modelCache.all()
  190. for _, mi := range models {
  191. for _, fi := range mi.fields.fieldsRel {
  192. switch fi.fieldType {
  193. case RelManyToMany:
  194. for _, ffi := range fi.relThroughModelInfo.fields.fieldsRel {
  195. switch ffi.fieldType {
  196. case RelOneToOne, RelForeignKey:
  197. if ffi.relModelInfo == fi.relModelInfo {
  198. fi.reverseFieldInfoTwo = ffi
  199. }
  200. if ffi.relModelInfo == mi {
  201. fi.reverseField = ffi.name
  202. fi.reverseFieldInfo = ffi
  203. }
  204. }
  205. }
  206. if fi.reverseFieldInfoTwo == nil {
  207. err = fmt.Errorf("can not find m2m field for m2m model `%s`, ensure your m2m model defined correct",
  208. fi.relThroughModelInfo.fullName)
  209. goto end
  210. }
  211. }
  212. }
  213. }
  214. models = modelCache.all()
  215. for _, mi := range models {
  216. for _, fi := range mi.fields.fieldsReverse {
  217. switch fi.fieldType {
  218. case RelReverseOne:
  219. found := false
  220. mForA:
  221. for _, ffi := range fi.relModelInfo.fields.fieldsByType[RelOneToOne] {
  222. if ffi.relModelInfo == mi {
  223. found = true
  224. fi.reverseField = ffi.name
  225. fi.reverseFieldInfo = ffi
  226. ffi.reverseField = fi.name
  227. ffi.reverseFieldInfo = fi
  228. break mForA
  229. }
  230. }
  231. if found == false {
  232. err = fmt.Errorf("reverse field `%s` not found in model `%s`", fi.fullName, fi.relModelInfo.fullName)
  233. goto end
  234. }
  235. case RelReverseMany:
  236. found := false
  237. mForB:
  238. for _, ffi := range fi.relModelInfo.fields.fieldsByType[RelForeignKey] {
  239. if ffi.relModelInfo == mi {
  240. found = true
  241. fi.reverseField = ffi.name
  242. fi.reverseFieldInfo = ffi
  243. ffi.reverseField = fi.name
  244. ffi.reverseFieldInfo = fi
  245. break mForB
  246. }
  247. }
  248. if found == false {
  249. mForC:
  250. for _, ffi := range fi.relModelInfo.fields.fieldsByType[RelManyToMany] {
  251. conditions := fi.relThrough != "" && fi.relThrough == ffi.relThrough ||
  252. fi.relTable != "" && fi.relTable == ffi.relTable ||
  253. fi.relThrough == "" && fi.relTable == ""
  254. if ffi.relModelInfo == mi && conditions {
  255. found = true
  256. fi.reverseField = ffi.reverseFieldInfoTwo.name
  257. fi.reverseFieldInfo = ffi.reverseFieldInfoTwo
  258. fi.relThroughModelInfo = ffi.relThroughModelInfo
  259. fi.reverseFieldInfoTwo = ffi.reverseFieldInfo
  260. fi.reverseFieldInfoM2M = ffi
  261. ffi.reverseFieldInfoM2M = fi
  262. break mForC
  263. }
  264. }
  265. }
  266. if found == false {
  267. err = fmt.Errorf("reverse field for `%s` not found in model `%s`", fi.fullName, fi.relModelInfo.fullName)
  268. goto end
  269. }
  270. }
  271. }
  272. }
  273. end:
  274. if err != nil {
  275. fmt.Println(err)
  276. os.Exit(2)
  277. }
  278. }
  279. // RegisterModel register models
  280. func RegisterModel(models ...interface{}) {
  281. if modelCache.done {
  282. panic(fmt.Errorf("RegisterModel must be run before BootStrap"))
  283. }
  284. RegisterModelWithPrefix("", models...)
  285. }
  286. // RegisterModelWithPrefix register models with a prefix
  287. func RegisterModelWithPrefix(prefix string, models ...interface{}) {
  288. if modelCache.done {
  289. panic(fmt.Errorf("RegisterModelWithPrefix must be run before BootStrap"))
  290. }
  291. for _, model := range models {
  292. registerModel(prefix, model, true)
  293. }
  294. }
  295. // RegisterModelWithSuffix register models with a suffix
  296. func RegisterModelWithSuffix(suffix string, models ...interface{}) {
  297. if modelCache.done {
  298. panic(fmt.Errorf("RegisterModelWithSuffix must be run before BootStrap"))
  299. }
  300. for _, model := range models {
  301. registerModel(suffix, model, false)
  302. }
  303. }
  304. // BootStrap bootrap models.
  305. // make all model parsed and can not add more models
  306. func BootStrap() {
  307. if modelCache.done {
  308. return
  309. }
  310. modelCache.Lock()
  311. defer modelCache.Unlock()
  312. bootStrap()
  313. modelCache.done = true
  314. }