github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/repo/get_test.go (about)

     1  package repo_test
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"regexp"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/DATA-DOG/go-sqlmock"
    11  	"github.com/kyma-incubator/compass/components/director/internal/repo"
    12  	"github.com/kyma-incubator/compass/components/director/internal/repo/testdb"
    13  	"github.com/kyma-incubator/compass/components/director/pkg/apperrors"
    14  	"github.com/kyma-incubator/compass/components/director/pkg/persistence"
    15  	"github.com/kyma-incubator/compass/components/director/pkg/resource"
    16  	"github.com/stretchr/testify/assert"
    17  	"github.com/stretchr/testify/require"
    18  )
    19  
    20  func TestGetSingle(t *testing.T) {
    21  	sut := repo.NewSingleGetter(appTableName, appColumns)
    22  	resourceType := resource.Application
    23  	m2mTable, ok := resourceType.TenantAccessTable()
    24  	require.True(t, ok)
    25  
    26  	t.Run("success", func(t *testing.T) {
    27  		// GIVEN
    28  		db, mock := testdb.MockDatabase(t)
    29  		ctx := persistence.SaveToContext(context.TODO(), db)
    30  		defer mock.AssertExpectations(t)
    31  
    32  		expectedQuery := regexp.QuoteMeta(fmt.Sprintf("SELECT id, name, description FROM %s WHERE id = $1 AND %s", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$2")))
    33  		rows := sqlmock.NewRows([]string{"id", "name", "description"}).AddRow(appID, appName, appDescription)
    34  		mock.ExpectQuery(expectedQuery).WithArgs(appID, tenantID).WillReturnRows(rows)
    35  		dest := App{}
    36  		// WHEN
    37  		err := sut.Get(ctx, resourceType, tenantID, repo.Conditions{repo.NewEqualCondition("id", appID)}, repo.NoOrderBy, &dest)
    38  		// THEN
    39  		require.NoError(t, err)
    40  		assert.Equal(t, appID, dest.ID)
    41  		assert.Equal(t, appName, dest.Name)
    42  		assert.Equal(t, appDescription, dest.Description)
    43  	})
    44  
    45  	t.Run("success when no conditions", func(t *testing.T) {
    46  		// GIVEN
    47  		db, mock := testdb.MockDatabase(t)
    48  		ctx := persistence.SaveToContext(context.TODO(), db)
    49  		defer mock.AssertExpectations(t)
    50  
    51  		expectedQuery := regexp.QuoteMeta(fmt.Sprintf("SELECT id, name, description FROM %s WHERE %s", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$1")))
    52  		rows := sqlmock.NewRows([]string{"id", "name", "description"}).AddRow(appID, appName, appDescription)
    53  		mock.ExpectQuery(expectedQuery).WithArgs(tenantID).WillReturnRows(rows)
    54  		dest := App{}
    55  		// WHEN
    56  		err := sut.Get(ctx, resourceType, tenantID, nil, repo.NoOrderBy, &dest)
    57  		// THEN
    58  		require.NoError(t, err)
    59  		assert.Equal(t, appID, dest.ID)
    60  		assert.Equal(t, appName, dest.Name)
    61  		assert.Equal(t, appDescription, dest.Description)
    62  	})
    63  
    64  	t.Run("success when more conditions", func(t *testing.T) {
    65  		db, mock := testdb.MockDatabase(t)
    66  		ctx := persistence.SaveToContext(context.TODO(), db)
    67  		defer mock.AssertExpectations(t)
    68  
    69  		expectedQuery := regexp.QuoteMeta(fmt.Sprintf("SELECT id, name, description FROM %s WHERE id = $1 AND name = $2 AND %s", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$3")))
    70  		rows := sqlmock.NewRows([]string{"id", "name", "description"}).AddRow(appID, appName, appDescription)
    71  		mock.ExpectQuery(expectedQuery).WithArgs(appID, appName, tenantID).WillReturnRows(rows)
    72  		dest := App{}
    73  		// WHEN
    74  		err := sut.Get(ctx, resourceType, tenantID, repo.Conditions{repo.NewEqualCondition("id", appID), repo.NewEqualCondition("name", appName)}, repo.NoOrderBy, &dest)
    75  		// THEN
    76  		require.NoError(t, err)
    77  		assert.Equal(t, appID, dest.ID)
    78  		assert.Equal(t, appName, dest.Name)
    79  		assert.Equal(t, appDescription, dest.Description)
    80  	})
    81  
    82  	t.Run("success when IN condition", func(t *testing.T) {
    83  		db, mock := testdb.MockDatabase(t)
    84  		ctx := persistence.SaveToContext(context.TODO(), db)
    85  		defer mock.AssertExpectations(t)
    86  
    87  		expectedQuery := regexp.QuoteMeta(fmt.Sprintf("SELECT id, name, description FROM %s WHERE name IN (SELECT name from names WHERE description = $1 AND id = $2) AND %s", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$3")))
    88  		rows := sqlmock.NewRows([]string{"id", "name", "description"}).AddRow(appID, appName, appDescription)
    89  		mock.ExpectQuery(expectedQuery).WithArgs("foo", 3, tenantID).WillReturnRows(rows)
    90  		dest := App{}
    91  		// WHEN
    92  		err := sut.Get(ctx, resourceType, tenantID, repo.Conditions{repo.NewInConditionForSubQuery("name", "SELECT name from names WHERE description = ? AND id = ?", []interface{}{"foo", 3})}, repo.NoOrderBy, &dest)
    93  		// THEN
    94  		require.NoError(t, err)
    95  		assert.Equal(t, appID, dest.ID)
    96  		assert.Equal(t, appName, dest.Name)
    97  		assert.Equal(t, appDescription, dest.Description)
    98  	})
    99  
   100  	t.Run("success when IN condition for values", func(t *testing.T) {
   101  		db, mock := testdb.MockDatabase(t)
   102  		ctx := persistence.SaveToContext(context.TODO(), db)
   103  		defer mock.AssertExpectations(t)
   104  
   105  		expectedQuery := regexp.QuoteMeta(fmt.Sprintf("SELECT id, name, description FROM %s WHERE name IN ($1, $2) AND %s", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$3")))
   106  		rows := sqlmock.NewRows([]string{"id", "name", "description"}).AddRow(appID, appName, appDescription)
   107  		mock.ExpectQuery(expectedQuery).WithArgs("foo", "bar", tenantID).WillReturnRows(rows)
   108  		dest := App{}
   109  		// WHEN
   110  		err := sut.Get(ctx, resourceType, tenantID, repo.Conditions{repo.NewInConditionForStringValues("name", []string{"foo", "bar"})}, repo.NoOrderBy, &dest)
   111  		// THEN
   112  		require.NoError(t, err)
   113  		assert.Equal(t, appID, dest.ID)
   114  		assert.Equal(t, appName, dest.Name)
   115  		assert.Equal(t, appDescription, dest.Description)
   116  	})
   117  
   118  	t.Run("success with order by params", func(t *testing.T) {
   119  		// GIVEN
   120  		db, mock := testdb.MockDatabase(t)
   121  		ctx := persistence.SaveToContext(context.TODO(), db)
   122  		defer mock.AssertExpectations(t)
   123  
   124  		expectedQuery := regexp.QuoteMeta(fmt.Sprintf("SELECT id, name, description FROM %s WHERE %s ORDER BY name ASC", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$1")))
   125  		rows := sqlmock.NewRows([]string{"id", "name", "description"}).AddRow(appID, appName, appDescription)
   126  		mock.ExpectQuery(expectedQuery).WithArgs(tenantID).WillReturnRows(rows)
   127  		dest := App{}
   128  		// WHEN
   129  		err := sut.Get(ctx, resourceType, tenantID, nil, repo.OrderByParams{repo.NewAscOrderBy("name")}, &dest)
   130  		// THEN
   131  		require.NoError(t, err)
   132  		assert.Equal(t, appID, dest.ID)
   133  		assert.Equal(t, appName, dest.Name)
   134  		assert.Equal(t, appDescription, dest.Description)
   135  	})
   136  
   137  	t.Run("success with multiple order by params", func(t *testing.T) {
   138  		// GIVEN
   139  		db, mock := testdb.MockDatabase(t)
   140  		ctx := persistence.SaveToContext(context.TODO(), db)
   141  		defer mock.AssertExpectations(t)
   142  
   143  		expectedQuery := regexp.QuoteMeta(fmt.Sprintf("SELECT id, name, description FROM %s WHERE %s ORDER BY name ASC, description DESC", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$1")))
   144  		rows := sqlmock.NewRows([]string{"id", "name", "description"}).AddRow(appID, appName, appDescription)
   145  		mock.ExpectQuery(expectedQuery).WithArgs(tenantID).WillReturnRows(rows)
   146  		dest := App{}
   147  		// WHEN
   148  		err := sut.Get(ctx, resourceType, tenantID, nil, repo.OrderByParams{repo.NewAscOrderBy("name"), repo.NewDescOrderBy("description")}, &dest)
   149  		// THEN
   150  		require.NoError(t, err)
   151  		assert.Equal(t, appID, dest.ID)
   152  		assert.Equal(t, appName, dest.Name)
   153  		assert.Equal(t, appDescription, dest.Description)
   154  	})
   155  
   156  	t.Run("success with conditions and order by params", func(t *testing.T) {
   157  		// GIVEN
   158  		db, mock := testdb.MockDatabase(t)
   159  		ctx := persistence.SaveToContext(context.TODO(), db)
   160  		defer mock.AssertExpectations(t)
   161  
   162  		expectedQuery := regexp.QuoteMeta(fmt.Sprintf("SELECT id, name, description FROM %s WHERE name = $1 AND description = $2 AND %s ORDER BY name ASC", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$3")))
   163  		rows := sqlmock.NewRows([]string{"id", "name", "description"}).AddRow(appID, appName, appDescription)
   164  		mock.ExpectQuery(expectedQuery).WithArgs(appName, appDescription, tenantID).WillReturnRows(rows)
   165  		dest := App{}
   166  		// WHEN
   167  		err := sut.Get(ctx, resourceType, tenantID, repo.Conditions{repo.NewEqualCondition("name", appName), repo.NewEqualCondition("description", appDescription)}, repo.OrderByParams{repo.NewAscOrderBy("name"), repo.NewDescOrderBy("description")}, &dest)
   168  		// THEN
   169  		require.NoError(t, err)
   170  		assert.Equal(t, appID, dest.ID)
   171  		assert.Equal(t, appName, dest.Name)
   172  		assert.Equal(t, appDescription, dest.Description)
   173  	})
   174  
   175  	t.Run("returns error when operation on db failed", func(t *testing.T) {
   176  		// GIVEN
   177  		db, mock := testdb.MockDatabase(t)
   178  		ctx := persistence.SaveToContext(context.TODO(), db)
   179  		defer mock.AssertExpectations(t)
   180  
   181  		expectedQuery := regexp.QuoteMeta(fmt.Sprintf("SELECT id, name, description FROM %s WHERE id = $1 AND %s", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$2")))
   182  		mock.ExpectQuery(expectedQuery).WithArgs(appID, tenantID).WillReturnError(someError())
   183  		dest := App{}
   184  		// WHEN
   185  		err := sut.Get(ctx, resourceType, tenantID, repo.Conditions{repo.NewEqualCondition("id", appID)}, repo.NoOrderBy, &dest)
   186  		// THEN
   187  		require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query")
   188  	})
   189  
   190  	t.Run("context properly canceled", func(t *testing.T) {
   191  		db, mock := testdb.MockDatabase(t)
   192  		defer mock.AssertExpectations(t)
   193  
   194  		ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
   195  		defer cancel()
   196  
   197  		ctx = persistence.SaveToContext(ctx, db)
   198  		dest := App{}
   199  
   200  		err := sut.Get(ctx, resourceType, tenantID, repo.Conditions{repo.NewEqualCondition("id", appID)}, repo.NoOrderBy, &dest)
   201  
   202  		require.EqualError(t, err, "Internal Server Error: Maximum processing timeout reached")
   203  	})
   204  
   205  	t.Run("returns ErrorNotFound if object not found", func(t *testing.T) {
   206  		// GIVEN
   207  		db, mock := testdb.MockDatabase(t)
   208  		ctx := persistence.SaveToContext(context.TODO(), db)
   209  		defer mock.AssertExpectations(t)
   210  		noRows := sqlmock.NewRows([]string{"id", "name", "description"})
   211  		expectedQuery := regexp.QuoteMeta(fmt.Sprintf("SELECT id, name, description FROM %s WHERE id = $1 AND %s", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$2")))
   212  		mock.ExpectQuery(expectedQuery).WithArgs(appID, tenantID).WillReturnRows(noRows)
   213  		dest := App{}
   214  		// WHEN
   215  		err := sut.Get(ctx, resourceType, tenantID, repo.Conditions{repo.NewEqualCondition("id", appID)}, repo.NoOrderBy, &dest)
   216  		// THEN
   217  		require.NotNil(t, err)
   218  		assert.True(t, apperrors.IsNotFoundError(err))
   219  	})
   220  
   221  	t.Run("returns error if entity does not have tenant access table", func(t *testing.T) {
   222  		db, mock := testdb.MockDatabase(t)
   223  		ctx := persistence.SaveToContext(context.TODO(), db)
   224  		defer mock.AssertExpectations(t)
   225  
   226  		err := sut.Get(ctx, UserType, tenantID, nil, repo.NoOrderBy, &User{})
   227  		require.EqualError(t, err, "entity UserType does not have access table")
   228  	})
   229  
   230  	t.Run("returns error if empty tenant id", func(t *testing.T) {
   231  		db, mock := testdb.MockDatabase(t)
   232  		ctx := persistence.SaveToContext(context.TODO(), db)
   233  		defer mock.AssertExpectations(t)
   234  
   235  		err := sut.Get(ctx, resourceType, "", nil, repo.NoOrderBy, &User{})
   236  		require.EqualError(t, err, apperrors.NewTenantRequiredError().Error())
   237  	})
   238  
   239  	t.Run("returns error if missing persistence context", func(t *testing.T) {
   240  		ctx := context.TODO()
   241  		err := sut.Get(ctx, resourceType, tenantID, repo.Conditions{repo.NewEqualCondition("id", appID)}, repo.NoOrderBy, &User{})
   242  		require.EqualError(t, err, apperrors.NewInternalError("unable to fetch database from context").Error())
   243  	})
   244  
   245  	t.Run("returns error if destination is nil", func(t *testing.T) {
   246  		err := sut.Get(context.TODO(), resourceType, tenantID, repo.Conditions{repo.NewEqualCondition("id", appID)}, repo.NoOrderBy, nil)
   247  		require.EqualError(t, err, apperrors.NewInternalError("item cannot be nil").Error())
   248  	})
   249  }
   250  
   251  func TestGetSingleForUpdate(t *testing.T) {
   252  	sut := repo.NewSingleGetter(appTableName, appColumns)
   253  	resourceType := resource.Application
   254  	m2mTable, ok := resourceType.TenantAccessTable()
   255  	require.True(t, ok)
   256  
   257  	t.Run("success", func(t *testing.T) {
   258  		// GIVEN
   259  		db, mock := testdb.MockDatabase(t)
   260  		ctx := persistence.SaveToContext(context.TODO(), db)
   261  		defer mock.AssertExpectations(t)
   262  
   263  		expectedQuery := regexp.QuoteMeta(fmt.Sprintf("SELECT id, name, description FROM %s WHERE id = $1 AND %s FOR UPDATE", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$2")))
   264  		rows := sqlmock.NewRows([]string{"id", "name", "description"}).AddRow(appID, appName, appDescription)
   265  		mock.ExpectQuery(expectedQuery).WithArgs(appID, tenantID).WillReturnRows(rows)
   266  		dest := App{}
   267  		// WHEN
   268  		err := sut.GetForUpdate(ctx, resourceType, tenantID, repo.Conditions{repo.NewEqualCondition("id", appID)}, repo.NoOrderBy, &dest)
   269  		// THEN
   270  		require.NoError(t, err)
   271  		assert.Equal(t, appID, dest.ID)
   272  		assert.Equal(t, appName, dest.Name)
   273  		assert.Equal(t, appDescription, dest.Description)
   274  	})
   275  }
   276  
   277  func TestGetSingleWithEmbeddedTenant(t *testing.T) {
   278  	givenID := "id"
   279  	sut := repo.NewSingleGetterWithEmbeddedTenant(userTableName, "tenant_id", []string{"id", "tenant_id", "first_name", "last_name", "age"})
   280  
   281  	t.Run("success", func(t *testing.T) {
   282  		// GIVEN
   283  		expectedQuery := regexp.QuoteMeta("SELECT id, tenant_id, first_name, last_name, age FROM users WHERE tenant_id = $1 AND id = $2")
   284  		db, mock := testdb.MockDatabase(t)
   285  		ctx := persistence.SaveToContext(context.TODO(), db)
   286  		defer mock.AssertExpectations(t)
   287  		rows := sqlmock.NewRows([]string{"id", "first_name", "last_name", "age"}).AddRow(givenID, "givenFirstName", "givenLastName", 18)
   288  		mock.ExpectQuery(expectedQuery).WithArgs(tenantID, givenID).WillReturnRows(rows)
   289  		dest := User{}
   290  		// WHEN
   291  		err := sut.Get(ctx, UserType, tenantID, repo.Conditions{repo.NewEqualCondition("id", givenID)}, repo.NoOrderBy, &dest)
   292  		// THEN
   293  		require.NoError(t, err)
   294  		assert.Equal(t, givenID, dest.ID)
   295  		assert.Equal(t, "givenFirstName", dest.FirstName)
   296  		assert.Equal(t, "givenLastName", dest.LastName)
   297  		assert.Equal(t, 18, dest.Age)
   298  	})
   299  
   300  	t.Run("success when no conditions", func(t *testing.T) {
   301  		// GIVEN
   302  		expectedQuery := regexp.QuoteMeta("SELECT id, tenant_id, first_name, last_name, age FROM users WHERE tenant_id = $1")
   303  		db, mock := testdb.MockDatabase(t)
   304  		ctx := persistence.SaveToContext(context.TODO(), db)
   305  		defer mock.AssertExpectations(t)
   306  		rows := sqlmock.NewRows([]string{"id", "first_name", "last_name", "age"}).AddRow(givenID, "givenFirstName", "givenLastName", 18)
   307  		mock.ExpectQuery(expectedQuery).WithArgs(tenantID).WillReturnRows(rows)
   308  		dest := User{}
   309  		// WHEN
   310  		err := sut.Get(ctx, UserType, tenantID, nil, repo.NoOrderBy, &dest)
   311  		// THEN
   312  		require.NoError(t, err)
   313  		assert.Equal(t, givenID, dest.ID)
   314  		assert.Equal(t, "givenFirstName", dest.FirstName)
   315  		assert.Equal(t, "givenLastName", dest.LastName)
   316  		assert.Equal(t, 18, dest.Age)
   317  	})
   318  
   319  	t.Run("success when more conditions", func(t *testing.T) {
   320  		// GIVEN
   321  		expectedQuery := regexp.QuoteMeta("SELECT id, tenant_id, first_name, last_name, age FROM users WHERE tenant_id = $1 AND first_name = $2 AND last_name = $3")
   322  		db, mock := testdb.MockDatabase(t)
   323  		ctx := persistence.SaveToContext(context.TODO(), db)
   324  		defer mock.AssertExpectations(t)
   325  		rows := sqlmock.NewRows([]string{"id"}).AddRow(givenID)
   326  		mock.ExpectQuery(expectedQuery).WithArgs(tenantID, "john", "doe").WillReturnRows(rows)
   327  		// WHEN
   328  		dest := User{}
   329  		err := sut.Get(ctx, UserType, tenantID, repo.Conditions{repo.NewEqualCondition("first_name", "john"), repo.NewEqualCondition("last_name", "doe")}, repo.NoOrderBy, &dest)
   330  		// THEN
   331  		require.NoError(t, err)
   332  	})
   333  
   334  	t.Run("success with order by params", func(t *testing.T) {
   335  		// GIVEN
   336  		expectedQuery := regexp.QuoteMeta("SELECT id, tenant_id, first_name, last_name, age FROM users WHERE tenant_id = $1 ORDER BY first_name ASC")
   337  		db, mock := testdb.MockDatabase(t)
   338  		ctx := persistence.SaveToContext(context.TODO(), db)
   339  		defer mock.AssertExpectations(t)
   340  		rows := sqlmock.NewRows([]string{"id"}).AddRow(givenID)
   341  		mock.ExpectQuery(expectedQuery).WithArgs(tenantID).WillReturnRows(rows)
   342  		// WHEN
   343  		dest := User{}
   344  		err := sut.Get(ctx, UserType, tenantID, nil, repo.OrderByParams{repo.NewAscOrderBy("first_name")}, &dest)
   345  		// THEN
   346  		require.NoError(t, err)
   347  	})
   348  
   349  	t.Run("success with multiple order by params", func(t *testing.T) {
   350  		// GIVEN
   351  		expectedQuery := regexp.QuoteMeta("SELECT id, tenant_id, first_name, last_name, age FROM users WHERE tenant_id = $1 ORDER BY first_name ASC, last_name DESC")
   352  		db, mock := testdb.MockDatabase(t)
   353  		ctx := persistence.SaveToContext(context.TODO(), db)
   354  		defer mock.AssertExpectations(t)
   355  		rows := sqlmock.NewRows([]string{"id"}).AddRow(givenID)
   356  		mock.ExpectQuery(expectedQuery).WithArgs(tenantID).WillReturnRows(rows)
   357  		// WHEN
   358  		dest := User{}
   359  		err := sut.Get(ctx, UserType, tenantID, nil, repo.OrderByParams{repo.NewAscOrderBy("first_name"), repo.NewDescOrderBy("last_name")}, &dest)
   360  		// THEN
   361  		require.NoError(t, err)
   362  	})
   363  
   364  	t.Run("success with conditions and order by params", func(t *testing.T) {
   365  		// GIVEN
   366  		expectedQuery := regexp.QuoteMeta("SELECT id, tenant_id, first_name, last_name, age FROM users WHERE tenant_id = $1 AND first_name = $2 AND last_name = $3 ORDER BY first_name ASC")
   367  		db, mock := testdb.MockDatabase(t)
   368  		ctx := persistence.SaveToContext(context.TODO(), db)
   369  		defer mock.AssertExpectations(t)
   370  		rows := sqlmock.NewRows([]string{"id"}).AddRow(givenID)
   371  		mock.ExpectQuery(expectedQuery).WithArgs(tenantID, "john", "doe").WillReturnRows(rows)
   372  		// WHEN
   373  		dest := User{}
   374  		err := sut.Get(ctx,
   375  			UserType,
   376  			tenantID,
   377  			repo.Conditions{repo.NewEqualCondition("first_name", "john"), repo.NewEqualCondition("last_name", "doe")},
   378  			repo.OrderByParams{repo.NewAscOrderBy("first_name")},
   379  			&dest)
   380  		// THEN
   381  		require.NoError(t, err)
   382  	})
   383  
   384  	t.Run("returns error when operation on db failed", func(t *testing.T) {
   385  		// GIVEN
   386  		expectedQuery := regexp.QuoteMeta("SELECT id, tenant_id, first_name, last_name, age FROM users WHERE tenant_id = $1 AND id = $2")
   387  		db, mock := testdb.MockDatabase(t)
   388  		ctx := persistence.SaveToContext(context.TODO(), db)
   389  		defer mock.AssertExpectations(t)
   390  		mock.ExpectQuery(expectedQuery).WithArgs(tenantID, givenID).WillReturnError(someError())
   391  		dest := User{}
   392  		// WHEN
   393  		err := sut.Get(ctx, UserType, tenantID, repo.Conditions{repo.NewEqualCondition("id", givenID)}, repo.NoOrderBy, &dest)
   394  		// THEN
   395  		require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query")
   396  	})
   397  
   398  	t.Run("returns ErrorNotFound if object not found", func(t *testing.T) {
   399  		// GIVEN
   400  		expectedQuery := regexp.QuoteMeta("SELECT id, tenant_id, first_name, last_name, age FROM users WHERE tenant_id = $1 AND id = $2")
   401  		db, mock := testdb.MockDatabase(t)
   402  		ctx := persistence.SaveToContext(context.TODO(), db)
   403  		defer mock.AssertExpectations(t)
   404  		noRows := sqlmock.NewRows([]string{"id", "first_name", "last_name", "age"})
   405  		mock.ExpectQuery(expectedQuery).WithArgs(tenantID, givenID).WillReturnRows(noRows)
   406  		dest := User{}
   407  		// WHEN
   408  		err := sut.Get(ctx, UserType, tenantID, repo.Conditions{repo.NewEqualCondition("id", givenID)}, repo.NoOrderBy, &dest)
   409  		// THEN
   410  		require.NotNil(t, err)
   411  		assert.True(t, apperrors.IsNotFoundError(err))
   412  	})
   413  
   414  	t.Run("returns error if missing persistence context", func(t *testing.T) {
   415  		ctx := context.TODO()
   416  		err := sut.Get(ctx, UserType, tenantID, repo.Conditions{repo.NewEqualCondition("id", givenID)}, repo.NoOrderBy, &User{})
   417  		require.EqualError(t, err, apperrors.NewInternalError("unable to fetch database from context").Error())
   418  	})
   419  
   420  	t.Run("returns error if destination is nil", func(t *testing.T) {
   421  		err := sut.Get(context.TODO(), UserType, tenantID, repo.Conditions{repo.NewEqualCondition("id", givenID)}, repo.NoOrderBy, nil)
   422  		require.EqualError(t, err, apperrors.NewInternalError("item cannot be nil").Error())
   423  	})
   424  }
   425  
   426  func TestGetSingleGlobal(t *testing.T) {
   427  	givenID := "id"
   428  	sut := repo.NewSingleGetterGlobal(UserType, "users", []string{"id", "tenant_id", "first_name", "last_name", "age"})
   429  
   430  	t.Run("success", func(t *testing.T) {
   431  		// GIVEN
   432  		expectedQuery := regexp.QuoteMeta("SELECT id, tenant_id, first_name, last_name, age FROM users WHERE id = $1")
   433  		db, mock := testdb.MockDatabase(t)
   434  		ctx := persistence.SaveToContext(context.TODO(), db)
   435  		defer mock.AssertExpectations(t)
   436  		rows := sqlmock.NewRows([]string{"id", "first_name", "last_name", "age"}).AddRow(givenID, "givenFirstName", "givenLastName", 18)
   437  		mock.ExpectQuery(expectedQuery).WithArgs(givenID).WillReturnRows(rows)
   438  		dest := User{}
   439  		// WHEN
   440  		err := sut.GetGlobal(ctx, repo.Conditions{repo.NewEqualCondition("id", givenID)}, repo.NoOrderBy, &dest)
   441  		// THEN
   442  		require.NoError(t, err)
   443  		assert.Equal(t, givenID, dest.ID)
   444  		assert.Equal(t, "givenFirstName", dest.FirstName)
   445  		assert.Equal(t, "givenLastName", dest.LastName)
   446  		assert.Equal(t, 18, dest.Age)
   447  	})
   448  
   449  	t.Run("success when no conditions", func(t *testing.T) {
   450  		// GIVEN
   451  		expectedQuery := regexp.QuoteMeta("SELECT id, tenant_id, first_name, last_name, age FROM users")
   452  		db, mock := testdb.MockDatabase(t)
   453  		ctx := persistence.SaveToContext(context.TODO(), db)
   454  		defer mock.AssertExpectations(t)
   455  		rows := sqlmock.NewRows([]string{"id", "first_name", "last_name", "age"}).AddRow(givenID, "givenFirstName", "givenLastName", 18)
   456  		mock.ExpectQuery(expectedQuery).WillReturnRows(rows)
   457  		dest := User{}
   458  		// WHEN
   459  		err := sut.GetGlobal(ctx, nil, repo.NoOrderBy, &dest)
   460  		// THEN
   461  		require.NoError(t, err)
   462  		assert.Equal(t, givenID, dest.ID)
   463  		assert.Equal(t, "givenFirstName", dest.FirstName)
   464  		assert.Equal(t, "givenLastName", dest.LastName)
   465  		assert.Equal(t, 18, dest.Age)
   466  	})
   467  
   468  	t.Run("success when more conditions", func(t *testing.T) {
   469  		// GIVEN
   470  		expectedQuery := regexp.QuoteMeta("SELECT id, tenant_id, first_name, last_name, age FROM users WHERE first_name = $1 AND last_name = $2")
   471  		db, mock := testdb.MockDatabase(t)
   472  		ctx := persistence.SaveToContext(context.TODO(), db)
   473  		defer mock.AssertExpectations(t)
   474  		rows := sqlmock.NewRows([]string{"id"}).AddRow(givenID)
   475  		mock.ExpectQuery(expectedQuery).WithArgs("john", "doe").WillReturnRows(rows)
   476  		// WHEN
   477  		dest := User{}
   478  		err := sut.GetGlobal(ctx, repo.Conditions{repo.NewEqualCondition("first_name", "john"), repo.NewEqualCondition("last_name", "doe")}, repo.NoOrderBy, &dest)
   479  		// THEN
   480  		require.NoError(t, err)
   481  	})
   482  
   483  	t.Run("success with order by params", func(t *testing.T) {
   484  		// GIVEN
   485  		expectedQuery := regexp.QuoteMeta("SELECT id, tenant_id, first_name, last_name, age FROM users ORDER BY first_name ASC")
   486  		db, mock := testdb.MockDatabase(t)
   487  		ctx := persistence.SaveToContext(context.TODO(), db)
   488  		defer mock.AssertExpectations(t)
   489  		rows := sqlmock.NewRows([]string{"id"}).AddRow(givenID)
   490  		mock.ExpectQuery(expectedQuery).WillReturnRows(rows)
   491  		// WHEN
   492  		dest := User{}
   493  		err := sut.GetGlobal(ctx, nil, repo.OrderByParams{repo.NewAscOrderBy("first_name")}, &dest)
   494  		// THEN
   495  		require.NoError(t, err)
   496  	})
   497  
   498  	t.Run("success with multiple order by params", func(t *testing.T) {
   499  		// GIVEN
   500  		expectedQuery := regexp.QuoteMeta("SELECT id, tenant_id, first_name, last_name, age FROM users ORDER BY first_name ASC, last_name DESC")
   501  		db, mock := testdb.MockDatabase(t)
   502  		ctx := persistence.SaveToContext(context.TODO(), db)
   503  		defer mock.AssertExpectations(t)
   504  		rows := sqlmock.NewRows([]string{"id"}).AddRow(givenID)
   505  		mock.ExpectQuery(expectedQuery).WillReturnRows(rows)
   506  		// WHEN
   507  		dest := User{}
   508  		err := sut.GetGlobal(ctx, nil, repo.OrderByParams{repo.NewAscOrderBy("first_name"), repo.NewDescOrderBy("last_name")}, &dest)
   509  		// THEN
   510  		require.NoError(t, err)
   511  	})
   512  
   513  	t.Run("success with conditions and order by params", func(t *testing.T) {
   514  		// GIVEN
   515  		expectedQuery := regexp.QuoteMeta("SELECT id, tenant_id, first_name, last_name, age FROM users WHERE first_name = $1 AND last_name = $2 ORDER BY first_name ASC")
   516  		db, mock := testdb.MockDatabase(t)
   517  		ctx := persistence.SaveToContext(context.TODO(), db)
   518  		defer mock.AssertExpectations(t)
   519  		rows := sqlmock.NewRows([]string{"id"}).AddRow(givenID)
   520  		mock.ExpectQuery(expectedQuery).WithArgs("john", "doe").WillReturnRows(rows)
   521  		// WHEN
   522  		dest := User{}
   523  		err := sut.GetGlobal(ctx,
   524  			repo.Conditions{repo.NewEqualCondition("first_name", "john"), repo.NewEqualCondition("last_name", "doe")},
   525  			repo.OrderByParams{repo.NewAscOrderBy("first_name")},
   526  			&dest)
   527  		// THEN
   528  		require.NoError(t, err)
   529  	})
   530  
   531  	t.Run("returns error when operation on db failed", func(t *testing.T) {
   532  		// GIVEN
   533  		expectedQuery := regexp.QuoteMeta("SELECT id, tenant_id, first_name, last_name, age FROM users WHERE id = $1")
   534  		db, mock := testdb.MockDatabase(t)
   535  		ctx := persistence.SaveToContext(context.TODO(), db)
   536  		defer mock.AssertExpectations(t)
   537  		mock.ExpectQuery(expectedQuery).WithArgs(givenID).WillReturnError(someError())
   538  		dest := User{}
   539  		// WHEN
   540  		err := sut.GetGlobal(ctx, repo.Conditions{repo.NewEqualCondition("id", givenID)}, repo.NoOrderBy, &dest)
   541  		// THEN
   542  		require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query")
   543  	})
   544  
   545  	t.Run("returns ErrorNotFound if object not found", func(t *testing.T) {
   546  		// GIVEN
   547  		expectedQuery := regexp.QuoteMeta("SELECT id, tenant_id, first_name, last_name, age FROM users WHERE id = $1")
   548  		db, mock := testdb.MockDatabase(t)
   549  		ctx := persistence.SaveToContext(context.TODO(), db)
   550  		defer mock.AssertExpectations(t)
   551  		noRows := sqlmock.NewRows([]string{"id", "first_name", "last_name", "age"})
   552  		mock.ExpectQuery(expectedQuery).WithArgs(givenID).WillReturnRows(noRows)
   553  		dest := User{}
   554  		// WHEN
   555  		err := sut.GetGlobal(ctx, repo.Conditions{repo.NewEqualCondition("id", givenID)}, repo.NoOrderBy, &dest)
   556  		// THEN
   557  		require.NotNil(t, err)
   558  		assert.True(t, apperrors.IsNotFoundError(err))
   559  	})
   560  
   561  	t.Run("returns error if missing persistence context", func(t *testing.T) {
   562  		ctx := context.TODO()
   563  		err := sut.GetGlobal(ctx, repo.Conditions{repo.NewEqualCondition("id", givenID)}, repo.NoOrderBy, &User{})
   564  		require.EqualError(t, err, apperrors.NewInternalError("unable to fetch database from context").Error())
   565  	})
   566  
   567  	t.Run("returns error if destination is nil", func(t *testing.T) {
   568  		err := sut.GetGlobal(context.TODO(), repo.Conditions{repo.NewEqualCondition("id", givenID)}, repo.NoOrderBy, nil)
   569  		require.EqualError(t, err, apperrors.NewInternalError("item cannot be nil").Error())
   570  	})
   571  }