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

     1  package destination
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/kyma-incubator/compass/components/director/internal/model"
     7  	"github.com/kyma-incubator/compass/components/director/internal/repo"
     8  	"github.com/kyma-incubator/compass/components/director/pkg/apperrors"
     9  	"github.com/kyma-incubator/compass/components/director/pkg/log"
    10  	"github.com/kyma-incubator/compass/components/director/pkg/resource"
    11  )
    12  
    13  const (
    14  	destinationTable            = "public.destinations"
    15  	revisionColumn              = "revision"
    16  	tenantIDColumn              = "tenant_id"
    17  	formationAssignmentIDColumn = "formation_assignment_id"
    18  	destinationNameColumn       = "name"
    19  )
    20  
    21  var (
    22  	destinationColumns = []string{"id", "name", "type", "url", "authentication", "tenant_id", "bundle_id", "revision", "formation_assignment_id"}
    23  	conflictingColumns = []string{"name", "tenant_id"}
    24  	updateColumns      = []string{"name", "type", "url", "authentication", "revision"}
    25  )
    26  
    27  // EntityConverter missing godoc
    28  //
    29  //go:generate mockery --name=EntityConverter --output=automock --outpkg=automock --case=underscore --disable-version-string
    30  type EntityConverter interface {
    31  	ToEntity(in *model.Destination) *Entity
    32  	FromEntity(entity *Entity) *model.Destination
    33  }
    34  
    35  type repository struct {
    36  	conv                       EntityConverter
    37  	globalCreator              repo.CreatorGlobal
    38  	deleter                    repo.Deleter
    39  	globalDeleter              repo.DeleterGlobal
    40  	upserterWithEmbeddedTenant repo.UpserterGlobal
    41  	upserterGlobal             repo.UpserterGlobal
    42  	lister                     repo.Lister
    43  }
    44  
    45  // NewRepository returns new destination repository
    46  func NewRepository(converter EntityConverter) *repository {
    47  	return &repository{
    48  		conv:                       converter,
    49  		globalCreator:              repo.NewCreatorGlobal(resource.Destination, destinationTable, destinationColumns),
    50  		deleter:                    repo.NewDeleterWithEmbeddedTenant(destinationTable, tenantIDColumn),
    51  		globalDeleter:              repo.NewDeleterGlobal(resource.Destination, destinationTable),
    52  		upserterWithEmbeddedTenant: repo.NewUpserterWithEmbeddedTenant(resource.Destination, destinationTable, destinationColumns, conflictingColumns, updateColumns, tenantIDColumn),
    53  		upserterGlobal:             repo.NewUpserterGlobal(resource.Destination, destinationTable, destinationColumns, conflictingColumns, updateColumns),
    54  		lister:                     repo.NewListerWithEmbeddedTenant(destinationTable, tenantIDColumn, destinationColumns),
    55  	}
    56  }
    57  
    58  // Upsert upserts a destination entity in db
    59  func (r *repository) Upsert(ctx context.Context, in model.DestinationInput, id, tenantID, bundleID, revisionID string) error {
    60  	destination := Entity{
    61  		ID:             id,
    62  		Name:           in.Name,
    63  		Type:           in.Type,
    64  		URL:            in.URL,
    65  		Authentication: in.Authentication,
    66  		BundleID:       repo.NewNullableString(&bundleID),
    67  		TenantID:       tenantID,
    68  		Revision:       repo.NewNullableString(&revisionID),
    69  	}
    70  	return r.upserterGlobal.UpsertGlobal(ctx, destination)
    71  }
    72  
    73  // UpsertWithEmbeddedTenant upserts a destination entity in th DB with embedded tenant
    74  func (r *repository) UpsertWithEmbeddedTenant(ctx context.Context, destination *model.Destination) error {
    75  	if destination == nil {
    76  		return apperrors.NewInternalError("destination model can not be empty")
    77  	}
    78  
    79  	return r.upserterWithEmbeddedTenant.UpsertGlobal(ctx, r.conv.ToEntity(destination))
    80  }
    81  
    82  // DeleteOld deletes all destinations in a given tenant that do not have latestRevision
    83  func (r *repository) DeleteOld(ctx context.Context, latestRevision, tenantID string) error {
    84  	conditions := repo.Conditions{repo.NewNotEqualCondition(revisionColumn, latestRevision), repo.NewEqualCondition(tenantIDColumn, tenantID), repo.NewNotNullCondition(revisionColumn)}
    85  	return r.globalDeleter.DeleteManyGlobal(ctx, conditions)
    86  }
    87  
    88  // CreateDestination creates destination in the DB with the provided `destination` data
    89  func (r *repository) CreateDestination(ctx context.Context, destination *model.Destination) error {
    90  	if destination == nil {
    91  		return apperrors.NewInternalError("destination model can not be empty")
    92  	}
    93  
    94  	return r.globalCreator.Create(ctx, r.conv.ToEntity(destination))
    95  }
    96  
    97  // ListByTenantIDAndAssignmentID returns all destinations for a given `tenantID` and `formationAssignmentID`
    98  func (r *repository) ListByTenantIDAndAssignmentID(ctx context.Context, tenantID, formationAssignmentID string) ([]*model.Destination, error) {
    99  	log.C(ctx).Infof("Listing destinations by tenant ID: %q and assignment ID: %q from the DB", tenantID, formationAssignmentID)
   100  	var destCollection EntityCollection
   101  	conditions := repo.Conditions{repo.NewEqualCondition(formationAssignmentIDColumn, formationAssignmentID)}
   102  	if err := r.lister.List(ctx, resource.Destination, tenantID, &destCollection, conditions...); err != nil {
   103  		return nil, err
   104  	}
   105  
   106  	items := make([]*model.Destination, 0, destCollection.Len())
   107  	for _, destEntity := range destCollection {
   108  		items = append(items, r.conv.FromEntity(&destEntity))
   109  	}
   110  
   111  	return items, nil
   112  }
   113  
   114  // DeleteByDestinationNameAndAssignmentID deletes all destinations for a given `destinationName`, `formationAssignmentID` and `tenantID` from the DB
   115  func (r *repository) DeleteByDestinationNameAndAssignmentID(ctx context.Context, destinationName, formationAssignmentID, tenantID string) error {
   116  	log.C(ctx).Infof("Deleting destination(s) by name: %q, assignment ID: %q and tenant ID: %q from the DB", destinationName, tenantID, formationAssignmentID)
   117  	conditions := repo.Conditions{repo.NewEqualCondition(destinationNameColumn, destinationName), repo.NewEqualCondition(formationAssignmentIDColumn, formationAssignmentID)}
   118  	return r.deleter.DeleteMany(ctx, resource.Destination, tenantID, conditions)
   119  }