github.com/ecodeclub/eorm@v0.0.2-0.20231001112437-dae71da914d0/internal/integration/select_test.go (about) 1 // Copyright 2021 ecodeclub 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //go:build e2e 16 17 package integration 18 19 import ( 20 "context" 21 "database/sql" 22 "testing" 23 24 "github.com/ecodeclub/eorm/internal/errs" 25 "github.com/stretchr/testify/require" 26 27 "github.com/ecodeclub/eorm" 28 "github.com/ecodeclub/eorm/internal/test" 29 "github.com/stretchr/testify/assert" 30 "github.com/stretchr/testify/suite" 31 ) 32 33 type SelectTestSuite struct { 34 Suite 35 data *test.SimpleStruct 36 } 37 38 func (s *SelectTestSuite) SetupSuite() { 39 s.Suite.SetupSuite() 40 s.data = test.NewSimpleStruct(1) 41 s.data.Int32Ptr = nil 42 res := eorm.NewInserter[test.SimpleStruct](s.orm).Values(s.data).Exec(context.Background()) 43 if res.Err() != nil { 44 s.T().Fatal(res.Err()) 45 } 46 } 47 48 func (s *SelectTestSuite) TearDownSuite() { 49 res := eorm.RawQuery[any](s.orm, "TRUNCATE TABLE `simple_struct`").Exec(context.Background()) 50 if res.Err() != nil { 51 s.T().Fatal(res.Err()) 52 } 53 } 54 55 func (s *SelectTestSuite) TestSelectorGet() { 56 testCases := []struct { 57 name string 58 s *eorm.Selector[test.SimpleStruct] 59 wantErr error 60 wantRes *test.SimpleStruct 61 }{ 62 { 63 name: "not found", 64 s: eorm.NewSelector[test.SimpleStruct](s.orm). 65 Where(eorm.C("Id").EQ(9)), 66 wantErr: eorm.ErrNoRows, 67 }, 68 { 69 name: "found", 70 s: eorm.NewSelector[test.SimpleStruct](s.orm). 71 Where(eorm.C("Id").EQ(1)), 72 wantRes: s.data, 73 }, 74 } 75 76 for _, tc := range testCases { 77 s.T().Run(tc.name, func(t *testing.T) { 78 res, err := tc.s.Get(context.Background()) 79 assert.Equal(t, tc.wantErr, err) 80 if err != nil { 81 return 82 } 83 assert.Equal(t, tc.wantRes, res) 84 }) 85 } 86 } 87 88 func (s *SelectTestSuite) TestSelectorGetBaseType() { 89 testCases := []struct { 90 name string 91 queryRes func() (any, error) 92 wantErr string 93 wantRes any 94 }{ 95 { 96 name: "not found", 97 queryRes: func() (any, error) { 98 queryer := eorm.NewSelector[test.SimpleStruct](s.orm). 99 Where(eorm.C("Id").EQ(9)) 100 return queryer.Get(context.Background()) 101 }, 102 wantErr: eorm.ErrNoRows.Error(), 103 }, 104 { 105 name: "res int", 106 queryRes: func() (any, error) { 107 queryer := eorm.NewSelector[int](s.orm).Select(eorm.C("Id")). 108 From(eorm.TableOf(&test.SimpleStruct{}, "t1")). 109 Where(eorm.C("Id").EQ(1)) 110 return queryer.Get(context.Background()) 111 }, 112 wantRes: func() *int { 113 res := 1 114 return &res 115 }(), 116 }, 117 { 118 name: "res string", 119 queryRes: func() (any, error) { 120 queryer := eorm.NewSelector[string](s.orm).Select(eorm.C("String")). 121 From(eorm.TableOf(&test.SimpleStruct{}, "t1")). 122 Where(eorm.C("Id").EQ(1)) 123 return queryer.Get(context.Background()) 124 }, 125 wantRes: func() *string { 126 res := "world" 127 return &res 128 }(), 129 }, 130 { 131 name: "res bytes", 132 queryRes: func() (any, error) { 133 queryer := eorm.NewSelector[[]byte](s.orm).Select(eorm.C("ByteArray")). 134 From(eorm.TableOf(&test.SimpleStruct{}, "t1")). 135 Where(eorm.C("Id").EQ(1)) 136 return queryer.Get(context.Background()) 137 }, 138 wantRes: func() *[]byte { 139 res := []byte("hello") 140 return &res 141 }(), 142 }, 143 { 144 name: "res bool", 145 queryRes: func() (any, error) { 146 queryer := eorm.NewSelector[bool](s.orm).Select(eorm.C("Bool")). 147 From(eorm.TableOf(&test.SimpleStruct{}, "t1")). 148 Where(eorm.C("Id").EQ(1)) 149 return queryer.Get(context.Background()) 150 }, 151 wantRes: func() *bool { 152 res := true 153 return &res 154 }(), 155 }, 156 { 157 name: "res null string ptr", 158 queryRes: func() (any, error) { 159 queryer := eorm.NewSelector[sql.NullString](s.orm).Select(eorm.C("NullStringPtr")). 160 From(eorm.TableOf(&test.SimpleStruct{}, "t1")). 161 Where(eorm.C("Id").EQ(1)) 162 return queryer.Get(context.Background()) 163 }, 164 wantRes: func() *sql.NullString { 165 res := sql.NullString{String: "null string", Valid: true} 166 return &res 167 }(), 168 }, 169 { 170 name: "res null int32 ptr", 171 queryRes: func() (any, error) { 172 queryer := eorm.NewSelector[sql.NullInt32](s.orm).Select(eorm.C("NullInt32Ptr")). 173 From(eorm.TableOf(&test.SimpleStruct{}, "t1")). 174 Where(eorm.C("Id").EQ(1)) 175 return queryer.Get(context.Background()) 176 }, 177 wantRes: func() *sql.NullInt32 { 178 res := sql.NullInt32{Int32: 32, Valid: true} 179 return &res 180 }(), 181 }, 182 { 183 name: "res null bool ptr", 184 queryRes: func() (any, error) { 185 queryer := eorm.NewSelector[sql.NullBool](s.orm).Select(eorm.C("NullBoolPtr")). 186 From(eorm.TableOf(&test.SimpleStruct{}, "t1")). 187 Where(eorm.C("Id").EQ(1)) 188 return queryer.Get(context.Background()) 189 }, 190 wantRes: func() *sql.NullBool { 191 res := sql.NullBool{Bool: true, Valid: true} 192 return &res 193 }(), 194 }, 195 { 196 name: "res null float64 ptr", 197 queryRes: func() (any, error) { 198 queryer := eorm.NewSelector[sql.NullFloat64](s.orm).Select(eorm.C("NullFloat64Ptr")). 199 From(eorm.TableOf(&test.SimpleStruct{}, "t1")). 200 Where(eorm.C("Id").EQ(1)) 201 return queryer.Get(context.Background()) 202 }, 203 wantRes: func() *sql.NullFloat64 { 204 res := sql.NullFloat64{Float64: 6.4, Valid: true} 205 return &res 206 }(), 207 }, 208 { 209 name: "res *int accept NULL", 210 queryRes: func() (any, error) { 211 queryer := eorm.NewSelector[*int](s.orm).Select(eorm.C("Int32Ptr")). 212 From(eorm.TableOf(&test.SimpleStruct{}, "t1")). 213 Where(eorm.C("Id").EQ(1)) 214 return queryer.Get(context.Background()) 215 }, 216 wantRes: func() **int { 217 return new(*int) 218 }(), 219 }, 220 { 221 name: "res int accept NULL", 222 queryRes: func() (any, error) { 223 queryer := eorm.NewSelector[int](s.orm).Select(eorm.C("Int32Ptr")). 224 From(eorm.TableOf(&test.SimpleStruct{}, "t1")). 225 Where(eorm.C("Id").EQ(1)) 226 return queryer.Get(context.Background()) 227 }, 228 wantErr: "sql: Scan error on column index 0, name \"int32_ptr\": converting NULL to int is unsupported", 229 }, 230 } 231 232 for _, tc := range testCases { 233 s.T().Run(tc.name, func(t *testing.T) { 234 res, err := tc.queryRes() 235 if err != nil { 236 assert.EqualError(t, err, tc.wantErr) 237 return 238 } 239 assert.Equal(t, tc.wantRes, res) 240 }) 241 } 242 } 243 244 func (s *SelectTestSuite) TestRawQueryGetBaseType() { 245 testCases := []struct { 246 name string 247 queryRes func() (any, error) 248 wantErr error 249 wantRes any 250 }{ 251 { 252 name: "res int", 253 queryRes: func() (any, error) { 254 queryer := eorm.RawQuery[int](s.orm, "SELECT `id` FROM `simple_struct` WHERE `id` = ?;", 1) 255 return queryer.Get(context.Background()) 256 }, 257 wantRes: func() *int { 258 res := 1 259 return &res 260 }(), 261 }, 262 { 263 name: "res int convert string", 264 queryRes: func() (any, error) { 265 queryer := eorm.RawQuery[string](s.orm, "SELECT `id` FROM `simple_struct` WHERE `id` = ?;", 1) 266 return queryer.Get(context.Background()) 267 }, 268 wantRes: func() *string { 269 res := "1" 270 return &res 271 }(), 272 }, 273 { 274 name: "res int convert bytes", 275 queryRes: func() (any, error) { 276 queryer := eorm.RawQuery[[]byte](s.orm, "SELECT `id` FROM `simple_struct` WHERE `id` = ?;", 1) 277 return queryer.Get(context.Background()) 278 }, 279 wantRes: func() *[]byte { 280 res := []byte("1") 281 return &res 282 }(), 283 }, 284 { 285 name: "res string", 286 queryRes: func() (any, error) { 287 queryer := eorm.RawQuery[string](s.orm, "SELECT `string` FROM `simple_struct` WHERE `id` = ?;", 1) 288 return queryer.Get(context.Background()) 289 }, 290 wantRes: func() *string { 291 res := "world" 292 return &res 293 }(), 294 }, 295 { 296 name: "res string convert bytes", 297 queryRes: func() (any, error) { 298 queryer := eorm.RawQuery[[]byte](s.orm, "SELECT `string` FROM `simple_struct` WHERE `id` = ?;", 1) 299 return queryer.Get(context.Background()) 300 }, 301 wantRes: func() *[]byte { 302 res := []byte("world") 303 return &res 304 }(), 305 }, 306 { 307 name: "res bytes", 308 queryRes: func() (any, error) { 309 queryer := eorm.RawQuery[[]byte](s.orm, "SELECT `byte_array` FROM `simple_struct` WHERE `id` = ?;", 1) 310 return queryer.Get(context.Background()) 311 }, 312 wantRes: func() *[]byte { 313 res := []byte("hello") 314 return &res 315 }(), 316 }, 317 { 318 name: "res bytes convert string", 319 queryRes: func() (any, error) { 320 queryer := eorm.RawQuery[string](s.orm, "SELECT `byte_array` FROM `simple_struct` WHERE `id` = ?;", 1) 321 return queryer.Get(context.Background()) 322 }, 323 wantRes: func() *string { 324 res := "hello" 325 return &res 326 }(), 327 }, 328 { 329 name: "res bool", 330 queryRes: func() (any, error) { 331 queryer := eorm.RawQuery[bool](s.orm, "SELECT `bool` FROM `simple_struct` WHERE `id` = ?;", 1) 332 return queryer.Get(context.Background()) 333 }, 334 wantRes: func() *bool { 335 res := true 336 return &res 337 }(), 338 }, 339 { 340 name: "res bool convert string", 341 queryRes: func() (any, error) { 342 queryer := eorm.RawQuery[string](s.orm, "SELECT `bool` FROM `simple_struct` WHERE `id` = ?;", 1) 343 return queryer.Get(context.Background()) 344 }, 345 wantRes: func() *string { 346 res := "1" 347 return &res 348 }(), 349 }, 350 { 351 name: "res bool convert in", 352 queryRes: func() (any, error) { 353 queryer := eorm.RawQuery[int](s.orm, "SELECT `bool` FROM `simple_struct` WHERE `id` = ?;", 1) 354 return queryer.Get(context.Background()) 355 }, 356 wantRes: func() *int { 357 res := 1 358 return &res 359 }(), 360 }, 361 { 362 name: "res null string ptr", 363 queryRes: func() (any, error) { 364 queryer := eorm.RawQuery[sql.NullString](s.orm, "SELECT `null_string_ptr` FROM `simple_struct` WHERE `id` = ?;", 1) 365 return queryer.Get(context.Background()) 366 }, 367 wantRes: func() *sql.NullString { 368 res := sql.NullString{String: "null string", Valid: true} 369 return &res 370 }(), 371 }, 372 { 373 name: "res sring convert null string ptr", 374 queryRes: func() (any, error) { 375 queryer := eorm.RawQuery[sql.NullString](s.orm, "SELECT `string` FROM `simple_struct` WHERE `id` = ?;", 1) 376 return queryer.Get(context.Background()) 377 }, 378 wantRes: func() *sql.NullString { 379 res := sql.NullString{String: "world", Valid: true} 380 return &res 381 }(), 382 }, 383 } 384 385 for _, tc := range testCases { 386 s.T().Run(tc.name, func(t *testing.T) { 387 res, err := tc.queryRes() 388 assert.Equal(t, tc.wantErr, err) 389 if err != nil { 390 return 391 } 392 assert.Equal(t, tc.wantRes, res) 393 }) 394 } 395 } 396 397 func TestMySQL8Select(t *testing.T) { 398 suite.Run(t, &SelectTestSuite{ 399 Suite: Suite{ 400 driver: "mysql", 401 dsn: "root:root@tcp(localhost:13306)/integration_test", 402 }, 403 }) 404 suite.Run(t, &SelectTestSuiteGetMulti{ 405 Suite: Suite{ 406 driver: "mysql", 407 dsn: "root:root@tcp(localhost:13306)/integration_test", 408 }, 409 }) 410 suite.Run(t, &SelectTestSuiteJoin{ 411 Suite: Suite{ 412 driver: "mysql", 413 dsn: "root:root@tcp(localhost:13306)/integration_test", 414 }, 415 }) 416 suite.Run(t, &SelectTestSuiteLeftJoin{ 417 Suite: Suite{ 418 driver: "mysql", 419 dsn: "root:root@tcp(localhost:13306)/integration_test", 420 }, 421 }) 422 suite.Run(t, &SelectTestSuiteRightJoin{ 423 Suite: Suite{ 424 driver: "mysql", 425 dsn: "root:root@tcp(localhost:13306)/integration_test", 426 }, 427 }) 428 } 429 430 type SelectTestSuiteGetMulti struct { 431 Suite 432 data []*test.SimpleStruct 433 } 434 435 func (s *SelectTestSuiteGetMulti) SetupSuite() { 436 s.Suite.SetupSuite() 437 s.data = append(s.data, test.NewSimpleStruct(1)) 438 s.data = append(s.data, test.NewSimpleStruct(2)) 439 s.data = append(s.data, test.NewSimpleStruct(3)) 440 res := eorm.NewInserter[test.SimpleStruct](s.orm).Values(s.data...).Exec(context.Background()) 441 if res.Err() != nil { 442 s.T().Fatal(res.Err()) 443 } 444 } 445 446 func (s *SelectTestSuiteGetMulti) TearDownSuite() { 447 res := eorm.RawQuery[any](s.orm, "DELETE FROM `simple_struct`").Exec(context.Background()) 448 if res.Err() != nil { 449 s.T().Fatal(res.Err()) 450 } 451 } 452 453 func (s *SelectTestSuiteGetMulti) TestSelectorGetMulti() { 454 testCases := []struct { 455 name string 456 s *eorm.Selector[test.SimpleStruct] 457 wantErr error 458 wantRes []*test.SimpleStruct 459 }{ 460 { 461 name: "not found", 462 s: eorm.NewSelector[test.SimpleStruct](s.orm). 463 Where(eorm.C("Id").EQ(9)), 464 wantRes: []*test.SimpleStruct{}, 465 }, 466 { 467 name: "found", 468 s: eorm.NewSelector[test.SimpleStruct](s.orm). 469 Where(eorm.C("Id").LT(4)), 470 wantRes: s.data, 471 }, 472 } 473 474 for _, tc := range testCases { 475 s.T().Run(tc.name, func(t *testing.T) { 476 res, err := tc.s.GetMulti(context.Background()) 477 assert.Equal(t, tc.wantErr, err) 478 if err != nil { 479 return 480 } 481 assert.Equal(t, tc.wantRes, res) 482 }) 483 } 484 } 485 486 func (s *SelectTestSuiteGetMulti) TestSelectorGetMultiBaseType() { 487 testCases := []struct { 488 name string 489 queryRes func() (any, error) 490 wantErr error 491 wantRes any 492 }{ 493 { 494 name: "res int", 495 queryRes: func() (any, error) { 496 queryer := eorm.NewSelector[int](s.orm).Select(eorm.C("Id")).From(eorm.TableOf(&test.SimpleStruct{}, "t1")) 497 return queryer.GetMulti(context.Background()) 498 }, 499 wantRes: func() (res []*int) { 500 vals := []int{1, 2, 3} 501 for i := 0; i < len(vals); i++ { 502 res = append(res, &vals[i]) 503 } 504 return 505 }(), 506 }, 507 { 508 name: "res string", 509 queryRes: func() (any, error) { 510 queryer := eorm.NewSelector[string](s.orm).Select(eorm.C("String")).From(eorm.TableOf(&test.SimpleStruct{}, "t1")) 511 return queryer.GetMulti(context.Background()) 512 }, 513 wantRes: func() (res []*string) { 514 vals := []string{"world", "world", "world"} 515 for i := 0; i < len(vals); i++ { 516 res = append(res, &vals[i]) 517 } 518 return 519 }(), 520 }, 521 { 522 name: "res bytes", 523 queryRes: func() (any, error) { 524 queryer := eorm.NewSelector[[]byte](s.orm).Select(eorm.C("ByteArray")).From(eorm.TableOf(&test.SimpleStruct{}, "t1")) 525 return queryer.GetMulti(context.Background()) 526 }, 527 wantRes: func() (res []*[]byte) { 528 vals := [][]byte{[]byte("hello"), []byte("hello"), []byte("hello")} 529 for i := 0; i < len(vals); i++ { 530 res = append(res, &vals[i]) 531 } 532 return 533 }(), 534 }, 535 { 536 name: "res bool", 537 queryRes: func() (any, error) { 538 queryer := eorm.NewSelector[bool](s.orm).Select(eorm.C("Bool")).From(eorm.TableOf(&test.SimpleStruct{}, "t1")) 539 return queryer.GetMulti(context.Background()) 540 }, 541 wantRes: func() (res []*bool) { 542 vals := []bool{true, true, true} 543 for i := 0; i < len(vals); i++ { 544 res = append(res, &vals[i]) 545 } 546 return 547 }(), 548 }, 549 { 550 name: "res null string ptr", 551 queryRes: func() (any, error) { 552 queryer := eorm.NewSelector[sql.NullString](s.orm).Select(eorm.C("NullStringPtr")).From(eorm.TableOf(&test.SimpleStruct{}, "t1")) 553 return queryer.GetMulti(context.Background()) 554 }, 555 wantRes: []*sql.NullString{ 556 { 557 String: "null string", 558 Valid: true, 559 }, 560 { 561 String: "null string", 562 Valid: true, 563 }, 564 { 565 String: "null string", 566 Valid: true, 567 }, 568 }, 569 }, 570 { 571 name: "res null int32 ptr", 572 queryRes: func() (any, error) { 573 queryer := eorm.NewSelector[sql.NullInt32](s.orm).Select(eorm.C("NullInt32Ptr")).From(eorm.TableOf(&test.SimpleStruct{}, "t1")) 574 return queryer.GetMulti(context.Background()) 575 }, 576 wantRes: []*sql.NullInt32{ 577 { 578 Int32: 32, 579 Valid: true, 580 }, 581 { 582 Int32: 32, 583 Valid: true, 584 }, 585 { 586 Int32: 32, 587 Valid: true, 588 }, 589 }, 590 }, 591 { 592 name: "res null bool ptr", 593 queryRes: func() (any, error) { 594 queryer := eorm.NewSelector[sql.NullBool](s.orm).Select(eorm.C("NullBoolPtr")).From(eorm.TableOf(&test.SimpleStruct{}, "t1")) 595 return queryer.GetMulti(context.Background()) 596 }, 597 wantRes: []*sql.NullBool{ 598 { 599 Bool: true, 600 Valid: true, 601 }, 602 { 603 Bool: true, 604 Valid: true, 605 }, 606 { 607 Bool: true, 608 Valid: true, 609 }, 610 }, 611 }, 612 { 613 name: "res null float64 ptr", 614 queryRes: func() (any, error) { 615 queryer := eorm.NewSelector[sql.NullFloat64](s.orm).Select(eorm.C("NullFloat64Ptr")).From(eorm.TableOf(&test.SimpleStruct{}, "t1")) 616 return queryer.GetMulti(context.Background()) 617 }, 618 wantRes: []*sql.NullFloat64{ 619 { 620 Float64: 6.4, 621 Valid: true, 622 }, 623 { 624 Float64: 6.4, 625 Valid: true, 626 }, 627 { 628 Float64: 6.4, 629 Valid: true, 630 }, 631 }, 632 }, 633 } 634 635 for _, tc := range testCases { 636 s.T().Run(tc.name, func(t *testing.T) { 637 res, err := tc.queryRes() 638 assert.Equal(t, tc.wantErr, err) 639 if err != nil { 640 return 641 } 642 assert.EqualValues(t, tc.wantRes, res) 643 }) 644 } 645 } 646 647 func (s *SelectTestSuiteGetMulti) TestRawQueryGetMultiBaseType() { 648 testCases := []struct { 649 name string 650 queryRes func() (any, error) 651 wantErr error 652 wantRes any 653 }{ 654 { 655 name: "res int", 656 queryRes: func() (any, error) { 657 queryer := eorm.RawQuery[int](s.orm, "SELECT `id` FROM `simple_struct`;") 658 return queryer.GetMulti(context.Background()) 659 }, 660 wantRes: func() (res []*int) { 661 vals := []int{1, 2, 3} 662 for i := 0; i < len(vals); i++ { 663 res = append(res, &vals[i]) 664 } 665 return 666 }(), 667 }, 668 { 669 name: "res string", 670 queryRes: func() (any, error) { 671 queryer := eorm.RawQuery[string](s.orm, "SELECT `string` FROM `simple_struct`;") 672 return queryer.GetMulti(context.Background()) 673 }, 674 wantRes: func() (res []*string) { 675 vals := []string{"world", "world", "world"} 676 for i := 0; i < len(vals); i++ { 677 res = append(res, &vals[i]) 678 } 679 return 680 }(), 681 }, 682 { 683 name: "res bytes", 684 queryRes: func() (any, error) { 685 queryer := eorm.RawQuery[[]byte](s.orm, "SELECT `byte_array` FROM `simple_struct`;") 686 return queryer.GetMulti(context.Background()) 687 }, 688 wantRes: func() (res []*[]byte) { 689 vals := [][]byte{[]byte("hello"), []byte("hello"), []byte("hello")} 690 for i := 0; i < len(vals); i++ { 691 res = append(res, &vals[i]) 692 } 693 return 694 }(), 695 }, 696 { 697 name: "res bool", 698 queryRes: func() (any, error) { 699 queryer := eorm.RawQuery[bool](s.orm, "SELECT `bool` FROM `simple_struct`;") 700 return queryer.GetMulti(context.Background()) 701 }, 702 wantRes: func() (res []*bool) { 703 vals := []bool{true, true, true} 704 for i := 0; i < len(vals); i++ { 705 res = append(res, &vals[i]) 706 } 707 return 708 }(), 709 }, 710 { 711 name: "res null string ptr", 712 queryRes: func() (any, error) { 713 queryer := eorm.RawQuery[sql.NullString](s.orm, "SELECT `null_string_ptr` FROM `simple_struct`;") 714 return queryer.GetMulti(context.Background()) 715 }, 716 wantRes: []*sql.NullString{ 717 { 718 String: "null string", 719 Valid: true, 720 }, 721 { 722 String: "null string", 723 Valid: true, 724 }, 725 { 726 String: "null string", 727 Valid: true, 728 }, 729 }, 730 }, 731 } 732 733 for _, tc := range testCases { 734 s.T().Run(tc.name, func(t *testing.T) { 735 res, err := tc.queryRes() 736 assert.Equal(t, tc.wantErr, err) 737 if err != nil { 738 return 739 } 740 assert.EqualValues(t, tc.wantRes, res) 741 }) 742 } 743 } 744 745 func (s *SelectTestSuiteGetMulti) TestSelectorDistinct() { 746 747 testcases := []struct { 748 name string 749 s func() (any, error) 750 wantErr error 751 wantRes any 752 }{ 753 { 754 name: "distinct col", 755 s: func() (any, error) { 756 return eorm.NewSelector[test.SimpleStruct](s.orm).Select(eorm.C("Int")).Distinct().GetMulti(context.Background()) 757 758 }, 759 wantRes: []*test.SimpleStruct{ 760 &test.SimpleStruct{ 761 Int: 12, 762 }, 763 }, 764 }, 765 { 766 name: "count distinct", 767 s: func() (any, error) { 768 return eorm.NewSelector[int](s.orm).Select(eorm.CountDistinct("Bool")). 769 From(eorm.TableOf(&test.SimpleStruct{}, "t1")).GetMulti(context.Background()) 770 }, 771 wantRes: func() []*int { 772 val := 1 773 return []*int{&val} 774 }(), 775 }, 776 { 777 name: "having count distinct", 778 s: func() (any, error) { 779 return eorm.NewSelector[test.SimpleStruct](s.orm).Select(eorm.C("JsonColumn")).GroupBy("JsonColumn").Having(eorm.CountDistinct("JsonColumn").EQ(1)).GetMulti(context.Background()) 780 }, 781 wantRes: []*test.SimpleStruct{ 782 &test.SimpleStruct{ 783 JsonColumn: &test.JsonColumn{ 784 Val: test.User{Name: "Tom"}, 785 Valid: true, 786 }, 787 }, 788 }, 789 }, 790 } 791 for _, tc := range testcases { 792 s.T().Run(tc.name, func(t *testing.T) { 793 res, err := tc.s() 794 assert.Equal(t, tc.wantErr, err) 795 if err != nil { 796 return 797 } 798 assert.Equal(t, tc.wantRes, res) 799 }) 800 } 801 802 } 803 804 func TestMySQL8SelectJoin(t *testing.T) { 805 suite.Run(t, &SelectTestSuiteJoin{ 806 Suite: Suite{ 807 driver: "mysql", 808 dsn: "root:root@tcp(localhost:13306)/integration_test", 809 }, 810 }) 811 suite.Run(t, &SelectTestSuiteRightJoin{ 812 Suite: Suite{ 813 driver: "mysql", 814 dsn: "root:root@tcp(localhost:13306)/integration_test", 815 }, 816 }) 817 suite.Run(t, &SelectTestSuiteLeftJoin{ 818 Suite: Suite{ 819 driver: "mysql", 820 dsn: "root:root@tcp(localhost:13306)/integration_test", 821 }, 822 }) 823 } 824 825 type SelectTestSuiteJoin struct { 826 Suite 827 data []*test.Order 828 } 829 830 func (s *SelectTestSuiteJoin) SetupSuite() { 831 s.Suite.SetupSuite() 832 initSql(s.orm, s.T()) 833 } 834 835 func (s *SelectTestSuiteJoin) TearDownSuite() { 836 res := eorm.RawQuery[any](s.orm, "DELETE FROM `order`").Exec(context.Background()) 837 require.NoError(s.T(), res.Err()) 838 res = eorm.RawQuery[any](s.orm, "DELETE FROM `order_detail`").Exec(context.Background()) 839 require.NoError(s.T(), res.Err()) 840 res = eorm.RawQuery[any](s.orm, "DELETE FROM `item`").Exec(context.Background()) 841 require.NoError(s.T(), res.Err()) 842 } 843 func (s *SelectTestSuiteJoin) TestSelectorJoin() { 844 testCases := []struct { 845 name string 846 s func() (any, error) 847 wantErr error 848 wantRes any 849 }{ 850 { 851 name: "join", 852 s: func() (any, error) { 853 t1 := eorm.TableOf(&test.Order{}, "t1") 854 t2 := eorm.TableOf(&test.OrderDetail{}, "t2") 855 t3 := t1.LeftJoin(t2).Using("UsingCol1", "UsingCol2") 856 return eorm.NewSelector[test.Order](s.orm).Select(t1.AllColumns()).From(t3).Get(context.Background()) 857 }, 858 wantRes: &test.Order{Id: 1, UsingCol1: "usingcoa1_1", UsingCol2: "usingcoa1_2"}, 859 }, 860 { 861 name: "join As", 862 s: func() (any, error) { 863 t1 := eorm.TableOf(&test.Order{}, "t1") 864 t2 := eorm.TableOf(&test.OrderDetail{}, "t2") 865 t3 := t1.Join(t2).On(t1.C("Id").EQ(t2.C("OrderId"))) 866 return eorm.NewSelector[test.Order](s.orm).Select(t1.AllColumns()).From(t3).Get(context.Background()) 867 }, 868 wantRes: &test.Order{Id: 1, UsingCol1: "usingcoa1_1", UsingCol2: "usingcoa1_2"}, 869 }, 870 { 871 name: "join using col", 872 s: func() (any, error) { 873 t1 := eorm.TableOf(&test.Order{}, "t1") 874 t2 := eorm.TableOf(&test.OrderDetail{}, "t2") 875 t3 := t1.Join(t2).Using("UsingCol1", "UsingCol2") 876 return eorm.NewSelector[test.Order](s.orm).Select(t1.AllColumns()).From(t3).Get(context.Background()) 877 }, 878 wantRes: &test.Order{Id: 1, UsingCol1: "usingcoa1_1", UsingCol2: "usingcoa1_2"}, 879 }, 880 { 881 name: "join using invalid col", 882 s: func() (any, error) { 883 t1 := eorm.TableOf(&test.Order{}, "t1") 884 t2 := eorm.TableOf(&test.OrderDetail{}, "t2") 885 t3 := t1.Join(t2).Using("invalid", "UsingCol2") 886 return eorm.NewSelector[test.Order](s.orm).Select(t1.AllColumns()).From(t3).Get(context.Background()) 887 }, 888 wantErr: errs.NewInvalidFieldError("invalid"), 889 }, 890 { 891 name: "join Avg", 892 s: func() (any, error) { 893 t1 := eorm.TableOf(&test.Order{}, "t1") 894 t2 := eorm.TableOf(&test.OrderDetail{}, "t2") 895 t3 := t1.Join(t2).On(t1.C("Id").EQ(t2.C("OrderId"))) 896 return eorm.NewSelector[test.Order](s.orm).From(t3).Select(t1.Avg("UsingCol1").As("using_col1"), t1.Avg("UsingCol2").As("using_col2")).Get(context.Background()) 897 }, 898 wantRes: &test.Order{Id: 0, UsingCol1: "0", UsingCol2: "0"}, 899 }, 900 { 901 name: "join Avg invalid", 902 s: func() (any, error) { 903 t1 := eorm.TableOf(&test.Order{}, "t1") 904 t2 := eorm.TableOf(&test.OrderDetail{}, "t2") 905 t3 := t1.Join(t2).On(t1.C("Id").EQ(t2.C("OrderId"))) 906 return eorm.NewSelector[test.Order](s.orm).From(t3).Select(t1.Avg("invalid").As("using_col1"), t1.Avg("UsingCol2").As("using_col2")).Get(context.Background()) 907 }, 908 wantErr: errs.NewInvalidFieldError("invalid"), 909 }, 910 { 911 name: "join col", 912 s: func() (any, error) { 913 t1 := eorm.TableOf(&test.Order{}, "t1") 914 t2 := eorm.TableOf(&test.OrderDetail{}, "t2") 915 t3 := t1.Join(t2).On(t1.C("Id").EQ(t2.C("OrderId"))) 916 return eorm.NewSelector[test.Order](s.orm).From(t3).Select(t1.C("UsingCol1"), t2.C("UsingCol2")).Get(context.Background()) 917 }, 918 wantRes: &test.Order{Id: 0, UsingCol1: "usingcoa1_1", UsingCol2: "usingcoa1_2"}, 919 }, 920 { 921 name: "join col invalid", 922 s: func() (any, error) { 923 t1 := eorm.TableOf(&test.Order{}, "t1") 924 t2 := eorm.TableOf(&test.OrderDetail{}, "t2") 925 t3 := t1.Join(t2).On(t1.C("Id").EQ(t2.C("OrderId"))) 926 return eorm.NewSelector[test.Order](s.orm).From(t3).Select(t1.C("invalid"), t2.C("UsingCol2")).Get(context.Background()) 927 }, 928 wantErr: errs.NewInvalidFieldError("invalid"), 929 }, 930 } 931 932 for _, tc := range testCases { 933 s.T().Run(tc.name, func(t *testing.T) { 934 res, err := tc.s() 935 assert.Equal(t, tc.wantErr, err) 936 if err != nil { 937 return 938 } 939 assert.Equal(t, tc.wantRes, res) 940 }) 941 } 942 } 943 944 // SelectTestSuiteLeftJoin left join 945 946 type SelectTestSuiteLeftJoin struct { 947 Suite 948 data []*test.SimpleStruct 949 } 950 951 func (s *SelectTestSuiteLeftJoin) SetupSuite() { 952 s.Suite.SetupSuite() 953 initSql(s.orm, s.T()) 954 } 955 956 func (s *SelectTestSuiteLeftJoin) TearDownSuite() { 957 res := eorm.RawQuery[any](s.orm, "DELETE FROM `order`").Exec(context.Background()) 958 require.NoError(s.T(), res.Err()) 959 res = eorm.RawQuery[any](s.orm, "DELETE FROM `order_detail`").Exec(context.Background()) 960 require.NoError(s.T(), res.Err()) 961 res = eorm.RawQuery[any](s.orm, "DELETE FROM `item`").Exec(context.Background()) 962 require.NoError(s.T(), res.Err()) 963 } 964 965 func (s *SelectTestSuiteLeftJoin) TestSelectorLeftJoin() { 966 testCases := []struct { 967 name string 968 s func() (any, error) 969 wantErr error 970 wantRes any 971 }{ 972 { 973 name: "left join", 974 s: func() (any, error) { 975 t1 := eorm.TableOf(&test.Order{}, "t1") 976 t2 := eorm.TableOf(&test.OrderDetail{}, "t2") 977 t3 := t1.LeftJoin(t2).Using("UsingCol1", "UsingCol2") 978 return eorm.NewSelector[test.Order](s.orm).Select(t1.AllColumns()).From(t3).Get(context.Background()) 979 }, 980 wantRes: &test.Order{Id: 1, UsingCol1: "usingcoa1_1", UsingCol2: "usingcoa1_2"}, 981 }, 982 { 983 name: "left join col", 984 s: func() (any, error) { 985 t1 := eorm.TableOf(&test.Order{}, "t1") 986 t2 := eorm.TableOf(&test.OrderDetail{}, "t2") 987 t3 := t1.LeftJoin(t2).On(t1.C("Id").EQ(t2.C("OrderId"))) 988 return eorm.NewSelector[test.Order](s.orm).From(t3).Select(t1.C("UsingCol1")).Get(context.Background()) 989 }, 990 wantRes: &test.Order{Id: 0, UsingCol1: "usingcoa1_1", UsingCol2: ""}, 991 }, 992 { 993 name: "left join invalid col", 994 s: func() (any, error) { 995 t1 := eorm.TableOf(&test.Order{}, "t1") 996 t2 := eorm.TableOf(&test.OrderDetail{}, "t2") 997 t3 := t1.LeftJoin(t2).On(t1.C("Id").EQ(t2.C("OrderId"))) 998 return eorm.NewSelector[test.Order](s.orm).From(t3).Select(t1.C("invalid")).Get(context.Background()) 999 }, 1000 wantErr: errs.NewInvalidFieldError("invalid"), 1001 }, 1002 { 1003 name: "left join using col", 1004 s: func() (any, error) { 1005 t1 := eorm.TableOf(&test.Order{}, "t1") 1006 t2 := eorm.TableOf(&test.OrderDetail{}, "t2") 1007 t3 := t1.LeftJoin(t2).Using("UsingCol1", "UsingCol2") 1008 return eorm.NewSelector[test.Order](s.orm).Select(t1.AllColumns()).From(t3).Get(context.Background()) 1009 }, 1010 wantRes: &test.Order{Id: 1, UsingCol1: "usingcoa1_1", UsingCol2: "usingcoa1_2"}, 1011 }, 1012 { 1013 name: "left join using invalid col", 1014 s: func() (any, error) { 1015 t1 := eorm.TableOf(&test.Order{}, "t1") 1016 t2 := eorm.TableOf(&test.OrderDetail{}, "t2") 1017 t3 := t1.LeftJoin(t2).Using("invalid", "UsingCol2") 1018 return eorm.NewSelector[test.Order](s.orm).Select(t1.AllColumns()).From(t3).Get(context.Background()) 1019 }, 1020 wantErr: errs.NewInvalidFieldError("invalid"), 1021 }, 1022 { 1023 name: "left join Avg ", 1024 s: func() (any, error) { 1025 t1 := eorm.TableOf(&test.Order{}, "t1") 1026 t2 := eorm.TableOf(&test.OrderDetail{}, "t2") 1027 t3 := t1.LeftJoin(t2).Using("UsingCol1", "UsingCol2") 1028 return eorm.NewSelector[test.Order](s.orm).From(t3).Select(t1.Avg("UsingCol1").As("using_col1")).Get(context.Background()) 1029 }, 1030 wantRes: &test.Order{Id: 0, UsingCol1: "0", UsingCol2: ""}, 1031 }, 1032 { 1033 name: "left join Avg invalid", 1034 s: func() (any, error) { 1035 t1 := eorm.TableOf(&test.Order{}, "t1") 1036 t2 := eorm.TableOf(&test.OrderDetail{}, "t2") 1037 t3 := t1.LeftJoin(t2).Using("UsingCol1", "UsingCol2") 1038 return eorm.NewSelector[test.Order](s.orm).From(t3).Select(t1.Avg("invalid").As("using_col1")).Get(context.Background()) 1039 }, 1040 wantErr: errs.NewInvalidFieldError("invalid"), 1041 }, 1042 } 1043 1044 for _, tc := range testCases { 1045 s.T().Run(tc.name, func(t *testing.T) { 1046 res, err := tc.s() 1047 assert.Equal(t, tc.wantErr, err) 1048 if err != nil { 1049 return 1050 } 1051 assert.Equal(t, tc.wantRes, res) 1052 }) 1053 } 1054 } 1055 1056 type SelectTestSuiteRightJoin struct { 1057 Suite 1058 data []*test.SimpleStruct 1059 } 1060 1061 func (s *SelectTestSuiteRightJoin) SetupSuite() { 1062 s.Suite.SetupSuite() 1063 initSql(s.orm, s.T()) 1064 } 1065 1066 func (s *SelectTestSuiteRightJoin) TearDownSuite() { 1067 res := eorm.RawQuery[any](s.orm, "DELETE FROM `order`").Exec(context.Background()) 1068 require.NoError(s.T(), res.Err()) 1069 res = eorm.RawQuery[any](s.orm, "DELETE FROM `order_detail`").Exec(context.Background()) 1070 require.NoError(s.T(), res.Err()) 1071 res = eorm.RawQuery[any](s.orm, "DELETE FROM `item`").Exec(context.Background()) 1072 require.NoError(s.T(), res.Err()) 1073 } 1074 1075 func (s *SelectTestSuiteRightJoin) TestSelectorRightJoin() { 1076 testCases := []struct { 1077 name string 1078 s func() (any, error) 1079 wantErr error 1080 wantRes any 1081 }{ 1082 { 1083 name: "Right join", 1084 s: func() (any, error) { 1085 t1 := eorm.TableOf(&test.Order{}, "t1") 1086 t2 := eorm.TableOf(&test.OrderDetail{}, "t2") 1087 t3 := t1.RightJoin(t2).Using("UsingCol1", "UsingCol2") 1088 return eorm.NewSelector[test.Order](s.orm).Select(t1.AllColumns()).From(t3).Get(context.Background()) 1089 }, 1090 wantRes: &test.Order{Id: 1, UsingCol1: "usingcoa1_1", UsingCol2: "usingcoa1_2"}, 1091 }, 1092 { 1093 name: "right join col", 1094 s: func() (any, error) { 1095 t1 := eorm.TableOf(&test.Order{}, "t1") 1096 t2 := eorm.TableOf(&test.OrderDetail{}, "t2") 1097 t3 := t1.RightJoin(t2).On(t1.C("Id").EQ(t2.C("OrderId"))) 1098 return eorm.NewSelector[test.Order](s.orm).From(t3).Select(t1.C("UsingCol1")).Get(context.Background()) 1099 }, 1100 wantRes: &test.Order{Id: 0, UsingCol1: "usingcoa1_1", UsingCol2: ""}, 1101 }, 1102 { 1103 name: "right join invalid col", 1104 s: func() (any, error) { 1105 t1 := eorm.TableOf(&test.Order{}, "t1") 1106 t2 := eorm.TableOf(&test.OrderDetail{}, "t2") 1107 t3 := t1.RightJoin(t2).Using("UsingCol1", "UsingCol2") 1108 return eorm.NewSelector[test.Order](s.orm).From(t3).Select(t1.C("invalid")).Get(context.Background()) 1109 }, 1110 wantErr: errs.NewInvalidFieldError("invalid"), 1111 }, 1112 { 1113 name: "right join using col", 1114 s: func() (any, error) { 1115 t1 := eorm.TableOf(&test.Order{}, "t1") 1116 t2 := eorm.TableOf(&test.OrderDetail{}, "t2") 1117 t3 := t1.RightJoin(t2).Using("UsingCol1", "UsingCol2") 1118 return eorm.NewSelector[test.Order](s.orm).Select(t1.AllColumns()).From(t3).Get(context.Background()) 1119 }, 1120 wantRes: &test.Order{Id: 1, UsingCol1: "usingcoa1_1", UsingCol2: "usingcoa1_2"}, 1121 }, 1122 { 1123 name: "right join using invalid col", 1124 s: func() (any, error) { 1125 t1 := eorm.TableOf(&test.Order{}, "t1") 1126 t2 := eorm.TableOf(&test.OrderDetail{}, "t2") 1127 t3 := t1.RightJoin(t2).Using("invalid", "UsingCol2") 1128 return eorm.NewSelector[test.Order](s.orm).Select(t1.AllColumns()).From(t3).Get(context.Background()) 1129 }, 1130 wantErr: errs.NewInvalidFieldError("invalid"), 1131 }, 1132 { 1133 name: "right join Avg", 1134 s: func() (any, error) { 1135 t1 := eorm.TableOf(&test.Order{}, "t1") 1136 t2 := eorm.TableOf(&test.OrderDetail{}, "t2") 1137 t3 := t1.RightJoin(t2).Using("UsingCol1", "UsingCol2") 1138 return eorm.NewSelector[test.Order](s.orm).From(t3).Select(t1.Avg("UsingCol1").As("using_col1")).Get(context.Background()) 1139 }, 1140 wantRes: &test.Order{Id: 0, UsingCol1: "0", UsingCol2: ""}, 1141 }, 1142 { 1143 name: "right join Avg invalid", 1144 s: func() (any, error) { 1145 t1 := eorm.TableOf(&test.Order{}, "t1") 1146 t2 := eorm.TableOf(&test.OrderDetail{}, "t2") 1147 t3 := t1.RightJoin(t2).Using("UsingCol1", "UsingCol2") 1148 return eorm.NewSelector[test.Order](s.orm).From(t3).Select(t1.Avg("invalid").As("using_col1")).Get(context.Background()) 1149 }, 1150 wantErr: errs.NewInvalidFieldError("invalid"), 1151 }, 1152 // 子查詢 1153 { 1154 name: "join & subquery", 1155 s: func() (any, error) { 1156 t1 := eorm.TableOf(&test.Order{}, "t1") 1157 sub := eorm.NewSelector[test.OrderDetail](s.orm).AsSubquery("sub") 1158 return eorm.NewSelector[test.Order](s.orm). 1159 Select(eorm.C("Id"), sub.C("UsingCol1")). 1160 From(t1.Join(sub).On(t1.C("Id").EQ(sub.C("OrderId")))). 1161 Get(context.Background()) 1162 }, 1163 wantRes: &test.Order{Id: 1, UsingCol1: "usingcoa1_1", UsingCol2: ""}, 1164 }, 1165 { 1166 name: "from", 1167 s: func() (any, error) { 1168 sub := eorm.NewSelector[test.OrderDetail](s.orm).AsSubquery("sub") 1169 return eorm.NewSelector[test.Order](s.orm). 1170 Select(sub.C("UsingCol1")). 1171 From(sub). 1172 Where().Get(context.Background()) 1173 }, 1174 wantRes: &test.Order{Id: 0, UsingCol1: "usingcoa1_1", UsingCol2: ""}, 1175 }, 1176 { 1177 name: "in", 1178 s: func() (any, error) { 1179 sub := eorm.NewSelector[test.OrderDetail](s.orm).Select(eorm.C("OrderId")).AsSubquery("sub") 1180 return eorm.NewSelector[test.Order](s.orm). 1181 Select(eorm.Columns("Id")).Where(eorm.C("Id").In(sub)). 1182 Get(context.Background()) 1183 }, 1184 wantRes: &test.Order{Id: 1, UsingCol1: "", UsingCol2: ""}, 1185 }, 1186 { 1187 name: "all", 1188 s: func() (any, error) { 1189 sub := eorm.NewSelector[test.OrderDetail](s.orm).Select(eorm.C("OrderId")).AsSubquery("sub") 1190 return eorm.NewSelector[test.Order](s.orm). 1191 Select(eorm.Columns("Id")). 1192 Where(eorm.C("Id").GT(eorm.All(sub))). 1193 Get(context.Background()) 1194 }, 1195 wantErr: eorm.ErrNoRows, 1196 }, 1197 } 1198 1199 for _, tc := range testCases { 1200 s.T().Run(tc.name, func(t *testing.T) { 1201 res, err := tc.s() 1202 assert.Equal(t, tc.wantErr, err) 1203 if err != nil { 1204 return 1205 } 1206 assert.Equal(t, tc.wantRes, res) 1207 }) 1208 } 1209 } 1210 1211 func initSql(orm *eorm.DB, t *testing.T) { 1212 orderRes := eorm.NewInserter[test.Order](orm).Values(&test.Order{Id: 1, UsingCol1: "usingcoa1_1", UsingCol2: "usingcoa1_2"}, 1213 &test.Order{Id: 2, UsingCol1: "usingcoa1_8", UsingCol2: "usingcoa1_2"}, 1214 &test.Order{Id: 3, UsingCol1: "usingcoa1_2", UsingCol2: "usingcoa1_2"}, 1215 &test.Order{Id: 4, UsingCol1: "usingcoa1_5", UsingCol2: "usingcoa1_2"}, 1216 ).Exec(context.Background()) 1217 require.NoError(t, orderRes.Err()) 1218 orderDetailRes := eorm.NewInserter[test.OrderDetail](orm).Values(&test.OrderDetail{OrderId: 1, ItemId: 1, UsingCol1: "usingcoa1_1", UsingCol2: "usingcoa1_2"}, 1219 &test.OrderDetail{OrderId: 2, ItemId: 1, UsingCol1: "usingcoa1_1", UsingCol2: "usingcoa1_2"}, 1220 &test.OrderDetail{OrderId: 3, ItemId: 2, UsingCol1: "usingcoa1_1", UsingCol2: "usingcoa1_2"}, 1221 &test.OrderDetail{OrderId: 4, ItemId: 2, UsingCol1: "usingcoa1_1", UsingCol2: "usingcoa1_2"}, 1222 ).Exec(context.Background()) 1223 require.NoError(t, orderDetailRes.Err()) 1224 1225 itemRes := eorm.NewInserter[test.Item](orm).Values(&test.Item{Id: 1}, &test.Item{Id: 2}, &test.Item{Id: 3}).Exec(context.Background()) 1226 require.NoError(t, itemRes.Err()) 1227 1228 }