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

     1  package repo_test
     2  
     3  import (
     4  	"context"
     5  	"database/sql/driver"
     6  	"fmt"
     7  	"regexp"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/DATA-DOG/go-sqlmock"
    12  	"github.com/jmoiron/sqlx"
    13  	"github.com/kyma-incubator/compass/components/director/internal/repo"
    14  	"github.com/kyma-incubator/compass/components/director/internal/repo/testdb"
    15  	"github.com/kyma-incubator/compass/components/director/pkg/apperrors"
    16  	"github.com/kyma-incubator/compass/components/director/pkg/persistence"
    17  	"github.com/kyma-incubator/compass/components/director/pkg/resource"
    18  	"github.com/stretchr/testify/assert"
    19  	"github.com/stretchr/testify/require"
    20  )
    21  
    22  func TestListPageable(t *testing.T) {
    23  	sut := repo.NewPageableQuerier(appTableName, appColumns)
    24  	resourceType := resource.Application
    25  	m2mTable, ok := resourceType.TenantAccessTable()
    26  	require.True(t, ok)
    27  
    28  	t.Run("returns first page and there are no more pages", func(t *testing.T) {
    29  		db, mock := testdb.MockDatabase(t)
    30  		defer mock.AssertExpectations(t)
    31  
    32  		rows := sqlmock.NewRows(appColumns).
    33  			AddRow(appID, appName, appDescription).
    34  			AddRow(appID2, appName2, appDescription2)
    35  		mock.ExpectQuery(regexp.QuoteMeta(fmt.Sprintf("SELECT id, name, description FROM %s WHERE %s ORDER BY id LIMIT 10 OFFSET 0", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$1")))).
    36  			WithArgs(tenantID).WillReturnRows(rows)
    37  		mock.ExpectQuery(regexp.QuoteMeta(fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE %s", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$1")))).
    38  			WithArgs(tenantID).WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(2))
    39  		ctx := persistence.SaveToContext(context.TODO(), db)
    40  		var dest AppCollection
    41  
    42  		actualPage, actualTotal, err := sut.List(ctx, resourceType, tenantID, 10, "", "id", &dest)
    43  		require.NoError(t, err)
    44  		assert.Equal(t, 2, actualTotal)
    45  		assert.Len(t, dest, 2)
    46  		assert.Equal(t, *fixApp, dest[0])
    47  		assert.Equal(t, *fixApp2, dest[1])
    48  		assert.False(t, actualPage.HasNextPage)
    49  	})
    50  
    51  	t.Run("returns full page and has next page", func(t *testing.T) {
    52  		db, mock := testdb.MockDatabase(t)
    53  		defer mock.AssertExpectations(t)
    54  
    55  		rows := sqlmock.NewRows(appColumns).
    56  			AddRow(appID, appName, appDescription).
    57  			AddRow(appID2, appName2, appDescription2)
    58  		mock.ExpectQuery(regexp.QuoteMeta(fmt.Sprintf("SELECT id, name, description FROM %s WHERE %s ORDER BY id LIMIT 2 OFFSET 0", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$1")))).
    59  			WithArgs(tenantID).WillReturnRows(rows)
    60  		mock.ExpectQuery(regexp.QuoteMeta(fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE %s", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$1")))).
    61  			WithArgs(tenantID).WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(100))
    62  		ctx := persistence.SaveToContext(context.TODO(), db)
    63  		var dest AppCollection
    64  
    65  		actualPage, actualTotal, err := sut.List(ctx, resourceType, tenantID, 2, "", "id", &dest)
    66  		require.NoError(t, err)
    67  		assert.Equal(t, 100, actualTotal)
    68  		assert.Len(t, dest, 2)
    69  		assert.True(t, actualPage.HasNextPage)
    70  		assert.NotEmpty(t, actualPage.EndCursor)
    71  	})
    72  
    73  	t.Run("returns many pages and I can traverse it using cursor", func(t *testing.T) {
    74  		db, mock := testdb.MockDatabase(t)
    75  		defer mock.AssertExpectations(t)
    76  
    77  		rowsForPage1 := sqlmock.NewRows(appColumns).
    78  			AddRow(appID, appName, appDescription)
    79  		rowsForPage2 := sqlmock.NewRows(appColumns).
    80  			AddRow(appID2, appName2, appDescription2)
    81  
    82  		mock.ExpectQuery(regexp.QuoteMeta(fmt.Sprintf("SELECT id, name, description FROM %s WHERE %s ORDER BY id LIMIT 1 OFFSET 0", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$1")))).
    83  			WithArgs(tenantID).WillReturnRows(rowsForPage1)
    84  		mock.ExpectQuery(regexp.QuoteMeta(fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE %s", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$1")))).
    85  			WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(100))
    86  		mock.ExpectQuery(regexp.QuoteMeta(fmt.Sprintf("SELECT id, name, description FROM %s WHERE %s ORDER BY id LIMIT 1 OFFSET 1", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$1")))).
    87  			WithArgs(tenantID).WillReturnRows(rowsForPage2)
    88  		mock.ExpectQuery(regexp.QuoteMeta(fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE %s", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$1")))).
    89  			WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(100))
    90  
    91  		ctx := persistence.SaveToContext(context.TODO(), db)
    92  		var first AppCollection
    93  
    94  		actualFirstPage, actualTotal, err := sut.List(ctx, resourceType, tenantID, 1, "", "id", &first)
    95  		require.NoError(t, err)
    96  		assert.Equal(t, 100, actualTotal)
    97  		assert.Len(t, first, 1)
    98  		assert.True(t, actualFirstPage.HasNextPage)
    99  		assert.NotEmpty(t, actualFirstPage.EndCursor)
   100  
   101  		var second AppCollection
   102  		actualSecondPage, actualTotal, err := sut.List(ctx, resourceType, tenantID, 1, actualFirstPage.EndCursor, "id", &second)
   103  		require.NoError(t, err)
   104  		assert.Equal(t, 100, actualTotal)
   105  		assert.Len(t, second, 1)
   106  		assert.True(t, actualSecondPage.HasNextPage)
   107  		assert.NotEmpty(t, actualSecondPage.EndCursor)
   108  	})
   109  
   110  	t.Run("returns page without conditions", func(t *testing.T) {
   111  		db, mock := testdb.MockDatabase(t)
   112  		defer mock.AssertExpectations(t)
   113  
   114  		rows := sqlmock.NewRows(appColumns).
   115  			AddRow(appID, appName, appDescription)
   116  		mock.ExpectQuery(regexp.QuoteMeta(fmt.Sprintf("SELECT id, name, description FROM %s WHERE %s ORDER BY id LIMIT 2 OFFSET 0", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$1")))).
   117  			WithArgs(tenantID).WillReturnRows(rows)
   118  		mock.ExpectQuery(regexp.QuoteMeta(fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE %s", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$1")))).
   119  			WithArgs(tenantID).WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(100))
   120  		ctx := persistence.SaveToContext(context.TODO(), db)
   121  		var dest AppCollection
   122  
   123  		actualPage, actualTotal, err := sut.List(ctx, resourceType, tenantID, 2, "", "id", &dest)
   124  		require.NoError(t, err)
   125  		assert.Equal(t, 100, actualTotal)
   126  		assert.Len(t, dest, 1)
   127  		assert.True(t, actualPage.HasNextPage)
   128  		assert.NotEmpty(t, actualPage.EndCursor)
   129  	})
   130  
   131  	t.Run("returns page with additional conditions", func(t *testing.T) {
   132  		db, mock := testdb.MockDatabase(t)
   133  		defer mock.AssertExpectations(t)
   134  
   135  		rows := sqlmock.NewRows(appColumns).
   136  			AddRow(appID, appName, appDescription)
   137  		mock.ExpectQuery(regexp.QuoteMeta(fmt.Sprintf("SELECT id, name, description FROM %s WHERE (name = $1 AND description != $2 AND %s) ORDER BY id LIMIT 2 OFFSET 0", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$3")))).
   138  			WithArgs(appName, appDescription2, tenantID).
   139  			WillReturnRows(rows)
   140  		mock.ExpectQuery(regexp.QuoteMeta(fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE (name = $1 AND description != $2 AND %s)", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$3")))).
   141  			WithArgs(appName, appDescription2, tenantID).
   142  			WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(100))
   143  		ctx := persistence.SaveToContext(context.TODO(), db)
   144  		var dest AppCollection
   145  
   146  		conditions := repo.Conditions{
   147  			repo.NewEqualCondition("name", appName),
   148  			repo.NewNotEqualCondition("description", appDescription2),
   149  		}
   150  
   151  		actualPage, actualTotal, err := sut.List(ctx, resourceType, tenantID, 2, "", "id", &dest, conditions...)
   152  		require.NoError(t, err)
   153  		assert.Equal(t, 100, actualTotal)
   154  		assert.Len(t, dest, 1)
   155  		assert.True(t, actualPage.HasNextPage)
   156  		assert.NotEmpty(t, actualPage.EndCursor)
   157  	})
   158  
   159  	t.Run("returns empty page", func(t *testing.T) {
   160  		db, mock := testdb.MockDatabase(t)
   161  		defer mock.AssertExpectations(t)
   162  
   163  		rows := sqlmock.NewRows(appColumns)
   164  		mock.ExpectQuery(regexp.QuoteMeta(fmt.Sprintf("SELECT id, name, description FROM %s WHERE %s ORDER BY id LIMIT 2 OFFSET 0", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$1")))).
   165  			WithArgs(tenantID).WillReturnRows(rows)
   166  		mock.ExpectQuery(regexp.QuoteMeta(fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE %s", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$1")))).
   167  			WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(0))
   168  		ctx := persistence.SaveToContext(context.TODO(), db)
   169  		var dest AppCollection
   170  
   171  		actualPage, actualTotal, err := sut.List(ctx, resourceType, tenantID, 2, "", "id", &dest)
   172  		require.NoError(t, err)
   173  		assert.Equal(t, 0, actualTotal)
   174  		assert.Empty(t, dest)
   175  		assert.False(t, actualPage.HasNextPage)
   176  	})
   177  
   178  	t.Run("returns error if missing persistence context", func(t *testing.T) {
   179  		ctx := context.TODO()
   180  		_, _, err := sut.List(ctx, resourceType, tenantID, 2, "", "id", nil)
   181  		require.EqualError(t, err, apperrors.NewInternalError("unable to fetch database from context").Error())
   182  	})
   183  
   184  	t.Run("returns error if empty tenant", func(t *testing.T) {
   185  		ctx := context.TODO()
   186  		_, _, err := sut.List(ctx, resourceType, "", 2, "", "id", nil)
   187  		require.EqualError(t, err, apperrors.NewTenantRequiredError().Error())
   188  	})
   189  
   190  	t.Run("returns error if wrong cursor", func(t *testing.T) {
   191  		ctx := persistence.SaveToContext(context.TODO(), &sqlx.Tx{})
   192  		_, _, err := sut.List(ctx, resourceType, tenantID, 2, "zzz", "", nil)
   193  		require.EqualError(t, err, "while decoding page cursor: cursor is not correct: illegal base64 data at input byte 0")
   194  	})
   195  
   196  	t.Run("returns error if wrong pagination attributes", func(t *testing.T) {
   197  		ctx := persistence.SaveToContext(context.TODO(), &sqlx.Tx{})
   198  		_, _, err := sut.List(ctx, resourceType, tenantID, -3, "", "id", nil)
   199  		require.EqualError(t, err, "while converting offset and limit to cursor: Invalid data [reason=page size cannot be smaller than 1]")
   200  	})
   201  
   202  	t.Run("returns error on db operation", func(t *testing.T) {
   203  		db, mock := testdb.MockDatabase(t)
   204  		defer mock.AssertExpectations(t)
   205  
   206  		mock.ExpectQuery(`SELECT .*`).WillReturnError(someError())
   207  		ctx := persistence.SaveToContext(context.TODO(), db)
   208  		var dest AppCollection
   209  
   210  		_, _, err := sut.List(ctx, resourceType, tenantID, 2, "", "id", &dest)
   211  
   212  		require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query")
   213  	})
   214  
   215  	t.Run("returns error on calculating total count", func(t *testing.T) {
   216  		db, mock := testdb.MockDatabase(t)
   217  		defer mock.AssertExpectations(t)
   218  
   219  		rows := sqlmock.NewRows(appColumns)
   220  		mock.ExpectQuery(regexp.QuoteMeta(fmt.Sprintf("SELECT id, name, description FROM %s WHERE %s ORDER BY id LIMIT 2 OFFSET 0", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$1")))).
   221  			WillReturnRows(rows)
   222  		mock.ExpectQuery(regexp.QuoteMeta(fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE %s", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$1")))).
   223  			WillReturnError(someError())
   224  		ctx := persistence.SaveToContext(context.TODO(), db)
   225  		var dest AppCollection
   226  
   227  		_, _, err := sut.List(ctx, resourceType, tenantID, 2, "", "id", &dest)
   228  		require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query")
   229  	})
   230  }
   231  
   232  func TestListPageableWithEmbeddedTenant(t *testing.T) {
   233  	peterID := "peterID"
   234  	homerID := "homerID"
   235  	peter := User{FirstName: "Peter", LastName: "Griffin", Age: 40, ID: peterID}
   236  	peterRow := []driver.Value{peterID, "Peter", "Griffin", 40}
   237  	homer := User{FirstName: "Homer", LastName: "Simpson", Age: 55, ID: homerID}
   238  	homerRow := []driver.Value{homerID, "Homer", "Simpson", 55}
   239  
   240  	sut := repo.NewPageableQuerierWithEmbeddedTenant(userTableName, "tenant_id", []string{"id", "first_name", "last_name", "age"})
   241  
   242  	t.Run("returns first page and there are no more pages", func(t *testing.T) {
   243  		db, mock := testdb.MockDatabase(t)
   244  		defer mock.AssertExpectations(t)
   245  
   246  		rows := sqlmock.NewRows([]string{"id", "first_name", "last_name", "age"}).
   247  			AddRow(peterRow...).
   248  			AddRow(homerRow...)
   249  		mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, first_name, last_name, age FROM users WHERE tenant_id = $1 ORDER BY id LIMIT 10 OFFSET 0`)).WithArgs(tenantID).WillReturnRows(rows)
   250  		mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM users WHERE tenant_id = $1`)).WithArgs(tenantID).WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(2))
   251  		ctx := persistence.SaveToContext(context.TODO(), db)
   252  		var dest UserCollection
   253  
   254  		actualPage, actualTotal, err := sut.List(ctx, UserType, tenantID, 10, "", "id", &dest)
   255  		require.NoError(t, err)
   256  		assert.Equal(t, 2, actualTotal)
   257  		assert.Len(t, dest, 2)
   258  		assert.Equal(t, peter, dest[0])
   259  		assert.Equal(t, homer, dest[1])
   260  		assert.False(t, actualPage.HasNextPage)
   261  	})
   262  
   263  	t.Run("returns full page and has next page", func(t *testing.T) {
   264  		db, mock := testdb.MockDatabase(t)
   265  		defer mock.AssertExpectations(t)
   266  
   267  		rows := sqlmock.NewRows([]string{"id", "first_name", "last_name", "age"}).
   268  			AddRow(peterRow...).
   269  			AddRow(homerRow...)
   270  		mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, first_name, last_name, age FROM users WHERE tenant_id = $1 ORDER BY id LIMIT 2 OFFSET 0`)).WithArgs(tenantID).WillReturnRows(rows)
   271  		mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM users WHERE tenant_id = $1`)).WithArgs(tenantID).WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(100))
   272  		ctx := persistence.SaveToContext(context.TODO(), db)
   273  		var dest UserCollection
   274  
   275  		actualPage, actualTotal, err := sut.List(ctx, UserType, tenantID, 2, "", "id", &dest)
   276  		require.NoError(t, err)
   277  		assert.Equal(t, 100, actualTotal)
   278  		assert.Len(t, dest, 2)
   279  		assert.True(t, actualPage.HasNextPage)
   280  		assert.NotEmpty(t, actualPage.EndCursor)
   281  	})
   282  
   283  	t.Run("returns many pages and I can traverse it using cursor", func(t *testing.T) {
   284  		db, mock := testdb.MockDatabase(t)
   285  		defer mock.AssertExpectations(t)
   286  
   287  		rowsForPage1 := sqlmock.NewRows([]string{"id", "first_name", "last_name", "age"}).
   288  			AddRow(peterRow...)
   289  		rowsForPage2 := sqlmock.NewRows([]string{"id", "first_name", "last_name", "age"}).
   290  			AddRow(homerRow...)
   291  
   292  		mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, first_name, last_name, age FROM users WHERE tenant_id = $1 ORDER BY id LIMIT 1 OFFSET 0`)).WithArgs(tenantID).WillReturnRows(rowsForPage1)
   293  		mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM users WHERE tenant_id = $1`)).WithArgs(tenantID).WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(100))
   294  		mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, first_name, last_name, age FROM users WHERE tenant_id = $1 ORDER BY id LIMIT 1 OFFSET 1`)).WithArgs(tenantID).WillReturnRows(rowsForPage2)
   295  		mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM users WHERE tenant_id = $1`)).WithArgs(tenantID).WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(100))
   296  
   297  		ctx := persistence.SaveToContext(context.TODO(), db)
   298  		var first UserCollection
   299  
   300  		actualFirstPage, actualTotal, err := sut.List(ctx, UserType, tenantID, 1, "", "id", &first)
   301  		require.NoError(t, err)
   302  		assert.Equal(t, 100, actualTotal)
   303  		assert.Len(t, first, 1)
   304  		assert.True(t, actualFirstPage.HasNextPage)
   305  		assert.NotEmpty(t, actualFirstPage.EndCursor)
   306  
   307  		var second UserCollection
   308  		actualSecondPage, actualTotal, err := sut.List(ctx, UserType, tenantID, 1, actualFirstPage.EndCursor, "id", &second)
   309  		require.NoError(t, err)
   310  		assert.Equal(t, 100, actualTotal)
   311  		assert.Len(t, second, 1)
   312  		assert.True(t, actualSecondPage.HasNextPage)
   313  		assert.NotEmpty(t, actualSecondPage.EndCursor)
   314  	})
   315  
   316  	t.Run("returns page without conditions", func(t *testing.T) {
   317  		db, mock := testdb.MockDatabase(t)
   318  		defer mock.AssertExpectations(t)
   319  
   320  		rows := sqlmock.NewRows([]string{"id", "first_name", "last_name", "age"}).
   321  			AddRow(peterRow...)
   322  		mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, first_name, last_name, age FROM users WHERE tenant_id = $1 ORDER BY id LIMIT 2 OFFSET 0`)).WithArgs(tenantID).WillReturnRows(rows)
   323  		mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM users WHERE tenant_id = $1`)).WithArgs(tenantID).WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(100))
   324  		ctx := persistence.SaveToContext(context.TODO(), db)
   325  		var dest UserCollection
   326  
   327  		actualPage, actualTotal, err := sut.List(ctx, UserType, tenantID, 2, "", "id", &dest)
   328  		require.NoError(t, err)
   329  		assert.Equal(t, 100, actualTotal)
   330  		assert.Len(t, dest, 1)
   331  		assert.True(t, actualPage.HasNextPage)
   332  		assert.NotEmpty(t, actualPage.EndCursor)
   333  	})
   334  
   335  	t.Run("returns page with additional conditions", func(t *testing.T) {
   336  		db, mock := testdb.MockDatabase(t)
   337  		defer mock.AssertExpectations(t)
   338  
   339  		rows := sqlmock.NewRows([]string{"id", "first_name", "last_name", "age"}).
   340  			AddRow(peterRow...)
   341  		mock.ExpectQuery(regexp.QuoteMeta("SELECT id, first_name, last_name, age FROM users WHERE (tenant_id = $1 AND first_name = $2 AND age != $3) ORDER BY id LIMIT 2 OFFSET 0")).
   342  			WithArgs(tenantID, "Peter", 18).
   343  			WillReturnRows(rows)
   344  		mock.ExpectQuery(regexp.QuoteMeta("SELECT COUNT(*) FROM users WHERE (tenant_id = $1 AND first_name = $2 AND age != $3)")).
   345  			WithArgs(tenantID, "Peter", 18).
   346  			WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(100))
   347  		ctx := persistence.SaveToContext(context.TODO(), db)
   348  		var dest UserCollection
   349  
   350  		conditions := repo.Conditions{
   351  			repo.NewEqualCondition("first_name", "Peter"),
   352  			repo.NewNotEqualCondition("age", 18),
   353  		}
   354  
   355  		actualPage, actualTotal, err := sut.List(ctx, UserType, tenantID, 2, "", "id", &dest, conditions...)
   356  		require.NoError(t, err)
   357  		assert.Equal(t, 100, actualTotal)
   358  		assert.Len(t, dest, 1)
   359  		assert.True(t, actualPage.HasNextPage)
   360  		assert.NotEmpty(t, actualPage.EndCursor)
   361  	})
   362  
   363  	t.Run("returns empty page", func(t *testing.T) {
   364  		db, mock := testdb.MockDatabase(t)
   365  		defer mock.AssertExpectations(t)
   366  
   367  		rows := sqlmock.NewRows([]string{"id", "first_name", "last_name", "age"})
   368  		mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, first_name, last_name, age FROM users WHERE tenant_id = $1 ORDER BY id LIMIT 2 OFFSET 0`)).WithArgs(tenantID).WillReturnRows(rows)
   369  		mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM users WHERE tenant_id = $1`)).WithArgs(tenantID).WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(0))
   370  		ctx := persistence.SaveToContext(context.TODO(), db)
   371  		var dest UserCollection
   372  
   373  		actualPage, actualTotal, err := sut.List(ctx, UserType, tenantID, 2, "", "id", &dest)
   374  		require.NoError(t, err)
   375  		assert.Equal(t, 0, actualTotal)
   376  		assert.Empty(t, dest)
   377  		assert.False(t, actualPage.HasNextPage)
   378  	})
   379  
   380  	t.Run("returns error if missing persistence context", func(t *testing.T) {
   381  		ctx := context.TODO()
   382  		_, _, err := sut.List(ctx, UserType, tenantID, 2, "", "id", nil)
   383  		require.EqualError(t, err, apperrors.NewInternalError("unable to fetch database from context").Error())
   384  	})
   385  
   386  	t.Run("returns error if wrong cursor", func(t *testing.T) {
   387  		ctx := persistence.SaveToContext(context.TODO(), &sqlx.Tx{})
   388  		_, _, err := sut.List(ctx, UserType, tenantID, 2, "zzz", "", nil)
   389  		require.EqualError(t, err, "while decoding page cursor: cursor is not correct: illegal base64 data at input byte 0")
   390  	})
   391  
   392  	t.Run("returns error if wrong pagination attributes", func(t *testing.T) {
   393  		ctx := persistence.SaveToContext(context.TODO(), &sqlx.Tx{})
   394  		_, _, err := sut.List(ctx, UserType, tenantID, -3, "", "id", nil)
   395  		require.EqualError(t, err, "while converting offset and limit to cursor: Invalid data [reason=page size cannot be smaller than 1]")
   396  	})
   397  
   398  	t.Run("returns error on db operation", func(t *testing.T) {
   399  		db, mock := testdb.MockDatabase(t)
   400  		defer mock.AssertExpectations(t)
   401  
   402  		mock.ExpectQuery(`SELECT .*`).WillReturnError(someError())
   403  		ctx := persistence.SaveToContext(context.TODO(), db)
   404  		var dest UserCollection
   405  
   406  		_, _, err := sut.List(ctx, UserType, tenantID, 2, "", "id", &dest)
   407  
   408  		require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query")
   409  	})
   410  
   411  	t.Run("context properly canceled", func(t *testing.T) {
   412  		db, mock := testdb.MockDatabase(t)
   413  		defer mock.AssertExpectations(t)
   414  
   415  		ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
   416  		defer cancel()
   417  
   418  		ctx = persistence.SaveToContext(ctx, db)
   419  		var dest UserCollection
   420  
   421  		_, _, err := sut.List(ctx, UserType, tenantID, 2, "", "id", &dest)
   422  
   423  		require.EqualError(t, err, "Internal Server Error: Maximum processing timeout reached")
   424  	})
   425  
   426  	t.Run("returns error on calculating total count", func(t *testing.T) {
   427  		db, mock := testdb.MockDatabase(t)
   428  		defer mock.AssertExpectations(t)
   429  
   430  		rows := sqlmock.NewRows([]string{"id", "first_name", "last_name", "age"})
   431  		mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, first_name, last_name, age FROM users WHERE tenant_id = $1 ORDER BY id LIMIT 2 OFFSET 0`)).WithArgs(tenantID).WillReturnRows(rows)
   432  		mock.ExpectQuery(`SELECT COUNT\(\*\).*`).WillReturnError(someError())
   433  		ctx := persistence.SaveToContext(context.TODO(), db)
   434  		var dest UserCollection
   435  
   436  		_, _, err := sut.List(ctx, UserType, tenantID, 2, "", "id", &dest)
   437  		require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query")
   438  	})
   439  }
   440  
   441  func TestListPageableGlobal(t *testing.T) {
   442  	peterID := "peterID"
   443  	homerID := "homerID"
   444  	peter := User{FirstName: "Peter", LastName: "Griffin", Age: 40, ID: peterID}
   445  	peterRow := []driver.Value{peterID, "Peter", "Griffin", 40}
   446  	homer := User{FirstName: "Homer", LastName: "Simpson", Age: 55, ID: homerID}
   447  	homerRow := []driver.Value{homerID, "Homer", "Simpson", 55}
   448  
   449  	sut := repo.NewPageableQuerierGlobal("UserType", "users",
   450  		[]string{"id", "first_name", "last_name", "age"})
   451  
   452  	t.Run("returns first page and there are no more pages", func(t *testing.T) {
   453  		db, mock := testdb.MockDatabase(t)
   454  		mockListOnePageDBSelect(peterRow, homerRow, mock, repo.NoLock)
   455  		ctx := persistence.SaveToContext(context.TODO(), db)
   456  		defer mock.AssertExpectations(t)
   457  
   458  		var dest UserCollection
   459  		actualPage, actualTotal, err := sut.ListGlobal(ctx, 10, "", "id", &dest)
   460  		require.NoError(t, err)
   461  		assert.Equal(t, 2, actualTotal)
   462  		assert.Len(t, dest, 2)
   463  		assert.Equal(t, peter, dest[0])
   464  		assert.Equal(t, homer, dest[1])
   465  		assert.False(t, actualPage.HasNextPage)
   466  	})
   467  
   468  	t.Run("returns full page and has next page", func(t *testing.T) {
   469  		db, mock := testdb.MockDatabase(t)
   470  		mockListOnePageOfManyDBSelect(peterRow, homerRow, mock, repo.NoLock)
   471  		ctx := persistence.SaveToContext(context.TODO(), db)
   472  		defer mock.AssertExpectations(t)
   473  
   474  		var dest UserCollection
   475  		actualPage, actualTotal, err := sut.ListGlobal(ctx, 2, "", "id", &dest)
   476  		require.NoError(t, err)
   477  		assert.Equal(t, 100, actualTotal)
   478  		assert.Len(t, dest, 2)
   479  		assert.True(t, actualPage.HasNextPage)
   480  		assert.NotEmpty(t, actualPage.EndCursor)
   481  	})
   482  
   483  	t.Run("returns many pages and I can traverse it using cursor", func(t *testing.T) {
   484  		db, mock := testdb.MockDatabase(t)
   485  		mockListManyPagesDBSelect(peterRow, homerRow, mock, repo.NoLock)
   486  		ctx := persistence.SaveToContext(context.TODO(), db)
   487  		defer mock.AssertExpectations(t)
   488  
   489  		var first UserCollection
   490  		actualFirstPage, actualTotal, err := sut.ListGlobal(ctx, 1, "", "id", &first)
   491  		require.NoError(t, err)
   492  		assert.Equal(t, 100, actualTotal)
   493  		assert.Len(t, first, 1)
   494  		assert.True(t, actualFirstPage.HasNextPage)
   495  		assert.NotEmpty(t, actualFirstPage.EndCursor)
   496  
   497  		var second UserCollection
   498  		actualSecondPage, actualTotal, err := sut.ListGlobal(ctx, 1, actualFirstPage.EndCursor, "id", &second)
   499  		require.NoError(t, err)
   500  		assert.Equal(t, 100, actualTotal)
   501  		assert.Len(t, second, 1)
   502  		assert.True(t, actualSecondPage.HasNextPage)
   503  		assert.NotEmpty(t, actualSecondPage.EndCursor)
   504  	})
   505  
   506  	t.Run("returns page without conditions", func(t *testing.T) {
   507  		db, mock := testdb.MockDatabase(t)
   508  		mockListOnePageDBSelectWithoutConditions(peterRow, mock, repo.NoLock)
   509  		ctx := persistence.SaveToContext(context.TODO(), db)
   510  		defer mock.AssertExpectations(t)
   511  
   512  		var dest UserCollection
   513  		actualPage, actualTotal, err := sut.ListGlobal(ctx, 2, "", "id", &dest)
   514  		require.NoError(t, err)
   515  		assert.Equal(t, 100, actualTotal)
   516  		assert.Len(t, dest, 1)
   517  		assert.True(t, actualPage.HasNextPage)
   518  		assert.NotEmpty(t, actualPage.EndCursor)
   519  	})
   520  
   521  	t.Run("returns page with additional conditions", func(t *testing.T) {
   522  		db, mock := testdb.MockDatabase(t)
   523  		mockListOnePageDBSelectWithConditions(peterRow, mock, repo.NoLock)
   524  		ctx := persistence.SaveToContext(context.TODO(), db)
   525  		defer mock.AssertExpectations(t)
   526  
   527  		var dest UserCollection
   528  		conditions := repo.Conditions{
   529  			repo.NewEqualCondition("first_name", "Peter"),
   530  			repo.NewNotEqualCondition("age", 18),
   531  		}
   532  
   533  		actualPage, actualTotal, err := sut.ListGlobalWithAdditionalConditions(ctx, 2, "", "id", &dest, repo.And(repo.ConditionTreesFromConditions(conditions)...))
   534  		require.NoError(t, err)
   535  		assert.Equal(t, 100, actualTotal)
   536  		assert.Len(t, dest, 1)
   537  		assert.True(t, actualPage.HasNextPage)
   538  		assert.NotEmpty(t, actualPage.EndCursor)
   539  	})
   540  
   541  	t.Run("returns empty page", func(t *testing.T) {
   542  		db, mock := testdb.MockDatabase(t)
   543  		mockListNoPagesDBSelect(mock, repo.NoLock)
   544  		ctx := persistence.SaveToContext(context.TODO(), db)
   545  		defer mock.AssertExpectations(t)
   546  
   547  		var dest UserCollection
   548  		actualPage, actualTotal, err := sut.ListGlobal(ctx, 2, "", "id", &dest)
   549  		require.NoError(t, err)
   550  		assert.Equal(t, 0, actualTotal)
   551  		assert.Empty(t, dest)
   552  		assert.False(t, actualPage.HasNextPage)
   553  	})
   554  
   555  	t.Run("returns error if missing persistence context", func(t *testing.T) {
   556  		ctx := context.TODO()
   557  		_, _, err := sut.ListGlobal(ctx, 2, "", "id", nil)
   558  		require.EqualError(t, err, apperrors.NewInternalError("unable to fetch database from context").Error())
   559  	})
   560  
   561  	t.Run("returns error if wrong cursor", func(t *testing.T) {
   562  		ctx := persistence.SaveToContext(context.TODO(), &sqlx.Tx{})
   563  		_, _, err := sut.ListGlobal(ctx, 2, "zzz", "", nil)
   564  		require.EqualError(t, err, "while decoding page cursor: cursor is not correct: illegal base64 data at input byte 0")
   565  	})
   566  
   567  	t.Run("returns error if wrong pagination attributes", func(t *testing.T) {
   568  		ctx := persistence.SaveToContext(context.TODO(), &sqlx.Tx{})
   569  		_, _, err := sut.ListGlobal(ctx, -3, "", "id", nil)
   570  		require.EqualError(t, err, "while converting offset and limit to cursor: Invalid data [reason=page size cannot be smaller than 1]")
   571  	})
   572  
   573  	t.Run("returns error on db operation", func(t *testing.T) {
   574  		db, mock := testdb.MockDatabase(t)
   575  		defer mock.AssertExpectations(t)
   576  
   577  		mock.ExpectQuery(`SELECT .*`).WillReturnError(someError())
   578  		ctx := persistence.SaveToContext(context.TODO(), db)
   579  		var dest UserCollection
   580  
   581  		_, _, err := sut.ListGlobal(ctx, 2, "", "id", &dest)
   582  
   583  		require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query")
   584  	})
   585  
   586  	t.Run("context properly canceled", func(t *testing.T) {
   587  		db, mock := testdb.MockDatabase(t)
   588  		defer mock.AssertExpectations(t)
   589  
   590  		ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
   591  		defer cancel()
   592  
   593  		ctx = persistence.SaveToContext(ctx, db)
   594  		var dest UserCollection
   595  
   596  		_, _, err := sut.ListGlobal(ctx, 2, "", "id", &dest)
   597  
   598  		require.EqualError(t, err, "Internal Server Error: Maximum processing timeout reached")
   599  	})
   600  
   601  	t.Run("returns error on calculating total count", func(t *testing.T) {
   602  		db, mock := testdb.MockDatabase(t)
   603  		mockListPageableDBSelectWithCountError(mock, db, repo.NoLock)
   604  		ctx := persistence.SaveToContext(context.TODO(), db)
   605  		defer mock.AssertExpectations(t)
   606  
   607  		var dest UserCollection
   608  		_, _, err := sut.ListGlobal(ctx, 2, "", "id", &dest)
   609  		require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query")
   610  	})
   611  }
   612  
   613  func TestListPageableGlobalWithSelectForUpdate(t *testing.T) {
   614  	peterID := "peterID"
   615  	homerID := "homerID"
   616  	peter := User{FirstName: "Peter", LastName: "Griffin", Age: 40, ID: peterID}
   617  	peterRow := []driver.Value{peterID, "Peter", "Griffin", 40}
   618  	homer := User{FirstName: "Homer", LastName: "Simpson", Age: 55, ID: homerID}
   619  	homerRow := []driver.Value{homerID, "Homer", "Simpson", 55}
   620  
   621  	sut := repo.NewPageableQuerierGlobal("UserType", "users",
   622  		[]string{"id", "first_name", "last_name", "age"})
   623  
   624  	t.Run("returns first page and there are no more pages", func(t *testing.T) {
   625  		db, mock := testdb.MockDatabase(t)
   626  		mockListOnePageDBSelect(peterRow, homerRow, mock, repo.ForUpdateLock)
   627  		ctx := persistence.SaveToContext(context.TODO(), db)
   628  		defer mock.AssertExpectations(t)
   629  
   630  		var dest UserCollection
   631  		actualPage, actualTotal, err := sut.ListGlobalWithSelectForUpdate(ctx, 10, "", "id", &dest)
   632  		require.NoError(t, err)
   633  		assert.Equal(t, 2, actualTotal)
   634  		assert.Len(t, dest, 2)
   635  		assert.Equal(t, peter, dest[0])
   636  		assert.Equal(t, homer, dest[1])
   637  		assert.False(t, actualPage.HasNextPage)
   638  	})
   639  
   640  	t.Run("returns full page and has next page", func(t *testing.T) {
   641  		db, mock := testdb.MockDatabase(t)
   642  		mockListOnePageOfManyDBSelect(peterRow, homerRow, mock, repo.ForUpdateLock)
   643  		ctx := persistence.SaveToContext(context.TODO(), db)
   644  		defer mock.AssertExpectations(t)
   645  
   646  		var dest UserCollection
   647  		actualPage, actualTotal, err := sut.ListGlobalWithSelectForUpdate(ctx, 2, "", "id", &dest)
   648  		require.NoError(t, err)
   649  		assert.Equal(t, 100, actualTotal)
   650  		assert.Len(t, dest, 2)
   651  		assert.True(t, actualPage.HasNextPage)
   652  		assert.NotEmpty(t, actualPage.EndCursor)
   653  	})
   654  
   655  	t.Run("returns many pages and I can traverse it using cursor", func(t *testing.T) {
   656  		db, mock := testdb.MockDatabase(t)
   657  		mockListManyPagesDBSelect(peterRow, homerRow, mock, repo.ForUpdateLock)
   658  		ctx := persistence.SaveToContext(context.TODO(), db)
   659  		defer mock.AssertExpectations(t)
   660  
   661  		var first UserCollection
   662  		actualFirstPage, actualTotal, err := sut.ListGlobalWithSelectForUpdate(ctx, 1, "", "id", &first)
   663  		require.NoError(t, err)
   664  		assert.Equal(t, 100, actualTotal)
   665  		assert.Len(t, first, 1)
   666  		assert.True(t, actualFirstPage.HasNextPage)
   667  		assert.NotEmpty(t, actualFirstPage.EndCursor)
   668  
   669  		var second UserCollection
   670  		actualSecondPage, actualTotal, err := sut.ListGlobalWithSelectForUpdate(ctx, 1, actualFirstPage.EndCursor, "id", &second)
   671  		require.NoError(t, err)
   672  		assert.Equal(t, 100, actualTotal)
   673  		assert.Len(t, second, 1)
   674  		assert.True(t, actualSecondPage.HasNextPage)
   675  		assert.NotEmpty(t, actualSecondPage.EndCursor)
   676  	})
   677  
   678  	t.Run("returns page without conditions", func(t *testing.T) {
   679  		db, mock := testdb.MockDatabase(t)
   680  		mockListOnePageDBSelectWithoutConditions(peterRow, mock, repo.ForUpdateLock)
   681  		ctx := persistence.SaveToContext(context.TODO(), db)
   682  		defer mock.AssertExpectations(t)
   683  
   684  		var dest UserCollection
   685  		actualPage, actualTotal, err := sut.ListGlobalWithSelectForUpdate(ctx, 2, "", "id", &dest)
   686  		require.NoError(t, err)
   687  		assert.Equal(t, 100, actualTotal)
   688  		assert.Len(t, dest, 1)
   689  		assert.True(t, actualPage.HasNextPage)
   690  		assert.NotEmpty(t, actualPage.EndCursor)
   691  	})
   692  
   693  	t.Run("returns empty page", func(t *testing.T) {
   694  		db, mock := testdb.MockDatabase(t)
   695  		mockListNoPagesDBSelect(mock, repo.ForUpdateLock)
   696  		ctx := persistence.SaveToContext(context.TODO(), db)
   697  		defer mock.AssertExpectations(t)
   698  
   699  		var dest UserCollection
   700  		actualPage, actualTotal, err := sut.ListGlobalWithSelectForUpdate(ctx, 2, "", "id", &dest)
   701  		require.NoError(t, err)
   702  		assert.Equal(t, 0, actualTotal)
   703  		assert.Empty(t, dest)
   704  		assert.False(t, actualPage.HasNextPage)
   705  	})
   706  
   707  	t.Run("returns error if missing persistence context", func(t *testing.T) {
   708  		ctx := context.TODO()
   709  		_, _, err := sut.ListGlobalWithSelectForUpdate(ctx, 2, "", "id", nil)
   710  		require.EqualError(t, err, apperrors.NewInternalError("unable to fetch database from context").Error())
   711  	})
   712  
   713  	t.Run("returns error if wrong cursor", func(t *testing.T) {
   714  		ctx := persistence.SaveToContext(context.TODO(), &sqlx.Tx{})
   715  		_, _, err := sut.ListGlobalWithSelectForUpdate(ctx, 2, "zzz", "", nil)
   716  		require.EqualError(t, err, "while decoding page cursor: cursor is not correct: illegal base64 data at input byte 0")
   717  	})
   718  
   719  	t.Run("returns error if wrong pagination attributes", func(t *testing.T) {
   720  		ctx := persistence.SaveToContext(context.TODO(), &sqlx.Tx{})
   721  		_, _, err := sut.ListGlobalWithSelectForUpdate(ctx, -3, "", "id", nil)
   722  		require.EqualError(t, err, "while converting offset and limit to cursor: Invalid data [reason=page size cannot be smaller than 1]")
   723  	})
   724  
   725  	t.Run("returns error on db operation", func(t *testing.T) {
   726  		db, mock := testdb.MockDatabase(t)
   727  		defer mock.AssertExpectations(t)
   728  
   729  		mock.ExpectQuery(`SELECT .*`).WillReturnError(someError())
   730  		ctx := persistence.SaveToContext(context.TODO(), db)
   731  		var dest UserCollection
   732  
   733  		_, _, err := sut.ListGlobalWithSelectForUpdate(ctx, 2, "", "id", &dest)
   734  
   735  		require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query")
   736  	})
   737  
   738  	t.Run("context properly canceled", func(t *testing.T) {
   739  		db, mock := testdb.MockDatabase(t)
   740  		defer mock.AssertExpectations(t)
   741  
   742  		ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
   743  		defer cancel()
   744  
   745  		ctx = persistence.SaveToContext(ctx, db)
   746  		var dest UserCollection
   747  
   748  		_, _, err := sut.ListGlobalWithSelectForUpdate(ctx, 2, "", "id", &dest)
   749  
   750  		require.EqualError(t, err, "Internal Server Error: Maximum processing timeout reached")
   751  	})
   752  
   753  	t.Run("returns error on calculating total count", func(t *testing.T) {
   754  		db, mock := testdb.MockDatabase(t)
   755  		mockListPageableDBSelectWithCountError(mock, db, repo.ForUpdateLock)
   756  		ctx := persistence.SaveToContext(context.TODO(), db)
   757  		defer mock.AssertExpectations(t)
   758  
   759  		var dest UserCollection
   760  		_, _, err := sut.ListGlobalWithSelectForUpdate(ctx, 2, "", "id", &dest)
   761  		require.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query")
   762  	})
   763  }
   764  
   765  func mockListOnePageDBSelect(peterRow []driver.Value, homerRow []driver.Value, mock testdb.DBMock, lockClause string) {
   766  	rows := sqlmock.NewRows([]string{"id", "first_name", "last_name", "age"}).
   767  		AddRow(peterRow...).
   768  		AddRow(homerRow...)
   769  	mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, first_name, last_name, age FROM users ORDER BY id LIMIT 10 OFFSET 0` + PrepareLockClause(lockClause))).WillReturnRows(rows)
   770  	mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM users`)).WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(2))
   771  }
   772  
   773  func mockListOnePageOfManyDBSelect(peterRow []driver.Value, homerRow []driver.Value, mock testdb.DBMock, lockClause string) {
   774  	rows := sqlmock.NewRows([]string{"id", "first_name", "last_name", "age"}).
   775  		AddRow(peterRow...).
   776  		AddRow(homerRow...)
   777  	mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, first_name, last_name, age FROM users ORDER BY id LIMIT 2 OFFSET 0` + PrepareLockClause(lockClause))).WillReturnRows(rows)
   778  	mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM users`)).WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(100))
   779  }
   780  
   781  func mockListManyPagesDBSelect(peterRow []driver.Value, homerRow []driver.Value, mock testdb.DBMock, lockClause string) {
   782  	rowsForPage1 := sqlmock.NewRows([]string{"id", "first_name", "last_name", "age"}).
   783  		AddRow(peterRow...)
   784  	rowsForPage2 := sqlmock.NewRows([]string{"id", "first_name", "last_name", "age"}).
   785  		AddRow(homerRow...)
   786  
   787  	mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, first_name, last_name, age FROM users ORDER BY id LIMIT 1 OFFSET 0` + PrepareLockClause(lockClause))).WillReturnRows(rowsForPage1)
   788  	mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM users`)).WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(100))
   789  	mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, first_name, last_name, age FROM users ORDER BY id LIMIT 1 OFFSET 1` + PrepareLockClause(lockClause))).WillReturnRows(rowsForPage2)
   790  	mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM users`)).WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(100))
   791  }
   792  
   793  func mockListOnePageDBSelectWithoutConditions(peterRow []driver.Value, mock testdb.DBMock, lockClause string) {
   794  	rows := sqlmock.NewRows([]string{"id", "first_name", "last_name", "age"}).
   795  		AddRow(peterRow...)
   796  	mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, first_name, last_name, age FROM users ORDER BY id LIMIT 2 OFFSET 0` + PrepareLockClause(lockClause))).WillReturnRows(rows)
   797  	mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM users`)).WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(100))
   798  }
   799  
   800  func mockListOnePageDBSelectWithConditions(peterRow []driver.Value, mock testdb.DBMock, lockClause string) {
   801  	rows := sqlmock.NewRows([]string{"id", "first_name", "last_name", "age"}).
   802  		AddRow(peterRow...)
   803  	mock.ExpectQuery(regexp.QuoteMeta("SELECT id, first_name, last_name, age FROM users WHERE (first_name = $1 AND age != $2) ORDER BY id LIMIT 2 OFFSET 0"+PrepareLockClause(lockClause))).
   804  		WithArgs("Peter", 18).
   805  		WillReturnRows(rows)
   806  	mock.ExpectQuery(regexp.QuoteMeta("SELECT COUNT(*) FROM users WHERE (first_name = $1 AND age != $2)")).
   807  		WithArgs("Peter", 18).
   808  		WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(100))
   809  }
   810  
   811  func mockListNoPagesDBSelect(mock testdb.DBMock, lockClause string) {
   812  	rows := sqlmock.NewRows([]string{"id", "first_name", "last_name", "age"})
   813  	mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, first_name, last_name, age FROM users ORDER BY id LIMIT 2 OFFSET 0` + PrepareLockClause(lockClause))).WillReturnRows(rows)
   814  	mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM users`)).WillReturnRows(sqlmock.NewRows([]string{""}).AddRow(0))
   815  }
   816  
   817  func mockListPageableDBSelectWithCountError(mock testdb.DBMock, db *sqlx.DB, lockClause string) {
   818  	rows := sqlmock.NewRows([]string{"id", "first_name", "last_name", "age"})
   819  	mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, first_name, last_name, age FROM users ORDER BY id LIMIT 2 OFFSET 0` + PrepareLockClause(lockClause))).WillReturnRows(rows)
   820  	mock.ExpectQuery(`SELECT COUNT\(\*\).*`).WillReturnError(someError())
   821  }