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  }