Simple and Powerful ORM for Go, support mysql,postgres,tidb,sqlite3,mssql,oracle https://xorm.io
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

609 lines
15KB

  1. // Copyright 2017 The Xorm Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package xorm
  5. import (
  6. "errors"
  7. "fmt"
  8. "testing"
  9. "time"
  10. "xorm.io/core"
  11. "github.com/stretchr/testify/assert"
  12. )
  13. type tempUser struct {
  14. Id int64
  15. Username string
  16. }
  17. type tempUser2 struct {
  18. TempUser tempUser `xorm:"extends"`
  19. Departname string
  20. }
  21. type tempUser3 struct {
  22. Temp *tempUser `xorm:"extends"`
  23. Departname string
  24. }
  25. type tempUser4 struct {
  26. TempUser2 tempUser2 `xorm:"extends"`
  27. }
  28. type Userinfo struct {
  29. Uid int64 `xorm:"id pk not null autoincr"`
  30. Username string `xorm:"unique"`
  31. Departname string
  32. Alias string `xorm:"-"`
  33. Created time.Time
  34. Detail Userdetail `xorm:"detail_id int(11)"`
  35. Height float64
  36. Avatar []byte
  37. IsMan bool
  38. }
  39. type Userdetail struct {
  40. Id int64
  41. Intro string `xorm:"text"`
  42. Profile string `xorm:"varchar(2000)"`
  43. }
  44. type UserAndDetail struct {
  45. Userinfo `xorm:"extends"`
  46. Userdetail `xorm:"extends"`
  47. }
  48. func TestExtends(t *testing.T) {
  49. assert.NoError(t, prepareEngine())
  50. err := testEngine.DropTables(&tempUser2{})
  51. assert.NoError(t, err)
  52. err = testEngine.CreateTables(&tempUser2{})
  53. assert.NoError(t, err)
  54. tu := &tempUser2{tempUser{0, "extends"}, "dev depart"}
  55. _, err = testEngine.Insert(tu)
  56. assert.NoError(t, err)
  57. tu2 := &tempUser2{}
  58. _, err = testEngine.Get(tu2)
  59. assert.NoError(t, err)
  60. tu3 := &tempUser2{tempUser{0, "extends update"}, ""}
  61. _, err = testEngine.ID(tu2.TempUser.Id).Update(tu3)
  62. assert.NoError(t, err)
  63. err = testEngine.DropTables(&tempUser4{})
  64. assert.NoError(t, err)
  65. err = testEngine.CreateTables(&tempUser4{})
  66. assert.NoError(t, err)
  67. tu8 := &tempUser4{tempUser2{tempUser{0, "extends"}, "dev depart"}}
  68. _, err = testEngine.Insert(tu8)
  69. assert.NoError(t, err)
  70. tu9 := &tempUser4{}
  71. _, err = testEngine.Get(tu9)
  72. assert.NoError(t, err)
  73. if tu9.TempUser2.TempUser.Username != tu8.TempUser2.TempUser.Username || tu9.TempUser2.Departname != tu8.TempUser2.Departname {
  74. err = errors.New(fmt.Sprintln("not equal for", tu8, tu9))
  75. t.Error(err)
  76. panic(err)
  77. }
  78. tu10 := &tempUser4{tempUser2{tempUser{0, "extends update"}, ""}}
  79. _, err = testEngine.ID(tu9.TempUser2.TempUser.Id).Update(tu10)
  80. assert.NoError(t, err)
  81. err = testEngine.DropTables(&tempUser3{})
  82. assert.NoError(t, err)
  83. err = testEngine.CreateTables(&tempUser3{})
  84. assert.NoError(t, err)
  85. tu4 := &tempUser3{&tempUser{0, "extends"}, "dev depart"}
  86. _, err = testEngine.Insert(tu4)
  87. assert.NoError(t, err)
  88. tu5 := &tempUser3{}
  89. _, err = testEngine.Get(tu5)
  90. assert.NoError(t, err)
  91. if tu5.Temp == nil {
  92. err = errors.New("error get data extends")
  93. t.Error(err)
  94. panic(err)
  95. }
  96. if tu5.Temp.Id != 1 || tu5.Temp.Username != "extends" ||
  97. tu5.Departname != "dev depart" {
  98. err = errors.New("error get data extends")
  99. t.Error(err)
  100. panic(err)
  101. }
  102. tu6 := &tempUser3{&tempUser{0, "extends update"}, ""}
  103. _, err = testEngine.ID(tu5.Temp.Id).Update(tu6)
  104. assert.NoError(t, err)
  105. users := make([]tempUser3, 0)
  106. err = testEngine.Find(&users)
  107. assert.NoError(t, err)
  108. assert.EqualValues(t, 1, len(users), "error get data not 1")
  109. assertSync(t, new(Userinfo), new(Userdetail))
  110. detail := Userdetail{
  111. Intro: "I'm in China",
  112. }
  113. _, err = testEngine.Insert(&detail)
  114. assert.NoError(t, err)
  115. _, err = testEngine.Insert(&Userinfo{
  116. Username: "lunny",
  117. Detail: detail,
  118. })
  119. assert.NoError(t, err)
  120. var info UserAndDetail
  121. qt := testEngine.Quote
  122. ui := testEngine.TableName(new(Userinfo), true)
  123. ud := testEngine.TableName(&detail, true)
  124. uiid := testEngine.GetColumnMapper().Obj2Table("Id")
  125. udid := "detail_id"
  126. sql := fmt.Sprintf("select * from %s, %s where %s.%s = %s.%s",
  127. qt(ui), qt(ud), qt(ui), qt(udid), qt(ud), qt(uiid))
  128. b, err := testEngine.SQL(sql).NoCascade().Get(&info)
  129. assert.NoError(t, err)
  130. if !b {
  131. err = errors.New("should has lest one record")
  132. t.Error(err)
  133. panic(err)
  134. }
  135. fmt.Println(info)
  136. if info.Userinfo.Uid == 0 || info.Userdetail.Id == 0 {
  137. err = errors.New("all of the id should has value")
  138. t.Error(err)
  139. panic(err)
  140. }
  141. fmt.Println("----join--info2")
  142. var info2 UserAndDetail
  143. b, err = testEngine.Table(&Userinfo{}).
  144. Join("LEFT", qt(ud), qt(ui)+"."+qt("detail_id")+" = "+qt(ud)+"."+qt(uiid)).
  145. NoCascade().Get(&info2)
  146. if err != nil {
  147. t.Error(err)
  148. panic(err)
  149. }
  150. if !b {
  151. err = errors.New("should has lest one record")
  152. t.Error(err)
  153. panic(err)
  154. }
  155. if info2.Userinfo.Uid == 0 || info2.Userdetail.Id == 0 {
  156. err = errors.New("all of the id should has value")
  157. t.Error(err)
  158. panic(err)
  159. }
  160. fmt.Println(info2)
  161. fmt.Println("----join--infos2")
  162. var infos2 = make([]UserAndDetail, 0)
  163. err = testEngine.Table(&Userinfo{}).
  164. Join("LEFT", qt(ud), qt(ui)+"."+qt("detail_id")+" = "+qt(ud)+"."+qt(uiid)).
  165. NoCascade().
  166. Find(&infos2)
  167. assert.NoError(t, err)
  168. fmt.Println(infos2)
  169. }
  170. type MessageBase struct {
  171. Id int64 `xorm:"int(11) pk autoincr"`
  172. TypeId int64 `xorm:"int(11) notnull"`
  173. }
  174. type Message struct {
  175. MessageBase `xorm:"extends"`
  176. Title string `xorm:"varchar(100) notnull"`
  177. Content string `xorm:"text notnull"`
  178. Uid int64 `xorm:"int(11) notnull"`
  179. ToUid int64 `xorm:"int(11) notnull"`
  180. CreateTime time.Time `xorm:"datetime notnull created"`
  181. }
  182. type MessageUser struct {
  183. Id int64
  184. Name string
  185. }
  186. type MessageType struct {
  187. Id int64
  188. Name string
  189. }
  190. type MessageExtend3 struct {
  191. Message `xorm:"extends"`
  192. Sender MessageUser `xorm:"extends"`
  193. Receiver MessageUser `xorm:"extends"`
  194. Type MessageType `xorm:"extends"`
  195. }
  196. type MessageExtend4 struct {
  197. Message `xorm:"extends"`
  198. MessageUser `xorm:"extends"`
  199. MessageType `xorm:"extends"`
  200. }
  201. func TestExtends2(t *testing.T) {
  202. assert.NoError(t, prepareEngine())
  203. err := testEngine.DropTables(&Message{}, &MessageUser{}, &MessageType{})
  204. assert.NoError(t, err)
  205. err = testEngine.CreateTables(&Message{}, &MessageUser{}, &MessageType{})
  206. assert.NoError(t, err)
  207. var sender = MessageUser{Name: "sender"}
  208. var receiver = MessageUser{Name: "receiver"}
  209. var msgtype = MessageType{Name: "type"}
  210. _, err = testEngine.Insert(&sender, &receiver, &msgtype)
  211. assert.NoError(t, err)
  212. msg := Message{
  213. MessageBase: MessageBase{
  214. Id: msgtype.Id,
  215. },
  216. Title: "test",
  217. Content: "test",
  218. Uid: sender.Id,
  219. ToUid: receiver.Id,
  220. }
  221. session := testEngine.NewSession()
  222. defer session.Close()
  223. // MSSQL deny insert identity column excep declare as below
  224. if testEngine.Dialect().DBType() == core.MSSQL {
  225. err = session.Begin()
  226. assert.NoError(t, err)
  227. _, err = session.Exec("SET IDENTITY_INSERT message ON")
  228. assert.NoError(t, err)
  229. }
  230. cnt, err := session.Insert(&msg)
  231. assert.NoError(t, err)
  232. assert.EqualValues(t, 1, cnt)
  233. if testEngine.Dialect().DBType() == core.MSSQL {
  234. err = session.Commit()
  235. assert.NoError(t, err)
  236. }
  237. var mapper = testEngine.GetTableMapper().Obj2Table
  238. var quote = testEngine.Quote
  239. userTableName := quote(testEngine.TableName(mapper("MessageUser"), true))
  240. typeTableName := quote(testEngine.TableName(mapper("MessageType"), true))
  241. msgTableName := quote(testEngine.TableName(mapper("Message"), true))
  242. list := make([]Message, 0)
  243. err = session.Table(msgTableName).Join("LEFT", []string{userTableName, "sender"}, "`sender`.`"+mapper("Id")+"`="+msgTableName+".`"+mapper("Uid")+"`").
  244. Join("LEFT", []string{userTableName, "receiver"}, "`receiver`.`"+mapper("Id")+"`="+msgTableName+".`"+mapper("ToUid")+"`").
  245. Join("LEFT", []string{typeTableName, "type"}, "`type`.`"+mapper("Id")+"`="+msgTableName+".`"+mapper("Id")+"`").
  246. Find(&list)
  247. assert.NoError(t, err)
  248. assert.EqualValues(t, 1, len(list), fmt.Sprintln("should have 1 message, got", len(list)))
  249. assert.EqualValues(t, msg.Id, list[0].Id, fmt.Sprintln("should message equal", list[0], msg))
  250. }
  251. func TestExtends3(t *testing.T) {
  252. assert.NoError(t, prepareEngine())
  253. err := testEngine.DropTables(&Message{}, &MessageUser{}, &MessageType{})
  254. if err != nil {
  255. t.Error(err)
  256. panic(err)
  257. }
  258. err = testEngine.CreateTables(&Message{}, &MessageUser{}, &MessageType{})
  259. if err != nil {
  260. t.Error(err)
  261. panic(err)
  262. }
  263. var sender = MessageUser{Name: "sender"}
  264. var receiver = MessageUser{Name: "receiver"}
  265. var msgtype = MessageType{Name: "type"}
  266. _, err = testEngine.Insert(&sender, &receiver, &msgtype)
  267. if err != nil {
  268. t.Error(err)
  269. panic(err)
  270. }
  271. msg := Message{
  272. MessageBase: MessageBase{
  273. Id: msgtype.Id,
  274. },
  275. Title: "test",
  276. Content: "test",
  277. Uid: sender.Id,
  278. ToUid: receiver.Id,
  279. }
  280. session := testEngine.NewSession()
  281. defer session.Close()
  282. // MSSQL deny insert identity column excep declare as below
  283. if testEngine.Dialect().DBType() == core.MSSQL {
  284. err = session.Begin()
  285. assert.NoError(t, err)
  286. _, err = session.Exec("SET IDENTITY_INSERT message ON")
  287. assert.NoError(t, err)
  288. }
  289. _, err = session.Insert(&msg)
  290. assert.NoError(t, err)
  291. if testEngine.Dialect().DBType() == core.MSSQL {
  292. err = session.Commit()
  293. assert.NoError(t, err)
  294. }
  295. var mapper = testEngine.GetTableMapper().Obj2Table
  296. var quote = testEngine.Quote
  297. userTableName := quote(testEngine.TableName(mapper("MessageUser"), true))
  298. typeTableName := quote(testEngine.TableName(mapper("MessageType"), true))
  299. msgTableName := quote(testEngine.TableName(mapper("Message"), true))
  300. list := make([]MessageExtend3, 0)
  301. err = session.Table(msgTableName).Join("LEFT", []string{userTableName, "sender"}, "`sender`.`"+mapper("Id")+"`="+msgTableName+".`"+mapper("Uid")+"`").
  302. Join("LEFT", []string{userTableName, "receiver"}, "`receiver`.`"+mapper("Id")+"`="+msgTableName+".`"+mapper("ToUid")+"`").
  303. Join("LEFT", []string{typeTableName, "type"}, "`type`.`"+mapper("Id")+"`="+msgTableName+".`"+mapper("Id")+"`").
  304. Find(&list)
  305. assert.NoError(t, err)
  306. if len(list) != 1 {
  307. err = errors.New(fmt.Sprintln("should have 1 message, got", len(list)))
  308. t.Error(err)
  309. panic(err)
  310. }
  311. if list[0].Message.Id != msg.Id {
  312. err = errors.New(fmt.Sprintln("should message equal", list[0].Message, msg))
  313. t.Error(err)
  314. panic(err)
  315. }
  316. if list[0].Sender.Id != sender.Id || list[0].Sender.Name != sender.Name {
  317. err = errors.New(fmt.Sprintln("should sender equal", list[0].Sender, sender))
  318. t.Error(err)
  319. panic(err)
  320. }
  321. if list[0].Receiver.Id != receiver.Id || list[0].Receiver.Name != receiver.Name {
  322. err = errors.New(fmt.Sprintln("should receiver equal", list[0].Receiver, receiver))
  323. t.Error(err)
  324. panic(err)
  325. }
  326. if list[0].Type.Id != msgtype.Id || list[0].Type.Name != msgtype.Name {
  327. err = errors.New(fmt.Sprintln("should msgtype equal", list[0].Type, msgtype))
  328. t.Error(err)
  329. panic(err)
  330. }
  331. }
  332. func TestExtends4(t *testing.T) {
  333. assert.NoError(t, prepareEngine())
  334. err := testEngine.DropTables(&Message{}, &MessageUser{}, &MessageType{})
  335. if err != nil {
  336. t.Error(err)
  337. panic(err)
  338. }
  339. err = testEngine.CreateTables(&Message{}, &MessageUser{}, &MessageType{})
  340. if err != nil {
  341. t.Error(err)
  342. panic(err)
  343. }
  344. var sender = MessageUser{Name: "sender"}
  345. var msgtype = MessageType{Name: "type"}
  346. _, err = testEngine.Insert(&sender, &msgtype)
  347. if err != nil {
  348. t.Error(err)
  349. panic(err)
  350. }
  351. msg := Message{
  352. MessageBase: MessageBase{
  353. Id: msgtype.Id,
  354. },
  355. Title: "test",
  356. Content: "test",
  357. Uid: sender.Id,
  358. }
  359. session := testEngine.NewSession()
  360. defer session.Close()
  361. // MSSQL deny insert identity column excep declare as below
  362. if testEngine.Dialect().DBType() == core.MSSQL {
  363. err = session.Begin()
  364. assert.NoError(t, err)
  365. _, err = session.Exec("SET IDENTITY_INSERT message ON")
  366. assert.NoError(t, err)
  367. }
  368. _, err = session.Insert(&msg)
  369. assert.NoError(t, err)
  370. if testEngine.Dialect().DBType() == core.MSSQL {
  371. err = session.Commit()
  372. assert.NoError(t, err)
  373. }
  374. var mapper = testEngine.GetTableMapper().Obj2Table
  375. var quote = testEngine.Quote
  376. userTableName := quote(testEngine.TableName(mapper("MessageUser"), true))
  377. typeTableName := quote(testEngine.TableName(mapper("MessageType"), true))
  378. msgTableName := quote(testEngine.TableName(mapper("Message"), true))
  379. list := make([]MessageExtend4, 0)
  380. err = session.Table(msgTableName).Join("LEFT", userTableName, userTableName+".`"+mapper("Id")+"`="+msgTableName+".`"+mapper("Uid")+"`").
  381. Join("LEFT", typeTableName, typeTableName+".`"+mapper("Id")+"`="+msgTableName+".`"+mapper("Id")+"`").
  382. Find(&list)
  383. if err != nil {
  384. t.Error(err)
  385. panic(err)
  386. }
  387. if len(list) != 1 {
  388. err = errors.New(fmt.Sprintln("should have 1 message, got", len(list)))
  389. t.Error(err)
  390. panic(err)
  391. }
  392. if list[0].Message.Id != msg.Id {
  393. err = errors.New(fmt.Sprintln("should message equal", list[0].Message, msg))
  394. t.Error(err)
  395. panic(err)
  396. }
  397. if list[0].MessageUser.Id != sender.Id || list[0].MessageUser.Name != sender.Name {
  398. err = errors.New(fmt.Sprintln("should sender equal", list[0].MessageUser, sender))
  399. t.Error(err)
  400. panic(err)
  401. }
  402. if list[0].MessageType.Id != msgtype.Id || list[0].MessageType.Name != msgtype.Name {
  403. err = errors.New(fmt.Sprintln("should msgtype equal", list[0].MessageType, msgtype))
  404. t.Error(err)
  405. panic(err)
  406. }
  407. }
  408. type Size struct {
  409. ID int64 `xorm:"int(4) 'id' pk autoincr"`
  410. Width float32 `json:"width" xorm:"float 'Width'"`
  411. Height float32 `json:"height" xorm:"float 'Height'"`
  412. }
  413. type Book struct {
  414. ID int64 `xorm:"int(4) 'id' pk autoincr"`
  415. SizeOpen *Size `xorm:"extends('Open')"`
  416. SizeClosed *Size `xorm:"extends('Closed')"`
  417. Size *Size `xorm:"extends('')"`
  418. }
  419. func TestExtends5(t *testing.T) {
  420. assert.NoError(t, prepareEngine())
  421. err := testEngine.DropTables(&Book{}, &Size{})
  422. if err != nil {
  423. t.Error(err)
  424. panic(err)
  425. }
  426. err = testEngine.CreateTables(&Size{}, &Book{})
  427. if err != nil {
  428. t.Error(err)
  429. panic(err)
  430. }
  431. var sc = Size{Width: 0.2, Height: 0.4}
  432. var so = Size{Width: 0.2, Height: 0.8}
  433. var s = Size{Width: 0.15, Height: 1.5}
  434. var bk1 = Book{
  435. SizeOpen: &so,
  436. SizeClosed: &sc,
  437. Size: &s,
  438. }
  439. var bk2 = Book{
  440. SizeOpen: &so,
  441. }
  442. var bk3 = Book{
  443. SizeClosed: &sc,
  444. Size: &s,
  445. }
  446. var bk4 = Book{}
  447. var bk5 = Book{Size: &s}
  448. _, err = testEngine.Insert(&sc, &so, &s, &bk1, &bk2, &bk3, &bk4, &bk5)
  449. if err != nil {
  450. t.Fatal(err)
  451. }
  452. var books = map[int64]Book{
  453. bk1.ID: bk1,
  454. bk2.ID: bk2,
  455. bk3.ID: bk3,
  456. bk4.ID: bk4,
  457. bk5.ID: bk5,
  458. }
  459. session := testEngine.NewSession()
  460. defer session.Close()
  461. var mapper = testEngine.GetTableMapper().Obj2Table
  462. var quote = testEngine.Quote
  463. bookTableName := quote(testEngine.TableName(mapper("Book"), true))
  464. sizeTableName := quote(testEngine.TableName(mapper("Size"), true))
  465. list := make([]Book, 0)
  466. err = session.
  467. Select(fmt.Sprintf(
  468. "%s.%s, sc.%s AS %s, sc.%s AS %s, s.%s, s.%s",
  469. quote(bookTableName),
  470. quote("id"),
  471. quote("Width"),
  472. quote("ClosedWidth"),
  473. quote("Height"),
  474. quote("ClosedHeight"),
  475. quote("Width"),
  476. quote("Height"),
  477. )).
  478. Table(bookTableName).
  479. Join(
  480. "LEFT",
  481. sizeTableName+" AS `sc`",
  482. bookTableName+".`SizeClosed`=sc.`id`",
  483. ).
  484. Join(
  485. "LEFT",
  486. sizeTableName+" AS `s`",
  487. bookTableName+".`Size`=s.`id`",
  488. ).
  489. Find(&list)
  490. if err != nil {
  491. t.Error(err)
  492. panic(err)
  493. }
  494. for _, book := range list {
  495. if ok := assert.Equal(t, books[book.ID].SizeClosed.Width, book.SizeClosed.Width); !ok {
  496. t.Error("Not bounded size closed")
  497. panic("Not bounded size closed")
  498. }
  499. if ok := assert.Equal(t, books[book.ID].SizeClosed.Height, book.SizeClosed.Height); !ok {
  500. t.Error("Not bounded size closed")
  501. panic("Not bounded size closed")
  502. }
  503. if books[book.ID].Size != nil || book.Size != nil {
  504. if ok := assert.Equal(t, books[book.ID].Size.Width, book.Size.Width); !ok {
  505. t.Error("Not bounded size")
  506. panic("Not bounded size")
  507. }
  508. if ok := assert.Equal(t, books[book.ID].Size.Height, book.Size.Height); !ok {
  509. t.Error("Not bounded size")
  510. panic("Not bounded size")
  511. }
  512. }
  513. }
  514. }