github.com/nshntarora/pop@v0.1.2/executors_test.go (about) 1 package pop 2 3 import ( 4 "fmt" 5 "testing" 6 "time" 7 8 "github.com/gobuffalo/nulls" 9 "github.com/gofrs/uuid" 10 "github.com/stretchr/testify/require" 11 ) 12 13 func Test_IsZeroOfUnderlyingType(t *testing.T) { 14 if PDB == nil { 15 t.Skip("skipping integration tests") 16 } 17 r := require.New(t) 18 transaction(func(tx *Connection) { 19 car := &ValidatableCar{Name: "VW"} 20 r.True(IsZeroOfUnderlyingType(car.ID)) 21 err := tx.Save(car) 22 r.NoError(err) 23 r.NotZero(car.ID) 24 r.NotZero(car.CreatedAt) 25 26 r.False(IsZeroOfUnderlyingType(car.ID)) 27 28 var i int 29 r.True(IsZeroOfUnderlyingType(i)) 30 i = 32 31 r.False(IsZeroOfUnderlyingType(i)) 32 33 var s string 34 r.True(IsZeroOfUnderlyingType(s)) 35 s = "42" 36 r.False(IsZeroOfUnderlyingType(s)) 37 38 var u uuid.UUID 39 r.True(IsZeroOfUnderlyingType(u)) 40 u, err = uuid.NewV1() 41 r.NoError(err) 42 r.False(IsZeroOfUnderlyingType(u)) 43 }) 44 } 45 46 func Test_ValidateAndSave(t *testing.T) { 47 if PDB == nil { 48 t.Skip("skipping integration tests") 49 } 50 r := require.New(t) 51 validationLogs = []string{} 52 transaction(func(tx *Connection) { 53 car := &ValidatableCar{Name: "VW"} 54 verrs, err := tx.ValidateAndSave(car) 55 r.NoError(err) 56 r.False(verrs.HasAny()) 57 r.Len(validationLogs, 2) 58 r.Equal([]string{"Validate", "ValidateSave"}, validationLogs) 59 r.NotZero(car.ID) 60 r.NotZero(car.CreatedAt) 61 62 validationLogs = []string{} 63 car = &ValidatableCar{Name: ""} 64 verrs, err = tx.ValidateAndSave(car) 65 r.NoError(err) 66 r.True(verrs.HasAny()) 67 r.Len(validationLogs, 2) 68 errs := verrs.Get("name") 69 r.Len(errs, 1) 70 71 validationLogs = []string{} 72 ncar := &NotValidatableCar{Name: ""} 73 verrs, err = tx.ValidateAndSave(ncar) 74 r.NoError(err) 75 r.False(verrs.HasAny()) 76 r.Len(validationLogs, 0) 77 }) 78 } 79 80 func Test_ValidateAndSave_With_Slice(t *testing.T) { 81 if PDB == nil { 82 t.Skip("skipping integration tests") 83 } 84 r := require.New(t) 85 validationLogs = []string{} 86 transaction(func(tx *Connection) { 87 car := []ValidatableCar{ 88 {Name: "VW"}, 89 {Name: "AU"}, 90 } 91 verrs, err := tx.ValidateAndSave(&car) 92 r.NoError(err) 93 r.False(verrs.HasAny()) 94 r.Len(validationLogs, 4) 95 r.Equal([]string{"Validate", "ValidateSave", "Validate", "ValidateSave"}, validationLogs) 96 97 r.NotZero(car[0].ID) 98 r.NotZero(car[0].CreatedAt) 99 r.NotZero(car[1].ID) 100 r.NotZero(car[1].CreatedAt) 101 102 validationLogs = []string{} 103 car = []ValidatableCar{ 104 {Name: ""}, 105 {Name: "AU"}, 106 } 107 verrs, err = tx.ValidateAndSave(&car) 108 r.NoError(err) 109 r.True(verrs.HasAny()) 110 r.Len(validationLogs, 2) 111 errs := verrs.Get("name") 112 r.Len(errs, 1) 113 114 validationLogs = []string{} 115 ncar := []NotValidatableCar{ 116 {Name: ""}, 117 {Name: "AU"}, 118 } 119 verrs, err = tx.ValidateAndSave(&ncar) 120 r.NoError(err) 121 r.False(verrs.HasAny()) 122 r.Len(validationLogs, 0) 123 }) 124 } 125 126 func Test_ValidateAndCreate(t *testing.T) { 127 if PDB == nil { 128 t.Skip("skipping integration tests") 129 } 130 r := require.New(t) 131 validationLogs = []string{} 132 transaction(func(tx *Connection) { 133 car := &ValidatableCar{Name: "VW"} 134 verrs, err := tx.ValidateAndCreate(car) 135 r.NoError(err) 136 r.False(verrs.HasAny()) 137 r.Len(validationLogs, 2) 138 r.Equal([]string{"Validate", "ValidateCreate"}, validationLogs) 139 r.NotZero(car.ID) 140 r.NotZero(car.CreatedAt) 141 142 validationLogs = []string{} 143 car = &ValidatableCar{Name: ""} 144 verrs, err = tx.ValidateAndSave(car) 145 r.NoError(err) 146 r.True(verrs.HasAny()) 147 r.Len(validationLogs, 2) 148 errs := verrs.Get("name") 149 r.Len(errs, 1) 150 151 validationLogs = []string{} 152 ncar := &NotValidatableCar{Name: ""} 153 verrs, err = tx.ValidateAndCreate(ncar) 154 r.NoError(err) 155 r.False(verrs.HasAny()) 156 r.Len(validationLogs, 0) 157 }) 158 } 159 160 func Test_Create_Single_Incremental_ID(t *testing.T) { 161 if PDB == nil { 162 t.Skip("skipping integration tests") 163 } 164 r := require.New(t) 165 validationLogs = []string{} 166 transaction(func(tx *Connection) { 167 singleID := &SingleID{} 168 err := tx.Create(singleID) 169 r.NoError(err) 170 r.NotZero(singleID.ID) 171 }) 172 } 173 174 func Test_ValidateAndCreate_With_Slice(t *testing.T) { 175 if PDB == nil { 176 t.Skip("skipping integration tests") 177 } 178 r := require.New(t) 179 validationLogs = []string{} 180 transaction(func(tx *Connection) { 181 car := []ValidatableCar{ 182 {Name: "VW"}, 183 {Name: "AU"}, 184 } 185 verrs, err := tx.ValidateAndCreate(&car) 186 r.NoError(err) 187 r.False(verrs.HasAny()) 188 r.Len(validationLogs, 4) 189 r.Equal([]string{"Validate", "ValidateCreate", "Validate", "ValidateCreate"}, validationLogs) 190 r.NotZero(car[0].ID) 191 r.NotZero(car[0].CreatedAt) 192 r.NotZero(car[1].ID) 193 r.NotZero(car[1].CreatedAt) 194 195 validationLogs = []string{} 196 car = []ValidatableCar{ 197 {Name: ""}, 198 {Name: "AU"}, 199 } 200 verrs, err = tx.ValidateAndSave(&car) 201 r.NoError(err) 202 r.True(verrs.HasAny()) 203 r.Len(validationLogs, 2) 204 errs := verrs.Get("name") 205 r.Len(errs, 1) 206 207 validationLogs = []string{} 208 ncar := []NotValidatableCar{ 209 {Name: ""}, 210 {Name: "AU"}, 211 } 212 verrs, err = tx.ValidateAndCreate(ncar) 213 r.NoError(err) 214 r.False(verrs.HasAny()) 215 r.Len(validationLogs, 0) 216 }) 217 } 218 219 func Test_ValidateAndUpdate(t *testing.T) { 220 if PDB == nil { 221 t.Skip("skipping integration tests") 222 } 223 r := require.New(t) 224 validationLogs = []string{} 225 transaction(func(tx *Connection) { 226 car := &ValidatableCar{Name: "VW"} 227 verrs, err := tx.ValidateAndCreate(car) 228 r.NoError(err) 229 r.False(verrs.HasAny()) 230 r.Len(validationLogs, 2) 231 r.Equal([]string{"Validate", "ValidateCreate"}, validationLogs) 232 r.NotZero(car.ID) 233 r.NotZero(car.CreatedAt) 234 235 validationLogs = []string{} 236 car.Name = "" 237 verrs, err = tx.ValidateAndUpdate(car) 238 r.NoError(err) 239 r.True(verrs.HasAny()) 240 r.Len(validationLogs, 2) 241 errs := verrs.Get("name") 242 r.Len(errs, 1) 243 244 validationLogs = []string{} 245 ncar := &NotValidatableCar{Name: ""} 246 verrs, err = tx.ValidateAndCreate(ncar) 247 r.NoError(err) 248 r.False(verrs.HasAny()) 249 r.Len(validationLogs, 0) 250 251 validationLogs = []string{} 252 ncar.Name = "" 253 verrs, err = tx.ValidateAndUpdate(ncar) 254 r.NoError(err) 255 r.False(verrs.HasAny()) 256 r.Len(validationLogs, 0) 257 }) 258 } 259 260 func Test_ValidateAndUpdate_With_Slice(t *testing.T) { 261 if PDB == nil { 262 t.Skip("skipping integration tests") 263 } 264 r := require.New(t) 265 validationLogs = []string{} 266 transaction(func(tx *Connection) { 267 car := []ValidatableCar{ 268 {Name: "VW"}, 269 {Name: "AU"}, 270 } 271 verrs, err := tx.ValidateAndCreate(&car) 272 r.NoError(err) 273 r.False(verrs.HasAny()) 274 r.Len(validationLogs, 4) 275 r.Equal([]string{"Validate", "ValidateCreate", "Validate", "ValidateCreate"}, validationLogs) 276 r.NotZero(car[0].ID) 277 r.NotZero(car[0].CreatedAt) 278 r.NotZero(car[1].ID) 279 r.NotZero(car[1].CreatedAt) 280 281 validationLogs = []string{} 282 car[0].Name = "" 283 verrs, err = tx.ValidateAndUpdate(&car) 284 r.NoError(err) 285 r.True(verrs.HasAny()) 286 r.Len(validationLogs, 2) 287 errs := verrs.Get("name") 288 r.Len(errs, 1) 289 290 validationLogs = []string{} 291 ncar := []NotValidatableCar{ 292 {Name: ""}, 293 {Name: "AU"}, 294 } 295 verrs, err = tx.ValidateAndCreate(&ncar) 296 r.NoError(err) 297 r.False(verrs.HasAny()) 298 r.Len(validationLogs, 0) 299 300 validationLogs = []string{} 301 ncar[1].Name = "" 302 verrs, err = tx.ValidateAndUpdate(&ncar) 303 r.NoError(err) 304 r.False(verrs.HasAny()) 305 r.Len(validationLogs, 0) 306 }) 307 } 308 309 func Test_Exec(t *testing.T) { 310 if PDB == nil { 311 t.Skip("skipping integration tests") 312 } 313 transaction(func(tx *Connection) { 314 r := require.New(t) 315 316 user := User{Name: nulls.NewString("Mark 'Awesome' Bates")} 317 r.NoError(tx.Create(&user)) 318 319 ctx, _ := tx.Count(user) 320 r.Equal(1, ctx) 321 322 q := tx.RawQuery("delete from users where id = ?", user.ID) 323 err := q.Exec() 324 r.NoError(err) 325 326 ctx, _ = tx.Count(user) 327 r.Equal(0, ctx) 328 }) 329 } 330 331 func Test_ExecCount(t *testing.T) { 332 if PDB == nil { 333 t.Skip("skipping integration tests") 334 } 335 transaction(func(tx *Connection) { 336 r := require.New(t) 337 338 user := User{Name: nulls.NewString("Mark 'Awesome' Bates")} 339 tx.Create(&user) 340 341 ctx, _ := tx.Count(user) 342 r.Equal(1, ctx) 343 344 q := tx.RawQuery("delete from users where id = ?", user.ID) 345 count, err := q.ExecWithCount() 346 r.NoError(err) 347 348 r.Equal(1, count) 349 350 ctx, _ = tx.Count(user) 351 r.Equal(0, ctx) 352 }) 353 } 354 355 func Test_Save(t *testing.T) { 356 if PDB == nil { 357 t.Skip("skipping integration tests") 358 } 359 r := require.New(t) 360 transaction(func(tx *Connection) { 361 u := &User{Name: nulls.NewString("Mark")} 362 r.Zero(u.ID) 363 r.NoError(tx.Save(u)) 364 r.NotZero(u.ID) 365 366 uat := u.UpdatedAt.UnixNano() 367 368 r.NoError(tx.Save(u)) 369 time.Sleep(1 * time.Second) 370 r.NotEqual(uat, u.UpdatedAt.UnixNano()) 371 }) 372 } 373 374 func Test_Save_With_Slice(t *testing.T) { 375 if PDB == nil { 376 t.Skip("skipping integration tests") 377 } 378 r := require.New(t) 379 transaction(func(tx *Connection) { 380 u := Users{ 381 {Name: nulls.NewString("Mark")}, 382 {Name: nulls.NewString("Larry")}, 383 } 384 r.Zero(u[0].ID) 385 r.Zero(u[1].ID) 386 387 r.NoError(tx.Save(&u)) 388 r.NotZero(u[0].ID) 389 r.NotZero(u[1].ID) 390 391 uat := u[0].UpdatedAt.UnixNano() 392 393 r.NoError(tx.Save(u)) 394 r.NotEqual(uat, u[0].UpdatedAt.UnixNano()) 395 }) 396 } 397 398 func Test_Create(t *testing.T) { 399 if PDB == nil { 400 t.Skip("skipping integration tests") 401 } 402 transaction(func(tx *Connection) { 403 r := require.New(t) 404 405 count, _ := tx.Count(&User{}) 406 user := User{Name: nulls.NewString("Mark 'Awesome' Bates")} 407 err := tx.Create(&user) 408 r.NoError(err) 409 r.NotEqual(0, user.ID) 410 411 ctx, _ := tx.Count(&User{}) 412 r.Equal(count+1, ctx) 413 414 u := User{} 415 q := tx.Where("name = ?", "Mark 'Awesome' Bates") 416 err = q.First(&u) 417 r.NoError(err) 418 r.Equal("Mark 'Awesome' Bates", user.Name.String) 419 }) 420 } 421 422 func Test_Create_stringID(t *testing.T) { 423 if PDB == nil { 424 t.Skip("skipping integration tests") 425 } 426 transaction(func(tx *Connection) { 427 r := require.New(t) 428 429 count, err := tx.Count(&Label{}) 430 r.NoError(err) 431 label := Label{ID: "red"} 432 err = tx.Create(&label) 433 r.NoError(err) 434 r.Equal("red", label.ID) 435 436 ctx, err := tx.Count(&Label{}) 437 r.NoError(err) 438 r.Equal(count+1, ctx) 439 440 l := Label{} 441 err = tx.Find(&l, "red") 442 r.NoError(err) 443 r.Equal("red", l.ID) 444 }) 445 } 446 447 func Test_Create_With_Slice(t *testing.T) { 448 if PDB == nil { 449 t.Skip("skipping integration tests") 450 } 451 transaction(func(tx *Connection) { 452 r := require.New(t) 453 454 count, _ := tx.Count(&User{}) 455 users := Users{ 456 {Name: nulls.NewString("Mark Bates")}, 457 {Name: nulls.NewString("Larry M. Jordan")}, 458 {Name: nulls.NewString("Pop")}, 459 } 460 err := tx.Create(&users) 461 r.NoError(err) 462 463 ctx, _ := tx.Count(&User{}) 464 r.Equal(count+3, ctx) 465 }) 466 } 467 468 func Test_Create_With_Non_ID_PK(t *testing.T) { 469 if PDB == nil { 470 t.Skip("skipping integration tests") 471 } 472 transaction(func(tx *Connection) { 473 r := require.New(t) 474 475 count, _ := tx.Count(&CrookedColour{}) 476 djs := []CrookedColour{ 477 {Name: "Phil Slabber"}, 478 {Name: "Leon Debaughn"}, 479 {Name: "Liam Merrett-Park"}, 480 } 481 err := tx.Create(&djs) 482 r.NoError(err) 483 484 ctx, _ := tx.Count(&CrookedColour{}) 485 r.Equal(count+3, ctx) 486 r.NotEqual(djs[0].ID, djs[1].ID) 487 r.NotEqual(djs[1].ID, djs[2].ID) 488 }) 489 } 490 491 func Test_Create_With_Non_ID_PK_String(t *testing.T) { 492 if PDB == nil { 493 t.Skip("skipping integration tests") 494 } 495 transaction(func(tx *Connection) { 496 r := require.New(t) 497 498 count, _ := tx.Count(&CrookedSong{}) 499 djs := []CrookedSong{ 500 {ID: "Flow"}, 501 {ID: "Do It Like You"}, 502 {ID: "I C Light"}, 503 } 504 err := tx.Create(&djs) 505 r.NoError(err) 506 507 ctx, _ := tx.Count(&CrookedSong{}) 508 r.Equal(count+3, ctx) 509 r.NotEqual(djs[0].ID, djs[1].ID) 510 r.NotEqual(djs[1].ID, djs[2].ID) 511 }) 512 } 513 514 func Test_Create_Non_PK_ID(t *testing.T) { 515 if PDB == nil { 516 t.Skip("skipping integration tests") 517 } 518 transaction(func(tx *Connection) { 519 r := require.New(t) 520 521 r.NoError(tx.Create(&NonStandardID{OutfacingID: "make sure the tested entry does not have pk=0"})) 522 523 count, err := tx.Count(&NonStandardID{}) 524 r.NoError(err) 525 entry := &NonStandardID{ 526 OutfacingID: "beautiful to the outside ID", 527 } 528 r.NoError(tx.Create(entry)) 529 530 ctx, err := tx.Count(&NonStandardID{}) 531 r.NoError(err) 532 r.Equal(count+1, ctx) 533 r.NotZero(entry.ID) 534 }) 535 } 536 537 func Test_Create_Parallel(t *testing.T) { 538 if PDB == nil { 539 t.Skip("skipping integration tests") 540 } 541 for i := 0; i < 5; i++ { 542 i := i 543 t.Run(fmt.Sprintf("case=%d", i), func(t *testing.T) { 544 t.Parallel() 545 require.NoError(t, PDB.Create(&CrookedColour{Name: fmt.Sprintf("Singer %d", i)})) 546 }) 547 } 548 } 549 550 func Test_Embedded_Struct(t *testing.T) { 551 if PDB == nil { 552 t.Skip("skipping integration tests") 553 } 554 transaction(func(tx *Connection) { 555 r := require.New(t) 556 557 entry := &EmbeddingStruct{ 558 InnerStruct: InnerStruct{}, 559 AdditionalField: "I am also important!", 560 } 561 r.NoError(tx.Create(entry)) 562 563 var actual EmbeddingStruct 564 r.NoError(tx.Find(&actual, entry.ID)) 565 r.Equal(entry.AdditionalField, actual.AdditionalField) 566 567 entry.AdditionalField = entry.AdditionalField + " updated" 568 r.NoError(tx.Update(entry)) 569 570 r.NoError(tx.Find(&actual, entry.ID)) 571 r.Equal(entry.AdditionalField, actual.AdditionalField) 572 573 entry.AdditionalField = entry.AdditionalField + "; updated again" 574 count, err := tx.Where("id = ?", entry.ID).UpdateQuery(entry, "additional_field") 575 r.NoError(err) 576 require.Equal(t, int64(1), count) 577 r.NoError(tx.Find(&actual, entry.ID)) 578 r.Equal(entry.AdditionalField, actual.AdditionalField) 579 580 r.NoError(tx.Destroy(entry)) 581 }) 582 } 583 584 func Test_Eager_Create_Has_Many(t *testing.T) { 585 if PDB == nil { 586 t.Skip("skipping integration tests") 587 } 588 transaction(func(tx *Connection) { 589 r := require.New(t) 590 count, _ := tx.Count(&User{}) 591 user := User{ 592 Name: nulls.NewString("Mark 'Awesome' Bates"), 593 Books: Books{{Title: "Pop Book", Description: "Pop Book", Isbn: "PB1"}}, 594 FavoriteSong: Song{Title: "Hook - Blues Traveler"}, 595 Houses: Addresses{ 596 Address{HouseNumber: 86, Street: "Modelo"}, 597 }, 598 } 599 600 err := tx.Eager().Create(&user) 601 r.NoError(err) 602 r.NotEqual(user.ID, 0) 603 604 ctx, _ := tx.Count(&User{}) 605 r.Equal(count+1, ctx) 606 607 ctx, _ = tx.Count(&Book{}) 608 r.Equal(count+1, ctx) 609 610 ctx, _ = tx.Count(&Song{}) 611 r.Equal(count+1, ctx) 612 613 ctx, _ = tx.Count(&Address{}) 614 r.Equal(count+1, ctx) 615 616 u := User{} 617 q := tx.Eager().Where("name = ?", "Mark 'Awesome' Bates") 618 err = q.First(&u) 619 r.NoError(err) 620 r.Equal(u.Name.String, "Mark 'Awesome' Bates") 621 r.Equal(1, len(u.Books)) 622 r.Equal(u.Books[0].Title, "Pop Book") 623 r.Equal(u.FavoriteSong.Title, "Hook - Blues Traveler") 624 r.Equal(1, len(u.Houses)) 625 r.Equal(u.Houses[0].Street, "Modelo") 626 }) 627 } 628 629 func Test_Eager_Create_Has_Many_With_Existing(t *testing.T) { 630 if PDB == nil { 631 t.Skip("skipping integration tests") 632 } 633 transaction(func(tx *Connection) { 634 r := require.New(t) 635 636 addr := Address{HouseNumber: 42, Street: "Life"} 637 addrVerrs, addrErr := tx.ValidateAndCreate(&addr) 638 r.NoError(addrErr) 639 addrCount, _ := tx.Count(&Address{}) 640 r.Zero(addrVerrs.Count()) 641 r.Equal(1, addrCount) 642 r.NotZero(addr.ID) 643 644 count, _ := tx.Count(&User{}) 645 user := User{ 646 Name: nulls.NewString("Mark 'Awesome' Bates"), 647 Books: Books{{Title: "Pop Book", Description: "Pop Book", Isbn: "PB1"}}, 648 FavoriteSong: Song{Title: "Hook - Blues Traveler"}, 649 Houses: Addresses{ 650 Address{HouseNumber: 86, Street: "Modelo"}, 651 addr, 652 }, 653 } 654 655 err := tx.Eager().Create(&user) 656 r.NoError(err) 657 r.NotEqual(user.ID, 0) 658 659 ctx, _ := tx.Count(&User{}) 660 r.Equal(count+1, ctx) 661 662 ctx, _ = tx.Count(&Book{}) 663 r.Equal(count+1, ctx) 664 665 ctx, _ = tx.Count(&Song{}) 666 r.Equal(count+1, ctx) 667 668 ctx, _ = tx.Count(&Address{}) 669 r.Equal(addrCount+1, ctx) 670 671 u := User{} 672 q := tx.Eager().Where("name = ?", "Mark 'Awesome' Bates") 673 err = q.First(&u) 674 r.NoError(err) 675 r.Equal(u.Name.String, "Mark 'Awesome' Bates") 676 r.Equal(1, len(u.Books)) 677 r.Equal(u.Books[0].Title, "Pop Book") 678 r.Equal(u.FavoriteSong.Title, "Hook - Blues Traveler") 679 r.Equal(2, len(u.Houses)) 680 if u.Houses[0].ID == addr.ID { 681 r.Equal(u.Houses[0].Street, "Life") 682 r.Equal(u.Houses[1].Street, "Modelo") 683 } else { 684 r.Equal(u.Houses[0].Street, "Modelo") 685 r.Equal(u.Houses[1].Street, "Life") 686 } 687 }) 688 } 689 690 func Test_Eager_Create_Has_Many_Reset_Eager_Mode_Connection(t *testing.T) { 691 if PDB == nil { 692 t.Skip("skipping integration tests") 693 } 694 transaction(func(tx *Connection) { 695 r := require.New(t) 696 count, _ := tx.Count(&User{}) 697 user1 := User{ 698 Name: nulls.NewString("Mark 'Awesome' Bates"), 699 Books: Books{{Title: "Pop Book", Description: "Pop Book", Isbn: "PB1"}}, 700 } 701 702 err := tx.Eager("Books").Create(&user1) 703 r.NoError(err) 704 ctx, _ := tx.Count(&User{}) 705 r.Equal(count+1, ctx) 706 ctx, _ = tx.Count(&Book{}) 707 r.Equal(count+1, ctx) 708 709 book := Book{Title: "Pop Book", Description: "Pop Book", Isbn: "PB1"} 710 711 err = tx.Eager().Create(&book) 712 r.NoError(err) 713 ctx, _ = tx.Count(&Book{}) 714 r.Equal(count+2, ctx) 715 }) 716 } 717 718 func Test_Eager_Validate_And_Create_Has_Many(t *testing.T) { 719 if PDB == nil { 720 t.Skip("skipping integration tests") 721 } 722 r := require.New(t) 723 transaction(func(tx *Connection) { 724 user := User{ 725 Name: nulls.NewString("Mark 'Awesome' Bates"), 726 Books: Books{{Title: "Pop Book", Isbn: "PB1"}}, 727 FavoriteSong: Song{Title: "Hook - Blues Traveler"}, 728 Houses: Addresses{ 729 Address{HouseNumber: 86, Street: "Modelo"}, 730 }, 731 } 732 733 verrs, err := tx.Eager().ValidateAndCreate(&user) 734 r.NoError(err) 735 ctx, _ := tx.Count(&User{}) 736 r.Zero(ctx) 737 r.Equal(1, verrs.Count()) // Missing Books.Description. 738 }) 739 } 740 741 func Test_Eager_Validate_And_Create_Parental(t *testing.T) { 742 if PDB == nil { 743 t.Skip("skipping integration tests") 744 } 745 r := require.New(t) 746 transaction(func(tx *Connection) { 747 user := User{ 748 Name: nulls.NewString(""), 749 Books: Books{{Title: "Pop Book", Isbn: "PB1", Description: "Awesome Book!"}}, 750 FavoriteSong: Song{Title: "Hook - Blues Traveler"}, 751 Houses: Addresses{ 752 Address{HouseNumber: 86, Street: "Modelo"}, 753 }, 754 } 755 756 verrs, err := tx.Eager().ValidateAndCreate(&user) 757 r.NoError(err) 758 ctx, _ := tx.Count(&User{}) 759 r.Zero(ctx) 760 r.Equal(1, verrs.Count()) // Missing Books.Description. 761 }) 762 } 763 764 func Test_Eager_Validate_And_Create_Parental_With_Existing(t *testing.T) { 765 if PDB == nil { 766 t.Skip("skipping integration tests") 767 } 768 r := require.New(t) 769 transaction(func(tx *Connection) { 770 addr := Address{HouseNumber: 42, Street: "Life"} 771 addrVerrs, addrErr := tx.ValidateAndCreate(&addr) 772 r.NoError(addrErr) 773 addrCount, _ := tx.Count(&Address{}) 774 r.Zero(addrVerrs.Count()) 775 r.Equal(1, addrCount) 776 r.NotZero(addr.ID) 777 778 m2mCount, m2mErr := tx.Count(&UsersAddress{}) 779 r.NoError(m2mErr) 780 r.Zero(m2mCount) 781 782 user := User{ 783 Name: nulls.NewString("Mark 'Awesome' Bates"), 784 Books: Books{{Title: "Pop Book", Isbn: "PB1", Description: "Awesome Book!"}}, 785 FavoriteSong: Song{Title: "Hook - Blues Traveler"}, 786 Houses: Addresses{ 787 Address{HouseNumber: 86, Street: "Modelo"}, 788 addr, 789 }, 790 } 791 count, _ := tx.Count(&User{}) 792 793 verrs, err := tx.Eager().ValidateAndCreate(&user) 794 r.NoError(err) 795 r.NotEqual(user.ID, 0) 796 r.Equal(0, verrs.Count()) 797 798 ctx, _ := tx.Count(&User{}) 799 r.Equal(count+1, ctx) 800 801 ctx, _ = tx.Count(&Address{}) 802 r.Equal(addrCount+1, ctx) 803 804 m2mCount, m2mErr = tx.Count(&UsersAddress{}) 805 r.NoError(m2mErr) 806 r.Equal(2, m2mCount) 807 808 u := User{} 809 q := tx.Eager().Where("name = ?", "Mark 'Awesome' Bates") 810 err = q.First(&u) 811 r.NoError(err) 812 r.Equal(u.Name.String, "Mark 'Awesome' Bates") 813 r.Equal(1, len(u.Books)) 814 r.Equal(u.Books[0].Title, "Pop Book") 815 r.Equal(u.FavoriteSong.Title, "Hook - Blues Traveler") 816 r.Equal(2, len(u.Houses)) 817 if u.Houses[0].ID == addr.ID { 818 r.Equal(u.Houses[0].Street, "Life") 819 r.Equal(u.Houses[1].Street, "Modelo") 820 } else { 821 r.Equal(u.Houses[1].ID, addr.ID) 822 r.Equal(u.Houses[0].Street, "Modelo") 823 r.Equal(u.Houses[1].Street, "Life") 824 } 825 }) 826 } 827 828 func Test_Eager_Validate_And_Create_Parental_With_Partial_Existing(t *testing.T) { 829 if PDB == nil { 830 t.Skip("skipping integration tests") 831 } 832 r := require.New(t) 833 transaction(func(tx *Connection) { 834 addr := Address{HouseNumber: 42, Street: "Life"} 835 addrVerrs, addrErr := tx.ValidateAndCreate(&addr) 836 r.NoError(addrErr) 837 addrCount, _ := tx.Count(&Address{}) 838 r.Zero(addrVerrs.Count()) 839 r.Equal(1, addrCount) 840 r.NotZero(addr.ID) 841 842 m2mCount, m2mErr := tx.Count(&UsersAddress{}) 843 r.NoError(m2mErr) 844 r.Zero(m2mCount) 845 846 user := User{ 847 Name: nulls.NewString("Mark 'Awesome' Bates"), 848 Books: Books{{Title: "Pop Book", Isbn: "PB1", Description: "Awesome Book!"}}, 849 FavoriteSong: Song{Title: "Hook - Blues Traveler"}, 850 Houses: Addresses{ 851 Address{HouseNumber: 86, Street: "Modelo"}, 852 Address{ID: addr.ID}, 853 }, 854 } 855 count, _ := tx.Count(&User{}) 856 857 verrs, err := tx.Eager().ValidateAndCreate(&user) 858 r.NoError(err) 859 r.NotEqual(user.ID, 0) 860 r.Equal(0, verrs.Count()) 861 862 ctx, _ := tx.Count(&User{}) 863 r.Equal(count+1, ctx) 864 865 ctx, _ = tx.Count(&Address{}) 866 r.Equal(addrCount+1, ctx) 867 868 m2mCount, m2mErr = tx.Count(&UsersAddress{}) 869 r.NoError(m2mErr) 870 r.Equal(2, m2mCount) 871 872 u := User{} 873 q := tx.Eager().Where("name = ?", "Mark 'Awesome' Bates") 874 err = q.First(&u) 875 r.NoError(err) 876 r.Equal(u.Name.String, "Mark 'Awesome' Bates") 877 r.Equal(1, len(u.Books)) 878 r.Equal(u.Books[0].Title, "Pop Book") 879 r.Equal(u.FavoriteSong.Title, "Hook - Blues Traveler") 880 r.Equal(2, len(u.Houses)) 881 if u.Houses[0].ID == addr.ID { 882 r.Equal("Life", u.Houses[0].Street) // Street is blanked out 883 r.Equal("Modelo", u.Houses[1].Street) 884 } else { 885 r.Equal(addr.ID, u.Houses[1].ID) 886 r.Equal("Modelo", u.Houses[0].Street) 887 r.Equal("Life", u.Houses[1].Street) // Street is blanked out 888 } 889 }) 890 } 891 892 func Test_Flat_Validate_And_Create_Parental_With_Existing(t *testing.T) { 893 if PDB == nil { 894 t.Skip("skipping integration tests") 895 } 896 r := require.New(t) 897 transaction(func(tx *Connection) { 898 addr := Address{HouseNumber: 42, Street: "Life"} 899 addrVerrs, addrErr := tx.ValidateAndCreate(&addr) 900 r.NoError(addrErr) 901 addrCount, _ := tx.Count(&Address{}) 902 r.Zero(addrVerrs.Count()) 903 r.Equal(1, addrCount) 904 r.NotZero(addr.ID) 905 906 book := Book{Title: "Pop Book", Isbn: "PB1", Description: "Awesome Book!"} 907 bookVerrs, bookErr := tx.ValidateAndCreate(&book) 908 r.NoError(bookErr) 909 r.Zero(bookVerrs.Count()) 910 r.NotZero(book.ID) 911 912 book2 := Book{Title: "Pop Book2", Isbn: "PB2", Description: "Awesome Book Also!"} 913 bookVerrs, bookErr = tx.ValidateAndCreate(&book2) 914 r.NoError(bookErr) 915 r.Zero(bookVerrs.Count()) 916 r.NotZero(book2.ID) 917 918 bookCount, _ := tx.Count(&Book{}) 919 r.Equal(2, bookCount) 920 921 song := Song{Title: "Hook - Blues Traveler"} 922 songVerrs, songErr := tx.ValidateAndCreate(&song) 923 r.NoError(songErr) 924 songCount, _ := tx.Count(&Song{}) 925 r.Zero(songVerrs.Count()) 926 r.Equal(1, songCount) 927 r.NotZero(song.ID) 928 929 m2mCount, m2mErr := tx.Count(&UsersAddress{}) 930 r.NoError(m2mErr) 931 r.Zero(m2mCount) 932 933 user := User{ 934 Name: nulls.NewString("Mark 'Awesome' Bates"), 935 Books: Books{book, book2}, 936 FavoriteSong: song, 937 Houses: Addresses{ 938 Address{HouseNumber: 86, Street: "Modelo"}, 939 addr, 940 }, 941 } 942 count, _ := tx.Count(&User{}) 943 944 verrs, err := tx.ValidateAndCreate(&user) 945 r.NoError(err) 946 r.NotEqual(user.ID, 0) 947 r.Equal(0, verrs.Count()) 948 949 ctx, _ := tx.Count(&User{}) 950 r.Equal(count+1, ctx) 951 952 ctx, _ = tx.Count(&Address{}) 953 r.Equal(addrCount, ctx) 954 955 ctx, _ = tx.Count(&Book{}) 956 r.Equal(bookCount, ctx) 957 958 ctx, _ = tx.Count(&Song{}) 959 r.Equal(songCount, ctx) 960 961 m2mCount, m2mErr = tx.Count(&UsersAddress{}) 962 r.NoError(m2mErr) 963 r.Equal(1, m2mCount) 964 965 u := User{} 966 q := tx.Eager().Where("name = ?", "Mark 'Awesome' Bates") 967 err = q.First(&u) 968 r.NoError(err) 969 r.Equal(u.Name.String, "Mark 'Awesome' Bates") 970 r.Equal(2, len(u.Books)) 971 if u.Books[0].ID == book.ID { 972 r.Equal(u.Books[0].Title, "Pop Book") 973 r.Equal(u.Books[1].Title, "Pop Book2") 974 } else { 975 r.Equal(u.Books[1].Title, "Pop Book") 976 r.Equal(u.Books[0].Title, "Pop Book2") 977 } 978 r.Equal(u.FavoriteSong.Title, "Hook - Blues Traveler") 979 r.Equal(1, len(u.Houses)) 980 r.Equal(addr.ID, u.Houses[0].ID) 981 r.Equal("Life", u.Houses[0].Street) 982 }) 983 } 984 985 func Test_Flat_Validate_And_Create_Parental_With_Partial_Existing(t *testing.T) { 986 if PDB == nil { 987 t.Skip("skipping integration tests") 988 } 989 r := require.New(t) 990 transaction(func(tx *Connection) { 991 addr := Address{HouseNumber: 42, Street: "Life"} 992 addrVerrs, addrErr := tx.ValidateAndCreate(&addr) 993 r.NoError(addrErr) 994 addrCount, _ := tx.Count(&Address{}) 995 r.Zero(addrVerrs.Count()) 996 r.Equal(1, addrCount) 997 r.NotZero(addr.ID) 998 999 book := Book{Title: "Pop Book", Isbn: "PB1", Description: "Awesome Book!"} 1000 bookVerrs, bookErr := tx.ValidateAndCreate(&book) 1001 r.NoError(bookErr) 1002 bookCount, _ := tx.Count(&Book{}) 1003 r.Zero(bookVerrs.Count()) 1004 r.Equal(1, bookCount) 1005 r.NotZero(book.ID) 1006 1007 song := Song{Title: "Hook - Blues Traveler"} 1008 songVerrs, songErr := tx.ValidateAndCreate(&song) 1009 r.NoError(songErr) 1010 songCount, _ := tx.Count(&Song{}) 1011 r.Zero(songVerrs.Count()) 1012 r.Equal(1, songCount) 1013 r.NotZero(song.ID) 1014 1015 m2mCount, m2mErr := tx.Count(&UsersAddress{}) 1016 r.NoError(m2mErr) 1017 r.Zero(m2mCount) 1018 1019 user := User{ 1020 Name: nulls.NewString("Mark 'Awesome' Bates"), 1021 //TODO: add another existing here and test for it to make sure this works with multiples (books) 1022 Books: Books{Book{ID: book.ID}}, 1023 FavoriteSong: Song{ID: song.ID}, 1024 Houses: Addresses{ 1025 Address{HouseNumber: 86, Street: "Modelo"}, 1026 Address{ID: addr.ID}, 1027 }, 1028 } 1029 count, _ := tx.Count(&User{}) 1030 1031 verrs, err := tx.ValidateAndCreate(&user) 1032 r.NoError(err) 1033 r.NotEqual(user.ID, 0) 1034 r.Equal(0, verrs.Count()) 1035 1036 ctx, _ := tx.Count(&User{}) 1037 r.Equal(count+1, ctx) 1038 1039 ctx, _ = tx.Count(&Address{}) 1040 r.Equal(addrCount, ctx) 1041 1042 ctx, _ = tx.Where("user_id = ?", user.ID).Count(&Book{}) 1043 r.Equal(bookCount, ctx) 1044 1045 ctx, _ = tx.Count(&Song{}) 1046 r.Equal(songCount, ctx) 1047 1048 m2mCount, m2mErr = tx.Count(&UsersAddress{}) 1049 r.NoError(m2mErr) 1050 r.Equal(1, m2mCount) 1051 1052 u := User{} 1053 q := tx.Eager().Where("name = ?", "Mark 'Awesome' Bates") 1054 err = q.First(&u) 1055 r.NoError(err) 1056 r.Equal(u.Name.String, "Mark 'Awesome' Bates") 1057 r.Equal(1, len(u.Books)) 1058 r.Equal(u.Books[0].Title, "Pop Book") 1059 r.Equal(u.FavoriteSong.Title, "Hook - Blues Traveler") 1060 r.Equal(1, len(u.Houses)) 1061 r.Equal(addr.ID, u.Houses[0].ID) 1062 r.Equal("Life", u.Houses[0].Street) 1063 }) 1064 } 1065 1066 func Test_Eager_Create_Belongs_To(t *testing.T) { 1067 if PDB == nil { 1068 t.Skip("skipping integration tests") 1069 } 1070 transaction(func(tx *Connection) { 1071 r := require.New(t) 1072 book := Book{ 1073 Title: "Pop Book", 1074 Description: "Pop Book", 1075 Isbn: "PB1", 1076 User: User{ 1077 Name: nulls.NewString("Larry"), 1078 }, 1079 } 1080 1081 err := tx.Eager().Create(&book) 1082 r.NoError(err) 1083 1084 ctx, _ := tx.Count(&Book{}) 1085 r.Equal(1, ctx) 1086 1087 ctx, _ = tx.Count(&User{}) 1088 r.Equal(1, ctx) 1089 1090 car := Taxi{ 1091 Model: "Fancy car", 1092 Driver: &User{ 1093 Name: nulls.NewString("Larry 2"), 1094 }, 1095 } 1096 1097 err = tx.Eager().Create(&car) 1098 r.NoError(err) 1099 1100 ctx, _ = tx.Count(&Taxi{}) 1101 r.Equal(1, ctx) 1102 1103 err = tx.Eager().Find(&car, car.ID) 1104 r.NoError(err) 1105 1106 r.Equal(nulls.NewString("Larry 2"), car.Driver.Name) 1107 }) 1108 } 1109 1110 func Test_Eager_Create_Belongs_To_Pointers(t *testing.T) { 1111 if PDB == nil { 1112 t.Skip("skipping integration tests") 1113 } 1114 transaction(func(tx *Connection) { 1115 r := require.New(t) 1116 // Create a body with a head 1117 body := Body{ 1118 Head: &Head{}, 1119 } 1120 1121 err := tx.Eager().Create(&body) 1122 r.NoError(err) 1123 r.NotZero(body.ID) 1124 r.NotZero(body.Head.ID) 1125 1126 ctx, _ := tx.Count(&Body{}) 1127 r.Equal(1, ctx) 1128 1129 ctx, _ = tx.Count(&Head{}) 1130 r.Equal(1, ctx) 1131 1132 // Create a body without a head: 1133 body = Body{ 1134 Head: nil, 1135 } 1136 1137 err = tx.Eager().Create(&body) 1138 r.NoError(err) 1139 r.NotZero(body.ID) 1140 r.Nil(body.Head) 1141 1142 ctx, _ = tx.Count(&Body{}) 1143 r.Equal(2, ctx) 1144 1145 ctx, _ = tx.Count(&Head{}) 1146 r.Equal(1, ctx) 1147 1148 err = tx.Eager().Create(&Head{ 1149 BodyID: body.ID, 1150 Body: nil, 1151 }) 1152 r.NoError(err) 1153 }) 1154 } 1155 1156 func Test_Create_Belongs_To_Pointers(t *testing.T) { 1157 if PDB == nil { 1158 t.Skip("skipping integration tests") 1159 } 1160 transaction(func(tx *Connection) { 1161 r := require.New(t) 1162 // Create a body without a head: 1163 body := Body{ 1164 Head: nil, 1165 } 1166 1167 err := tx.Create(&body) 1168 r.NoError(err) 1169 r.NotZero(body.ID) 1170 r.Nil(body.Head) 1171 1172 // Create a head with the associated model set but not the ID 1173 created := HeadPtr{ 1174 Body: &body, 1175 } 1176 err = tx.Create(&created) 1177 r.NoError(err) 1178 1179 found := HeadPtr{} 1180 err = tx.Find(&found, created.ID) 1181 r.NoError(err) 1182 r.Equal(body.ID, *found.BodyID) 1183 }) 1184 } 1185 1186 func Test_Flat_Create_Belongs_To(t *testing.T) { 1187 if PDB == nil { 1188 t.Skip("skipping integration tests") 1189 } 1190 transaction(func(tx *Connection) { 1191 r := require.New(t) 1192 user := User{ 1193 Name: nulls.NewString("Larry"), 1194 } 1195 1196 err := tx.Create(&user) 1197 r.NoError(err) 1198 ctx, _ := tx.Count(&User{}) 1199 r.Equal(1, ctx) 1200 1201 book := Book{ 1202 Title: "Pop Book", 1203 Description: "Pop Book", 1204 Isbn: "PB1", 1205 User: user, 1206 } 1207 1208 err = tx.Create(&book) 1209 r.NoError(err) 1210 1211 ctx, _ = tx.Count(&Book{}) 1212 r.Equal(1, ctx) 1213 1214 err = tx.Eager().Find(&book, book.ID) 1215 r.NoError(err) 1216 1217 r.Equal(nulls.NewString("Larry"), book.User.Name) 1218 1219 car := Taxi{ 1220 Model: "Fancy car", 1221 Driver: &user, 1222 } 1223 1224 err = tx.Create(&car) 1225 r.NoError(err) 1226 1227 ctx, _ = tx.Count(&Taxi{}) 1228 r.Equal(1, ctx) 1229 1230 err = tx.Eager().Find(&car, car.ID) 1231 r.NoError(err) 1232 1233 r.Equal(nulls.NewString("Larry"), car.Driver.Name) 1234 }) 1235 } 1236 1237 func Test_Eager_Creation_Without_Associations(t *testing.T) { 1238 if PDB == nil { 1239 t.Skip("skipping integration tests") 1240 } 1241 transaction(func(tx *Connection) { 1242 r := require.New(t) 1243 code := CourseCode{ 1244 Course: Course{}, 1245 } 1246 1247 err := tx.Eager().Create(&code) 1248 r.NoError(err) 1249 1250 ctx, _ := tx.Count(&CourseCode{}) 1251 r.Equal(1, ctx) 1252 }) 1253 } 1254 1255 func Test_Eager_Embedded_Struct(t *testing.T) { 1256 if PDB == nil { 1257 t.Skip("skipping integration tests") 1258 } 1259 transaction(func(tx *Connection) { 1260 r := require.New(t) 1261 1262 type AssocFields struct { 1263 Books Books `has_many:"books" order_by:"title asc"` 1264 FavoriteSong Song `has_one:"song" fk_id:"u_id"` 1265 Houses Addresses `many_to_many:"users_addresses"` 1266 } 1267 1268 type User struct { 1269 ID int `db:"id"` 1270 UserName string `db:"user_name"` 1271 Email string `db:"email"` 1272 Name nulls.String `db:"name"` 1273 Alive nulls.Bool `db:"alive"` 1274 CreatedAt time.Time `db:"created_at"` 1275 UpdatedAt time.Time `db:"updated_at"` 1276 BirthDate nulls.Time `db:"birth_date"` 1277 Bio nulls.String `db:"bio"` 1278 Price nulls.Float64 `db:"price"` 1279 FullName nulls.String `db:"full_name" select:"name as full_name"` 1280 1281 AssocFields 1282 } 1283 1284 count, _ := tx.Count(&User{}) 1285 user := User{ 1286 UserName: "dumb-dumb", 1287 Name: nulls.NewString("Arthur Dent"), 1288 AssocFields: AssocFields{ 1289 Books: Books{{Title: "The Hitchhiker's Guide to the Galaxy", Description: "Comedy Science Fiction somewhere in Space", Isbn: "PB42"}}, 1290 FavoriteSong: Song{Title: "Wish You Were Here", ComposedBy: Composer{Name: "Pink Floyd"}}, 1291 Houses: Addresses{ 1292 Address{HouseNumber: 155, Street: "Country Lane"}, 1293 }, 1294 }, 1295 } 1296 1297 err := tx.Eager().Create(&user) 1298 r.NoError(err) 1299 r.NotZero(user.ID) 1300 1301 ctx, _ := tx.Count(&User{}) 1302 r.Equal(count+1, ctx) 1303 1304 ctx, _ = tx.Count(&Book{}) 1305 r.Equal(count+1, ctx) 1306 1307 ctx, _ = tx.Count(&Song{}) 1308 r.Equal(count+1, ctx) 1309 1310 ctx, _ = tx.Count(&Address{}) 1311 r.Equal(count+1, ctx) 1312 1313 u := User{} 1314 q := tx.Eager().Where("name = ?", user.Name.String) 1315 err = q.First(&u) 1316 r.NoError(err) 1317 1318 r.Equal(user.Name.String, u.Name.String) 1319 r.Len(u.Books, 1) 1320 r.Equal(user.Books[0].Title, u.Books[0].Title) 1321 r.Equal(user.FavoriteSong.Title, u.FavoriteSong.Title) 1322 r.Len(u.Houses, 1) 1323 r.Equal(user.Houses[0].Street, u.Houses[0].Street) 1324 }) 1325 } 1326 1327 func Test_Eager_Embedded_Ptr_Struct(t *testing.T) { 1328 if PDB == nil { 1329 t.Skip("skipping integration tests") 1330 } 1331 transaction(func(tx *Connection) { 1332 r := require.New(t) 1333 1334 type AssocFields struct { 1335 Books Books `has_many:"books" order_by:"title asc"` 1336 FavoriteSong Song `has_one:"song" fk_id:"u_id"` 1337 Houses Addresses `many_to_many:"users_addresses"` 1338 } 1339 1340 type User struct { 1341 ID int `db:"id"` 1342 UserName string `db:"user_name"` 1343 Email string `db:"email"` 1344 Name nulls.String `db:"name"` 1345 Alive nulls.Bool `db:"alive"` 1346 CreatedAt time.Time `db:"created_at"` 1347 UpdatedAt time.Time `db:"updated_at"` 1348 BirthDate nulls.Time `db:"birth_date"` 1349 Bio nulls.String `db:"bio"` 1350 Price nulls.Float64 `db:"price"` 1351 FullName nulls.String `db:"full_name" select:"name as full_name"` 1352 1353 *AssocFields 1354 } 1355 1356 count, _ := tx.Count(&User{}) 1357 user := User{ 1358 UserName: "dumb-dumb", 1359 Name: nulls.NewString("Arthur Dent"), 1360 AssocFields: &AssocFields{ 1361 Books: Books{{Title: "The Hitchhiker's Guide to the Galaxy", Description: "Comedy Science Fiction somewhere in Space", Isbn: "PB42"}}, 1362 FavoriteSong: Song{Title: "Wish You Were Here", ComposedBy: Composer{Name: "Pink Floyd"}}, 1363 Houses: Addresses{ 1364 Address{HouseNumber: 155, Street: "Country Lane"}, 1365 }, 1366 }, 1367 } 1368 1369 err := tx.Eager().Create(&user) 1370 r.NoError(err) 1371 r.NotZero(user.ID) 1372 1373 ctx, _ := tx.Count(&User{}) 1374 r.Equal(count+1, ctx) 1375 1376 ctx, _ = tx.Count(&Book{}) 1377 r.Equal(count+1, ctx) 1378 1379 ctx, _ = tx.Count(&Song{}) 1380 r.Equal(count+1, ctx) 1381 1382 ctx, _ = tx.Count(&Address{}) 1383 r.Equal(count+1, ctx) 1384 1385 u := User{} 1386 q := tx.Eager().Where("name = ?", user.Name.String) 1387 err = q.First(&u) 1388 r.NoError(err) 1389 1390 r.Equal(user.Name.String, u.Name.String) 1391 r.Len(u.Books, 1) 1392 r.Equal(user.Books[0].Title, u.Books[0].Title) 1393 r.Equal(user.FavoriteSong.Title, u.FavoriteSong.Title) 1394 r.Len(u.Houses, 1) 1395 r.Equal(user.Houses[0].Street, u.Houses[0].Street) 1396 }) 1397 } 1398 1399 func Test_Create_UUID(t *testing.T) { 1400 if PDB == nil { 1401 t.Skip("skipping integration tests") 1402 } 1403 transaction(func(tx *Connection) { 1404 r := require.New(t) 1405 1406 count, _ := tx.Count(&Song{}) 1407 song := Song{Title: "Automatic Buffalo"} 1408 r.Equal(uuid.Nil, song.ID) 1409 err := tx.Create(&song) 1410 r.NoError(err) 1411 r.NotZero(song.ID) 1412 r.NotEqual(uuid.Nil, song.ID) 1413 1414 ctx, _ := tx.Count(&Song{}) 1415 r.Equal(count+1, ctx) 1416 1417 u := Song{} 1418 q := tx.Where("title = ?", "Automatic Buffalo") 1419 err = q.First(&u) 1420 r.NoError(err) 1421 }) 1422 } 1423 1424 func Test_Create_Existing_UUID(t *testing.T) { 1425 if PDB == nil { 1426 t.Skip("skipping integration tests") 1427 } 1428 transaction(func(tx *Connection) { 1429 r := require.New(t) 1430 id, err := uuid.NewV4() 1431 r.NoError(err) 1432 1433 count, _ := tx.Count(&Song{}) 1434 song := Song{ 1435 ID: id, 1436 Title: "Automatic Buffalo", 1437 } 1438 1439 err = tx.Create(&song) 1440 r.NoError(err) 1441 r.NotZero(song.ID) 1442 r.Equal(id.String(), song.ID.String()) 1443 1444 ctx, _ := tx.Count(&Song{}) 1445 r.Equal(count+1, ctx) 1446 1447 }) 1448 } 1449 1450 func Test_Create_Timestamps(t *testing.T) { 1451 if PDB == nil { 1452 t.Skip("skipping integration tests") 1453 } 1454 transaction(func(tx *Connection) { 1455 r := require.New(t) 1456 1457 user := User{Name: nulls.NewString("Mark 'Awesome' Bates")} 1458 r.Zero(user.CreatedAt) 1459 r.Zero(user.UpdatedAt) 1460 1461 err := tx.Create(&user) 1462 r.NoError(err) 1463 1464 r.NotZero(user.CreatedAt) 1465 r.NotZero(user.UpdatedAt) 1466 1467 friend := Friend{FirstName: "Ross", LastName: "Gellar"} 1468 err = tx.Create(&friend) 1469 r.NoError(err) 1470 }) 1471 } 1472 1473 func Test_Update(t *testing.T) { 1474 if PDB == nil { 1475 t.Skip("skipping integration tests") 1476 } 1477 transaction(func(tx *Connection) { 1478 r := require.New(t) 1479 1480 user := User{Name: nulls.NewString("Mark")} 1481 tx.Create(&user) 1482 1483 r.NotZero(user.CreatedAt) 1484 r.NotZero(user.UpdatedAt) 1485 1486 user.Name.String = "Marky" 1487 err := tx.Update(&user) 1488 r.NoError(err) 1489 1490 r.NoError(tx.Reload(&user)) 1491 r.Equal(user.Name.String, "Marky") 1492 }) 1493 } 1494 1495 func Test_UpdateColumns(t *testing.T) { 1496 if PDB == nil { 1497 t.Skip("skipping integration tests") 1498 } 1499 transaction(func(tx *Connection) { 1500 r := require.New(t) 1501 1502 user := User{Name: nulls.NewString("Mark")} 1503 tx.Create(&user) 1504 1505 r.NotZero(user.CreatedAt) 1506 r.NotZero(user.UpdatedAt) 1507 1508 user.Name.String = "Fulano" 1509 user.UserName = "Fulano" 1510 err := tx.UpdateColumns(&user, "user_name") // Update UserName field/column only 1511 r.NoError(err) 1512 1513 r.NoError(tx.Reload(&user)) 1514 r.Equal(user.Name.String, "Mark") // Name column should not be updated 1515 r.Equal(user.UserName, "Fulano") 1516 }) 1517 } 1518 1519 func Test_UpdateQuery_NoUpdatedAt(t *testing.T) { 1520 if PDB == nil { 1521 t.Skip("skipping integration tests") 1522 } 1523 transaction(func(tx *Connection) { 1524 r := require.New(t) 1525 existing, err := PDB.Count(&NonStandardID{}) // from previous test runs 1526 r.NoError(err) 1527 r.GreaterOrEqual(existing, 0) 1528 r.NoError(PDB.Create(&NonStandardID{OutfacingID: "must-change"})) 1529 count, err := PDB.Where("true").UpdateQuery(&NonStandardID{OutfacingID: "has-changed"}, "id") 1530 r.NoError(err) 1531 r.Equal(int64(existing+1), count) 1532 entity := NonStandardID{} 1533 r.NoError(PDB.First(&entity)) 1534 r.Equal("has-changed", entity.OutfacingID) 1535 }) 1536 } 1537 1538 func Test_UpdateQuery_NoTransaction(t *testing.T) { 1539 if PDB == nil { 1540 t.Skip("skipping integration tests") 1541 } 1542 1543 r := require.New(t) 1544 u1 := User{Name: nulls.NewString("Foo"), Bio: nulls.NewString("must-not-change-1")} 1545 r.NoError(PDB.Create(&u1)) 1546 r.NoError(PDB.Reload(&u1)) 1547 count, err := PDB.Where("name = ?", "Nemo").UpdateQuery(&User{Bio: nulls.NewString("did-change")}, "bio") 1548 r.NoError(err) 1549 require.Equal(t, int64(0), count) 1550 1551 count, err = PDB.Where("name = ?", "Foo").UpdateQuery(&User{Name: nulls.NewString("Bar")}, "name") 1552 r.NoError(err) 1553 r.Equal(int64(1), count) 1554 1555 require.NoError(t, PDB.Destroy(&u1)) 1556 } 1557 1558 func Test_UpdateQuery(t *testing.T) { 1559 if PDB == nil { 1560 t.Skip("skipping integration tests") 1561 } 1562 transaction(func(tx *Connection) { 1563 r := require.New(t) 1564 1565 u1 := User{Name: nulls.NewString("Foo"), Bio: nulls.NewString("must-not-change-1")} 1566 u2 := User{Name: nulls.NewString("Foo"), Bio: nulls.NewString("must-not-change-2")} 1567 u3 := User{Name: nulls.NewString("Baz"), Bio: nulls.NewString("must-not-change-3")} 1568 tx.Create(&u1) 1569 tx.Create(&u2) 1570 tx.Create(&u3) 1571 r.NoError(tx.Reload(&u1)) 1572 r.NoError(tx.Reload(&u2)) 1573 r.NoError(tx.Reload(&u3)) 1574 time.Sleep(time.Millisecond * 1) 1575 1576 // No affected rows 1577 count, err := tx.Where("name = ?", "Nemo").UpdateQuery(&User{Bio: nulls.NewString("did-change")}, "bio") 1578 r.NoError(err) 1579 require.Equal(t, int64(0), count) 1580 mustUnchanged := &User{} 1581 r.NoError(tx.Find(mustUnchanged, u1.ID)) 1582 r.Equal(u1.Bio, mustUnchanged.Bio) 1583 r.Equal(u1.UpdatedAt, mustUnchanged.UpdatedAt) 1584 1585 // Correct rows are updated, including updated_at 1586 count, err = tx.Where("name = ?", "Foo").UpdateQuery(&User{Name: nulls.NewString("Bar")}, "name") 1587 r.NoError(err) 1588 r.Equal(int64(2), count) 1589 1590 u1b, u2b, u3b := &User{}, &User{}, &User{} 1591 r.NoError(tx.Find(u1b, u1.ID)) 1592 r.NoError(tx.Find(u2b, u2.ID)) 1593 r.NoError(tx.Find(u3b, u3.ID)) 1594 r.Equal(u1b.Name.String, "Bar") 1595 r.Equal(u2b.Name.String, "Bar") 1596 r.Equal(u3b.Name.String, "Baz") 1597 r.Equal(u1b.Bio.String, "must-not-change-1") 1598 r.Equal(u2b.Bio.String, "must-not-change-2") 1599 r.Equal(u3b.Bio.String, "must-not-change-3") 1600 if tx.Dialect.Name() != nameMySQL { // MySQL timestamps are in seconds 1601 r.NotEqual(u1.UpdatedAt, u1b.UpdatedAt) 1602 r.NotEqual(u2.UpdatedAt, u2b.UpdatedAt) 1603 } 1604 r.Equal(u3.UpdatedAt, u3b.UpdatedAt) 1605 1606 // ID is ignored 1607 count, err = tx.Where("true").UpdateQuery(&User{ID: 123, Name: nulls.NewString("Bar")}, "id", "name") 1608 r.NoError(tx.Find(u1b, u1.ID)) 1609 r.NoError(tx.Find(u2b, u2.ID)) 1610 r.NoError(tx.Find(u3b, u3.ID)) 1611 r.Equal(u1b.Name.String, "Bar") 1612 r.Equal(u2b.Name.String, "Bar") 1613 r.Equal(u3b.Name.String, "Bar") 1614 1615 // Invalid column yields an error 1616 count, err = tx.Where("name = ?", "Foo").UpdateQuery(&User{Name: nulls.NewString("Bar")}, "mistake") 1617 r.Contains(err.Error(), "could not find name mistake") 1618 1619 tx.Where("true").Delete(&User{}) 1620 }) 1621 } 1622 1623 func Test_UpdateColumns_UpdatedAt(t *testing.T) { 1624 if PDB == nil { 1625 t.Skip("skipping integration tests") 1626 } 1627 transaction(func(tx *Connection) { 1628 r := require.New(t) 1629 1630 user := User{Name: nulls.NewString("Foo")} 1631 tx.Create(&user) 1632 1633 r.NotZero(user.CreatedAt) 1634 r.NotZero(user.UpdatedAt) 1635 updatedAtBefore := user.UpdatedAt 1636 1637 user.Name.String = "Bar" 1638 err := tx.UpdateColumns(&user, "name", "updated_at") // Update name and updated_at 1639 r.NoError(err) 1640 1641 r.NoError(tx.Reload(&user)) 1642 r.NotEqual(user.UpdatedAt, updatedAtBefore) // UpdatedAt should be updated automatically 1643 }) 1644 } 1645 1646 func Test_UpdateColumns_MultipleColumns(t *testing.T) { 1647 if PDB == nil { 1648 t.Skip("skipping integration tests") 1649 } 1650 transaction(func(tx *Connection) { 1651 r := require.New(t) 1652 1653 user := User{Name: nulls.NewString("Mark"), UserName: "Sagan", Email: "test@example.com"} 1654 tx.Create(&user) 1655 1656 r.NotZero(user.CreatedAt) 1657 r.NotZero(user.UpdatedAt) 1658 1659 user.Name.String = "Ping" 1660 user.UserName = "Pong" 1661 user.Email = "fulano@example" 1662 err := tx.UpdateColumns(&user, "name", "user_name") // Update multiple columns 1663 r.NoError(err) 1664 1665 r.NoError(tx.Reload(&user)) 1666 r.Equal(user.Name.String, "Ping") 1667 r.Equal(user.UserName, "Pong") 1668 r.Equal(user.Email, "test@example.com") // Email should not be updated 1669 }) 1670 } 1671 1672 func Test_UpdateColumns_All(t *testing.T) { 1673 if PDB == nil { 1674 t.Skip("skipping integration tests") 1675 } 1676 transaction(func(tx *Connection) { 1677 r := require.New(t) 1678 1679 user := User{Name: nulls.NewString("Mark"), UserName: "Sagan"} 1680 tx.Create(&user) 1681 1682 r.NotZero(user.CreatedAt) 1683 r.NotZero(user.UpdatedAt) 1684 1685 user.Name.String = "Ping" 1686 user.UserName = "Pong" 1687 user.Email = "ping@pong.com" 1688 err := tx.UpdateColumns(&user) // Update all columns 1689 r.NoError(err) 1690 1691 r.NoError(tx.Reload(&user)) 1692 r.Equal(user.Name.String, "Ping") 1693 r.Equal(user.UserName, "Pong") 1694 r.Equal(user.Email, "ping@pong.com") 1695 }) 1696 } 1697 1698 func Test_UpdateColumns_With_Slice(t *testing.T) { 1699 if PDB == nil { 1700 t.Skip("skipping integration tests") 1701 } 1702 transaction(func(tx *Connection) { 1703 r := require.New(t) 1704 1705 user := Users{ 1706 { 1707 Name: nulls.NewString("Mark"), 1708 UserName: "Ping", 1709 }, 1710 { 1711 Name: nulls.NewString("Larry"), 1712 UserName: "Pong", 1713 }, 1714 } 1715 tx.Create(&user) 1716 1717 r.NotZero(user[0].CreatedAt) 1718 r.NotZero(user[0].UpdatedAt) 1719 1720 r.NotZero(user[1].CreatedAt) 1721 r.NotZero(user[1].UpdatedAt) 1722 1723 user[0].Name.String = "Fulano" 1724 user[0].UserName = "Thor" 1725 user[1].Name.String = "Fulana" 1726 user[1].UserName = "Freya" 1727 1728 err := tx.UpdateColumns(&user, "name") // Update Name field/column only 1729 r.NoError(err) 1730 1731 r.NoError(tx.Reload(&user)) 1732 r.Equal(user[0].Name.String, "Fulano") 1733 r.Equal(user[0].UserName, "Ping") // UserName should not be updated 1734 r.Equal(user[1].Name.String, "Fulana") 1735 r.Equal(user[1].UserName, "Pong") // UserName should not be updated 1736 }) 1737 } 1738 1739 func Test_Update_With_Slice(t *testing.T) { 1740 if PDB == nil { 1741 t.Skip("skipping integration tests") 1742 } 1743 transaction(func(tx *Connection) { 1744 r := require.New(t) 1745 1746 user := Users{ 1747 {Name: nulls.NewString("Mark")}, 1748 {Name: nulls.NewString("Larry")}, 1749 } 1750 tx.Create(&user) 1751 1752 r.NotZero(user[0].CreatedAt) 1753 r.NotZero(user[0].UpdatedAt) 1754 1755 r.NotZero(user[1].CreatedAt) 1756 r.NotZero(user[1].UpdatedAt) 1757 1758 user[0].Name.String = "Marky" 1759 user[1].Name.String = "Lawrence" 1760 1761 err := tx.Update(&user) 1762 r.NoError(err) 1763 1764 r.NoError(tx.Reload(&user)) 1765 r.Equal(user[0].Name.String, "Marky") 1766 r.Equal(user[1].Name.String, "Lawrence") 1767 }) 1768 } 1769 1770 func Test_Update_UUID(t *testing.T) { 1771 if PDB == nil { 1772 t.Skip("skipping integration tests") 1773 } 1774 transaction(func(tx *Connection) { 1775 r := require.New(t) 1776 1777 song := Song{Title: "Automatic Buffalo"} 1778 err := tx.Create(&song) 1779 r.NoError(err) 1780 1781 r.NotZero(song.CreatedAt) 1782 r.NotZero(song.UpdatedAt) 1783 1784 song.Title = "Hum" 1785 err = tx.Update(&song) 1786 r.NoError(err) 1787 1788 err = tx.Reload(&song) 1789 r.NoError(err) 1790 r.Equal("Hum", song.Title) 1791 }) 1792 } 1793 1794 func Test_Update_With_Non_ID_PK(t *testing.T) { 1795 if PDB == nil { 1796 t.Skip("skipping integration tests") 1797 } 1798 transaction(func(tx *Connection) { 1799 r := require.New(t) 1800 1801 r.NoError(tx.Create(&CrookedColour{Name: "cc is not the first one"})) 1802 1803 cc := CrookedColour{ 1804 Name: "You?", 1805 } 1806 err := tx.Create(&cc) 1807 r.NoError(err) 1808 r.NotZero(cc.ID) 1809 id := cc.ID 1810 1811 updatedName := "Me!" 1812 cc.Name = updatedName 1813 r.NoError(tx.Update(&cc)) 1814 r.Equal(id, cc.ID) 1815 1816 r.NoError(tx.Reload(&cc)) 1817 r.Equal(updatedName, cc.Name) 1818 r.Equal(id, cc.ID) 1819 }) 1820 } 1821 1822 func Test_Update_Non_PK_ID(t *testing.T) { 1823 if PDB == nil { 1824 t.Skip("skipping integration tests") 1825 } 1826 transaction(func(tx *Connection) { 1827 r := require.New(t) 1828 1829 client := &NonStandardID{ 1830 OutfacingID: "my awesome hydra client", 1831 } 1832 r.NoError(tx.Create(client)) 1833 1834 updatedID := "your awesome hydra client" 1835 client.OutfacingID = updatedID 1836 r.NoError(tx.Update(client)) 1837 r.NoError(tx.Reload(client)) 1838 r.Equal(updatedID, client.OutfacingID) 1839 }) 1840 } 1841 1842 func Test_Destroy(t *testing.T) { 1843 if PDB == nil { 1844 t.Skip("skipping integration tests") 1845 } 1846 transaction(func(tx *Connection) { 1847 r := require.New(t) 1848 1849 count, err := tx.Count("users") 1850 r.NoError(err) 1851 user := User{Name: nulls.NewString("Mark")} 1852 err = tx.Create(&user) 1853 r.NoError(err) 1854 r.NotEqual(user.ID, 0) 1855 1856 ctx, err := tx.Count("users") 1857 r.NoError(err) 1858 r.Equal(count+1, ctx) 1859 1860 err = tx.Destroy(&user) 1861 r.NoError(err) 1862 1863 ctx, _ = tx.Count("users") 1864 r.Equal(count, ctx) 1865 }) 1866 } 1867 1868 func Test_Destroy_With_Slice(t *testing.T) { 1869 if PDB == nil { 1870 t.Skip("skipping integration tests") 1871 } 1872 transaction(func(tx *Connection) { 1873 r := require.New(t) 1874 1875 count, err := tx.Count("users") 1876 r.NoError(err) 1877 user := Users{ 1878 {Name: nulls.NewString("Mark")}, 1879 {Name: nulls.NewString("Larry")}, 1880 } 1881 err = tx.Create(&user) 1882 r.NoError(err) 1883 r.NotEqual(user[0].ID, 0) 1884 r.NotEqual(user[1].ID, 0) 1885 1886 ctx, err := tx.Count("users") 1887 r.NoError(err) 1888 r.Equal(count+2, ctx) 1889 1890 err = tx.Destroy(&user) 1891 r.NoError(err) 1892 1893 ctx, _ = tx.Count("users") 1894 r.Equal(count, ctx) 1895 }) 1896 } 1897 1898 func Test_Destroy_UUID(t *testing.T) { 1899 if PDB == nil { 1900 t.Skip("skipping integration tests") 1901 } 1902 transaction(func(tx *Connection) { 1903 r := require.New(t) 1904 1905 count, err := tx.Count("songs") 1906 r.NoError(err) 1907 song := Song{Title: "Automatic Buffalo"} 1908 err = tx.Create(&song) 1909 r.NoError(err) 1910 r.NotZero(song.ID) 1911 1912 ctx, err := tx.Count("songs") 1913 r.NoError(err) 1914 r.Equal(count+1, ctx) 1915 1916 err = tx.Destroy(&song) 1917 r.NoError(err) 1918 1919 ctx, _ = tx.Count("songs") 1920 r.Equal(count, ctx) 1921 }) 1922 } 1923 1924 func Test_TruncateAll(t *testing.T) { 1925 if PDB == nil { 1926 t.Skip("skipping integration tests") 1927 } 1928 count := int(0) 1929 transaction(func(tx *Connection) { 1930 r := require.New(t) 1931 1932 var err error 1933 count, err = tx.Count("users") 1934 r.NoError(err) 1935 user := User{Name: nulls.NewString("Mark")} 1936 err = tx.Create(&user) 1937 r.NoError(err) 1938 r.NotEqual(user.ID, 0) 1939 1940 ctx, err := tx.Count("users") 1941 r.NoError(err) 1942 r.Equal(count+1, ctx) 1943 1944 err = tx.TruncateAll() 1945 r.NoError(err) 1946 1947 ctx, _ = tx.Count("users") 1948 r.Equal(count, ctx) 1949 }) 1950 } 1951 1952 func Test_Delete(t *testing.T) { 1953 if PDB == nil { 1954 t.Skip("skipping integration tests") 1955 } 1956 1957 transaction(func(tx *Connection) { 1958 r := require.New(t) 1959 1960 songTitles := []string{"Yoshimi Battles the Pink Robots, Pt. 1", "Face Down In The Gutter Of Your Love"} 1961 user := User{Name: nulls.NewString("Patrik")} 1962 1963 r.NoError(tx.Create(&user)) 1964 r.NotZero(user.ID) 1965 1966 count, err := tx.Count("songs") 1967 r.NoError(err) 1968 1969 for _, title := range songTitles { 1970 err = tx.Create(&Song{Title: title, UserID: user.ID}) 1971 r.NoError(err) 1972 } 1973 1974 ctx, err := tx.Count("songs") 1975 r.NoError(err) 1976 r.Equal(count+len(songTitles), ctx) 1977 1978 err = tx.Where("u_id = ?", user.ID).Delete("songs") 1979 r.NoError(err) 1980 1981 ctx, err = tx.Count("songs") 1982 r.NoError(err) 1983 r.Equal(count, ctx) 1984 }) 1985 } 1986 1987 func Test_Create_Timestamps_With_NowFunc(t *testing.T) { 1988 if PDB == nil { 1989 t.Skip("skipping integration tests") 1990 } 1991 transaction(func(tx *Connection) { 1992 r := require.New(t) 1993 1994 originalNowFunc := nowFunc 1995 // ensure the original function is restored 1996 defer func() { 1997 nowFunc = originalNowFunc 1998 }() 1999 2000 fakeNow, _ := time.Parse(time.RFC3339, "2019-07-14T00:00:00Z") 2001 SetNowFunc(func() time.Time { return fakeNow }) 2002 2003 friend := Friend{FirstName: "Yester", LastName: "Day"} 2004 err := tx.Create(&friend) 2005 r.NoError(err) 2006 2007 r.Equal(fakeNow, friend.CreatedAt) 2008 r.Equal(fakeNow, friend.UpdatedAt) 2009 }) 2010 }