github.com/go-generalize/volcago@v1.7.0/generator/testfiles/auto/tests/model_test.go (about) 1 //go:build internal 2 // +build internal 3 4 package tests 5 6 import ( 7 "context" 8 "fmt" 9 "os" 10 "reflect" 11 "strings" 12 "testing" 13 "time" 14 15 "cloud.google.com/go/firestore" 16 model "github.com/go-generalize/volcago/generator/testfiles/auto" 17 "golang.org/x/xerrors" 18 ) 19 20 var desc = "Hello, World!" 21 22 func initFirestoreClient(t *testing.T) *firestore.Client { 23 t.Helper() 24 25 if os.Getenv("FIRESTORE_EMULATOR_HOST") == "" { 26 os.Setenv("FIRESTORE_EMULATOR_HOST", "localhost:8000") 27 } 28 29 if os.Getenv("FIRESTORE_PROJECT_ID") == "" { 30 os.Setenv("FIRESTORE_PROJECT_ID", "project-id-in-google") 31 } 32 33 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 34 defer cancel() 35 36 client, err := firestore.NewClient(ctx, os.Getenv("FIRESTORE_PROJECT_ID")) 37 38 if err != nil { 39 t.Fatalf("failed to initialize firestore client: %+v", err) 40 } 41 42 return client 43 } 44 45 func compareTask(t *testing.T, expected, actual *model.Task) { 46 t.Helper() 47 48 if actual.ID != expected.ID { 49 t.Fatalf("unexpected identity: %s (expected: %s)", actual.ID, expected.ID) 50 } 51 52 if !actual.Created.Equal(expected.Created) { 53 t.Fatalf("unexpected time: %s(expected: %s)", actual.Created, expected.Created) 54 } 55 56 if actual.Desc != expected.Desc { 57 t.Fatalf("unexpected desc: %s(expected: %s)", actual.Desc, expected.Created) 58 } 59 60 if actual.Done != expected.Done { 61 t.Fatalf("unexpected done: %v(expected: %v)", actual.Done, expected.Done) 62 } 63 } 64 65 func TestFirestore(t *testing.T) { 66 client := initFirestoreClient(t) 67 68 taskRepo := model.NewTaskRepository(client) 69 70 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 71 var ids []string 72 defer func() { 73 defer cancel() 74 if err := taskRepo.DeleteMultiByIDs(ctx, ids); err != nil { 75 t.Fatal(err) 76 } 77 }() 78 79 now := time.Unix(0, time.Now().UnixNano()).UTC() 80 81 t.Run("Multi", func(tr *testing.T) { 82 tks := make([]*model.Task, 0) 83 for i := int64(1); i <= 10; i++ { 84 tk := &model.Task{ 85 Desc: fmt.Sprintf("%s%d", desc, i), 86 Created: now, 87 Done: true, 88 Done2: false, 89 Count: int(i), 90 Count64: 0, 91 Proportion: 0.12345 + float64(i), 92 NameList: []string{"a", "b", "c"}, 93 Flag: map[string]float64{ 94 "1": 1.1, 95 "2": 2.2, 96 "3": 3.3, 97 }, 98 } 99 tks = append(tks, tk) 100 } 101 idList, err := taskRepo.InsertMulti(ctx, tks) 102 if err != nil { 103 tr.Fatalf("%+v", err) 104 } 105 ids = append(ids, idList...) 106 107 tks2 := make([]*model.Task, 0) 108 for i := int64(1); i <= 10; i++ { 109 tk := &model.Task{ 110 ID: ids[i-1], 111 Desc: fmt.Sprintf("%s%d", desc, i), 112 Created: now, 113 Done: true, 114 Done2: false, 115 Count: int(i), 116 Count64: i, 117 Proportion: 0.12345 + float64(i), 118 NameList: []string{"a", "b", "c"}, 119 Flag: map[string]float64{ 120 "4": 4.4, 121 "5": 5.5, 122 "6": 6.6, 123 }, 124 } 125 tks2 = append(tks2, tk) 126 } 127 if err := taskRepo.UpdateMulti(ctx, tks2); err != nil { 128 tr.Fatalf("%+v", err) 129 } 130 131 if tks[0].ID != tks2[0].ID { 132 tr.Fatalf("unexpected identity: %s (expected: %s)", tks[0].ID, tks2[0].ID) 133 } 134 }) 135 136 t.Run("Single", func(tr *testing.T) { 137 tk := &model.Task{ 138 Desc: fmt.Sprintf("%s%d", desc, 1001), 139 Created: now, 140 Done: true, 141 Done2: false, 142 Count: 11, 143 Count64: 11, 144 Proportion: 11.12345, 145 NameList: []string{"a", "b", "c"}, 146 Flag: map[string]float64{ 147 "1": 1.1, 148 "2": 2.2, 149 "3": 3.3, 150 }, 151 } 152 id, err := taskRepo.Insert(ctx, tk) 153 if err != nil { 154 tr.Fatalf("%+v", err) 155 } 156 ids = append(ids, id) 157 158 tk.Count++ 159 tk.Flag["4"] = 4.4 160 if err = taskRepo.Update(ctx, tk); err != nil { 161 tr.Fatalf("%+v", err) 162 } 163 164 tsk, err := taskRepo.Get(ctx, tk.ID) 165 if err != nil { 166 tr.Fatalf("%+v", err) 167 } 168 169 if tsk.Count != 12 { 170 tr.Fatalf("unexpected Count: %d (expected: %d)", tsk.Count, 12) 171 } 172 173 if _, ok := tsk.Flag["4"]; !ok { 174 tr.Fatalf("unexpected Flag: %v (expected: %v)", ok, true) 175 } 176 177 tr.Run("UpdateBuilder", func(ttr *testing.T) { 178 desc1002 := fmt.Sprintf("%s%d", desc, 1002) 179 180 updateParam := &model.TaskUpdateParam{ 181 Desc: desc1002, 182 Created: firestore.ServerTimestamp, 183 Done: false, 184 Count: firestore.Increment(1), 185 Count64: firestore.Increment(2), 186 Proportion: firestore.Increment(0.1), 187 } 188 189 if err = taskRepo.StrictUpdate(ctx, tsk.ID, updateParam); err != nil { 190 ttr.Fatalf("%+v", err) 191 } 192 193 tsk, err = taskRepo.Get(ctx, tk.ID) 194 if err != nil { 195 ttr.Fatalf("%+v", err) 196 } 197 198 if tsk.Desc != desc1002 { 199 ttr.Fatalf("unexpected Desc: %s (expected: %s)", tsk.Desc, desc1002) 200 } 201 202 if tsk.Created.Before(now) { 203 ttr.Fatalf("unexpected Created > now: %t (expected: %t)", tsk.Created.Before(now), tsk.Created.After(now)) 204 } 205 206 if tsk.Done { 207 ttr.Fatalf("unexpected Done: %t (expected: %t)", tsk.Done, false) 208 } 209 210 if tsk.Count != 13 { 211 ttr.Fatalf("unexpected Count: %d (expected: %d)", tsk.Count, 13) 212 } 213 214 if tsk.Count64 != 13 { 215 ttr.Fatalf("unexpected Count64: %d (expected: %d)", tsk.Count64, 13) 216 } 217 218 if tsk.Proportion != 11.22345 { 219 ttr.Fatalf("unexpected Proportion: %g (expected: %g)", tsk.Proportion, 11.22345) 220 } 221 }) 222 223 tr.Run("ParentDocWithNewInstance", func(ttr *testing.T) { 224 subTask := &model.SubCollection{ 225 Flag: true, 226 } 227 228 subTaskRepo := model.NewSubCollectionRepository(client, nil). 229 NewRepositoryByParent(taskRepo.GetDocRef(id)) 230 id, err := subTaskRepo.Insert(ctx, subTask) 231 if err != nil { 232 ttr.Fatalf("unexpected err: %+v", err) 233 } 234 gotSubTask, err := subTaskRepo.Get(ctx, id) 235 if err != nil { 236 ttr.Fatalf("unexpected err: %+v", err) 237 } 238 if subTask.Flag != gotSubTask.Flag { 239 ttr.Fatal("wrong model") 240 } 241 }) 242 }) 243 } 244 245 func TestFirestoreTransaction_Single(t *testing.T) { 246 client := initFirestoreClient(t) 247 248 taskRepo := model.NewTaskRepository(client) 249 250 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 251 var ids []string 252 defer func() { 253 defer cancel() 254 if err := taskRepo.DeleteMultiByIDs(ctx, ids); err != nil { 255 t.Fatal(err) 256 } 257 }() 258 259 now := time.Unix(0, time.Now().UnixNano()) 260 261 t.Run("Insert", func(tr *testing.T) { 262 err := client.RunTransaction(ctx, func(cx context.Context, tx *firestore.Transaction) error { 263 tk := &model.Task{ 264 Desc: fmt.Sprintf("%s01", desc), 265 Created: now, 266 Done: true, 267 Done2: false, 268 Count: 10, 269 Count64: 11, 270 Proportion: 11.12345, 271 NameList: []string{"a", "b", "c"}, 272 Flag: map[string]float64{ 273 "1": 1.1, 274 "2": 2.2, 275 "3": 3.3, 276 }, 277 } 278 279 id, err := taskRepo.InsertWithTx(cx, tx, tk) 280 if err != nil { 281 return err 282 } 283 284 ids = append(ids, id) 285 return nil 286 }) 287 288 if err != nil { 289 tr.Fatalf("error: %+v", err) 290 } 291 292 tsk, err := taskRepo.Get(ctx, ids[len(ids)-1]) 293 if err != nil { 294 tr.Fatalf("%+v", err) 295 } 296 297 if tsk.Count != 10 { 298 tr.Fatalf("unexpected Count: %d (expected: %d)", tsk.Count, 10) 299 } 300 }) 301 302 t.Run("Update", func(tr *testing.T) { 303 tkID := ids[len(ids)-1] 304 err := client.RunTransaction(ctx, func(cx context.Context, tx *firestore.Transaction) error { 305 tk, err := taskRepo.GetWithTx(tx, tkID) 306 if err != nil { 307 return err 308 } 309 310 if tk.Count != 10 { 311 return fmt.Errorf("unexpected Count: %d (expected: %d)", tk.Count, 10) 312 } 313 314 tk.Count = 11 315 if err = taskRepo.UpdateWithTx(cx, tx, tk); err != nil { 316 return err 317 } 318 return nil 319 }) 320 321 if err != nil { 322 tr.Fatalf("error: %+v", err) 323 } 324 325 tsk, err := taskRepo.Get(ctx, tkID) 326 if err != nil { 327 tr.Fatalf("%+v", err) 328 } 329 330 if tsk.Count != 11 { 331 tr.Fatalf("unexpected Count: %d (expected: %d)", tsk.Count, 11) 332 } 333 }) 334 335 t.Run("UseUpdateBuilder", func(tr *testing.T) { 336 tkID := ids[len(ids)-1] 337 desc1002 := fmt.Sprintf("%s%d", desc, 1002) 338 err := client.RunTransaction(ctx, func(cx context.Context, tx *firestore.Transaction) error { 339 tk, err := taskRepo.GetWithTx(tx, tkID) 340 if err != nil { 341 return err 342 } 343 344 if tk.Count != 11 { 345 return fmt.Errorf("unexpected Count: %d (expected: %d)", tk.Count, 11) 346 } 347 348 updateParam := &model.TaskUpdateParam{ 349 Desc: desc1002, 350 Created: firestore.ServerTimestamp, 351 Done: false, 352 Count: firestore.Increment(1), 353 Count64: firestore.Increment(2), 354 Proportion: firestore.Increment(0.1), 355 } 356 if err = taskRepo.StrictUpdateWithTx(tx, tk.ID, updateParam); err != nil { 357 return err 358 } 359 return nil 360 }) 361 362 if err != nil { 363 tr.Fatalf("error: %+v", err) 364 } 365 366 tsk, err := taskRepo.Get(ctx, tkID) 367 if err != nil { 368 tr.Fatalf("%+v", err) 369 } 370 371 if tsk.Desc != desc1002 { 372 tr.Fatalf("unexpected Desc: %s (expected: %s)", tsk.Desc, desc1002) 373 } 374 375 if tsk.Created.Before(now) { 376 tr.Fatalf("unexpected Created > now: %t (expected: %t)", tsk.Created.Before(now), tsk.Created.After(now)) 377 } 378 379 if tsk.Done { 380 tr.Fatalf("unexpected Done: %t (expected: %t)", tsk.Done, false) 381 } 382 383 if tsk.Count != 12 { 384 tr.Fatalf("unexpected Count: %d (expected: %d)", tsk.Count, 12) 385 } 386 387 if tsk.Count64 != 13 { 388 tr.Fatalf("unexpected Count64: %d (expected: %d)", tsk.Count64, 13) 389 } 390 391 if tsk.Proportion != 11.22345 { 392 tr.Fatalf("unexpected Proportion: %g (expected: %g)", tsk.Proportion, 11.22345) 393 } 394 }) 395 } 396 397 func TestFirestoreTransaction_Multi(t *testing.T) { 398 client := initFirestoreClient(t) 399 400 taskRepo := model.NewTaskRepository(client) 401 402 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 403 var ids []string 404 defer func() { 405 defer cancel() 406 if err := taskRepo.DeleteMultiByIDs(ctx, ids); err != nil { 407 t.Fatal(err) 408 } 409 }() 410 411 now := time.Unix(0, time.Now().UnixNano()) 412 413 tks := make([]*model.Task, 0) 414 t.Run("InsertMulti", func(tr *testing.T) { 415 for i := int64(1); i <= 10; i++ { 416 tk := &model.Task{ 417 ID: fmt.Sprintf("Task_%d", i), 418 Desc: fmt.Sprintf("%s%d", desc, i), 419 Created: now, 420 Done: true, 421 Done2: false, 422 Count: int(i), 423 Count64: 0, 424 NameList: []string{"a", "b", "c"}, 425 Proportion: 0.12345 + float64(i), 426 Flag: map[string]float64{ 427 "1": 1.1, 428 "2": 2.2, 429 "3": 3.3, 430 }, 431 } 432 tks = append(tks, tk) 433 } 434 435 if err := client.RunTransaction(ctx, func(cx context.Context, tx *firestore.Transaction) error { 436 idList, err := taskRepo.InsertMultiWithTx(ctx, tx, tks) 437 if err != nil { 438 return err 439 } 440 ids = append(ids, idList...) 441 return nil 442 }); err != nil { 443 tr.Fatalf("error: %+v", err) 444 } 445 }) 446 447 tks2 := make([]*model.Task, 0) 448 t.Run("UpdateMulti", func(tr *testing.T) { 449 for i := int64(1); i <= 10; i++ { 450 tk := &model.Task{ 451 ID: ids[i-1], 452 Desc: fmt.Sprintf("%s%d", desc, i+1), 453 Created: now, 454 Done: false, 455 Done2: true, 456 Count: int(i), 457 Count64: i, 458 NameList: []string{"a", "b", "c"}, 459 Proportion: 0.12345 + float64(i), 460 Flag: map[string]float64{ 461 "1": 1.1, 462 "2": 2.2, 463 "3": 3.3, 464 }, 465 } 466 tks2 = append(tks2, tk) 467 } 468 469 if err := client.RunTransaction(ctx, func(cx context.Context, tx *firestore.Transaction) error { 470 if err := taskRepo.UpdateMultiWithTx(cx, tx, tks2); err != nil { 471 return err 472 } 473 return nil 474 }); err != nil { 475 tr.Fatalf("error: %+v", err) 476 } 477 478 if tks[0].ID != tks2[0].ID { 479 tr.Fatalf("unexpected identity: %s (expected: %s)", tks[0].ID, tks2[0].ID) 480 } 481 }) 482 } 483 484 func TestFirestoreQuery(t *testing.T) { 485 client := initFirestoreClient(t) 486 487 taskRepo := model.NewTaskRepository(client) 488 489 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 490 var ids []string 491 defer func() { 492 defer cancel() 493 if err := taskRepo.DeleteMultiByIDs(ctx, ids); err != nil { 494 t.Fatalf("%+v\n", err) 495 } 496 }() 497 498 now := time.Unix(0, time.Now().UnixNano()) 499 500 tks := make([]*model.Task, 0) 501 for i := 1; i <= 10; i++ { 502 tk := &model.Task{ 503 ID: fmt.Sprintf("%d", i), 504 Desc: fmt.Sprintf("%s%d", desc, i), 505 Created: now.Add(time.Millisecond * time.Duration(i)), 506 Done: true, 507 Done2: false, 508 Count: i, 509 Count64: int64(i), 510 NameList: []string{"a", "b", "c"}, 511 Proportion: 0.12345 + float64(i), 512 Flag: map[string]float64{ 513 "1": 1.1, 514 "2": 2.2, 515 "3": 3.3, 516 "4": 4.4, 517 "5": 5.5, 518 }, 519 SliceSubTask: []*model.SubTask{ 520 { 521 Name: "slice_nested", 522 }, 523 }, 524 } 525 tks = append(tks, tk) 526 } 527 ids, err := taskRepo.InsertMulti(ctx, tks) 528 if err != nil { 529 t.Fatalf("%+v", err) 530 } 531 532 t.Run("Paging", func(tr *testing.T) { 533 param := &model.TaskSearchParam{ 534 Done: model.NewQueryChainer().Equal(true), 535 CursorLimit: 8, 536 } 537 538 tasks, pagingResult, err := taskRepo.SearchByParam(ctx, param) 539 if err != nil { 540 tr.Fatalf("%+v", err) 541 } 542 543 if len(tasks) != 8 && pagingResult.Length == len(tasks) { 544 tr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 8) 545 } 546 547 param = &model.TaskSearchParam{ 548 Done: model.NewQueryChainer().Equal(true), 549 CursorLimit: 5, 550 CursorKey: pagingResult.NextCursorKey, 551 } 552 553 tasks, pagingResult, err = taskRepo.SearchByParam(ctx, param) 554 if err != nil { 555 tr.Fatalf("%+v", err) 556 } 557 558 if len(tasks) != 2 && pagingResult.Length == len(tasks) { 559 tr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 2) 560 } 561 }) 562 563 t.Run("Paging", func(tr *testing.T) { 564 param := &model.TaskSearchParam{ 565 Done: model.NewQueryChainer().Equal(true), 566 CursorLimit: 30, 567 } 568 569 tasks, _, err := taskRepo.SearchByParam(ctx, param) 570 if err != nil { 571 tr.Fatalf("%+v", err) 572 } 573 574 if len(tasks) != 10 { 575 tr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 10) 576 } 577 }) 578 579 t.Run("document id(1件)", func(tr *testing.T) { 580 param := &model.TaskSearchParam{ 581 ID: model.NewQueryChainer().Equal(ids[0]), 582 } 583 584 tasks, err := taskRepo.Search(ctx, param, nil) 585 if err != nil { 586 tr.Fatalf("%+v", err) 587 } 588 589 if len(tasks) != 1 { 590 tr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 1) 591 } 592 }) 593 t.Run("document id for IN(3件)", func(tr *testing.T) { 594 param := &model.TaskSearchParam{ 595 ID: model.NewQueryChainer().In([]string{ids[0], ids[1], ids[2]}), 596 } 597 598 tasks, err := taskRepo.Search(ctx, param, nil) 599 if err != nil { 600 tr.Fatalf("%+v", err) 601 } 602 603 if len(tasks) != 3 { 604 tr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 3) 605 } 606 }) 607 t.Run("document id for NOT IN(7件)", func(tr *testing.T) { 608 param := &model.TaskSearchParam{ 609 ID: model.NewQueryChainer().NotIn([]string{ids[0], ids[1], ids[2]}), 610 } 611 612 tasks, err := taskRepo.Search(ctx, param, nil) 613 if err != nil { 614 tr.Fatalf("%+v", err) 615 } 616 617 if len(tasks) != 7 { 618 tr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 7) 619 } 620 }) 621 622 t.Run("int(1件)", func(tr *testing.T) { 623 param := &model.TaskSearchParam{ 624 Count: model.NewQueryChainer().Equal(1), 625 } 626 627 tasks, err := taskRepo.Search(ctx, param, nil) 628 if err != nil { 629 tr.Fatalf("%+v", err) 630 } 631 632 if len(tasks) != 1 { 633 tr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 1) 634 } 635 }) 636 637 t.Run("int64(5件)", func(tr *testing.T) { 638 param := &model.TaskSearchParam{ 639 Count64: model.NewQueryChainer().LessThanOrEqual(5), 640 } 641 642 tasks, err := taskRepo.Search(ctx, param, nil) 643 if err != nil { 644 tr.Fatalf("%+v", err) 645 } 646 647 if len(tasks) != 5 { 648 tr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 5) 649 } 650 }) 651 652 t.Run("float(1件)", func(tr *testing.T) { 653 param := &model.TaskSearchParam{ 654 Proportion: model.NewQueryChainer().Equal(1.12345), 655 } 656 657 tasks, err := taskRepo.Search(ctx, param, nil) 658 if err != nil { 659 tr.Fatalf("%+v", err) 660 } 661 662 if len(tasks) != 1 { 663 tr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 1) 664 } 665 }) 666 667 t.Run("bool(10件)", func(tr *testing.T) { 668 param := &model.TaskSearchParam{ 669 Done: model.NewQueryChainer().Equal(true), 670 } 671 672 tasks, err := taskRepo.Search(ctx, param, nil) 673 if err != nil { 674 tr.Fatalf("%+v", err) 675 } 676 677 if len(tasks) != 10 { 678 tr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 10) 679 } 680 }) 681 682 t.Run("time.Time(1件)", func(tr *testing.T) { 683 param := &model.TaskSearchParam{ 684 Created: model.NewQueryChainer().Equal(now.Add(time.Millisecond)), 685 } 686 687 tasks, err := taskRepo.Search(ctx, param, nil) 688 if err != nil { 689 tr.Fatalf("%+v", err) 690 } 691 692 if len(tasks) != 1 { 693 tr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 1) 694 } 695 }) 696 697 t.Run("[]string(10件)", func(tr *testing.T) { 698 param := &model.TaskSearchParam{ 699 NameList: model.NewQueryChainer().ArrayContainsAny([]string{"a", "b"}), 700 } 701 702 tasks, err := taskRepo.Search(ctx, param, nil) 703 if err != nil { 704 tr.Fatalf("%+v", err) 705 } 706 707 if len(tasks) != 10 { 708 tr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 10) 709 } 710 }) 711 712 t.Run("[]Object(10件)", func(tr *testing.T) { 713 param := &model.TaskSearchParam{ 714 SliceSubTask: model.NewQueryChainer().ArrayContainsAny([]*model.SubTask{{Name: "slice_struct"}}), 715 } 716 717 tasks, err := taskRepo.Search(ctx, param, nil) 718 if err != nil { 719 tr.Fatalf("%+v", err) 720 } 721 722 if len(tasks) != 10 { 723 tr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 10) 724 } 725 }) 726 727 t.Run("[]Object(0件)", func(tr *testing.T) { 728 param := &model.TaskSearchParam{ 729 SliceSubTask: model.NewQueryChainer().ArrayContains("slice_struct"), 730 } 731 732 tasks, err := taskRepo.Search(ctx, param, nil) 733 if err != nil { 734 tr.Fatalf("%+v", err) 735 } 736 737 if len(tasks) != 0 { 738 tr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 10) 739 } 740 }) 741 742 t.Run("Flag(10件)", func(tr *testing.T) { 743 param := &model.TaskSearchParam{ 744 Flag: model.NewQueryChainer().Equal(map[string]float64{ 745 "1": 1.1, 746 "2": 2.2, 747 "3": 3.3, 748 }), 749 } 750 751 tasks, err := taskRepo.Search(ctx, param, nil) 752 if err != nil { 753 tr.Fatalf("%+v", err) 754 } 755 756 if len(tasks) != 10 { 757 tr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 10) 758 } 759 }) 760 761 t.Run("NotEqual(9件)", func(tr *testing.T) { 762 description := fmt.Sprintf("%s%d", desc, 1) 763 param := &model.TaskSearchParam{ 764 Desc: model.NewQueryChainer().NotEqual(description), 765 } 766 tasks, err := taskRepo.Search(ctx, param, nil) 767 if err != nil { 768 tr.Fatalf("%+v", err) 769 } 770 if len(tasks) != 9 { 771 tr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 9) 772 } 773 }) 774 775 t.Run("NotIn(8件)", func(tr *testing.T) { 776 description1 := fmt.Sprintf("%s%d", desc, 1) 777 description2 := fmt.Sprintf("%s%d", desc, 2) 778 param := &model.TaskSearchParam{ 779 Desc: model.NewQueryChainer().NotIn([]string{description1, description2}), 780 } 781 tasks, err := taskRepo.Search(ctx, param, nil) 782 if err != nil { 783 tr.Fatalf("%+v", err) 784 } 785 if len(tasks) != 8 { 786 tr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 8) 787 } 788 }) 789 790 t.Run("UseQueryBuilder", func(tr *testing.T) { 791 tr.Run("range query(3<count<8)", func(ttr *testing.T) { 792 qb := model.NewQueryBuilder(taskRepo.GetCollection()) 793 qb.GreaterThan("count", 3) 794 qb.LessThan("count", 8) 795 796 tasks, err := taskRepo.Search(ctx, nil, qb.Query()) 797 if err != nil { 798 ttr.Fatalf("%+v", err) 799 } 800 801 if len(tasks) != 4 { 802 ttr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 4) 803 } 804 }) 805 tr.Run("!=(count!=1)", func(ttr *testing.T) { 806 qb := model.NewQueryBuilder(taskRepo.GetCollection()) 807 qb.NotEqual("count", 1) 808 809 tasks, err := taskRepo.Search(ctx, nil, qb.Query()) 810 if err != nil { 811 ttr.Fatalf("%+v", err) 812 } 813 814 if len(tasks) != 9 { 815 ttr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 9) 816 } 817 }) 818 tr.Run("not-in(count not-in [1,2,3,4,5])", func(ttr *testing.T) { 819 qb := model.NewQueryBuilder(taskRepo.GetCollection()) 820 qb.NotIn("count", []int{1, 2, 3, 4, 5}) 821 822 tasks, err := taskRepo.Search(ctx, nil, qb.Query()) 823 if err != nil { 824 ttr.Fatalf("%+v", err) 825 } 826 827 if len(tasks) != 5 { 828 ttr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 5) 829 } 830 }) 831 tr.Run("search by document id", func(ttr *testing.T) { 832 qb := model.NewQueryBuilder(taskRepo.GetCollection()) 833 qb.Equal(firestore.DocumentID, taskRepo.GetDocRef(tks[0].ID)) 834 qb.Desc(firestore.DocumentID) 835 836 tasks, err := taskRepo.Search(ctx, nil, qb.Query()) 837 if err != nil { 838 ttr.Fatalf("%+v", err) 839 } 840 841 if len(tasks) != 1 { 842 ttr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 1) 843 } 844 }) 845 }) 846 847 t.Run("Indexes", func(tr *testing.T) { 848 tr.Run("Equal", func(ttr *testing.T) { 849 param := &model.TaskSearchParam{ 850 Desc: model.NewQueryChainer().Filters("Hello, World!1"), 851 } 852 853 tasks, err := taskRepo.Search(ctx, param, nil) 854 if err != nil { 855 ttr.Fatalf("%+v", err) 856 } 857 858 if len(tasks) != 1 { 859 ttr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 1) 860 } 861 }) 862 tr.Run("Prefix", func(ttr *testing.T) { 863 chainer := model.NewQueryChainer 864 param := &model.TaskSearchParam{ 865 Desc: chainer().Filters("Hel", model.FilterTypeAddPrefix), 866 Done: chainer().Equal(true), 867 } 868 869 tasks, err := taskRepo.Search(ctx, param, nil) 870 if err != nil { 871 ttr.Fatalf("%+v", err) 872 } 873 874 if len(tasks) != 10 { 875 ttr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 10) 876 } 877 }) 878 tr.Run("Suffix", func(ttr *testing.T) { 879 param := &model.TaskSearchParam{ 880 Desc: model.NewQueryChainer().Filters("10", model.FilterTypeAddSuffix), 881 } 882 883 tasks, err := taskRepo.Search(ctx, param, nil) 884 if err != nil { 885 ttr.Fatalf("%+v", err) 886 } 887 888 if len(tasks) != 1 { 889 ttr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 1) 890 } 891 }) 892 tr.Run("Biunigrams", func(ttr *testing.T) { 893 ttr.Run("1", func(ttrr *testing.T) { 894 param := &model.TaskSearchParam{ 895 Desc: model.NewQueryChainer().Filters("o, Wor", model.FilterTypeAddBiunigrams), 896 } 897 898 tasks, err := taskRepo.Search(ctx, param, nil) 899 if err != nil { 900 ttrr.Fatalf("%+v", err) 901 } 902 903 if len(tasks) != 10 { 904 ttrr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 10) 905 } 906 }) 907 ttr.Run("2", func(ttrr *testing.T) { 908 param := &model.TaskSearchParam{ 909 Desc: model.NewQueryChainer().Filters("!1", model.FilterTypeAddBiunigrams), 910 } 911 912 tasks, err := taskRepo.Search(ctx, param, nil) 913 if err != nil { 914 ttr.Fatalf("%+v", err) 915 } 916 917 if len(tasks) != 2 { 918 ttr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 2) 919 } 920 }) 921 ttr.Run("3", func(ttrr *testing.T) { 922 param := &model.TaskSearchParam{ 923 Desc: model.NewQueryChainer().Filters("Hello, W", model.FilterTypeAddBiunigrams), 924 } 925 926 tasks, err := taskRepo.Search(ctx, param, nil) 927 if err != nil { 928 ttr.Fatalf("%+v", err) 929 } 930 931 if len(tasks) != 10 { 932 ttr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 10) 933 } 934 }) 935 ttr.Run("NG", func(ttrr *testing.T) { 936 param := &model.TaskSearchParam{ 937 Desc: model.NewQueryChainer().Filters("Hello,W", model.FilterTypeAddBiunigrams), 938 } 939 940 tasks, err := taskRepo.Search(ctx, param, nil) 941 if err != nil { 942 ttr.Fatalf("%+v", err) 943 } 944 945 if len(tasks) != 0 { 946 ttr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 0) 947 } 948 }) 949 }) 950 tr.Run("Something", func(ttr *testing.T) { 951 param := &model.TaskSearchParam{ 952 Proportion: model.NewQueryChainer().Filters(10.12345, model.FilterTypeAddSomething), 953 } 954 955 tasks, err := taskRepo.Search(ctx, param, nil) 956 if err != nil { 957 ttr.Fatalf("%+v", err) 958 } 959 960 if len(tasks) != 1 { 961 ttr.Fatalf("unexpected length: %d (expected: %d)", len(tasks), 1) 962 } 963 }) 964 }) 965 } 966 967 func TestFirestoreError(t *testing.T) { 968 client := initFirestoreClient(t) 969 970 taskRepo := model.NewTaskRepository(client) 971 972 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 973 var ids []string 974 defer func() { 975 defer cancel() 976 if err := taskRepo.DeleteMultiByIDs(ctx, ids); err != nil { 977 t.Fatalf("%+v\n", err) 978 } 979 }() 980 981 now := time.Unix(0, time.Now().UnixNano()) 982 983 t.Run("Prepare", func(tr *testing.T) { 984 tk := &model.Task{ 985 Desc: desc, 986 Created: now, 987 Done: true, 988 Done2: false, 989 Count: 11, 990 Count64: 11, 991 Proportion: 0.12345 + 11, 992 NameList: []string{"a", "b", "c"}, 993 Flag: map[string]float64{ 994 "1": 1.1, 995 "2": 2.2, 996 "3": 3.3, 997 }, 998 } 999 id, err := taskRepo.Insert(ctx, tk) 1000 if err != nil { 1001 tr.Fatalf("%+v", err) 1002 } 1003 ids = append(ids, id) 1004 }) 1005 1006 t.Run("ErrorReadAfterWrite", func(tr *testing.T) { 1007 tkID := ids[len(ids)-1] 1008 errReadAfterWrite := xerrors.New("firestore: read after write in transaction") 1009 1010 if err := client.RunTransaction(ctx, func(cx context.Context, tx *firestore.Transaction) error { 1011 tk, err := taskRepo.GetWithTx(tx, tkID) 1012 if err != nil { 1013 return err 1014 } 1015 1016 if tk.Count != 11 { 1017 return fmt.Errorf("unexpected Count: %d (expected: %d)", tk.Count, 11) 1018 } 1019 1020 tk.Count = 12 1021 if err = taskRepo.UpdateWithTx(cx, tx, tk); err != nil { 1022 return err 1023 } 1024 1025 if _, err = taskRepo.GetWithTx(tx, tkID); err != nil { 1026 return err 1027 } 1028 return nil 1029 }); err != nil && xerrors.Is(xerrors.Unwrap(err), errReadAfterWrite) { 1030 tr.Fatalf("error: %+v", err) 1031 } 1032 1033 tsk, err := taskRepo.Get(ctx, tkID) 1034 if err != nil { 1035 tr.Fatalf("%+v", err) 1036 } 1037 1038 if tsk.Count != 11 { 1039 tr.Fatalf("unexpected Count: %d (expected: %d)", tsk.Count, 11) 1040 } 1041 1042 if err = client.RunTransaction(ctx, func(cx context.Context, tx *firestore.Transaction) error { 1043 id, er := taskRepo.InsertWithTx(cx, tx, new(model.Task)) 1044 if er != nil { 1045 return er 1046 } 1047 1048 if _, err = taskRepo.GetWithTx(tx, id); err != nil { 1049 return err 1050 } 1051 return nil 1052 }); err != nil && xerrors.Is(xerrors.Unwrap(err), errReadAfterWrite) { 1053 tr.Fatalf("error: %+v", err) 1054 } 1055 }) 1056 } 1057 1058 func TestFirestoreOfTaskRepo(t *testing.T) { 1059 client := initFirestoreClient(t) 1060 1061 taskRepo := model.NewTaskRepository(client) 1062 1063 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 1064 defer cancel() 1065 1066 now := time.Unix(time.Now().Unix(), 0) 1067 1068 id, err := taskRepo.Insert(ctx, &model.Task{ 1069 Desc: desc, 1070 Created: now, 1071 Done: true, 1072 }) 1073 1074 if err != nil { 1075 t.Fatalf("failed to put item: %+v", err) 1076 } 1077 1078 ret, err := taskRepo.Get(ctx, id) 1079 1080 if err != nil { 1081 t.Fatalf("failed to get item: %+v", err) 1082 } 1083 1084 compareTask(t, &model.Task{ 1085 ID: id, 1086 Desc: desc, 1087 Created: now, 1088 Done: true, 1089 }, ret) 1090 1091 returns, err := taskRepo.GetMulti(ctx, []string{id}) 1092 1093 if err != nil { 1094 t.Fatalf("failed to get item: %+v", err) 1095 } 1096 1097 if len(returns) != 1 { 1098 t.Fatalf("GetMulti should return 1 item: %#v", returns) 1099 } 1100 1101 compareTask(t, &model.Task{ 1102 ID: id, 1103 Desc: desc, 1104 Created: now, 1105 Done: true, 1106 }, returns[0]) 1107 1108 compareTask(t, &model.Task{ 1109 ID: id, 1110 Desc: desc, 1111 Created: now, 1112 Done: true, 1113 }, ret) 1114 1115 if err := taskRepo.DeleteByID(ctx, id); err != nil { 1116 t.Fatalf("delete failed: %+v", err) 1117 } 1118 1119 if _, err := taskRepo.Get(ctx, id); err == nil { 1120 t.Fatalf("should get an error") 1121 } 1122 } 1123 1124 func TestFirestoreOfLockRepo(t *testing.T) { 1125 client := initFirestoreClient(t) 1126 1127 lockRepo := model.NewLockRepository(client) 1128 1129 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 1130 ids := make([]string, 0) 1131 defer func() { 1132 defer cancel() 1133 mode := model.DeleteOption{Mode: model.DeleteModeHard} 1134 if err := lockRepo.DeleteMultiByIDs(ctx, ids, mode); err != nil { 1135 t.Fatal(err) 1136 } 1137 }() 1138 1139 text := "hello" 1140 1141 t.Run("insert_test", func(tr *testing.T) { 1142 l := &model.Lock{ 1143 Text: text, 1144 Flag: nil, 1145 Meta: model.Meta{}, 1146 } 1147 1148 id, err := lockRepo.Insert(ctx, l) 1149 if err != nil { 1150 tr.Fatalf("failed to put item: %+v", err) 1151 } 1152 1153 ids = append(ids, id) 1154 1155 ret, err := lockRepo.Get(ctx, id) 1156 1157 if err != nil { 1158 tr.Fatalf("failed to get item: %+v", err) 1159 } 1160 1161 if text != ret.Text { 1162 tr.Fatalf("unexpected Text: %s (expected: %s)", ret.Text, text) 1163 } 1164 if ret.CreatedAt.IsZero() { 1165 tr.Fatal("unexpected createdAt zero") 1166 } 1167 if ret.UpdatedAt.IsZero() { 1168 tr.Fatal("unexpected updatedAt zero") 1169 } 1170 }) 1171 1172 t.Run("update_test", func(tr *testing.T) { 1173 l := &model.Lock{ 1174 Text: text, 1175 Flag: nil, 1176 Meta: model.Meta{}, 1177 } 1178 1179 id, err := lockRepo.Insert(ctx, l) 1180 if err != nil { 1181 tr.Fatalf("failed to put item: %+v", err) 1182 } 1183 1184 ids = append(ids, id) 1185 1186 text = "hello!!!" 1187 l.Text = text 1188 err = lockRepo.Update(ctx, l) 1189 if err != nil { 1190 tr.Fatalf("failed to update item: %+v", err) 1191 } 1192 1193 ret, err := lockRepo.Get(ctx, id) 1194 if err != nil { 1195 tr.Fatalf("failed to get item: %+v", err) 1196 } 1197 1198 if text != ret.Text { 1199 tr.Fatalf("unexpected Text: %s (expected: %s)", ret.Text, text) 1200 } 1201 if ret.CreatedAt.Equal(ret.UpdatedAt) { 1202 tr.Fatalf("unexpected CreatedAt == updatedAt: %d == %d", 1203 ret.CreatedAt.Unix(), ret.UpdatedAt.Unix()) 1204 } 1205 }) 1206 1207 t.Run("soft_delete_test", func(tr *testing.T) { 1208 l := &model.Lock{ 1209 Text: text, 1210 Flag: nil, 1211 Meta: model.Meta{}, 1212 } 1213 1214 id, err := lockRepo.Insert(ctx, l) 1215 if err != nil { 1216 tr.Fatalf("failed to put item: %+v", err) 1217 } 1218 1219 ids = append(ids, id) 1220 1221 l.Text = text 1222 err = lockRepo.Delete(ctx, l, model.DeleteOption{ 1223 Mode: model.DeleteModeSoft, 1224 }) 1225 if err != nil { 1226 tr.Fatalf("failed to soft delete item: %+v", err) 1227 } 1228 1229 ret, err := lockRepo.Get(ctx, id, model.GetOption{ 1230 IncludeSoftDeleted: true, 1231 }) 1232 if err != nil { 1233 tr.Fatalf("failed to get item: %+v", err) 1234 } 1235 1236 if text != ret.Text { 1237 tr.Fatalf("unexpected Text: %s (expected: %s)", ret.Text, text) 1238 } 1239 if ret.DeletedAt == nil { 1240 tr.Fatalf("unexpected DeletedAt == nil: %+v", ret.DeletedAt) 1241 } 1242 }) 1243 1244 t.Run("hard_delete_test", func(tr *testing.T) { 1245 l := &model.Lock{ 1246 Text: text, 1247 Flag: nil, 1248 Meta: model.Meta{}, 1249 } 1250 1251 id, err := lockRepo.Insert(ctx, l) 1252 if err != nil { 1253 tr.Fatalf("failed to put item: %+v", err) 1254 } 1255 1256 l.Text = text 1257 err = lockRepo.Delete(ctx, l) 1258 if err != nil { 1259 tr.Fatalf("failed to hard delete item: %+v", err) 1260 } 1261 1262 ret, err := lockRepo.Get(ctx, id, model.GetOption{ 1263 IncludeSoftDeleted: true, 1264 }) 1265 if err != nil && !strings.Contains(err.Error(), "not found") { 1266 tr.Fatalf("failed to get item: %+v", err) 1267 } 1268 1269 if ret != nil { 1270 tr.Fatalf("failed to delete item (found!): %+v", ret) 1271 } 1272 }) 1273 1274 t.Run("UseQueryBuilder", func(tr *testing.T) { 1275 l := &model.Lock{ 1276 Text: text, 1277 Flag: nil, 1278 Meta: model.Meta{}, 1279 } 1280 id, err := lockRepo.Insert(ctx, l) 1281 if err != nil { 1282 tr.Fatalf("failed to put item: %+v", err) 1283 } 1284 1285 ids = append(ids, id) 1286 1287 qb := model.NewQueryBuilder(lockRepo.GetCollection()) 1288 qb.GreaterThanOrEqual("createdAt", model.SetLastThreeToZero(l.CreatedAt).Add(-100)) 1289 qb.LessThanOrEqual("createdAt", model.SetLastThreeToZero(l.CreatedAt).Add(100)) 1290 if err = qb.Check(); err != nil { 1291 tr.Fatal(err) 1292 } 1293 1294 locks, err := lockRepo.Search(ctx, nil, qb.Query()) 1295 if err != nil { 1296 tr.Fatalf("%+v", err) 1297 } 1298 1299 if len(locks) != 1 { 1300 tr.Fatalf("unexpected length: %d (expected: %d)", len(locks), 1) 1301 } 1302 1303 if id != locks[0].ID { 1304 tr.Fatalf("unexpected length: %s (expected: %s)", locks[0].ID, id) 1305 } 1306 }) 1307 1308 t.Run("UseQueryChainer", func(tr *testing.T) { 1309 l := &model.Lock{ 1310 Text: "Hello", 1311 Flag: nil, 1312 Meta: model.Meta{}, 1313 } 1314 id, err := lockRepo.Insert(ctx, l) 1315 if err != nil { 1316 tr.Fatalf("failed to put item: %+v", err) 1317 } 1318 ids = append(ids, id) 1319 l = &model.Lock{ 1320 Text: "World", 1321 Flag: nil, 1322 Meta: model.Meta{}, 1323 } 1324 id, err = lockRepo.Insert(ctx, l) 1325 if err != nil { 1326 tr.Fatalf("failed to put item: %+v", err) 1327 } 1328 ids = append(ids, id) 1329 param := &model.LockSearchParam{ 1330 Text: model.NewQueryChainer().In([]string{"Hello", "World"}), 1331 IncludeSoftDeleted: true, 1332 } 1333 locks, err := lockRepo.Search(ctx, param, nil) 1334 if err != nil { 1335 tr.Fatalf("%+v", err) 1336 } 1337 if len(locks) != 2 { 1338 tr.Fatalf("unexpected length: %d (expected: %d)", len(locks), 2) 1339 } 1340 1341 now := time.Now() 1342 param = &model.LockSearchParam{ 1343 CreatedAt: model.NewQueryChainer().GreaterThanOrEqual(now.Add(time.Second * 5 * -1)).LessThanOrEqual(now.Add(time.Second * 5)), 1344 IncludeSoftDeleted: true, 1345 } 1346 locks, err = lockRepo.Search(ctx, param, nil) 1347 if err != nil { 1348 tr.Fatalf("%+v", err) 1349 } 1350 if len(locks) != 6 { 1351 tr.Fatalf("unexpected length: %d (expected: %d)", len(locks), 6) 1352 } 1353 1354 param = &model.LockSearchParam{ 1355 CreatedAt: model.NewQueryChainer().Asc(), 1356 CursorLimit: 5, 1357 IncludeSoftDeleted: true, 1358 } 1359 locks, err = lockRepo.Search(ctx, param, nil) 1360 if err != nil { 1361 tr.Fatalf("%+v", err) 1362 } 1363 1364 if len(locks) != 5 { 1365 tr.Fatalf("unexpected length: %d (expected: %d)", len(locks), 5) 1366 } 1367 1368 param = &model.LockSearchParam{ 1369 CreatedAt: model.NewQueryChainer().Asc().StartAfter(locks[len(locks)-1].CreatedAt), 1370 CursorLimit: 5, 1371 IncludeSoftDeleted: true, 1372 } 1373 locks, err = lockRepo.Search(ctx, param, nil) 1374 if err != nil { 1375 tr.Fatalf("%+v", err) 1376 } 1377 1378 if len(locks) != 1 { 1379 tr.Fatalf("unexpected length: %d (expected: %d)", len(locks), 1) 1380 } 1381 1382 param = &model.LockSearchParam{ 1383 CreatedAt: model.NewQueryChainer().Asc().EndAt(locks[len(locks)-1].CreatedAt), 1384 IncludeSoftDeleted: true, 1385 } 1386 locks, err = lockRepo.Search(ctx, param, nil) 1387 if err != nil { 1388 tr.Fatalf("%+v", err) 1389 } 1390 1391 if len(locks) != 6 { 1392 tr.Fatalf("unexpected length: %d (expected: %d)", len(locks), 6) 1393 } 1394 1395 param = &model.LockSearchParam{ 1396 CreatedAt: model.NewQueryChainer().Asc().EndBefore(locks[len(locks)-1].CreatedAt), 1397 IncludeSoftDeleted: true, 1398 } 1399 locks, err = lockRepo.Search(ctx, param, nil) 1400 if err != nil { 1401 tr.Fatalf("%+v", err) 1402 } 1403 1404 if len(locks) != 5 { 1405 tr.Fatalf("unexpected length: %d (expected: %d)", len(locks), 5) 1406 } 1407 }) 1408 1409 t.Run("update_builder", func(tr *testing.T) { 1410 l := &model.Lock{ 1411 Text: text, 1412 Flag: nil, 1413 Meta: model.Meta{}, 1414 } 1415 1416 id, err := lockRepo.Insert(ctx, l) 1417 if err != nil { 1418 tr.Fatalf("failed to put item: %+v", err) 1419 } 1420 1421 ids = append(ids, id) 1422 1423 flag := map[string]float64{"test": 123.456} 1424 hello := fmt.Sprintf("%s world", text) 1425 1426 t := time.NewTicker(1 * time.Millisecond) 1427 defer t.Stop() 1428 <-t.C 1429 1430 updateParam := &model.LockUpdateParam{ 1431 Text: hello, 1432 Flag: flag, 1433 UpdatedAt: firestore.ServerTimestamp, 1434 Version: firestore.Increment(1), 1435 } 1436 1437 if err = lockRepo.StrictUpdate(ctx, id, updateParam); err != nil { 1438 tr.Fatalf("failed to update item: %+v", err) 1439 } 1440 1441 ret, err := lockRepo.Get(ctx, id) 1442 if err != nil { 1443 tr.Fatalf("failed to get item: %+v", err) 1444 } 1445 1446 if ret.Text != hello { 1447 tr.Fatalf("unexpected Text: %s (expected: %s)", ret.Text, hello) 1448 } 1449 1450 if !reflect.DeepEqual(ret.Flag, flag) { 1451 tr.Fatalf("unexpected Flag: %v (expected: %v)", ret.Flag, flag) 1452 } 1453 1454 if ret.CreatedAt.Equal(ret.UpdatedAt) { 1455 tr.Fatalf("unexpected CreatedAt == UpdatedAt: %d == %d", 1456 ret.CreatedAt.Unix(), ret.UpdatedAt.Unix()) 1457 } 1458 1459 if ret.UpdatedAt.Before(ret.CreatedAt) { 1460 tr.Fatalf("unexpected UpdatedAt > CreatedAt: %t (expected: %t)", ret.UpdatedAt.Before(ret.CreatedAt), ret.UpdatedAt.After(ret.CreatedAt)) 1461 } 1462 1463 if ret.Version != 2 { 1464 tr.Fatalf("unexpected Version: %d (expected: %d)", ret.Version, 2) 1465 } 1466 }) 1467 1468 t.Run("GetByXXX test", func(tr *testing.T) { 1469 l := &model.Lock{ 1470 Text2: text, 1471 } 1472 1473 id, err := lockRepo.Insert(ctx, l) 1474 if err != nil { 1475 tr.Fatalf("failed to put item: %+v", err) 1476 } 1477 1478 l, err = lockRepo.GetByText2(ctx, text) 1479 if err != nil { 1480 tr.Fatalf("%+v", err) 1481 } 1482 if err = lockRepo.DeleteByID(ctx, id, model.DeleteOption{Mode: model.DeleteModeSoft}); err != nil { 1483 tr.Fatalf("%+v", err) 1484 } 1485 l, err = lockRepo.GetByText2(ctx, text) 1486 if !xerrors.Is(err, model.ErrNotFound) { 1487 tr.Fatalf("%+v", err) 1488 } 1489 l, err = lockRepo.GetByText2(ctx, text, model.GetOption{IncludeSoftDeleted: true}) 1490 if err != nil { 1491 tr.Fatalf("%+v", err) 1492 } 1493 }) 1494 1495 t.Run("UniqueConstraints", func(tr *testing.T) { 1496 l := &model.Lock{ 1497 Text2: text + "2", 1498 } 1499 1500 if _, err := lockRepo.Insert(ctx, l); err != nil { 1501 tr.Fatalf("unexpected error: %+v", err) 1502 } 1503 1504 // Check if the documents in the Unique collection can be deleted. 1505 if err := lockRepo.DeleteByID(ctx, l.ID, model.DeleteOption{Mode: model.DeleteModeSoft}); err != nil { 1506 tr.Fatalf("unexpected err != nil: %+v", err) 1507 } 1508 1509 l = &model.Lock{ 1510 Text2: text + "2", 1511 } 1512 1513 if _, err := lockRepo.Insert(ctx, l); err != nil { 1514 tr.Fatalf("unexpected error: %+v", err) 1515 } 1516 }) 1517 }