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  }