github.com/angryronald/go-kit@v0.0.0-20240505173814-ff2bd9c79dbf/generic/repository/sql/repositorytest/generic.repository_test.go (about) 1 package repositorytest 2 3 import ( 4 "context" 5 "fmt" 6 "sync" 7 "testing" 8 "time" 9 10 "github.com/google/uuid" 11 "github.com/sirupsen/logrus" 12 13 "github.com/angryronald/go-kit/generic/repository" 14 "github.com/angryronald/go-kit/generic/repository/sql" 15 ) 16 17 var TEST_ID = uuid.MustParse("25ebc2e2-7fd2-47a0-bd2f-a8ec6e4d0163") 18 19 var sample *TestModel 20 var mutex sync.Mutex 21 var isDone bool 22 23 func init() { 24 isDone = false 25 sample = &TestModel{ 26 ID: TEST_ID, 27 Text: "text", 28 CreatedAt: time.Now().UTC(), 29 CreatedBy: uuid.Nil, 30 UpdatedAt: time.Now().UTC(), 31 UpdatedBy: uuid.Nil, 32 } 33 } 34 35 func preSeeding() { 36 mutex.Lock() 37 if !isDone { 38 if err := db.Create(sample).Error; err != nil { 39 logrus.Debugf("failed to inject data: %v", err) 40 } 41 isDone = true 42 } 43 mutex.Unlock() 44 } 45 46 // func removePreseeding() { 47 // mutex.Lock() 48 // if isDone { 49 // if err := db.Delete(sample).Error; err != nil { 50 // logrus.Debugf("failed to remove seed data: %v", err) 51 // } 52 // isDone = false 53 // } 54 // mutex.Unlock() 55 // } 56 57 func TestGenericRepository_FindAll(t *testing.T) { 58 repo := sql.NewRepository(db) 59 60 ctx := context.Background() 61 params := map[string]interface{}{"text": "text"} 62 conditionalOperations := []repository.ConditionalOperation{repository.EQUAL_WITH} 63 page := 1 64 limit := 10 65 66 preSeeding() 67 // defer removePreseeding() 68 69 resultsRaw, err := repo.FindAll(ctx, params, conditionalOperations, nil, page, limit, []*TestModel{}) 70 if err != nil { 71 t.Fatalf("Error in FindAll: %v", err) 72 } 73 74 /* 75 alternative casting: 76 results := []*TestModel{} 77 cast.TransformObject(resultsRaw, &results) 78 */ 79 results := resultsRaw.([]*TestModel) 80 if len(results) != 1 { 81 t.Fatalf("Expected 1 result, but got %d", len(results)) 82 } 83 } 84 85 func TestGenericRepository_FindAll_WithComplexQuery(t *testing.T) { 86 repo := sql.NewRepository(db) 87 ctx := context.Background() 88 89 preSeeding() 90 // // defer removePreseeding() 91 92 testCases := []struct { 93 name string 94 params map[string]interface{} 95 conditionalOperations []repository.ConditionalOperation 96 page int 97 limit int 98 expectedResultCount int 99 expectedError error 100 }{ 101 { 102 name: "FindAll with IN Query", 103 params: map[string]interface{}{"id": []interface{}{TEST_ID}}, 104 conditionalOperations: []repository.ConditionalOperation{repository.IN}, 105 page: 1, 106 limit: 10, 107 expectedResultCount: 1, 108 expectedError: nil, 109 }, 110 { 111 name: "FindAll with ILIKE Query", 112 params: map[string]interface{}{"text": "ex"}, 113 conditionalOperations: []repository.ConditionalOperation{repository.ILIKE}, 114 page: 1, 115 limit: 10, 116 expectedResultCount: 1, 117 expectedError: nil, 118 }, 119 } 120 121 for _, test := range testCases { 122 t.Run(test.name, func(t *testing.T) { 123 resultsRaw, err := repo.FindAll(ctx, test.params, test.conditionalOperations, nil, test.page, test.limit, []*TestModel{}) 124 if err != test.expectedError { 125 t.Fatalf("Expected %v, but got %v", test.expectedError, err) 126 } 127 128 /* 129 alternative casting: 130 results := []*TestModel{} 131 cast.TransformObject(resultsRaw, &results) 132 */ 133 results := resultsRaw.([]*TestModel) 134 if len(results) != test.expectedResultCount { 135 t.Fatalf("Expected %d result, but got %d", test.expectedResultCount, len(results)) 136 } 137 }) 138 } 139 } 140 141 func TestGenericRepository_FindAll_WithRelationalOperation(t *testing.T) { 142 repo := sql.NewRepository(db) 143 144 ctx := context.Background() 145 params := map[string]interface{}{ 146 "text": "text", 147 `"id"`: TEST_ID, 148 } 149 conditionalOperations := []repository.ConditionalOperation{repository.EQUAL_WITH, repository.EQUAL_WITH} 150 relationalOperations := []repository.RelationalOperation{repository.AND} 151 page := 1 152 limit := 10 153 154 preSeeding() 155 // defer removePreseeding() 156 157 resultsRaw, err := repo.FindAll(ctx, params, conditionalOperations, relationalOperations, page, limit, []*TestModel{}) 158 if err != nil { 159 t.Fatalf("Error in FindAll: %v", err) 160 } 161 162 /* 163 alternative casting: 164 results := []*TestModel{} 165 cast.TransformObject(resultsRaw, &results) 166 */ 167 results := resultsRaw.([]*TestModel) 168 if len(results) != 1 { 169 t.Fatalf("Expected 1 result, but got %d", len(results)) 170 } 171 } 172 173 func TestGenericRepository_FindOne(t *testing.T) { 174 repo := sql.NewRepository(db) 175 176 ctx := context.Background() 177 key := "text" 178 value := "text" 179 180 preSeeding() 181 // defer removePreseeding() 182 183 result := &TestModel{} 184 _, err := repo.FindOne(ctx, key, value, result) 185 if err != nil { 186 t.Fatalf("Error in FindOne: %v", err) 187 } 188 189 if result.ID != sample.ID || result.Text != sample.Text { 190 t.Fatalf("Unexpected result: %+v", result) 191 } 192 } 193 194 func TestGenericRepository_FindByID(t *testing.T) { 195 repo := sql.NewRepository(db) 196 197 id := TEST_ID 198 199 preSeeding() 200 // defer removePreseeding() 201 202 ctx := context.Background() 203 result := &TestModel{} 204 _, err := repo.FindByID(ctx, id, result) 205 if err != nil { 206 t.Fatalf("Error in FindByID: %v", err) 207 } 208 209 if result.ID != id || result.Text != sample.Text { 210 t.Fatalf("Unexpected result: %+v", result) 211 } 212 } 213 214 func TestGenericRepository_Insert(t *testing.T) { 215 repo := sql.NewRepository(db) 216 217 ctx := context.Background() 218 id, _ := uuid.NewRandom() 219 data := &TestModel{ 220 ID: id, 221 Text: "test insert", 222 CreatedAt: time.Now().UTC(), 223 CreatedBy: uuid.Nil, 224 UpdatedAt: time.Now().UTC(), 225 UpdatedBy: uuid.Nil, 226 } 227 228 result, err := repo.Insert(ctx, data) 229 if err != nil { 230 t.Fatalf("Error in Insert: %v", err) 231 } 232 233 if result.(*TestModel) == nil { 234 t.Fatalf("Unexpected result: %+v", result) 235 } 236 } 237 238 func TestGenericRepository_Update(t *testing.T) { 239 repo := sql.NewRepository(db) 240 241 ctx := context.Background() 242 243 preSeeding() 244 // defer removePreseeding() 245 246 data := sample 247 data.Text = "updated text" 248 249 result, err := repo.Update(ctx, data) 250 if err != nil { 251 t.Fatalf("Error in Update: %v", err) 252 } 253 254 if result.(*TestModel).ID != TEST_ID { 255 t.Fatalf("Unexpected result: %+v", result) 256 } 257 } 258 259 func TestGenericRepository_Update_DataDeleted_ErrNotFound(t *testing.T) { 260 repo := sql.NewRepository(db) 261 262 ctx := context.Background() 263 264 now := time.Now().UTC() 265 data := sample 266 data.DeletedAt = &now 267 if err := db.Create(sample).Error; err != nil { 268 logrus.Debugf("failed to inject deleted data: %v", err) 269 } 270 271 data.Text = "updated text" 272 273 _, err := repo.Update(ctx, data) 274 if err != repository.ErrNotFound { 275 t.Fatalf("expected %v, got %v", repository.ErrNotFound, err) 276 } 277 } 278 279 func TestGenericRepository_Delete(t *testing.T) { 280 repo := sql.NewRepository(db) 281 282 ctx := context.Background() 283 284 id, _ := uuid.NewRandom() 285 data := &TestModel{ 286 ID: id, 287 Text: "test insert", 288 CreatedAt: time.Now().UTC(), 289 CreatedBy: uuid.Nil, 290 UpdatedAt: time.Now().UTC(), 291 UpdatedBy: uuid.Nil, 292 } 293 294 if err := db.Create(data).Error; err != nil { 295 logrus.Debugf("failed to inject data: %v", err) 296 } 297 298 _, err := repo.Delete(ctx, data) 299 if err != nil { 300 t.Fatalf("Error in Delete: %v", err) 301 } 302 } 303 304 func TestGenericRepository_Upsert(t *testing.T) { 305 repo := sql.NewRepository(db) 306 307 ctx := context.Background() 308 data := sample 309 310 result, err := repo.Upsert(ctx, data) 311 if err != nil { 312 t.Fatalf("Error in Upsert: %v", err) 313 } 314 315 if result.(*TestModel).ID != TEST_ID { 316 t.Fatalf("Unexpected result: %+v", result) 317 } 318 } 319 320 func TestGenericRepository_BulkInsert(t *testing.T) { 321 id, _ := uuid.NewRandom() 322 secondId, _ := uuid.NewRandom() 323 sample.ID = secondId 324 data := []*TestModel{ 325 sample, 326 &TestModel{ 327 ID: id, 328 Text: "test bulk insert", 329 CreatedAt: time.Now().UTC(), 330 CreatedBy: uuid.Nil, 331 UpdatedAt: time.Now().UTC(), 332 UpdatedBy: uuid.Nil, 333 }, 334 } 335 336 repo := sql.NewRepository(db) 337 338 ctx := context.Background() 339 340 resultsRaw, err := repo.BulkInsert(ctx, data) 341 if err != nil { 342 t.Fatalf("Error in BulkInsert: %v", err) 343 } 344 345 /* 346 alternative casting: 347 results := []*TestModel{} 348 cast.TransformObject(resultsRaw, &results) 349 */ 350 results := resultsRaw.([]*TestModel) 351 if len(results) != 2 { 352 t.Fatalf("Expected 2 results, but got %d", len(results)) 353 } 354 } 355 356 func TestGenericRepository_BulkUpsert(t *testing.T) { 357 repo := sql.NewRepository(db) 358 359 preSeeding() 360 // defer removePreseeding() 361 362 one := sample 363 one.Text = "updated text" 364 id, _ := uuid.NewRandom() 365 data := []*TestModel{ 366 one, 367 &TestModel{ 368 ID: id, 369 Text: "test bulk insert", 370 CreatedAt: time.Now().UTC(), 371 CreatedBy: uuid.Nil, 372 UpdatedAt: time.Now().UTC(), 373 UpdatedBy: uuid.Nil, 374 }, 375 } 376 377 ctx := context.Background() 378 379 resultsRaw, err := repo.BulkUpsert(ctx, data) 380 if err != nil { 381 t.Fatalf("Error in BulkUpsert: %v", err) 382 } 383 384 /* 385 alternative casting: 386 results := []*TestModel{} 387 cast.TransformObject(resultsRaw, &results) 388 */ 389 results := resultsRaw.([]*TestModel) 390 if len(results) != 2 { 391 t.Fatalf("Expected 2 results, but got %d", len(results)) 392 } 393 } 394 395 func TestGenericRepository_Query(t *testing.T) { 396 repo := sql.NewRepository(db) 397 398 ctx := context.Background() 399 id, _ := uuid.NewRandom() 400 params := []interface{}{ 401 "text", 402 id, 403 } 404 405 data := &TestModel{ 406 ID: id, 407 Text: "text", 408 CreatedAt: time.Now().UTC(), 409 CreatedBy: uuid.Nil, 410 UpdatedAt: time.Now().UTC(), 411 UpdatedBy: uuid.Nil, 412 } 413 414 if err := db.Create(data).Error; err != nil { 415 logrus.Debugf("failed to inject data: %v", err) 416 } 417 418 result := []*TestModel{} 419 resultsRaw, err := repo.Query( 420 ctx, 421 fmt.Sprintf(` 422 SELECT 423 * 424 FROM 425 %s 426 WHERE 427 text = ? AND id = ? 428 `, repository.GetTableName(&TestModel{})), 429 params, 430 result, 431 ) 432 if err != nil { 433 t.Fatalf("Error in Query: %v", err) 434 } 435 436 /* 437 alternative casting: 438 results := []*TestModel{} 439 cast.TransformObject(resultsRaw, &results) 440 */ 441 results := resultsRaw.([]*TestModel) 442 if len(results) != 1 { 443 t.Fatalf("Expected 1 result, but got %d", len(results)) 444 } 445 } 446 447 func TestGenericRepository_Query_DELETE(t *testing.T) { 448 repo := sql.NewRepository(db) 449 450 ctx := context.Background() 451 id, _ := uuid.NewRandom() 452 params := []interface{}{ 453 time.Now().UTC(), 454 } 455 456 data := &TestModel{ 457 ID: id, 458 Text: "text", 459 CreatedAt: time.Now().Add(-5 * time.Minute).UTC(), 460 CreatedBy: uuid.Nil, 461 UpdatedAt: time.Now().UTC(), 462 UpdatedBy: uuid.Nil, 463 } 464 465 if err := db.Create(data).Error; err != nil { 466 logrus.Debugf("failed to inject data: %v", err) 467 } 468 469 result := []*TestModel{} 470 if _, err := repo.Query( 471 ctx, 472 fmt.Sprintf(` 473 DELETE FROM 474 %s 475 WHERE 476 created_at < ? 477 `, repository.GetTableName(&TestModel{})), 478 params, 479 result, 480 ); err != nil { 481 t.Fatalf("Error in Query: %v", err) 482 } 483 484 if _, err := repo.FindByID(ctx, id, result); err != nil && err != repository.ErrNotFound { 485 t.Fatalf("expected %v, got %v", repository.ErrNotFound, err) 486 } 487 }