main_test.go 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252
  1. package gorm_test
  2. import (
  3. "database/sql"
  4. "database/sql/driver"
  5. "fmt"
  6. "os"
  7. "path/filepath"
  8. "reflect"
  9. "strconv"
  10. "strings"
  11. "sync"
  12. "testing"
  13. "time"
  14. "github.com/erikstmartin/go-testdb"
  15. "github.com/jinzhu/gorm"
  16. _ "github.com/jinzhu/gorm/dialects/mssql"
  17. _ "github.com/jinzhu/gorm/dialects/mysql"
  18. "github.com/jinzhu/gorm/dialects/postgres"
  19. _ "github.com/jinzhu/gorm/dialects/sqlite"
  20. "github.com/jinzhu/now"
  21. )
  22. var (
  23. DB *gorm.DB
  24. t1, t2, t3, t4, t5 time.Time
  25. )
  26. func init() {
  27. var err error
  28. if DB, err = OpenTestConnection(); err != nil {
  29. panic(fmt.Sprintf("No error should happen when connecting to test database, but got err=%+v", err))
  30. }
  31. runMigration()
  32. }
  33. func OpenTestConnection() (db *gorm.DB, err error) {
  34. dbDSN := os.Getenv("GORM_DSN")
  35. switch os.Getenv("GORM_DIALECT") {
  36. case "mysql":
  37. fmt.Println("testing mysql...")
  38. if dbDSN == "" {
  39. dbDSN = "gorm:gorm@tcp(localhost:9910)/gorm?charset=utf8&parseTime=True"
  40. }
  41. db, err = gorm.Open("mysql", dbDSN)
  42. case "postgres":
  43. fmt.Println("testing postgres...")
  44. if dbDSN == "" {
  45. dbDSN = "user=gorm password=gorm DB.name=gorm port=9920 sslmode=disable"
  46. }
  47. db, err = gorm.Open("postgres", dbDSN)
  48. case "mssql":
  49. // CREATE LOGIN gorm WITH PASSWORD = 'LoremIpsum86';
  50. // CREATE DATABASE gorm;
  51. // USE gorm;
  52. // CREATE USER gorm FROM LOGIN gorm;
  53. // sp_changedbowner 'gorm';
  54. fmt.Println("testing mssql...")
  55. if dbDSN == "" {
  56. dbDSN = "sqlserver://gorm:LoremIpsum86@localhost:9930?database=gorm"
  57. }
  58. db, err = gorm.Open("mssql", dbDSN)
  59. default:
  60. fmt.Println("testing sqlite3...")
  61. db, err = gorm.Open("sqlite3", filepath.Join(os.TempDir(), "gorm.db"))
  62. }
  63. // db.SetLogger(Logger{log.New(os.Stdout, "\r\n", 0)})
  64. // db.SetLogger(log.New(os.Stdout, "\r\n", 0))
  65. if debug := os.Getenv("DEBUG"); debug == "true" {
  66. db.LogMode(true)
  67. } else if debug == "false" {
  68. db.LogMode(false)
  69. }
  70. db.DB().SetMaxIdleConns(10)
  71. return
  72. }
  73. func TestOpen_ReturnsError_WithBadArgs(t *testing.T) {
  74. stringRef := "foo"
  75. testCases := []interface{}{42, time.Now(), &stringRef}
  76. for _, tc := range testCases {
  77. t.Run(fmt.Sprintf("%v", tc), func(t *testing.T) {
  78. _, err := gorm.Open("postgresql", tc)
  79. if err == nil {
  80. t.Error("Should got error with invalid database source")
  81. }
  82. if !strings.HasPrefix(err.Error(), "invalid database source:") {
  83. t.Errorf("Should got error starting with \"invalid database source:\", but got %q", err.Error())
  84. }
  85. })
  86. }
  87. }
  88. func TestStringPrimaryKey(t *testing.T) {
  89. type UUIDStruct struct {
  90. ID string `gorm:"primary_key"`
  91. Name string
  92. }
  93. DB.DropTable(&UUIDStruct{})
  94. DB.AutoMigrate(&UUIDStruct{})
  95. data := UUIDStruct{ID: "uuid", Name: "hello"}
  96. if err := DB.Save(&data).Error; err != nil || data.ID != "uuid" || data.Name != "hello" {
  97. t.Errorf("string primary key should not be populated")
  98. }
  99. data = UUIDStruct{ID: "uuid", Name: "hello world"}
  100. if err := DB.Save(&data).Error; err != nil || data.ID != "uuid" || data.Name != "hello world" {
  101. t.Errorf("string primary key should not be populated")
  102. }
  103. }
  104. func TestExceptionsWithInvalidSql(t *testing.T) {
  105. var columns []string
  106. if DB.Where("sdsd.zaaa = ?", "sd;;;aa").Pluck("aaa", &columns).Error == nil {
  107. t.Errorf("Should got error with invalid SQL")
  108. }
  109. if DB.Model(&User{}).Where("sdsd.zaaa = ?", "sd;;;aa").Pluck("aaa", &columns).Error == nil {
  110. t.Errorf("Should got error with invalid SQL")
  111. }
  112. if DB.Where("sdsd.zaaa = ?", "sd;;;aa").Find(&User{}).Error == nil {
  113. t.Errorf("Should got error with invalid SQL")
  114. }
  115. var count1, count2 int64
  116. DB.Model(&User{}).Count(&count1)
  117. if count1 <= 0 {
  118. t.Errorf("Should find some users")
  119. }
  120. if DB.Where("name = ?", "jinzhu; delete * from users").First(&User{}).Error == nil {
  121. t.Errorf("Should got error with invalid SQL")
  122. }
  123. DB.Model(&User{}).Count(&count2)
  124. if count1 != count2 {
  125. t.Errorf("No user should not be deleted by invalid SQL")
  126. }
  127. }
  128. func TestSetTable(t *testing.T) {
  129. DB.Create(getPreparedUser("pluck_user1", "pluck_user"))
  130. DB.Create(getPreparedUser("pluck_user2", "pluck_user"))
  131. DB.Create(getPreparedUser("pluck_user3", "pluck_user"))
  132. if err := DB.Table("users").Where("role = ?", "pluck_user").Pluck("age", &[]int{}).Error; err != nil {
  133. t.Error("No errors should happen if set table for pluck", err)
  134. }
  135. var users []User
  136. if DB.Table("users").Find(&[]User{}).Error != nil {
  137. t.Errorf("No errors should happen if set table for find")
  138. }
  139. if DB.Table("invalid_table").Find(&users).Error == nil {
  140. t.Errorf("Should got error when table is set to an invalid table")
  141. }
  142. DB.Exec("drop table deleted_users;")
  143. if DB.Table("deleted_users").CreateTable(&User{}).Error != nil {
  144. t.Errorf("Create table with specified table")
  145. }
  146. DB.Table("deleted_users").Save(&User{Name: "DeletedUser"})
  147. var deletedUsers []User
  148. DB.Table("deleted_users").Find(&deletedUsers)
  149. if len(deletedUsers) != 1 {
  150. t.Errorf("Query from specified table")
  151. }
  152. DB.Save(getPreparedUser("normal_user", "reset_table"))
  153. DB.Table("deleted_users").Save(getPreparedUser("deleted_user", "reset_table"))
  154. var user1, user2, user3 User
  155. DB.Where("role = ?", "reset_table").First(&user1).Table("deleted_users").First(&user2).Table("").First(&user3)
  156. if (user1.Name != "normal_user") || (user2.Name != "deleted_user") || (user3.Name != "normal_user") {
  157. t.Errorf("unset specified table with blank string")
  158. }
  159. }
  160. type Order struct {
  161. }
  162. type Cart struct {
  163. }
  164. func (c Cart) TableName() string {
  165. return "shopping_cart"
  166. }
  167. func TestHasTable(t *testing.T) {
  168. type Foo struct {
  169. Id int
  170. Stuff string
  171. }
  172. DB.DropTable(&Foo{})
  173. // Table should not exist at this point, HasTable should return false
  174. if ok := DB.HasTable("foos"); ok {
  175. t.Errorf("Table should not exist, but does")
  176. }
  177. if ok := DB.HasTable(&Foo{}); ok {
  178. t.Errorf("Table should not exist, but does")
  179. }
  180. // We create the table
  181. if err := DB.CreateTable(&Foo{}).Error; err != nil {
  182. t.Errorf("Table should be created")
  183. }
  184. // And now it should exits, and HasTable should return true
  185. if ok := DB.HasTable("foos"); !ok {
  186. t.Errorf("Table should exist, but HasTable informs it does not")
  187. }
  188. if ok := DB.HasTable(&Foo{}); !ok {
  189. t.Errorf("Table should exist, but HasTable informs it does not")
  190. }
  191. }
  192. func TestTableName(t *testing.T) {
  193. DB := DB.Model("")
  194. if DB.NewScope(Order{}).TableName() != "orders" {
  195. t.Errorf("Order's table name should be orders")
  196. }
  197. if DB.NewScope(&Order{}).TableName() != "orders" {
  198. t.Errorf("&Order's table name should be orders")
  199. }
  200. if DB.NewScope([]Order{}).TableName() != "orders" {
  201. t.Errorf("[]Order's table name should be orders")
  202. }
  203. if DB.NewScope(&[]Order{}).TableName() != "orders" {
  204. t.Errorf("&[]Order's table name should be orders")
  205. }
  206. DB.SingularTable(true)
  207. if DB.NewScope(Order{}).TableName() != "order" {
  208. t.Errorf("Order's singular table name should be order")
  209. }
  210. if DB.NewScope(&Order{}).TableName() != "order" {
  211. t.Errorf("&Order's singular table name should be order")
  212. }
  213. if DB.NewScope([]Order{}).TableName() != "order" {
  214. t.Errorf("[]Order's singular table name should be order")
  215. }
  216. if DB.NewScope(&[]Order{}).TableName() != "order" {
  217. t.Errorf("&[]Order's singular table name should be order")
  218. }
  219. if DB.NewScope(&Cart{}).TableName() != "shopping_cart" {
  220. t.Errorf("&Cart's singular table name should be shopping_cart")
  221. }
  222. if DB.NewScope(Cart{}).TableName() != "shopping_cart" {
  223. t.Errorf("Cart's singular table name should be shopping_cart")
  224. }
  225. if DB.NewScope(&[]Cart{}).TableName() != "shopping_cart" {
  226. t.Errorf("&[]Cart's singular table name should be shopping_cart")
  227. }
  228. if DB.NewScope([]Cart{}).TableName() != "shopping_cart" {
  229. t.Errorf("[]Cart's singular table name should be shopping_cart")
  230. }
  231. DB.SingularTable(false)
  232. }
  233. func TestTableNameConcurrently(t *testing.T) {
  234. DB := DB.Model("")
  235. if DB.NewScope(Order{}).TableName() != "orders" {
  236. t.Errorf("Order's table name should be orders")
  237. }
  238. var wg sync.WaitGroup
  239. wg.Add(10)
  240. for i := 1; i <= 10; i++ {
  241. go func(db *gorm.DB) {
  242. DB.SingularTable(true)
  243. wg.Done()
  244. }(DB)
  245. }
  246. wg.Wait()
  247. if DB.NewScope(Order{}).TableName() != "order" {
  248. t.Errorf("Order's singular table name should be order")
  249. }
  250. DB.SingularTable(false)
  251. }
  252. func TestNullValues(t *testing.T) {
  253. DB.DropTable(&NullValue{})
  254. DB.AutoMigrate(&NullValue{})
  255. if err := DB.Save(&NullValue{
  256. Name: sql.NullString{String: "hello", Valid: true},
  257. Gender: &sql.NullString{String: "M", Valid: true},
  258. Age: sql.NullInt64{Int64: 18, Valid: true},
  259. Male: sql.NullBool{Bool: true, Valid: true},
  260. Height: sql.NullFloat64{Float64: 100.11, Valid: true},
  261. AddedAt: NullTime{Time: time.Now(), Valid: true},
  262. }).Error; err != nil {
  263. t.Errorf("Not error should raise when test null value")
  264. }
  265. var nv NullValue
  266. DB.First(&nv, "name = ?", "hello")
  267. if nv.Name.String != "hello" || nv.Gender.String != "M" || nv.Age.Int64 != 18 || nv.Male.Bool != true || nv.Height.Float64 != 100.11 || nv.AddedAt.Valid != true {
  268. t.Errorf("Should be able to fetch null value")
  269. }
  270. if err := DB.Save(&NullValue{
  271. Name: sql.NullString{String: "hello-2", Valid: true},
  272. Gender: &sql.NullString{String: "F", Valid: true},
  273. Age: sql.NullInt64{Int64: 18, Valid: false},
  274. Male: sql.NullBool{Bool: true, Valid: true},
  275. Height: sql.NullFloat64{Float64: 100.11, Valid: true},
  276. AddedAt: NullTime{Time: time.Now(), Valid: false},
  277. }).Error; err != nil {
  278. t.Errorf("Not error should raise when test null value")
  279. }
  280. var nv2 NullValue
  281. DB.First(&nv2, "name = ?", "hello-2")
  282. if nv2.Name.String != "hello-2" || nv2.Gender.String != "F" || nv2.Age.Int64 != 0 || nv2.Male.Bool != true || nv2.Height.Float64 != 100.11 || nv2.AddedAt.Valid != false {
  283. t.Errorf("Should be able to fetch null value")
  284. }
  285. if err := DB.Save(&NullValue{
  286. Name: sql.NullString{String: "hello-3", Valid: false},
  287. Gender: &sql.NullString{String: "M", Valid: true},
  288. Age: sql.NullInt64{Int64: 18, Valid: false},
  289. Male: sql.NullBool{Bool: true, Valid: true},
  290. Height: sql.NullFloat64{Float64: 100.11, Valid: true},
  291. AddedAt: NullTime{Time: time.Now(), Valid: false},
  292. }).Error; err == nil {
  293. t.Errorf("Can't save because of name can't be null")
  294. }
  295. }
  296. func TestNullValuesWithFirstOrCreate(t *testing.T) {
  297. var nv1 = NullValue{
  298. Name: sql.NullString{String: "first_or_create", Valid: true},
  299. Gender: &sql.NullString{String: "M", Valid: true},
  300. }
  301. var nv2 NullValue
  302. result := DB.Where(nv1).FirstOrCreate(&nv2)
  303. if result.RowsAffected != 1 {
  304. t.Errorf("RowsAffected should be 1 after create some record")
  305. }
  306. if result.Error != nil {
  307. t.Errorf("Should not raise any error, but got %v", result.Error)
  308. }
  309. if nv2.Name.String != "first_or_create" || nv2.Gender.String != "M" {
  310. t.Errorf("first or create with nullvalues")
  311. }
  312. if err := DB.Where(nv1).Assign(NullValue{Age: sql.NullInt64{Int64: 18, Valid: true}}).FirstOrCreate(&nv2).Error; err != nil {
  313. t.Errorf("Should not raise any error, but got %v", err)
  314. }
  315. if nv2.Age.Int64 != 18 {
  316. t.Errorf("should update age to 18")
  317. }
  318. }
  319. func TestTransaction(t *testing.T) {
  320. tx := DB.Begin()
  321. u := User{Name: "transcation"}
  322. if err := tx.Save(&u).Error; err != nil {
  323. t.Errorf("No error should raise")
  324. }
  325. if err := tx.First(&User{}, "name = ?", "transcation").Error; err != nil {
  326. t.Errorf("Should find saved record")
  327. }
  328. if sqlTx, ok := tx.CommonDB().(*sql.Tx); !ok || sqlTx == nil {
  329. t.Errorf("Should return the underlying sql.Tx")
  330. }
  331. tx.Rollback()
  332. if err := tx.First(&User{}, "name = ?", "transcation").Error; err == nil {
  333. t.Errorf("Should not find record after rollback")
  334. }
  335. tx2 := DB.Begin()
  336. u2 := User{Name: "transcation-2"}
  337. if err := tx2.Save(&u2).Error; err != nil {
  338. t.Errorf("No error should raise")
  339. }
  340. if err := tx2.First(&User{}, "name = ?", "transcation-2").Error; err != nil {
  341. t.Errorf("Should find saved record")
  342. }
  343. tx2.Commit()
  344. if err := DB.First(&User{}, "name = ?", "transcation-2").Error; err != nil {
  345. t.Errorf("Should be able to find committed record")
  346. }
  347. }
  348. func TestRow(t *testing.T) {
  349. user1 := User{Name: "RowUser1", Age: 1, Birthday: parseTime("2000-1-1")}
  350. user2 := User{Name: "RowUser2", Age: 10, Birthday: parseTime("2010-1-1")}
  351. user3 := User{Name: "RowUser3", Age: 20, Birthday: parseTime("2020-1-1")}
  352. DB.Save(&user1).Save(&user2).Save(&user3)
  353. row := DB.Table("users").Where("name = ?", user2.Name).Select("age").Row()
  354. var age int64
  355. row.Scan(&age)
  356. if age != 10 {
  357. t.Errorf("Scan with Row")
  358. }
  359. }
  360. func TestRows(t *testing.T) {
  361. user1 := User{Name: "RowsUser1", Age: 1, Birthday: parseTime("2000-1-1")}
  362. user2 := User{Name: "RowsUser2", Age: 10, Birthday: parseTime("2010-1-1")}
  363. user3 := User{Name: "RowsUser3", Age: 20, Birthday: parseTime("2020-1-1")}
  364. DB.Save(&user1).Save(&user2).Save(&user3)
  365. rows, err := DB.Table("users").Where("name = ? or name = ?", user2.Name, user3.Name).Select("name, age").Rows()
  366. if err != nil {
  367. t.Errorf("Not error should happen, got %v", err)
  368. }
  369. count := 0
  370. for rows.Next() {
  371. var name string
  372. var age int64
  373. rows.Scan(&name, &age)
  374. count++
  375. }
  376. if count != 2 {
  377. t.Errorf("Should found two records")
  378. }
  379. }
  380. func TestScanRows(t *testing.T) {
  381. user1 := User{Name: "ScanRowsUser1", Age: 1, Birthday: parseTime("2000-1-1")}
  382. user2 := User{Name: "ScanRowsUser2", Age: 10, Birthday: parseTime("2010-1-1")}
  383. user3 := User{Name: "ScanRowsUser3", Age: 20, Birthday: parseTime("2020-1-1")}
  384. DB.Save(&user1).Save(&user2).Save(&user3)
  385. rows, err := DB.Table("users").Where("name = ? or name = ?", user2.Name, user3.Name).Select("name, age").Rows()
  386. if err != nil {
  387. t.Errorf("Not error should happen, got %v", err)
  388. }
  389. type Result struct {
  390. Name string
  391. Age int
  392. }
  393. var results []Result
  394. for rows.Next() {
  395. var result Result
  396. if err := DB.ScanRows(rows, &result); err != nil {
  397. t.Errorf("should get no error, but got %v", err)
  398. }
  399. results = append(results, result)
  400. }
  401. if !reflect.DeepEqual(results, []Result{{Name: "ScanRowsUser2", Age: 10}, {Name: "ScanRowsUser3", Age: 20}}) {
  402. t.Errorf("Should find expected results")
  403. }
  404. }
  405. func TestScan(t *testing.T) {
  406. user1 := User{Name: "ScanUser1", Age: 1, Birthday: parseTime("2000-1-1")}
  407. user2 := User{Name: "ScanUser2", Age: 10, Birthday: parseTime("2010-1-1")}
  408. user3 := User{Name: "ScanUser3", Age: 20, Birthday: parseTime("2020-1-1")}
  409. DB.Save(&user1).Save(&user2).Save(&user3)
  410. type result struct {
  411. Name string
  412. Age int
  413. }
  414. var res result
  415. DB.Table("users").Select("name, age").Where("name = ?", user3.Name).Scan(&res)
  416. if res.Name != user3.Name {
  417. t.Errorf("Scan into struct should work")
  418. }
  419. var doubleAgeRes = &result{}
  420. if err := DB.Table("users").Select("age + age as age").Where("name = ?", user3.Name).Scan(&doubleAgeRes).Error; err != nil {
  421. t.Errorf("Scan to pointer of pointer")
  422. }
  423. if doubleAgeRes.Age != res.Age*2 {
  424. t.Errorf("Scan double age as age")
  425. }
  426. var ress []result
  427. DB.Table("users").Select("name, age").Where("name in (?)", []string{user2.Name, user3.Name}).Scan(&ress)
  428. if len(ress) != 2 || ress[0].Name != user2.Name || ress[1].Name != user3.Name {
  429. t.Errorf("Scan into struct map")
  430. }
  431. }
  432. func TestRaw(t *testing.T) {
  433. user1 := User{Name: "ExecRawSqlUser1", Age: 1, Birthday: parseTime("2000-1-1")}
  434. user2 := User{Name: "ExecRawSqlUser2", Age: 10, Birthday: parseTime("2010-1-1")}
  435. user3 := User{Name: "ExecRawSqlUser3", Age: 20, Birthday: parseTime("2020-1-1")}
  436. DB.Save(&user1).Save(&user2).Save(&user3)
  437. type result struct {
  438. Name string
  439. Email string
  440. }
  441. var ress []result
  442. DB.Raw("SELECT name, age FROM users WHERE name = ? or name = ?", user2.Name, user3.Name).Scan(&ress)
  443. if len(ress) != 2 || ress[0].Name != user2.Name || ress[1].Name != user3.Name {
  444. t.Errorf("Raw with scan")
  445. }
  446. rows, _ := DB.Raw("select name, age from users where name = ?", user3.Name).Rows()
  447. count := 0
  448. for rows.Next() {
  449. count++
  450. }
  451. if count != 1 {
  452. t.Errorf("Raw with Rows should find one record with name 3")
  453. }
  454. DB.Exec("update users set name=? where name in (?)", "jinzhu", []string{user1.Name, user2.Name, user3.Name})
  455. if DB.Where("name in (?)", []string{user1.Name, user2.Name, user3.Name}).First(&User{}).Error != gorm.ErrRecordNotFound {
  456. t.Error("Raw sql to update records")
  457. }
  458. }
  459. func TestGroup(t *testing.T) {
  460. rows, err := DB.Select("name").Table("users").Group("name").Rows()
  461. if err == nil {
  462. defer rows.Close()
  463. for rows.Next() {
  464. var name string
  465. rows.Scan(&name)
  466. }
  467. } else {
  468. t.Errorf("Should not raise any error")
  469. }
  470. }
  471. func TestJoins(t *testing.T) {
  472. var user = User{
  473. Name: "joins",
  474. CreditCard: CreditCard{Number: "411111111111"},
  475. Emails: []Email{{Email: "join1@example.com"}, {Email: "join2@example.com"}},
  476. }
  477. DB.Save(&user)
  478. var users1 []User
  479. DB.Joins("left join emails on emails.user_id = users.id").Where("name = ?", "joins").Find(&users1)
  480. if len(users1) != 2 {
  481. t.Errorf("should find two users using left join")
  482. }
  483. var users2 []User
  484. DB.Joins("left join emails on emails.user_id = users.id AND emails.email = ?", "join1@example.com").Where("name = ?", "joins").First(&users2)
  485. if len(users2) != 1 {
  486. t.Errorf("should find one users using left join with conditions")
  487. }
  488. var users3 []User
  489. DB.Joins("join emails on emails.user_id = users.id AND emails.email = ?", "join1@example.com").Joins("join credit_cards on credit_cards.user_id = users.id AND credit_cards.number = ?", "411111111111").Where("name = ?", "joins").First(&users3)
  490. if len(users3) != 1 {
  491. t.Errorf("should find one users using multiple left join conditions")
  492. }
  493. var users4 []User
  494. DB.Joins("join emails on emails.user_id = users.id AND emails.email = ?", "join1@example.com").Joins("join credit_cards on credit_cards.user_id = users.id AND credit_cards.number = ?", "422222222222").Where("name = ?", "joins").First(&users4)
  495. if len(users4) != 0 {
  496. t.Errorf("should find no user when searching with unexisting credit card")
  497. }
  498. var users5 []User
  499. db5 := DB.Joins("join emails on emails.user_id = users.id AND emails.email = ?", "join1@example.com").Joins("join credit_cards on credit_cards.user_id = users.id AND credit_cards.number = ?", "411111111111").Where(User{Id: 1}).Where(Email{Id: 1}).Not(Email{Id: 10}).First(&users5)
  500. if db5.Error != nil {
  501. t.Errorf("Should not raise error for join where identical fields in different tables. Error: %s", db5.Error.Error())
  502. }
  503. }
  504. type JoinedIds struct {
  505. UserID int64 `gorm:"column:id"`
  506. BillingAddressID int64 `gorm:"column:id"`
  507. EmailID int64 `gorm:"column:id"`
  508. }
  509. func TestScanIdenticalColumnNames(t *testing.T) {
  510. var user = User{
  511. Name: "joinsIds",
  512. Email: "joinIds@example.com",
  513. BillingAddress: Address{
  514. Address1: "One Park Place",
  515. },
  516. Emails: []Email{{Email: "join1@example.com"}, {Email: "join2@example.com"}},
  517. }
  518. DB.Save(&user)
  519. var users []JoinedIds
  520. DB.Select("users.id, addresses.id, emails.id").Table("users").
  521. Joins("left join addresses on users.billing_address_id = addresses.id").
  522. Joins("left join emails on emails.user_id = users.id").
  523. Where("name = ?", "joinsIds").Scan(&users)
  524. if len(users) != 2 {
  525. t.Fatal("should find two rows using left join")
  526. }
  527. if user.Id != users[0].UserID {
  528. t.Errorf("Expected result row to contain UserID %d, but got %d", user.Id, users[0].UserID)
  529. }
  530. if user.Id != users[1].UserID {
  531. t.Errorf("Expected result row to contain UserID %d, but got %d", user.Id, users[1].UserID)
  532. }
  533. if user.BillingAddressID.Int64 != users[0].BillingAddressID {
  534. t.Errorf("Expected result row to contain BillingAddressID %d, but got %d", user.BillingAddressID.Int64, users[0].BillingAddressID)
  535. }
  536. if user.BillingAddressID.Int64 != users[1].BillingAddressID {
  537. t.Errorf("Expected result row to contain BillingAddressID %d, but got %d", user.BillingAddressID.Int64, users[0].BillingAddressID)
  538. }
  539. if users[0].EmailID == users[1].EmailID {
  540. t.Errorf("Email ids should be unique. Got %d and %d", users[0].EmailID, users[1].EmailID)
  541. }
  542. if int64(user.Emails[0].Id) != users[0].EmailID && int64(user.Emails[1].Id) != users[0].EmailID {
  543. t.Errorf("Expected result row ID to be either %d or %d, but was %d", user.Emails[0].Id, user.Emails[1].Id, users[0].EmailID)
  544. }
  545. if int64(user.Emails[0].Id) != users[1].EmailID && int64(user.Emails[1].Id) != users[1].EmailID {
  546. t.Errorf("Expected result row ID to be either %d or %d, but was %d", user.Emails[0].Id, user.Emails[1].Id, users[1].EmailID)
  547. }
  548. }
  549. func TestJoinsWithSelect(t *testing.T) {
  550. type result struct {
  551. Name string
  552. Email string
  553. }
  554. user := User{
  555. Name: "joins_with_select",
  556. Emails: []Email{{Email: "join1@example.com"}, {Email: "join2@example.com"}},
  557. }
  558. DB.Save(&user)
  559. var results []result
  560. DB.Table("users").Select("name, emails.email").Joins("left join emails on emails.user_id = users.id").Where("name = ?", "joins_with_select").Scan(&results)
  561. if len(results) != 2 || results[0].Email != "join1@example.com" || results[1].Email != "join2@example.com" {
  562. t.Errorf("Should find all two emails with Join select")
  563. }
  564. }
  565. func TestHaving(t *testing.T) {
  566. rows, err := DB.Select("name, count(*) as total").Table("users").Group("name").Having("name IN (?)", []string{"2", "3"}).Rows()
  567. if err == nil {
  568. defer rows.Close()
  569. for rows.Next() {
  570. var name string
  571. var total int64
  572. rows.Scan(&name, &total)
  573. if name == "2" && total != 1 {
  574. t.Errorf("Should have one user having name 2")
  575. }
  576. if name == "3" && total != 2 {
  577. t.Errorf("Should have two users having name 3")
  578. }
  579. }
  580. } else {
  581. t.Errorf("Should not raise any error")
  582. }
  583. }
  584. func TestQueryBuilderSubselectInWhere(t *testing.T) {
  585. user := User{Name: "query_expr_select_ruser1", Email: "root@user1.com", Age: 32}
  586. DB.Save(&user)
  587. user = User{Name: "query_expr_select_ruser2", Email: "nobody@user2.com", Age: 16}
  588. DB.Save(&user)
  589. user = User{Name: "query_expr_select_ruser3", Email: "root@user3.com", Age: 64}
  590. DB.Save(&user)
  591. user = User{Name: "query_expr_select_ruser4", Email: "somebody@user3.com", Age: 128}
  592. DB.Save(&user)
  593. var users []User
  594. DB.Select("*").Where("name IN (?)", DB.
  595. Select("name").Table("users").Where("name LIKE ?", "query_expr_select%").QueryExpr()).Find(&users)
  596. if len(users) != 4 {
  597. t.Errorf("Four users should be found, instead found %d", len(users))
  598. }
  599. DB.Select("*").Where("name LIKE ?", "query_expr_select%").Where("age >= (?)", DB.
  600. Select("AVG(age)").Table("users").Where("name LIKE ?", "query_expr_select%").QueryExpr()).Find(&users)
  601. if len(users) != 2 {
  602. t.Errorf("Two users should be found, instead found %d", len(users))
  603. }
  604. }
  605. func TestQueryBuilderRawQueryWithSubquery(t *testing.T) {
  606. user := User{Name: "subquery_test_user1", Age: 10}
  607. DB.Save(&user)
  608. user = User{Name: "subquery_test_user2", Age: 11}
  609. DB.Save(&user)
  610. user = User{Name: "subquery_test_user3", Age: 12}
  611. DB.Save(&user)
  612. var count int
  613. err := DB.Raw("select count(*) from (?) tmp",
  614. DB.Table("users").
  615. Select("name").
  616. Where("age >= ? and name in (?)", 10, []string{"subquery_test_user1", "subquery_test_user2"}).
  617. Group("name").
  618. QueryExpr(),
  619. ).Count(&count).Error
  620. if err != nil {
  621. t.Errorf("Expected to get no errors, but got %v", err)
  622. }
  623. if count != 2 {
  624. t.Errorf("Row count must be 2, instead got %d", count)
  625. }
  626. err = DB.Raw("select count(*) from (?) tmp",
  627. DB.Table("users").
  628. Select("name").
  629. Where("name LIKE ?", "subquery_test%").
  630. Not("age <= ?", 10).Not("name in (?)", []string{"subquery_test_user1", "subquery_test_user2"}).
  631. Group("name").
  632. QueryExpr(),
  633. ).Count(&count).Error
  634. if err != nil {
  635. t.Errorf("Expected to get no errors, but got %v", err)
  636. }
  637. if count != 1 {
  638. t.Errorf("Row count must be 1, instead got %d", count)
  639. }
  640. }
  641. func TestQueryBuilderSubselectInHaving(t *testing.T) {
  642. user := User{Name: "query_expr_having_ruser1", Email: "root@user1.com", Age: 64}
  643. DB.Save(&user)
  644. user = User{Name: "query_expr_having_ruser2", Email: "root@user2.com", Age: 128}
  645. DB.Save(&user)
  646. user = User{Name: "query_expr_having_ruser3", Email: "root@user1.com", Age: 64}
  647. DB.Save(&user)
  648. user = User{Name: "query_expr_having_ruser4", Email: "root@user2.com", Age: 128}
  649. DB.Save(&user)
  650. var users []User
  651. DB.Select("AVG(age) as avgage").Where("name LIKE ?", "query_expr_having_%").Group("email").Having("AVG(age) > (?)", DB.
  652. Select("AVG(age)").Where("name LIKE ?", "query_expr_having_%").Table("users").QueryExpr()).Find(&users)
  653. if len(users) != 1 {
  654. t.Errorf("Two user group should be found, instead found %d", len(users))
  655. }
  656. }
  657. func DialectHasTzSupport() bool {
  658. // NB: mssql and FoundationDB do not support time zones.
  659. if dialect := os.Getenv("GORM_DIALECT"); dialect == "foundation" {
  660. return false
  661. }
  662. return true
  663. }
  664. func TestTimeWithZone(t *testing.T) {
  665. var format = "2006-01-02 15:04:05 -0700"
  666. var times []time.Time
  667. GMT8, _ := time.LoadLocation("Asia/Shanghai")
  668. times = append(times, time.Date(2013, 02, 19, 1, 51, 49, 123456789, GMT8))
  669. times = append(times, time.Date(2013, 02, 18, 17, 51, 49, 123456789, time.UTC))
  670. for index, vtime := range times {
  671. name := "time_with_zone_" + strconv.Itoa(index)
  672. user := User{Name: name, Birthday: &vtime}
  673. if !DialectHasTzSupport() {
  674. // If our driver dialect doesn't support TZ's, just use UTC for everything here.
  675. utcBirthday := user.Birthday.UTC()
  676. user.Birthday = &utcBirthday
  677. }
  678. DB.Save(&user)
  679. expectedBirthday := "2013-02-18 17:51:49 +0000"
  680. foundBirthday := user.Birthday.UTC().Format(format)
  681. if foundBirthday != expectedBirthday {
  682. t.Errorf("User's birthday should not be changed after save for name=%s, expected bday=%+v but actual value=%+v", name, expectedBirthday, foundBirthday)
  683. }
  684. var findUser, findUser2, findUser3 User
  685. DB.First(&findUser, "name = ?", name)
  686. foundBirthday = findUser.Birthday.UTC().Format(format)
  687. if foundBirthday != expectedBirthday {
  688. t.Errorf("User's birthday should not be changed after find for name=%s, expected bday=%+v but actual value=%+v", name, expectedBirthday, foundBirthday)
  689. }
  690. if DB.Where("id = ? AND birthday >= ?", findUser.Id, user.Birthday.Add(-time.Minute)).First(&findUser2).RecordNotFound() {
  691. t.Errorf("User should be found")
  692. }
  693. if !DB.Where("id = ? AND birthday >= ?", findUser.Id, user.Birthday.Add(time.Minute)).First(&findUser3).RecordNotFound() {
  694. t.Errorf("User should not be found")
  695. }
  696. }
  697. }
  698. func TestHstore(t *testing.T) {
  699. type Details struct {
  700. Id int64
  701. Bulk postgres.Hstore
  702. }
  703. if dialect := os.Getenv("GORM_DIALECT"); dialect != "postgres" {
  704. t.Skip()
  705. }
  706. if err := DB.Exec("CREATE EXTENSION IF NOT EXISTS hstore").Error; err != nil {
  707. fmt.Println("\033[31mHINT: Must be superuser to create hstore extension (ALTER USER gorm WITH SUPERUSER;)\033[0m")
  708. panic(fmt.Sprintf("No error should happen when create hstore extension, but got %+v", err))
  709. }
  710. DB.Exec("drop table details")
  711. if err := DB.CreateTable(&Details{}).Error; err != nil {
  712. panic(fmt.Sprintf("No error should happen when create table, but got %+v", err))
  713. }
  714. bankAccountId, phoneNumber, opinion := "123456", "14151321232", "sharkbait"
  715. bulk := map[string]*string{
  716. "bankAccountId": &bankAccountId,
  717. "phoneNumber": &phoneNumber,
  718. "opinion": &opinion,
  719. }
  720. d := Details{Bulk: bulk}
  721. DB.Save(&d)
  722. var d2 Details
  723. if err := DB.First(&d2).Error; err != nil {
  724. t.Errorf("Got error when tried to fetch details: %+v", err)
  725. }
  726. for k := range bulk {
  727. if r, ok := d2.Bulk[k]; ok {
  728. if res, _ := bulk[k]; *res != *r {
  729. t.Errorf("Details should be equal")
  730. }
  731. } else {
  732. t.Errorf("Details should be existed")
  733. }
  734. }
  735. }
  736. func TestSetAndGet(t *testing.T) {
  737. if value, ok := DB.Set("hello", "world").Get("hello"); !ok {
  738. t.Errorf("Should be able to get setting after set")
  739. } else {
  740. if value.(string) != "world" {
  741. t.Errorf("Setted value should not be changed")
  742. }
  743. }
  744. if _, ok := DB.Get("non_existing"); ok {
  745. t.Errorf("Get non existing key should return error")
  746. }
  747. }
  748. func TestCompatibilityMode(t *testing.T) {
  749. DB, _ := gorm.Open("testdb", "")
  750. testdb.SetQueryFunc(func(query string) (driver.Rows, error) {
  751. columns := []string{"id", "name", "age"}
  752. result := `
  753. 1,Tim,20
  754. 2,Joe,25
  755. 3,Bob,30
  756. `
  757. return testdb.RowsFromCSVString(columns, result), nil
  758. })
  759. var users []User
  760. DB.Find(&users)
  761. if (users[0].Name != "Tim") || len(users) != 3 {
  762. t.Errorf("Unexcepted result returned")
  763. }
  764. }
  765. func TestOpenExistingDB(t *testing.T) {
  766. DB.Save(&User{Name: "jnfeinstein"})
  767. dialect := os.Getenv("GORM_DIALECT")
  768. db, err := gorm.Open(dialect, DB.DB())
  769. if err != nil {
  770. t.Errorf("Should have wrapped the existing DB connection")
  771. }
  772. var user User
  773. if db.Where("name = ?", "jnfeinstein").First(&user).Error == gorm.ErrRecordNotFound {
  774. t.Errorf("Should have found existing record")
  775. }
  776. }
  777. func TestDdlErrors(t *testing.T) {
  778. var err error
  779. if err = DB.Close(); err != nil {
  780. t.Errorf("Closing DDL test db connection err=%s", err)
  781. }
  782. defer func() {
  783. // Reopen DB connection.
  784. if DB, err = OpenTestConnection(); err != nil {
  785. t.Fatalf("Failed re-opening db connection: %s", err)
  786. }
  787. }()
  788. if err := DB.Find(&User{}).Error; err == nil {
  789. t.Errorf("Expected operation on closed db to produce an error, but err was nil")
  790. }
  791. }
  792. func TestOpenWithOneParameter(t *testing.T) {
  793. db, err := gorm.Open("dialect")
  794. if db != nil {
  795. t.Error("Open with one parameter returned non nil for db")
  796. }
  797. if err == nil {
  798. t.Error("Open with one parameter returned err as nil")
  799. }
  800. }
  801. func TestSaveAssociations(t *testing.T) {
  802. db := DB.New()
  803. deltaAddressCount := 0
  804. if err := db.Model(&Address{}).Count(&deltaAddressCount).Error; err != nil {
  805. t.Errorf("failed to fetch address count")
  806. t.FailNow()
  807. }
  808. placeAddress := &Address{
  809. Address1: "somewhere on earth",
  810. }
  811. ownerAddress1 := &Address{
  812. Address1: "near place address",
  813. }
  814. ownerAddress2 := &Address{
  815. Address1: "address2",
  816. }
  817. db.Create(placeAddress)
  818. addressCountShouldBe := func(t *testing.T, expectedCount int) {
  819. countFromDB := 0
  820. t.Helper()
  821. err := db.Model(&Address{}).Count(&countFromDB).Error
  822. if err != nil {
  823. t.Error("failed to fetch address count")
  824. }
  825. if countFromDB != expectedCount {
  826. t.Errorf("address count mismatch: %d", countFromDB)
  827. }
  828. }
  829. addressCountShouldBe(t, deltaAddressCount+1)
  830. // owner address should be created, place address should be reused
  831. place1 := &Place{
  832. PlaceAddressID: placeAddress.ID,
  833. PlaceAddress: placeAddress,
  834. OwnerAddress: ownerAddress1,
  835. }
  836. err := db.Create(place1).Error
  837. if err != nil {
  838. t.Errorf("failed to store place: %s", err.Error())
  839. }
  840. addressCountShouldBe(t, deltaAddressCount+2)
  841. // owner address should be created again, place address should be reused
  842. place2 := &Place{
  843. PlaceAddressID: placeAddress.ID,
  844. PlaceAddress: &Address{
  845. ID: 777,
  846. Address1: "address1",
  847. },
  848. OwnerAddress: ownerAddress2,
  849. OwnerAddressID: 778,
  850. }
  851. err = db.Create(place2).Error
  852. if err != nil {
  853. t.Errorf("failed to store place: %s", err.Error())
  854. }
  855. addressCountShouldBe(t, deltaAddressCount+3)
  856. count := 0
  857. db.Model(&Place{}).Where(&Place{
  858. PlaceAddressID: placeAddress.ID,
  859. OwnerAddressID: ownerAddress1.ID,
  860. }).Count(&count)
  861. if count != 1 {
  862. t.Errorf("only one instance of (%d, %d) should be available, found: %d",
  863. placeAddress.ID, ownerAddress1.ID, count)
  864. }
  865. db.Model(&Place{}).Where(&Place{
  866. PlaceAddressID: placeAddress.ID,
  867. OwnerAddressID: ownerAddress2.ID,
  868. }).Count(&count)
  869. if count != 1 {
  870. t.Errorf("only one instance of (%d, %d) should be available, found: %d",
  871. placeAddress.ID, ownerAddress2.ID, count)
  872. }
  873. db.Model(&Place{}).Where(&Place{
  874. PlaceAddressID: placeAddress.ID,
  875. }).Count(&count)
  876. if count != 2 {
  877. t.Errorf("two instances of (%d) should be available, found: %d",
  878. placeAddress.ID, count)
  879. }
  880. }
  881. func TestBlockGlobalUpdate(t *testing.T) {
  882. db := DB.New()
  883. db.Create(&Toy{Name: "Stuffed Animal", OwnerType: "Nobody"})
  884. err := db.Model(&Toy{}).Update("OwnerType", "Human").Error
  885. if err != nil {
  886. t.Error("Unexpected error on global update")
  887. }
  888. err = db.Delete(&Toy{}).Error
  889. if err != nil {
  890. t.Error("Unexpected error on global delete")
  891. }
  892. db.BlockGlobalUpdate(true)
  893. db.Create(&Toy{Name: "Stuffed Animal", OwnerType: "Nobody"})
  894. err = db.Model(&Toy{}).Update("OwnerType", "Human").Error
  895. if err == nil {
  896. t.Error("Expected error on global update")
  897. }
  898. err = db.Model(&Toy{}).Where(&Toy{OwnerType: "Martian"}).Update("OwnerType", "Astronaut").Error
  899. if err != nil {
  900. t.Error("Unxpected error on conditional update")
  901. }
  902. err = db.Delete(&Toy{}).Error
  903. if err == nil {
  904. t.Error("Expected error on global delete")
  905. }
  906. err = db.Where(&Toy{OwnerType: "Martian"}).Delete(&Toy{}).Error
  907. if err != nil {
  908. t.Error("Unexpected error on conditional delete")
  909. }
  910. }
  911. func TestCountWithHaving(t *testing.T) {
  912. db := DB.New()
  913. db.Delete(User{})
  914. defer db.Delete(User{})
  915. DB.Create(getPreparedUser("user1", "pluck_user"))
  916. DB.Create(getPreparedUser("user2", "pluck_user"))
  917. user3 := getPreparedUser("user3", "pluck_user")
  918. user3.Languages = []Language{}
  919. DB.Create(user3)
  920. var count int
  921. err := db.Model(User{}).Select("users.id").
  922. Joins("LEFT JOIN user_languages ON user_languages.user_id = users.id").
  923. Joins("LEFT JOIN languages ON user_languages.language_id = languages.id").
  924. Group("users.id").Having("COUNT(languages.id) > 1").Count(&count).Error
  925. if err != nil {
  926. t.Error("Unexpected error on query count with having")
  927. }
  928. if count != 2 {
  929. t.Error("Unexpected result on query count with having")
  930. }
  931. }
  932. func TestPluck(t *testing.T) {
  933. db := DB.New()
  934. db.Delete(User{})
  935. defer db.Delete(User{})
  936. DB.Create(&User{Id: 1, Name: "user1"})
  937. DB.Create(&User{Id: 2, Name: "user2"})
  938. DB.Create(&User{Id: 3, Name: "user3"})
  939. var ids []int64
  940. err := db.Model(User{}).Order("id").Pluck("id", &ids).Error
  941. if err != nil {
  942. t.Error("Unexpected error on pluck")
  943. }
  944. if len(ids) != 3 || ids[0] != 1 || ids[1] != 2 || ids[2] != 3 {
  945. t.Error("Unexpected result on pluck")
  946. }
  947. err = db.Model(User{}).Order("id").Pluck("id", &ids).Error
  948. if err != nil {
  949. t.Error("Unexpected error on pluck again")
  950. }
  951. if len(ids) != 3 || ids[0] != 1 || ids[1] != 2 || ids[2] != 3 {
  952. t.Error("Unexpected result on pluck again")
  953. }
  954. }
  955. func TestCountWithQueryOption(t *testing.T) {
  956. db := DB.New()
  957. db.Delete(User{})
  958. defer db.Delete(User{})
  959. DB.Create(&User{Name: "user1"})
  960. DB.Create(&User{Name: "user2"})
  961. DB.Create(&User{Name: "user3"})
  962. var count int
  963. err := db.Model(User{}).Select("users.id").
  964. Set("gorm:query_option", "WHERE users.name='user2'").
  965. Count(&count).Error
  966. if err != nil {
  967. t.Error("Unexpected error on query count with query_option")
  968. }
  969. if count != 1 {
  970. t.Error("Unexpected result on query count with query_option")
  971. }
  972. }
  973. func TestFloatColumnPrecision(t *testing.T) {
  974. if dialect := os.Getenv("GORM_DIALECT"); dialect != "mysql" && dialect != "sqlite" {
  975. t.Skip()
  976. }
  977. type FloatTest struct {
  978. ID string `gorm:"primary_key"`
  979. FloatValue float64 `gorm:"column:float_value" sql:"type:float(255,5);"`
  980. }
  981. DB.DropTable(&FloatTest{})
  982. DB.AutoMigrate(&FloatTest{})
  983. data := FloatTest{ID: "uuid", FloatValue: 112.57315}
  984. if err := DB.Save(&data).Error; err != nil || data.ID != "uuid" || data.FloatValue != 112.57315 {
  985. t.Errorf("Float value should not lose precision")
  986. }
  987. }
  988. func TestWhereUpdates(t *testing.T) {
  989. type OwnerEntity struct {
  990. gorm.Model
  991. OwnerID uint
  992. OwnerType string
  993. }
  994. type SomeEntity struct {
  995. gorm.Model
  996. Name string
  997. OwnerEntity OwnerEntity `gorm:"polymorphic:Owner"`
  998. }
  999. db := DB.Debug()
  1000. db.DropTable(&SomeEntity{})
  1001. db.AutoMigrate(&SomeEntity{})
  1002. a := SomeEntity{Name: "test"}
  1003. db.Model(&a).Where(a).Updates(SomeEntity{Name: "test2"})
  1004. }
  1005. func BenchmarkGorm(b *testing.B) {
  1006. b.N = 2000
  1007. for x := 0; x < b.N; x++ {
  1008. e := strconv.Itoa(x) + "benchmark@example.org"
  1009. now := time.Now()
  1010. email := EmailWithIdx{Email: e, UserAgent: "pc", RegisteredAt: &now}
  1011. // Insert
  1012. DB.Save(&email)
  1013. // Query
  1014. DB.First(&EmailWithIdx{}, "email = ?", e)
  1015. // Update
  1016. DB.Model(&email).UpdateColumn("email", "new-"+e)
  1017. // Delete
  1018. DB.Delete(&email)
  1019. }
  1020. }
  1021. func BenchmarkRawSql(b *testing.B) {
  1022. DB, _ := sql.Open("postgres", "user=gorm DB.ame=gorm sslmode=disable")
  1023. DB.SetMaxIdleConns(10)
  1024. insertSql := "INSERT INTO emails (user_id,email,user_agent,registered_at,created_at,updated_at) VALUES ($1,$2,$3,$4,$5,$6) RETURNING id"
  1025. querySql := "SELECT * FROM emails WHERE email = $1 ORDER BY id LIMIT 1"
  1026. updateSql := "UPDATE emails SET email = $1, updated_at = $2 WHERE id = $3"
  1027. deleteSql := "DELETE FROM orders WHERE id = $1"
  1028. b.N = 2000
  1029. for x := 0; x < b.N; x++ {
  1030. var id int64
  1031. e := strconv.Itoa(x) + "benchmark@example.org"
  1032. now := time.Now()
  1033. email := EmailWithIdx{Email: e, UserAgent: "pc", RegisteredAt: &now}
  1034. // Insert
  1035. DB.QueryRow(insertSql, email.UserId, email.Email, email.UserAgent, email.RegisteredAt, time.Now(), time.Now()).Scan(&id)
  1036. // Query
  1037. rows, _ := DB.Query(querySql, email.Email)
  1038. rows.Close()
  1039. // Update
  1040. DB.Exec(updateSql, "new-"+e, time.Now(), id)
  1041. // Delete
  1042. DB.Exec(deleteSql, id)
  1043. }
  1044. }
  1045. func parseTime(str string) *time.Time {
  1046. t := now.New(time.Now().UTC()).MustParse(str)
  1047. return &t
  1048. }