github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/service/model/model_test.go (about) 1 package model 2 3 import ( 4 "fmt" 5 "reflect" 6 "sort" 7 "strings" 8 "testing" 9 10 "github.com/gofrs/uuid" 11 fs "github.com/tickoalcantara12/micro/v3/service/store/file" 12 ) 13 14 type User struct { 15 ID string `json:"id"` 16 Age int `json:"age"` 17 HasPet bool `json:"hasPet"` 18 Created int64 `json:"created"` 19 Tag string `json:"tag"` 20 Updated int64 `json:"updated"` 21 } 22 23 func TestQueryEqualsByID(t *testing.T) { 24 table := New(User{}, &Options{ 25 Store: fs.NewStore(), 26 Namespace: uuid.Must(uuid.NewV4()).String(), 27 }) 28 29 err := table.Create(User{ 30 ID: "1", 31 Age: 12, 32 }) 33 if err != nil { 34 t.Fatal(err) 35 } 36 err = table.Create(User{ 37 ID: "2", 38 Age: 25, 39 }) 40 if err != nil { 41 t.Fatal(err) 42 } 43 users := []User{} 44 q := QueryEquals("ID", "1") 45 q.Order.Type = OrderTypeUnordered 46 err = table.Read(q, &users) 47 if err != nil { 48 t.Fatal(err) 49 } 50 if len(users) != 1 { 51 t.Fatal(users) 52 } 53 } 54 55 type User1 struct { 56 Id string `json:"id"` 57 Age int `json:"age"` 58 HasPet bool `json:"hasPet"` 59 Created int64 `json:"created"` 60 Tag string `json:"tag"` 61 Updated int64 `json:"updated"` 62 } 63 64 func TestQueryEqualsLowerCaseID(t *testing.T) { 65 table := New(&User1{}, &Options{ 66 Store: fs.NewStore(), 67 Namespace: uuid.Must(uuid.NewV4()).String(), 68 }) 69 70 // pointer insert 71 err := table.Create(&User1{ 72 Id: "1", 73 Age: 12, 74 }) 75 if err != nil { 76 t.Fatal(err) 77 } 78 err = table.Create(User1{ 79 Id: "2", 80 Age: 25, 81 }) 82 if err != nil { 83 t.Fatal(err) 84 } 85 users := []User1{} 86 q := QueryEquals("Id", "1") 87 q.Order.Type = OrderTypeUnordered 88 err = table.Read(q, &users) 89 if err != nil { 90 t.Fatal(err) 91 } 92 if len(users) != 1 { 93 t.Fatal(users) 94 } 95 } 96 97 func TestQueryEqualsMismatchIDCapitalization(t *testing.T) { 98 table := New(&User1{}, &Options{ 99 Store: fs.NewStore(), 100 Namespace: uuid.Must(uuid.NewV4()).String(), 101 }) 102 103 // pointer insert 104 err := table.Create(&User1{ 105 Id: "1", 106 Age: 12, 107 }) 108 if err != nil { 109 t.Fatal(err) 110 } 111 err = table.Create(User1{ 112 Id: "2", 113 Age: 25, 114 }) 115 if err != nil { 116 t.Fatal(err) 117 } 118 users := []User1{} 119 q := QueryEquals("id", "1") 120 q.Order.Type = OrderTypeUnordered 121 err = table.Read(q, &users) 122 if err != nil { 123 t.Fatal(err) 124 } 125 if len(users) != 1 { 126 t.Fatal(users) 127 } 128 } 129 130 func TestQueryEqualsByIDMap(t *testing.T) { 131 m := map[string]interface{}{ 132 "ID": "id", 133 "age": 1, 134 "hasPet": true, 135 "created": 1, 136 "tag": "tag", 137 "updated": 1, 138 } 139 table := New(m, &Options{ 140 Store: fs.NewStore(), 141 Namespace: uuid.Must(uuid.NewV4()).String(), 142 }) 143 144 err := table.Create(map[string]interface{}{ 145 "ID": "1", 146 "Age": 12, 147 }) 148 if err != nil { 149 t.Fatal(err) 150 } 151 err = table.Create(map[string]interface{}{ 152 "ID": "2", 153 "Age": 25, 154 }) 155 if err != nil { 156 t.Fatal(err) 157 } 158 users := []map[string]interface{}{} 159 q := QueryEquals("ID", "1") 160 q.Order.Type = OrderTypeUnordered 161 err = table.Read(q, &users) 162 if err != nil { 163 t.Fatal(err) 164 } 165 if len(users) != 1 { 166 t.Fatal(users) 167 } 168 } 169 170 func TestQueryEqualsByIDMapNoSchemaWithIndexes(t *testing.T) { 171 m := map[string]interface{}{} 172 table := New(m, &Options{ 173 Store: fs.NewStore(), 174 Namespace: uuid.Must(uuid.NewV4()).String(), 175 Indexes: []Index{ByEquality("Age")}, 176 }) 177 178 err := table.Create(map[string]interface{}{ 179 "ID": "1", 180 "Age": 12, 181 }) 182 if err != nil { 183 t.Fatal(err) 184 } 185 err = table.Create(map[string]interface{}{ 186 "ID": "2", 187 "Age": 25, 188 }) 189 if err != nil { 190 t.Fatal(err) 191 } 192 users := []map[string]interface{}{} 193 q := QueryEquals("ID", "1") 194 q.Order.Type = OrderTypeUnordered 195 err = table.Read(q, &users) 196 if err != nil { 197 t.Fatal(err) 198 } 199 if len(users) != 1 { 200 t.Fatal(users) 201 } 202 } 203 204 func TestListAllMap(t *testing.T) { 205 m := map[string]interface{}{ 206 "ID": "id", 207 "age": 1, 208 "hasPet": true, 209 "created": 1, 210 "tag": "tag", 211 "updated": 1, 212 } 213 table := New(m, &Options{ 214 Store: fs.NewStore(), 215 Namespace: uuid.Must(uuid.NewV4()).String(), 216 }) 217 218 err := table.Create(map[string]interface{}{ 219 "ID": "1", 220 "Age": 12, 221 }) 222 if err != nil { 223 t.Fatal(err) 224 } 225 err = table.Create(map[string]interface{}{ 226 "ID": "2", 227 "Age": 25, 228 }) 229 if err != nil { 230 t.Fatal(err) 231 } 232 users := []map[string]interface{}{} 233 q := QueryAll() 234 err = table.Read(q, &users) 235 if err != nil { 236 t.Fatal(err) 237 } 238 if len(users) != 2 { 239 t.Fatal(users) 240 } 241 } 242 243 func TestListAllMapCutomID(t *testing.T) { 244 m := map[string]interface{}{ 245 "name": "id", 246 "age": 1, 247 "hasPet": true, 248 "created": 1, 249 "tag": "tag", 250 "updated": 1, 251 } 252 table := New(m, &Options{ 253 Store: fs.NewStore(), 254 Key: "name", 255 Namespace: uuid.Must(uuid.NewV4()).String(), 256 }) 257 258 err := table.Create(map[string]interface{}{ 259 "name": "1", 260 "age": 12, 261 }) 262 if err != nil { 263 t.Fatal(err) 264 } 265 err = table.Create(map[string]interface{}{ 266 "name": "2", 267 "age": 25, 268 }) 269 if err != nil { 270 t.Fatal(err) 271 } 272 users := []map[string]interface{}{} 273 q := QueryAll() 274 err = table.Read(q, &users) 275 if err != nil { 276 t.Fatal(err) 277 } 278 if len(users) != 2 { 279 t.Fatal(users) 280 } 281 } 282 283 func TestListLimitMap(t *testing.T) { 284 ageAsc := ByEquality("age") 285 ageAsc.Order.Type = OrderTypeAsc 286 287 ageDesc := ByEquality("age") 288 ageDesc.Order.Type = OrderTypeDesc 289 290 m := map[string]interface{}{ 291 "ID": "id", 292 "age": 1, 293 "hasPet": true, 294 "created": 1, 295 "tag": "tag", 296 "updated": 1, 297 } 298 table := New(m, &Options{ 299 Store: fs.NewStore(), 300 Indexes: []Index{ageAsc, ageDesc}, 301 Namespace: uuid.Must(uuid.NewV4()).String(), 302 }) 303 304 err := table.Create(map[string]interface{}{ 305 "ID": "1", 306 "age": 12, 307 }) 308 if err != nil { 309 t.Fatal(err) 310 } 311 err = table.Create(map[string]interface{}{ 312 "ID": "2", 313 "age": 25, 314 }) 315 if err != nil { 316 t.Fatal(err) 317 } 318 err = table.Create(map[string]interface{}{ 319 "ID": "3", 320 "age": 35, 321 }) 322 if err != nil { 323 t.Fatal(err) 324 } 325 users := []map[string]interface{}{} 326 q := QueryAll() 327 q.Limit = 1 328 err = table.Read(q, &users) 329 if err != nil { 330 t.Fatal(err) 331 } 332 if len(users) != 1 { 333 t.Fatal(users) 334 } 335 336 q = ageDesc.ToQuery(nil) 337 q.Limit = 1 338 err = table.Read(q, &users) 339 if err != nil { 340 t.Fatal(err) 341 } 342 if len(users) != 1 { 343 t.Fatal(users) 344 } 345 if users[0]["age"].(float64) != 35 { 346 t.Fatal(users[0]) 347 } 348 349 q = ageAsc.ToQuery(nil) 350 q.Limit = 1 351 err = table.Read(q, &users) 352 if err != nil { 353 t.Fatal(err) 354 } 355 if len(users) != 1 { 356 t.Fatal(users) 357 } 358 if users[0]["age"].(float64) != 12 { 359 t.Fatal(users[0]) 360 } 361 } 362 363 // TestNewModel tests the creation using NewModel and Register 364 func TestNewModel(t *testing.T) { 365 // create a new model 366 table := NewModel( 367 WithStore(fs.NewStore()), 368 WithNamespace(uuid.Must(uuid.NewV4()).String()), 369 ) 370 371 // register the instance 372 table.Register(User{}) 373 374 err := table.Create(User{ 375 ID: "1", 376 Age: 12, 377 }) 378 if err != nil { 379 t.Fatal(err) 380 } 381 err = table.Create(User{ 382 ID: "2", 383 Age: 25, 384 }) 385 if err != nil { 386 t.Fatal(err) 387 } 388 users := []User{} 389 q := QueryEquals("ID", "1") 390 q.Order.Type = OrderTypeUnordered 391 err = table.Read(q, &users) 392 if err != nil { 393 t.Fatal(err) 394 } 395 if len(users) != 1 { 396 t.Fatal(users) 397 } 398 } 399 400 func TestRead(t *testing.T) { 401 table := New(User{}, &Options{ 402 Store: fs.NewStore(), 403 Indexes: []Index{ByEquality("age")}, 404 Namespace: uuid.Must(uuid.NewV4()).String(), 405 }) 406 user := User{} 407 // intentionally querying Age to test case tolerance 408 err := table.Read(QueryEquals("Age", 25), &user) 409 if err != ErrorNotFound { 410 t.Fatal(err) 411 } 412 413 // test pointer create 414 err = table.Create(&User{ 415 ID: "1", 416 Age: 25, 417 }) 418 if err != nil { 419 t.Fatal(err) 420 } 421 422 err = table.Read(QueryEquals("age", 25), &user) 423 if err != nil { 424 t.Fatal(err) 425 } 426 if user.ID != "1" { 427 t.Fatal(user) 428 } 429 430 err = table.Create(User{ 431 ID: "2", 432 Age: 25, 433 }) 434 if err != nil { 435 t.Fatal(err) 436 } 437 438 err = table.Read(QueryEquals("age", 25), &user) 439 if err == ErrorMultipleRecordsFound { 440 t.Fatal(err) 441 } 442 } 443 444 func TestQueryEquals(t *testing.T) { 445 table := New(User{}, &Options{ 446 Store: fs.NewStore(), 447 Indexes: []Index{ByEquality("age")}, 448 Namespace: uuid.Must(uuid.NewV4()).String(), 449 }) 450 451 err := table.Create(User{ 452 ID: "1", 453 Age: 12, 454 }) 455 if err != nil { 456 t.Fatal(err) 457 } 458 err = table.Create(User{ 459 ID: "2", 460 Age: 25, 461 }) 462 if err != nil { 463 t.Fatal(err) 464 } 465 err = table.Create(User{ 466 ID: "3", 467 Age: 12, 468 }) 469 if err != nil { 470 t.Fatal(err) 471 } 472 users := []User{} 473 err = table.Read(QueryEquals("age", 12), &users) 474 if err != nil { 475 t.Fatal(err) 476 } 477 if len(users) != 2 { 478 t.Fatal(users) 479 } 480 } 481 482 func reverse(ss []string) { 483 last := len(ss) - 1 484 for i := 0; i < len(ss)/2; i++ { 485 ss[i], ss[last-i] = ss[last-i], ss[i] 486 } 487 } 488 489 func TestOrderingStrings(t *testing.T) { 490 type caze struct { 491 tags []string 492 reverse bool 493 } 494 cazes := []caze{ 495 { 496 tags: []string{"2", "1"}, 497 reverse: false, 498 }, 499 { 500 tags: []string{"2", "1"}, 501 reverse: true, 502 }, 503 { 504 505 tags: []string{"abcd", "abcde", "abcdf"}, 506 reverse: false, 507 }, 508 { 509 tags: []string{"abcd", "abcde", "abcdf"}, 510 reverse: true, 511 }, 512 { 513 tags: []string{"2", "abcd", "abcde", "abcdf", "1"}, 514 reverse: false, 515 }, 516 { 517 tags: []string{"2", "abcd", "abcde", "abcdf", "1"}, 518 reverse: true, 519 }, 520 } 521 for _, c := range cazes { 522 tagIndex := ByEquality("tag") 523 if c.reverse { 524 tagIndex.Order.Type = OrderTypeDesc 525 } 526 tagIndex.StringOrderPadLength = 12 527 table := New(User{}, &Options{ 528 Store: fs.NewStore(), 529 Indexes: []Index{tagIndex}, 530 Namespace: uuid.Must(uuid.NewV4()).String(), 531 }) 532 for _, key := range c.tags { 533 err := table.Create(User{ 534 ID: uuid.Must(uuid.NewV4()).String(), 535 Tag: key, 536 }) 537 if err != nil { 538 t.Fatal(err) 539 } 540 } 541 users := []User{} 542 q := QueryEquals("tag", nil) 543 if c.reverse { 544 q.Order.Type = OrderTypeDesc 545 } 546 err := table.Read(q, &users) 547 if err != nil { 548 t.Fatal(err) 549 } 550 551 tags := sort.StringSlice(c.tags) 552 sort.Sort(tags) 553 if c.reverse { 554 reverse(tags) 555 } 556 if len(tags) != len(users) { 557 t.Fatal(tags, users) 558 } 559 for i, key := range tags { 560 if users[i].Tag != key { 561 userTags := []string{} 562 for _, v := range users { 563 userTags = append(userTags, v.Tag) 564 } 565 t.Fatalf("Should be %v, got %v, is reverse: %v", tags, userTags, c.reverse) 566 } 567 } 568 } 569 570 } 571 572 func reverseInt(is []int) { 573 last := len(is) - 1 574 for i := 0; i < len(is)/2; i++ { 575 is[i], is[last-i] = is[last-i], is[i] 576 } 577 } 578 579 func TestOrderingNumbers(t *testing.T) { 580 type caze struct { 581 dates []int 582 reverse bool 583 } 584 cazes := []caze{ 585 { 586 dates: []int{20, 30}, 587 reverse: false, 588 }, 589 { 590 dates: []int{20, 30}, 591 reverse: true, 592 }, 593 } 594 for _, c := range cazes { 595 createdIndex := ByEquality("created") 596 if c.reverse { 597 createdIndex.Order.Type = OrderTypeDesc 598 } 599 table := New(User{}, &Options{ 600 Store: fs.NewStore(), 601 Indexes: []Index{createdIndex}, 602 Namespace: uuid.Must(uuid.NewV4()).String(), 603 }) 604 for _, key := range c.dates { 605 err := table.Create(User{ 606 ID: uuid.Must(uuid.NewV4()).String(), 607 Created: int64(key), 608 }) 609 if err != nil { 610 t.Fatal(err) 611 } 612 } 613 users := []User{} 614 q := QueryEquals("created", nil) 615 if c.reverse { 616 q.Order.Type = OrderTypeDesc 617 } 618 err := table.Read(q, &users) 619 if err != nil { 620 t.Fatal(err) 621 } 622 623 dates := sort.IntSlice(c.dates) 624 sort.Sort(dates) 625 if c.reverse { 626 reverseInt([]int(dates)) 627 } 628 if len(users) != len(dates) { 629 t.Fatalf("Expected %v, got %v", len(dates), len(users)) 630 } 631 for i, date := range dates { 632 if users[i].Created != int64(date) { 633 userDates := []int{} 634 for _, v := range users { 635 userDates = append(userDates, int(v.Created)) 636 } 637 t.Fatalf("Should be %v, got %v, is reverse: %v", dates, userDates, c.reverse) 638 } 639 } 640 } 641 642 } 643 644 func TestStaleIndexRemoval(t *testing.T) { 645 tagIndex := ByEquality("tag") 646 table := New(User{}, &Options{ 647 Store: fs.NewStore(), 648 Indexes: []Index{tagIndex}, 649 Namespace: uuid.Must(uuid.NewV4()).String(), 650 }) 651 err := table.Create(User{ 652 ID: "1", 653 Tag: "hi-there", 654 }) 655 if err != nil { 656 t.Fatal(err) 657 } 658 err = table.Create(User{ 659 ID: "1", 660 Tag: "hello-there", 661 }) 662 if err != nil { 663 t.Fatal(err) 664 } 665 res := []User{} 666 err = table.Read(QueryEquals("tag", nil), &res) 667 if err != nil { 668 t.Fatal(err) 669 } 670 if len(res) > 1 { 671 t.Fatal(res) 672 } 673 } 674 675 func TestUniqueIndex(t *testing.T) { 676 tagIndex := ByEquality("tag") 677 tagIndex.Unique = true 678 table := New(User{}, &Options{ 679 Store: fs.NewStore(), 680 Indexes: []Index{tagIndex}, 681 Namespace: uuid.Must(uuid.NewV4()).String(), 682 }) 683 err := table.Create(User{ 684 ID: "1", 685 Tag: "hi-there", 686 }) 687 if err != nil { 688 t.Fatal(err) 689 } 690 err = table.Create(User{ 691 ID: "2", 692 Tag: "hello-there", 693 }) 694 if err != nil { 695 t.Fatal(err) 696 } 697 err = table.Create(User{ 698 ID: "3", 699 Tag: "hi-there", 700 }) 701 if err == nil { 702 t.Fatal("Create shoud fail with duplicate tag error because the index is unique") 703 } 704 } 705 706 type Tag struct { 707 Slug string `json:"slug"` 708 Age int `json:"age"` 709 Type string `json:"type"` 710 } 711 712 func TestNonIDKeys(t *testing.T) { 713 table := New(Tag{}, &Options{ 714 Store: fs.NewStore(), 715 Key: "slug", 716 Namespace: uuid.Must(uuid.NewV4()).String(), 717 }) 718 719 err := table.Create(Tag{ 720 Slug: "1", 721 Age: 12, 722 }) 723 if err != nil { 724 t.Fatal(err) 725 } 726 err = table.Create(Tag{ 727 Slug: "2", 728 Age: 25, 729 }) 730 if err != nil { 731 t.Fatal(err) 732 } 733 users := []User{} 734 q := QueryEquals("slug", "1") 735 q.Order.Type = OrderTypeUnordered 736 err = table.Read(q, &users) 737 if err != nil { 738 t.Fatal(err) 739 } 740 if len(users) != 1 { 741 t.Fatal(users) 742 } 743 } 744 745 // This might be an almost duplicate test, I used it to try reproduce an issue 746 // Leaving this here for now as we dont have enough tests anyway. 747 func TestReadByString(t *testing.T) { 748 typeIndex := ByEquality("type") 749 750 table := New(Tag{}, &Options{ 751 Key: "slug", 752 Store: fs.NewStore(), 753 Indexes: []Index{typeIndex}, 754 Debug: false, 755 Namespace: uuid.Must(uuid.NewV4()).String(), 756 }) 757 758 err := table.Create(Tag{ 759 Slug: "1", 760 Type: "post-tag", 761 }) 762 if err != nil { 763 t.Fatal(err) 764 } 765 err = table.Create(Tag{ 766 Slug: "2", 767 Type: "post-tag", 768 }) 769 if err != nil { 770 t.Fatal(err) 771 } 772 tags := []Tag{} 773 q := QueryEquals("type", "post-tag") 774 err = table.Read(q, &tags) 775 if err != nil { 776 t.Fatal(err) 777 } 778 if len(tags) != 2 { 779 t.Fatal(tags) 780 } 781 } 782 783 func TestOderByDifferentFieldThanFilterField(t *testing.T) { 784 typeIndex := ByEquality("type") 785 typeIndex.Order = Order{ 786 Type: OrderTypeDesc, 787 FieldName: "age", 788 } 789 790 table := New(Tag{}, &Options{ 791 Key: "slug", 792 Store: fs.NewStore(), 793 Indexes: []Index{typeIndex}, 794 Namespace: uuid.Must(uuid.NewV4()).String(), 795 Debug: false, 796 }) 797 798 err := table.Create(Tag{ 799 Slug: "1", 800 Type: "post-tag", 801 Age: 15, 802 }) 803 if err != nil { 804 t.Fatal(err) 805 } 806 err = table.Create(Tag{ 807 Slug: "2", 808 Type: "post-tag", 809 Age: 25, 810 }) 811 if err != nil { 812 t.Fatal(err) 813 } 814 err = table.Create(Tag{ 815 Slug: "3", 816 Type: "other-tag", 817 Age: 30, 818 }) 819 if err != nil { 820 t.Fatal(err) 821 } 822 tags := []Tag{} 823 err = table.Read(typeIndex.ToQuery("post-tag"), &tags) 824 if err != nil { 825 t.Fatal(err) 826 } 827 if len(tags) != 2 { 828 t.Fatal(tags) 829 } 830 if tags[0].Age != 25 { 831 t.Fatal(tags) 832 } 833 if tags[1].Age != 15 { 834 t.Fatal(tags) 835 } 836 837 err = table.Read(typeIndex.ToQuery(nil), &tags) 838 if err != nil { 839 t.Fatal(err) 840 } 841 if len(tags) != 3 { 842 t.Fatal(tags) 843 } 844 } 845 846 func TestDeleteIndexCleanup(t *testing.T) { 847 slugIndex := ByEquality("slug") 848 slugIndex.Order.Type = OrderTypeUnordered 849 850 typeIndex := ByEquality("type") 851 852 table := New(Tag{}, &Options{ 853 Key: "slug", 854 Store: fs.NewStore(), 855 Indexes: []Index{typeIndex}, 856 Namespace: uuid.Must(uuid.NewV4()).String(), 857 Debug: false, 858 }) 859 860 err := table.Create(Tag{ 861 Slug: "1", 862 Type: "post-tag", 863 }) 864 if err != nil { 865 t.Fatal(err) 866 } 867 err = table.Create(Tag{ 868 Slug: "2", 869 Type: "post-tag", 870 }) 871 if err != nil { 872 t.Fatal(err) 873 } 874 tags := []Tag{} 875 q := QueryEquals("type", "post-tag") 876 err = table.Read(q, &tags) 877 if err != nil { 878 t.Fatal(err) 879 } 880 if len(tags) != 2 { 881 t.Fatal(tags) 882 } 883 884 err = table.Delete(slugIndex.ToQuery("1")) 885 if err != nil { 886 t.Fatal(err) 887 } 888 889 q = QueryEquals("type", "post-tag") 890 err = table.Read(q, &tags) 891 if err != nil { 892 t.Fatal(err) 893 } 894 if len(tags) != 1 { 895 t.Fatal(tags) 896 } 897 } 898 899 func TestDeleteByUnmatchingIndex(t *testing.T) { 900 table := New(User{}, &Options{ 901 Store: fs.NewStore(), 902 Namespace: uuid.Must(uuid.NewV4()).String(), 903 Debug: false, 904 }) 905 906 err := table.Create(User{ 907 ID: "1", 908 Age: 20, 909 }) 910 if err != nil { 911 t.Fatal(err) 912 } 913 err = table.Create(User{ 914 ID: "2", 915 Age: 30, 916 }) 917 if err != nil { 918 t.Fatal(err) 919 } 920 921 err = table.Delete(QueryEquals("ID", "1")) 922 if err != nil { 923 t.Fatal(err) 924 } 925 t.Run("Test read by unspecified index", func(t *testing.T) { 926 users := []User{} 927 err = table.Read(QueryEquals("ID", "1"), &users) 928 if err != nil { 929 t.Fatal(err) 930 } 931 if len(users) != 0 { 932 t.Fatal(users) 933 } 934 err = table.Read(QueryEquals("ID", "2"), &users) 935 if err != nil { 936 t.Fatal(err) 937 } 938 if len(users) != 1 { 939 t.Fatal(users) 940 } 941 }) 942 } 943 944 func TestDeleteByUnmatchingIndexMap(t *testing.T) { 945 table := New(map[string]interface{}{}, &Options{ 946 Store: fs.NewStore(), 947 Namespace: uuid.Must(uuid.NewV4()).String(), 948 Debug: false, 949 }) 950 951 err := table.Create(map[string]interface{}{ 952 "ID": "1", 953 "Age": 20, 954 }) 955 if err != nil { 956 t.Fatal(err) 957 } 958 err = table.Create(map[string]interface{}{ 959 "ID": "2", 960 "Age": 30, 961 }) 962 if err != nil { 963 t.Fatal(err) 964 } 965 966 err = table.Delete(QueryEquals("ID", "1")) 967 if err != nil { 968 t.Fatal(err) 969 } 970 t.Run("Test read by unspecified index", func(t *testing.T) { 971 users := []map[string]interface{}{} 972 err = table.Read(QueryEquals("ID", "1"), &users) 973 if err != nil { 974 t.Fatal(err) 975 } 976 if len(users) != 0 { 977 t.Fatal(users) 978 } 979 err = table.Read(QueryEquals("ID", "2"), &users) 980 if err != nil { 981 t.Fatal(err) 982 } 983 if len(users) != 1 { 984 t.Fatal(users) 985 } 986 }) 987 } 988 989 func TestUpdateDeleteIndexMaintenance(t *testing.T) { 990 updIndex := ByEquality("updated") 991 updIndex.Order.Type = OrderTypeDesc 992 993 table := New(User{}, &Options{ 994 Store: fs.NewStore(), 995 Indexes: []Index{updIndex}, 996 Namespace: uuid.Must(uuid.NewV4()).String(), 997 Debug: false, 998 }) 999 1000 err := table.Create(User{ 1001 ID: "1", 1002 Age: 12, 1003 Updated: 5000, 1004 }) 1005 if err != nil { 1006 t.Fatal(err) 1007 } 1008 1009 err = table.Create(User{ 1010 ID: "2", 1011 Age: 25, 1012 Updated: 5001, 1013 }) 1014 if err != nil { 1015 t.Fatal(err) 1016 } 1017 users := []User{} 1018 q := updIndex.ToQuery(nil) 1019 err = table.Read(q, &users) 1020 if err != nil { 1021 t.Fatal(err) 1022 } 1023 if len(users) != 2 { 1024 t.Fatal(users) 1025 } 1026 if users[0].ID != "2" || users[1].ID != "1" { 1027 t.Fatal(users) 1028 } 1029 1030 err = table.Create(User{ 1031 ID: "1", 1032 Age: 12, 1033 Updated: 5002, 1034 }) 1035 if err != nil { 1036 t.Fatal(err) 1037 } 1038 1039 err = table.Read(q, &users) 1040 if err != nil { 1041 t.Fatal(err) 1042 } 1043 if len(users) != 2 { 1044 t.Fatal(users) 1045 } 1046 if users[0].ID != "1" || users[1].ID != "2" { 1047 t.Fatal(users) 1048 } 1049 } 1050 1051 func TestUpdateDeleteIndexMaintenanceMap(t *testing.T) { 1052 updIndex := ByEquality("Updated") 1053 updIndex.Order.Type = OrderTypeDesc 1054 1055 table := New(map[string]interface{}{}, &Options{ 1056 Store: fs.NewStore(), 1057 Indexes: []Index{updIndex}, 1058 Namespace: uuid.Must(uuid.NewV4()).String(), 1059 Debug: false, 1060 }) 1061 1062 err := table.Create(map[string]interface{}{ 1063 "ID": "1", 1064 "Age": "12", 1065 "Updated": "5000", 1066 }) 1067 if err != nil { 1068 t.Fatal(err) 1069 } 1070 1071 err = table.Create(map[string]interface{}{ 1072 "ID": "2", 1073 "Age": "25", 1074 "Updated": "5001", 1075 }) 1076 if err != nil { 1077 t.Fatal(err) 1078 } 1079 users := []map[string]interface{}{} 1080 q := updIndex.ToQuery(nil) 1081 err = table.Read(q, &users) 1082 if err != nil { 1083 t.Fatal(err) 1084 } 1085 if len(users) != 2 { 1086 t.Fatal(users) 1087 } 1088 if users[0]["ID"] != "2" || users[1]["ID"] != "1" { 1089 t.Fatal(users) 1090 } 1091 1092 err = table.Create(map[string]interface{}{ 1093 "ID": "1", 1094 "Age": "12", 1095 "Updated": "5002", 1096 }) 1097 if err != nil { 1098 t.Fatal(err) 1099 } 1100 1101 err = table.Read(q, &users) 1102 if err != nil { 1103 t.Fatal(err) 1104 } 1105 if len(users) != 2 { 1106 t.Fatal(users) 1107 } 1108 if users[0]["ID"] != "1" || users[1]["ID"] != "2" { 1109 t.Fatal(users) 1110 } 1111 } 1112 1113 type TypeTest struct { 1114 ID string `json:"ID"` 1115 F32 float32 1116 F64 float64 1117 I int 1118 I32 int32 1119 I64 int64 1120 S string 1121 B bool 1122 } 1123 1124 // Test aimed specifically to test all types 1125 func TestAllCombos(t *testing.T) { 1126 // go over all filter + order combos 1127 // for equality indexing 1128 1129 v := reflect.ValueOf(TypeTest{}) 1130 for filterFieldI := 0; filterFieldI < v.NumField(); filterFieldI++ { 1131 filterField := v.Field(filterFieldI) 1132 for orderFieldI := 0; orderFieldI < v.NumField(); orderFieldI++ { 1133 orderField := v.Field(orderFieldI) 1134 1135 filterFieldName := v.Type().Field(filterFieldI).Name 1136 orderFieldName := v.Type().Field(orderFieldI).Name 1137 if filterFieldName == "ID" || orderFieldName == "ID" { 1138 continue 1139 } 1140 if filterFieldName == orderFieldName { 1141 continue 1142 } 1143 1144 t.Run(fmt.Sprintf("Filter by %v, order by %v ASC", filterField.Type().Name(), orderField.Type().Name()), func(t *testing.T) { 1145 index := ByEquality(filterFieldName) 1146 index.Order.Type = OrderTypeAsc 1147 index.Order.FieldName = orderFieldName 1148 1149 table := New(TypeTest{}, &Options{ 1150 Store: fs.NewStore(), 1151 Indexes: []Index{index}, 1152 Namespace: uuid.Must(uuid.NewV4()).String(), 1153 Debug: false, 1154 }) 1155 1156 small := TypeTest{ 1157 ID: "1", 1158 } 1159 v1 := getExampleValue(table.(*model).getFieldValue(small, orderFieldName), 1) 1160 table.(*model).setFieldValue(&small, orderFieldName, v1) 1161 1162 large := TypeTest{ 1163 ID: "2", 1164 } 1165 v2 := getExampleValue(table.(*model).getFieldValue(large, orderFieldName), 2) 1166 table.(*model).setFieldValue(&large, orderFieldName, v2) 1167 1168 err := table.Create(small) 1169 if err != nil { 1170 t.Fatal(err) 1171 } 1172 err = table.Create(large) 1173 if err != nil { 1174 t.Fatal(err) 1175 } 1176 results := []TypeTest{} 1177 err = table.Read(QueryEquals(filterFieldName, nil), &results) 1178 if err != nil { 1179 t.Fatal(err) 1180 } 1181 if len(results) < 2 { 1182 t.Fatal(results) 1183 } 1184 if results[0].ID != "1" || results[1].ID != "2" { 1185 t.Fatal("Results:", results, results[0].ID, results[1].ID) 1186 } 1187 }) 1188 t.Run(fmt.Sprintf("Filter by %v, order by %v DESC", filterField.Type().Name(), orderField.Type().Name()), func(t *testing.T) { 1189 index := ByEquality(filterFieldName) 1190 index.Order.Type = OrderTypeDesc 1191 index.Order.FieldName = orderFieldName 1192 1193 table := New(TypeTest{}, &Options{ 1194 Store: fs.NewStore(), 1195 Indexes: []Index{index}, 1196 Namespace: uuid.Must(uuid.NewV4()).String(), 1197 Debug: false, 1198 }) 1199 1200 small := TypeTest{ 1201 ID: "1", 1202 } 1203 v1 := getExampleValue(table.(*model).getFieldValue(small, orderFieldName), 1) 1204 table.(*model).setFieldValue(&small, orderFieldName, v1) 1205 1206 large := TypeTest{ 1207 ID: "2", 1208 } 1209 v2 := getExampleValue(table.(*model).getFieldValue(large, orderFieldName), 2) 1210 table.(*model).setFieldValue(&large, orderFieldName, v2) 1211 1212 err := table.Create(small) 1213 if err != nil { 1214 t.Fatal(err) 1215 } 1216 err = table.Create(large) 1217 if err != nil { 1218 t.Fatal(err) 1219 } 1220 results := []TypeTest{} 1221 err = table.Read(index.ToQuery(nil), &results) 1222 if err != nil { 1223 t.Fatal(err) 1224 } 1225 if len(results) < 2 { 1226 t.Fatal(results) 1227 } 1228 if results[0].ID != "2" || results[1].ID != "1" { 1229 t.Fatal("Results:", results, results[0].ID, results[1].ID) 1230 } 1231 }) 1232 } 1233 } 1234 } 1235 1236 // returns an example value generated 1237 // nth = each successive number should cause this 1238 // function to return a "bigger value" for each type 1239 func getExampleValue(i interface{}, nth int) interface{} { 1240 switch v := i.(type) { 1241 case string: 1242 return strings.Repeat("a", nth) 1243 case bool: 1244 if nth == 1 { 1245 return false 1246 } 1247 return true 1248 case float32: 1249 return v + float32(nth) + .1 1250 case float64: 1251 return v + float64(nth) + 0.1 1252 case int: 1253 return v + nth 1254 case int32: 1255 return v + int32(nth) 1256 case int64: 1257 return v + int64(nth) 1258 } 1259 return nil 1260 }