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