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

     1  package repo_test
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"testing"
     7  
     8  	"github.com/kyma-incubator/compass/components/director/internal/repo"
     9  	"github.com/kyma-incubator/compass/components/director/pkg/apperrors"
    10  	"github.com/kyma-incubator/compass/components/director/pkg/resource"
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  )
    14  
    15  func TestQueryBuilder(t *testing.T) {
    16  	sut := repo.NewQueryBuilder(appTableName, appColumns)
    17  	resourceType := resource.Application
    18  	m2mTable, ok := resourceType.TenantAccessTable()
    19  	require.True(t, ok)
    20  
    21  	t.Run("success with only default tenant condition", func(t *testing.T) {
    22  		// GIVEN
    23  		expectedQuery := fmt.Sprintf("SELECT id, name, description FROM %s WHERE %s", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$1"))
    24  
    25  		// WHEN
    26  		query, args, err := sut.BuildQuery(resourceType, tenantID, true, repo.Conditions{}...)
    27  
    28  		// THEN
    29  		require.NoError(t, err)
    30  		assert.Equal(t, 1, len(args))
    31  		assert.Equal(t, tenantID, args[0])
    32  		assert.Equal(t, expectedQuery, removeWhitespace(query))
    33  	})
    34  
    35  	t.Run("success with only default tenant condition and no argument rebinding", func(t *testing.T) {
    36  		// GIVEN
    37  		expectedQuery := fmt.Sprintf("SELECT id, name, description FROM %s WHERE %s", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "?"))
    38  
    39  		// WHEN
    40  		query, args, err := sut.BuildQuery(resourceType, tenantID, false, repo.Conditions{}...)
    41  
    42  		// THEN
    43  		require.NoError(t, err)
    44  		assert.Equal(t, 1, len(args))
    45  		assert.Equal(t, tenantID, args[0])
    46  		assert.Equal(t, expectedQuery, removeWhitespace(query))
    47  	})
    48  
    49  	t.Run("success with more conditions", func(t *testing.T) {
    50  		// GIVEN
    51  		expectedQuery := fmt.Sprintf("SELECT id, name, description FROM %s WHERE first_name = $1 AND %s", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$2"))
    52  		expectedFirstName := "foo"
    53  
    54  		// WHEN
    55  		query, args, err := sut.BuildQuery(resourceType, tenantID, true, repo.Conditions{repo.NewEqualCondition("first_name", expectedFirstName)}...)
    56  
    57  		// THEN
    58  		require.NoError(t, err)
    59  		assert.Equal(t, 2, len(args))
    60  		assert.Equal(t, expectedFirstName, args[0])
    61  		assert.Equal(t, tenantID, args[1])
    62  		assert.Equal(t, expectedQuery, removeWhitespace(query))
    63  	})
    64  
    65  	t.Run("success with IN condition with values", func(t *testing.T) {
    66  		// GIVEN
    67  		expectedQuery := fmt.Sprintf("SELECT id, name, description FROM %s WHERE first_name IN ($1, $2) AND %s", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$3"))
    68  		expectedFirstINValue := "foo"
    69  		expectedSecondINValue := "bar"
    70  
    71  		// WHEN
    72  		query, args, err := sut.BuildQuery(resourceType, tenantID, true, repo.Conditions{repo.NewInConditionForStringValues("first_name", []string{"foo", "bar"})}...)
    73  
    74  		// THEN
    75  		require.NoError(t, err)
    76  		assert.Equal(t, 3, len(args))
    77  		assert.Equal(t, expectedFirstINValue, args[0])
    78  		assert.Equal(t, expectedSecondINValue, args[1])
    79  		assert.Equal(t, tenantID, args[2])
    80  		assert.Equal(t, expectedQuery, removeWhitespace(query))
    81  	})
    82  
    83  	t.Run("success with IN condition with subquery", func(t *testing.T) {
    84  		// GIVEN
    85  		expectedQuery := fmt.Sprintf("SELECT id, name, description FROM %s WHERE first_name IN (SELECT name from names WHERE description = $1 AND id = $2) AND %s", appTableName, fmt.Sprintf(tenantIsolationConditionWithoutOwnerCheckFmt, m2mTable, "$3"))
    86  		expectedFirstArgument := "foo"
    87  		expectedSecondArgument := 3
    88  
    89  		// WHEN
    90  		query, args, err := sut.BuildQuery(resourceType, tenantID, true, repo.Conditions{repo.NewInConditionForSubQuery("first_name", "SELECT name from names WHERE description = ? AND id = ?", []interface{}{"foo", 3})}...)
    91  
    92  		// THEN
    93  		require.NoError(t, err)
    94  		assert.Equal(t, 3, len(args))
    95  		assert.Equal(t, expectedFirstArgument, args[0])
    96  		assert.Equal(t, expectedSecondArgument, args[1])
    97  		assert.Equal(t, tenantID, args[2])
    98  		assert.Equal(t, expectedQuery, removeWhitespace(query))
    99  	})
   100  
   101  	t.Run("returns error when tenantID is empty", func(t *testing.T) {
   102  		// WHEN
   103  		query, args, err := sut.BuildQuery(resourceType, "", true, repo.Conditions{}...)
   104  
   105  		// THEN
   106  		require.NotNil(t, err)
   107  		assert.True(t, apperrors.IsTenantRequired(err))
   108  		assert.Equal(t, "", removeWhitespace(query))
   109  		assert.Equal(t, []interface{}(nil), args)
   110  	})
   111  }
   112  
   113  func TestQueryBuilderWithEmbeddedTenant(t *testing.T) {
   114  	sut := repo.NewQueryBuilderWithEmbeddedTenant(userTableName, "tenant_id", []string{"id", "tenant_id", "first_name", "last_name", "age"})
   115  
   116  	t.Run("success with only default tenant condition", func(t *testing.T) {
   117  		// GIVEN
   118  		expectedQuery := "SELECT id, tenant_id, first_name, last_name, age FROM users WHERE tenant_id = $1"
   119  
   120  		// WHEN
   121  		query, args, err := sut.BuildQuery(UserType, tenantID, true, repo.Conditions{}...)
   122  
   123  		// THEN
   124  		require.NoError(t, err)
   125  		assert.Equal(t, 1, len(args))
   126  		assert.Equal(t, tenantID, args[0])
   127  		assert.Equal(t, expectedQuery, removeWhitespace(query))
   128  	})
   129  
   130  	t.Run("success with only default tenant condition and no argument rebinding", func(t *testing.T) {
   131  		// GIVEN
   132  		expectedQuery := "SELECT id, tenant_id, first_name, last_name, age FROM users WHERE tenant_id = ?"
   133  
   134  		// WHEN
   135  		query, args, err := sut.BuildQuery(UserType, tenantID, false, repo.Conditions{}...)
   136  
   137  		// THEN
   138  		require.NoError(t, err)
   139  		assert.Equal(t, 1, len(args))
   140  		assert.Equal(t, tenantID, args[0])
   141  		assert.Equal(t, expectedQuery, removeWhitespace(query))
   142  	})
   143  
   144  	t.Run("success with more conditions", func(t *testing.T) {
   145  		// GIVEN
   146  		expectedQuery := "SELECT id, tenant_id, first_name, last_name, age FROM users WHERE tenant_id = $1 AND first_name = $2"
   147  		expectedFirstName := "foo"
   148  
   149  		// WHEN
   150  		query, args, err := sut.BuildQuery(UserType, tenantID, true, repo.Conditions{repo.NewEqualCondition("first_name", expectedFirstName)}...)
   151  
   152  		// THEN
   153  		require.NoError(t, err)
   154  		assert.Equal(t, 2, len(args))
   155  		assert.Equal(t, tenantID, args[0])
   156  		assert.Equal(t, expectedFirstName, args[1])
   157  		assert.Equal(t, expectedQuery, removeWhitespace(query))
   158  	})
   159  
   160  	t.Run("success with IN condition with values", func(t *testing.T) {
   161  		// GIVEN
   162  		expectedQuery := "SELECT id, tenant_id, first_name, last_name, age FROM users WHERE tenant_id = $1 AND first_name IN ($2, $3)"
   163  		expectedFirstINValue := "foo"
   164  		expectedSecondINValue := "bar"
   165  
   166  		// WHEN
   167  		query, args, err := sut.BuildQuery(UserType, tenantID, true, repo.Conditions{repo.NewInConditionForStringValues("first_name", []string{"foo", "bar"})}...)
   168  
   169  		// THEN
   170  		require.NoError(t, err)
   171  		assert.Equal(t, 3, len(args))
   172  		assert.Equal(t, tenantID, args[0])
   173  		assert.Equal(t, expectedFirstINValue, args[1])
   174  		assert.Equal(t, expectedSecondINValue, args[2])
   175  		assert.Equal(t, expectedQuery, removeWhitespace(query))
   176  	})
   177  
   178  	t.Run("success with IN condition with subquery", func(t *testing.T) {
   179  		// GIVEN
   180  		expectedQuery := "SELECT id, tenant_id, first_name, last_name, age FROM users WHERE tenant_id = $1 AND first_name IN (SELECT name from names WHERE description = $2 AND id = $3)"
   181  		expectedFirstArgument := "foo"
   182  		expectedSecondArgument := 3
   183  
   184  		// WHEN
   185  		query, args, err := sut.BuildQuery(UserType, tenantID, true, repo.Conditions{repo.NewInConditionForSubQuery("first_name", "SELECT name from names WHERE description = ? AND id = ?", []interface{}{"foo", 3})}...)
   186  
   187  		// THEN
   188  		require.NoError(t, err)
   189  		assert.Equal(t, 3, len(args))
   190  		assert.Equal(t, tenantID, args[0])
   191  		assert.Equal(t, expectedFirstArgument, args[1])
   192  		assert.Equal(t, expectedSecondArgument, args[2])
   193  		assert.Equal(t, expectedQuery, removeWhitespace(query))
   194  	})
   195  
   196  	t.Run("returns error when tenantID is empty", func(t *testing.T) {
   197  		// WHEN
   198  		query, args, err := sut.BuildQuery(UserType, "", true, repo.Conditions{}...)
   199  
   200  		// THEN
   201  		require.NotNil(t, err)
   202  		assert.True(t, apperrors.IsTenantRequired(err))
   203  		assert.Equal(t, "", removeWhitespace(query))
   204  		assert.Equal(t, []interface{}(nil), args)
   205  	})
   206  }
   207  
   208  func TestQueryBuilderGlobal(t *testing.T) {
   209  	sut := repo.NewQueryBuilderGlobal(UserType, userTableName, []string{"id", "tenant_id", "first_name", "last_name", "age"})
   210  
   211  	t.Run("success without conditions", func(t *testing.T) {
   212  		// GIVEN
   213  		expectedQuery := "SELECT id, tenant_id, first_name, last_name, age FROM users"
   214  
   215  		// WHEN
   216  		query, args, err := sut.BuildQueryGlobal(false, repo.Conditions{}...)
   217  
   218  		// THEN
   219  		require.NoError(t, err)
   220  		assert.Equal(t, 0, len(args))
   221  		assert.Equal(t, expectedQuery, removeWhitespace(query))
   222  	})
   223  
   224  	t.Run("success with conditions", func(t *testing.T) {
   225  		// GIVEN
   226  		expectedQuery := "SELECT id, tenant_id, first_name, last_name, age FROM users WHERE first_name = $1"
   227  		expectedFirstName := "foo"
   228  
   229  		// WHEN
   230  		query, args, err := sut.BuildQueryGlobal(true, repo.Conditions{repo.NewEqualCondition("first_name", expectedFirstName)}...)
   231  
   232  		// THEN
   233  		require.NoError(t, err)
   234  		assert.Equal(t, 1, len(args))
   235  		assert.Equal(t, expectedFirstName, args[0])
   236  		assert.Equal(t, expectedQuery, removeWhitespace(query))
   237  	})
   238  
   239  	t.Run("success with IN condition with values", func(t *testing.T) {
   240  		// GIVEN
   241  		expectedQuery := "SELECT id, tenant_id, first_name, last_name, age FROM users WHERE first_name IN ($1, $2)"
   242  		expectedFirstINValue := "foo"
   243  		expectedSecondINValue := "bar"
   244  
   245  		// WHEN
   246  		query, args, err := sut.BuildQueryGlobal(true, repo.Conditions{repo.NewInConditionForStringValues("first_name", []string{"foo", "bar"})}...)
   247  
   248  		// THEN
   249  		require.NoError(t, err)
   250  		assert.Equal(t, 2, len(args))
   251  		assert.Equal(t, expectedFirstINValue, args[0])
   252  		assert.Equal(t, expectedSecondINValue, args[1])
   253  		assert.Equal(t, expectedQuery, removeWhitespace(query))
   254  	})
   255  
   256  	t.Run("success with IN condition with subquery", func(t *testing.T) {
   257  		// GIVEN
   258  		expectedQuery := "SELECT id, tenant_id, first_name, last_name, age FROM users WHERE first_name IN (SELECT name from names WHERE description = $1 AND id = $2)"
   259  		expectedFirstArgument := "foo"
   260  		expectedSecondArgument := 3
   261  
   262  		// WHEN
   263  		query, args, err := sut.BuildQueryGlobal(true, repo.Conditions{repo.NewInConditionForSubQuery("first_name", "SELECT name from names WHERE description = ? AND id = ?", []interface{}{"foo", 3})}...)
   264  
   265  		// THEN
   266  		require.NoError(t, err)
   267  		assert.Equal(t, 2, len(args))
   268  		assert.Equal(t, expectedFirstArgument, args[0])
   269  		assert.Equal(t, expectedSecondArgument, args[1])
   270  		assert.Equal(t, expectedQuery, removeWhitespace(query))
   271  	})
   272  }
   273  
   274  func removeWhitespace(s string) string {
   275  	return strings.Join(strings.Fields(s), " ")
   276  }