github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/repo/exist.go (about) 1 package repo 2 3 import ( 4 "context" 5 "fmt" 6 "strings" 7 8 "github.com/kyma-incubator/compass/components/director/pkg/log" 9 10 "github.com/kyma-incubator/compass/components/director/pkg/resource" 11 12 "github.com/kyma-incubator/compass/components/director/pkg/apperrors" 13 14 "github.com/kyma-incubator/compass/components/director/pkg/persistence" 15 "github.com/pkg/errors" 16 ) 17 18 // ExistQuerier is an interface for checking existence of tenant scoped entities with either externally managed tenant accesses (m2m table or view) or embedded tenant in them. 19 type ExistQuerier interface { 20 Exists(ctx context.Context, resourceType resource.Type, tenant string, conditions Conditions) (bool, error) 21 } 22 23 // ExistQuerierGlobal is an interface for checking existence of global entities. 24 type ExistQuerierGlobal interface { 25 ExistsGlobal(ctx context.Context, conditions Conditions) (bool, error) 26 } 27 28 type universalExistQuerier struct { 29 tableName string 30 tenantColumn *string 31 resourceType resource.Type 32 ownerCheck bool 33 } 34 35 // NewExistQuerier is a constructor for ExistQuerier about entities with externally managed tenant accesses (m2m table or view) 36 func NewExistQuerier(tableName string) ExistQuerier { 37 return &universalExistQuerier{tableName: tableName} 38 } 39 40 // NewExistQuerierWithOwnerCheck is a constructor for ExistQuerier about entities with externally managed tenant accesses (m2m table or view) with additional owner check. 41 func NewExistQuerierWithOwnerCheck(tableName string) ExistQuerier { 42 return &universalExistQuerier{tableName: tableName, ownerCheck: true} 43 } 44 45 // NewExistQuerierWithEmbeddedTenant is a constructor for ExistQuerier about entities with tenant embedded in them. 46 func NewExistQuerierWithEmbeddedTenant(tableName string, tenantColumn string) ExistQuerier { 47 return &universalExistQuerier{tableName: tableName, tenantColumn: &tenantColumn} 48 } 49 50 // NewExistQuerierGlobal is a constructor for ExistQuerierGlobal about global entities. 51 func NewExistQuerierGlobal(resourceType resource.Type, tableName string) ExistQuerierGlobal { 52 return &universalExistQuerier{tableName: tableName, resourceType: resourceType} 53 } 54 55 // Exists checks for existence of tenant scoped entities with tenant isolation subquery. 56 // If the tenantColumn is configured the isolation is based on equal condition on tenantColumn. 57 // If the tenantColumn is not configured an entity with externally managed tenant accesses in m2m table / view is assumed. 58 func (g *universalExistQuerier) Exists(ctx context.Context, resourceType resource.Type, tenant string, conditions Conditions) (bool, error) { 59 if tenant == "" { 60 return false, apperrors.NewTenantRequiredError() 61 } 62 63 if g.tenantColumn != nil { 64 conditions = append(Conditions{NewEqualCondition(*g.tenantColumn, tenant)}, conditions...) 65 return g.exists(ctx, resourceType, conditions) 66 } 67 68 tenantIsolation, err := NewTenantIsolationCondition(resourceType, tenant, g.ownerCheck) 69 if err != nil { 70 return false, err 71 } 72 73 conditions = append(conditions, tenantIsolation) 74 75 return g.exists(ctx, resourceType, conditions) 76 } 77 78 // ExistsGlobal checks for existence of global entities without tenant isolation. 79 func (g *universalExistQuerier) ExistsGlobal(ctx context.Context, conditions Conditions) (bool, error) { 80 return g.exists(ctx, g.resourceType, conditions) 81 } 82 83 func (g *universalExistQuerier) exists(ctx context.Context, resourceType resource.Type, conditions Conditions) (bool, error) { 84 persist, err := persistence.FromCtx(ctx) 85 if err != nil { 86 return false, err 87 } 88 89 var stmtBuilder strings.Builder 90 91 stmtBuilder.WriteString(fmt.Sprintf("SELECT 1 FROM %s", g.tableName)) 92 if len(conditions) > 0 { 93 stmtBuilder.WriteString(" WHERE") 94 } 95 96 err = writeEnumeratedConditions(&stmtBuilder, conditions) 97 if err != nil { 98 return false, errors.Wrap(err, "while writing enumerated conditions") 99 } 100 allArgs := getAllArgs(conditions) 101 102 query := getQueryFromBuilder(stmtBuilder) 103 104 log.C(ctx).Debugf("Executing DB query: %s", query) 105 var count int 106 err = persist.GetContext(ctx, &count, query, allArgs...) 107 err = persistence.MapSQLError(ctx, err, resourceType, resource.Exists, "while getting object from '%s' table", g.tableName) 108 109 if err != nil { 110 if apperrors.IsNotFoundError(err) { 111 return false, nil 112 } 113 return false, err 114 } 115 return true, nil 116 }