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 }