place_repo_test.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. package repository
  2. import (
  3. "context"
  4. "testing"
  5. "time"
  6. "gogs.fxtmmsk.ru/foxtime/photoplaces/backend/internal/models"
  7. )
  8. func TestPlaceRepo_List_WithStatusFilter(t *testing.T) {
  9. if testPool == nil {
  10. t.Skip("DATABASE_URL_TEST not set")
  11. }
  12. cleanTables(t, "places", "users")
  13. user := insertTestUser(t)
  14. ctx := context.Background()
  15. repo := NewPlaceRepo(testPool)
  16. insertTestPlace(t, user.ID, nil)
  17. insertTestPlace(t, user.ID, nil)
  18. pending := insertTestPlace(t, user.ID, nil)
  19. if _, err := testPool.Exec(ctx,
  20. `UPDATE places SET status = $1 WHERE id = $2`, "pending_moderation", pending.ID); err != nil {
  21. t.Fatal(err)
  22. }
  23. t.Run("filter by status published", func(t *testing.T) {
  24. results, err := repo.List(ctx, models.PlaceFilter{Status: "published"})
  25. if err != nil {
  26. t.Fatalf("List: %v", err)
  27. }
  28. if len(results) < 2 {
  29. t.Errorf("expected at least 2 published places, got %d", len(results))
  30. }
  31. })
  32. t.Run("filter by status pending_moderation", func(t *testing.T) {
  33. results, err := repo.List(ctx, models.PlaceFilter{Status: "pending_moderation"})
  34. if err != nil {
  35. t.Fatalf("List: %v", err)
  36. }
  37. if len(results) != 1 {
  38. t.Errorf("expected 1 pending_moderation place, got %d", len(results))
  39. }
  40. })
  41. t.Run("filter by both status and type", func(t *testing.T) {
  42. results, err := repo.List(ctx, models.PlaceFilter{Type: "studio", Status: "published"})
  43. if err != nil {
  44. t.Fatalf("List: %v", err)
  45. }
  46. if len(results) < 2 {
  47. t.Errorf("expected at least 2 published studios, got %d", len(results))
  48. }
  49. })
  50. }
  51. func TestPlaceRepo_List_CursorPagination(t *testing.T) {
  52. if testPool == nil {
  53. t.Skip("DATABASE_URL_TEST not set")
  54. }
  55. cleanTables(t, "places", "users")
  56. user := insertTestUser(t)
  57. repo := NewPlaceRepo(testPool)
  58. // Create 5 places with slightly different created_at times
  59. for i := 0; i < 5; i++ {
  60. insertTestPlace(t, user.ID, nil)
  61. time.Sleep(5 * time.Millisecond) // ensure different created_at
  62. }
  63. t.Run("first page returns limit items with hasMore", func(t *testing.T) {
  64. results, err := repo.List(context.Background(), models.PlaceFilter{
  65. Limit_: 2,
  66. Status: "published",
  67. })
  68. if err != nil {
  69. t.Fatalf("List: %v", err)
  70. }
  71. if len(results) != 3 { // LIMIT 2 + 1 (extra for hasMore detection)
  72. t.Errorf("expected 3 results (2 + 1 extra), got %d", len(results))
  73. }
  74. })
  75. t.Run("cursor returns correct page", func(t *testing.T) {
  76. // Get first page
  77. page1, err := repo.List(context.Background(), models.PlaceFilter{
  78. Limit_: 2,
  79. Status: "published",
  80. })
  81. if err != nil {
  82. t.Fatalf("List page1: %v", err)
  83. }
  84. if len(page1) < 2 {
  85. t.Skip("not enough places for cursor test")
  86. }
  87. // Get second page using cursor from last item of page1
  88. last := page1[1]
  89. cursorCreatedAt := last.CreatedAt
  90. page2, err := repo.List(context.Background(), models.PlaceFilter{
  91. Cursor: last.ID,
  92. CursorCreatedAt: &cursorCreatedAt,
  93. Limit_: 2,
  94. Status: "published",
  95. })
  96. if err != nil {
  97. t.Fatalf("List page2 with cursor: %v", err)
  98. }
  99. if len(page2) == 0 {
  100. t.Error("expected at least 1 result after cursor, got 0")
  101. }
  102. })
  103. }
  104. func TestPlaceRepo_GetTagsBatch(t *testing.T) {
  105. if testPool == nil {
  106. t.Skip("DATABASE_URL_TEST not set")
  107. }
  108. cleanTables(t, "place_tags", "tags", "places", "users")
  109. user := insertTestUser(t)
  110. ctx := context.Background()
  111. repo := NewPlaceRepo(testPool)
  112. place1 := insertTestPlace(t, user.ID, nil)
  113. place2 := insertTestPlace(t, user.ID, nil)
  114. tag1 := insertTestTag(t)
  115. tag2 := insertTestTag(t)
  116. insertTestPlaceTag(t, place1.ID, tag1.ID)
  117. insertTestPlaceTag(t, place1.ID, tag2.ID)
  118. insertTestPlaceTag(t, place2.ID, tag1.ID)
  119. tagsMap, err := repo.GetTagsBatch(ctx, []string{place1.ID, place2.ID})
  120. if err != nil {
  121. t.Fatalf("GetTagsBatch: %v", err)
  122. }
  123. if len(tagsMap[place1.ID]) != 2 {
  124. t.Errorf("place1 expected 2 tags, got %d", len(tagsMap[place1.ID]))
  125. }
  126. if len(tagsMap[place2.ID]) != 1 {
  127. t.Errorf("place2 expected 1 tag, got %d", len(tagsMap[place2.ID]))
  128. }
  129. if len(tagsMap) != 2 {
  130. t.Errorf("expected 2 place entries in map, got %d", len(tagsMap))
  131. }
  132. }
  133. func TestPlaceRepo_GetTagsBatch_EmptyInput(t *testing.T) {
  134. if testPool == nil {
  135. t.Skip("DATABASE_URL_TEST not set")
  136. }
  137. repo := NewPlaceRepo(testPool)
  138. result, err := repo.GetTagsBatch(context.Background(), nil)
  139. if err != nil {
  140. t.Fatalf("GetTagsBatch with nil: %v", err)
  141. }
  142. if len(result) != 0 {
  143. t.Errorf("expected empty map, got %d entries", len(result))
  144. }
  145. result, err = repo.GetTagsBatch(context.Background(), []string{})
  146. if err != nil {
  147. t.Fatalf("GetTagsBatch with empty: %v", err)
  148. }
  149. if len(result) != 0 {
  150. t.Errorf("expected empty map, got %d entries", len(result))
  151. }
  152. }