github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/repo/get.go (about) 1 package repo 2 3 import ( 4 "context" 5 "strings" 6 7 "github.com/kyma-incubator/compass/components/director/pkg/log" 8 9 "github.com/kyma-incubator/compass/components/director/pkg/resource" 10 11 "github.com/kyma-incubator/compass/components/director/pkg/apperrors" 12 13 "github.com/kyma-incubator/compass/components/director/pkg/persistence" 14 "github.com/pkg/errors" 15 ) 16 17 // SingleGetter is an interface for getting tenant scoped entities with either externally managed tenant accesses (m2m table or view) or embedded tenant in them. 18 type SingleGetter interface { 19 Get(ctx context.Context, resourceType resource.Type, tenant string, conditions Conditions, orderByParams OrderByParams, dest interface{}) error 20 GetForUpdate(ctx context.Context, resourceType resource.Type, tenant string, conditions Conditions, orderByParams OrderByParams, dest interface{}) error 21 } 22 23 // SingleGetterGlobal is an interface for getting global entities. 24 type SingleGetterGlobal interface { 25 GetGlobal(ctx context.Context, conditions Conditions, orderByParams OrderByParams, dest interface{}) error 26 } 27 28 type universalSingleGetter struct { 29 tableName string 30 resourceType resource.Type 31 tenantColumn *string 32 selectedColumns string 33 } 34 35 // NewSingleGetterWithEmbeddedTenant is a constructor for SingleGetter about entities with tenant embedded in them. 36 func NewSingleGetterWithEmbeddedTenant(tableName string, tenantColumn string, selectedColumns []string) SingleGetter { 37 return &universalSingleGetter{ 38 tableName: tableName, 39 tenantColumn: &tenantColumn, 40 selectedColumns: strings.Join(selectedColumns, ", "), 41 } 42 } 43 44 // NewSingleGetter is a constructor for SingleGetter about entities with externally managed tenant accesses (m2m table or view) 45 func NewSingleGetter(tableName string, selectedColumns []string) SingleGetter { 46 return &universalSingleGetter{ 47 tableName: tableName, 48 selectedColumns: strings.Join(selectedColumns, ", "), 49 } 50 } 51 52 // NewSingleGetterGlobal is a constructor for SingleGetterGlobal about global entities. 53 func NewSingleGetterGlobal(resourceType resource.Type, tableName string, selectedColumns []string) SingleGetterGlobal { 54 return &universalSingleGetter{ 55 resourceType: resourceType, 56 tableName: tableName, 57 selectedColumns: strings.Join(selectedColumns, ", "), 58 } 59 } 60 61 // Get gets tenant scoped entities with tenant isolation subquery. 62 // If the tenantColumn is configured the isolation is based on equal condition on tenantColumn. 63 // If the tenantColumn is not configured an entity with externally managed tenant accesses in m2m table / view is assumed. 64 func (g *universalSingleGetter) Get(ctx context.Context, resourceType resource.Type, tenant string, conditions Conditions, orderByParams OrderByParams, dest interface{}) error { 65 return g.getWithTenantIsolation(ctx, resourceType, tenant, conditions, orderByParams, dest, NoLock) 66 } 67 68 // GetForUpdate gets tenant scoped entities with tenant isolation subquery and locks them explicitly until the transaction is finished. 69 // If the tenantColumn is configured the isolation is based on equal condition on tenantColumn. 70 // If the tenantColumn is not configured an entity with externally managed tenant accesses in m2m table / view is assumed. 71 func (g *universalSingleGetter) GetForUpdate(ctx context.Context, resourceType resource.Type, tenant string, conditions Conditions, orderByParams OrderByParams, dest interface{}) error { 72 return g.getWithTenantIsolation(ctx, resourceType, tenant, conditions, orderByParams, dest, ForUpdateLock) 73 } 74 75 func (g *universalSingleGetter) getWithTenantIsolation(ctx context.Context, resourceType resource.Type, tenant string, conditions Conditions, orderByParams OrderByParams, dest interface{}, lockClause string) error { 76 if tenant == "" { 77 return apperrors.NewTenantRequiredError() 78 } 79 80 if g.tenantColumn != nil { 81 conditions = append(Conditions{NewEqualCondition(*g.tenantColumn, tenant)}, conditions...) 82 return g.get(ctx, resourceType, conditions, orderByParams, dest, NoLock) 83 } 84 85 tenantIsolation, err := NewTenantIsolationCondition(resourceType, tenant, false) 86 if err != nil { 87 return err 88 } 89 90 conditions = append(conditions, tenantIsolation) 91 92 return g.get(ctx, resourceType, conditions, orderByParams, dest, lockClause) 93 } 94 95 // GetGlobal gets global entities without tenant isolation. 96 func (g *universalSingleGetter) GetGlobal(ctx context.Context, conditions Conditions, orderByParams OrderByParams, dest interface{}) error { 97 return g.get(ctx, g.resourceType, conditions, orderByParams, dest, NoLock) 98 } 99 100 func (g *universalSingleGetter) get(ctx context.Context, resourceType resource.Type, conditions Conditions, orderByParams OrderByParams, dest interface{}, lockClause string) error { 101 if dest == nil { 102 return apperrors.NewInternalError("item cannot be nil") 103 } 104 persist, err := persistence.FromCtx(ctx) 105 if err != nil { 106 return err 107 } 108 109 query, args, err := buildSelectQuery(g.tableName, g.selectedColumns, conditions, orderByParams, lockClause, true) 110 if err != nil { 111 return errors.Wrap(err, "while building list query") 112 } 113 114 log.C(ctx).Debugf("Executing DB query: %s", query) 115 err = persist.GetContext(ctx, dest, query, args...) 116 117 return persistence.MapSQLError(ctx, err, resourceType, resource.Get, "while getting object from '%s' table", g.tableName) 118 }