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

     1  package product
     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  	"github.com/pkg/errors"
    12  )
    13  
    14  const productTable string = `public.products`
    15  
    16  var (
    17  	productColumns   = []string{"ord_id", "app_id", "app_template_version_id", "title", "short_description", "vendor", "parent", "labels", "correlation_ids", "id", "tags", "documentation_labels"}
    18  	updatableColumns = []string{"title", "short_description", "vendor", "parent", "labels", "correlation_ids", "tags", "documentation_labels"}
    19  )
    20  
    21  // EntityConverter missing godoc
    22  //
    23  //go:generate mockery --name=EntityConverter --output=automock --outpkg=automock --case=underscore --disable-version-string
    24  type EntityConverter interface {
    25  	ToEntity(in *model.Product) *Entity
    26  	FromEntity(entity *Entity) (*model.Product, error)
    27  }
    28  
    29  type pgRepository struct {
    30  	conv               EntityConverter
    31  	existQuerier       repo.ExistQuerier
    32  	lister             repo.Lister
    33  	listerGlobal       repo.ListerGlobal
    34  	singleGetter       repo.SingleGetter
    35  	singleGetterGlobal repo.SingleGetterGlobal
    36  	deleter            repo.Deleter
    37  	deleterGlobal      repo.DeleterGlobal
    38  	creator            repo.Creator
    39  	creatorGlobal      repo.CreatorGlobal
    40  	updater            repo.Updater
    41  	updaterGlobal      repo.UpdaterGlobal
    42  }
    43  
    44  // NewRepository creates a new instance of product repository
    45  func NewRepository(conv EntityConverter) *pgRepository {
    46  	return &pgRepository{
    47  		conv:               conv,
    48  		existQuerier:       repo.NewExistQuerier(productTable),
    49  		singleGetter:       repo.NewSingleGetter(productTable, productColumns),
    50  		singleGetterGlobal: repo.NewSingleGetterGlobal(resource.Product, productTable, productColumns),
    51  		lister:             repo.NewLister(productTable, productColumns),
    52  		listerGlobal:       repo.NewListerGlobal(resource.Product, productTable, productColumns),
    53  		deleter:            repo.NewDeleter(productTable),
    54  		deleterGlobal:      repo.NewDeleterGlobal(resource.Product, productTable),
    55  		creator:            repo.NewCreator(productTable, productColumns),
    56  		creatorGlobal:      repo.NewCreatorGlobal(resource.Product, productTable, productColumns),
    57  		updater:            repo.NewUpdater(productTable, updatableColumns, []string{"id"}),
    58  		updaterGlobal:      repo.NewUpdaterGlobal(resource.Product, productTable, updatableColumns, []string{"id"}),
    59  	}
    60  }
    61  
    62  // Create creates a new product
    63  func (r *pgRepository) Create(ctx context.Context, tenant string, model *model.Product) error {
    64  	if model == nil {
    65  		return apperrors.NewInternalError("model can not be nil")
    66  	}
    67  
    68  	log.C(ctx).Infof("Persisting Product entity with id %q", model.ID)
    69  	return r.creator.Create(ctx, resource.Product, tenant, r.conv.ToEntity(model))
    70  }
    71  
    72  // CreateGlobal creates a new product without tenant isolation
    73  func (r *pgRepository) CreateGlobal(ctx context.Context, model *model.Product) error {
    74  	if model == nil {
    75  		return apperrors.NewInternalError("model can not be nil")
    76  	}
    77  
    78  	log.C(ctx).Debugf("Persisting Product entity with id %q", model.ID)
    79  	return r.creatorGlobal.Create(ctx, r.conv.ToEntity(model))
    80  }
    81  
    82  // Update updates an existing product
    83  func (r *pgRepository) Update(ctx context.Context, tenant string, model *model.Product) error {
    84  	if model == nil {
    85  		return apperrors.NewInternalError("model can not be nil")
    86  	}
    87  	log.C(ctx).Debugf("Updating Product entity with id %q", model.ID)
    88  	return r.updater.UpdateSingle(ctx, resource.Product, tenant, r.conv.ToEntity(model))
    89  }
    90  
    91  // UpdateGlobal updates an existing product without tenant isolation
    92  func (r *pgRepository) UpdateGlobal(ctx context.Context, model *model.Product) error {
    93  	if model == nil {
    94  		return apperrors.NewInternalError("model can not be nil")
    95  	}
    96  	log.C(ctx).Debugf("Updating Product entity with id %q", model.ID)
    97  	return r.updaterGlobal.UpdateSingleGlobal(ctx, r.conv.ToEntity(model))
    98  }
    99  
   100  // Delete deletes an existing product
   101  func (r *pgRepository) Delete(ctx context.Context, tenant, id string) error {
   102  	log.C(ctx).Debugf("Deleting Product entity with id %q", id)
   103  	return r.deleter.DeleteOne(ctx, resource.Product, tenant, repo.Conditions{repo.NewEqualCondition("id", id)})
   104  }
   105  
   106  // DeleteGlobal deletes an existing product without tenant isolation
   107  func (r *pgRepository) DeleteGlobal(ctx context.Context, id string) error {
   108  	log.C(ctx).Debugf("Deleting Product entity with id %q", id)
   109  	return r.deleterGlobal.DeleteOneGlobal(ctx, repo.Conditions{repo.NewEqualCondition("id", id)})
   110  }
   111  
   112  // Exists checks if a product exists
   113  func (r *pgRepository) Exists(ctx context.Context, tenant, id string) (bool, error) {
   114  	return r.existQuerier.Exists(ctx, resource.Product, tenant, repo.Conditions{repo.NewEqualCondition("id", id)})
   115  }
   116  
   117  // GetByID gets a product by its id
   118  func (r *pgRepository) GetByID(ctx context.Context, tenant, id string) (*model.Product, error) {
   119  	log.C(ctx).Debugf("Getting Product entity with id %q", id)
   120  	var productEnt Entity
   121  	if err := r.singleGetter.Get(ctx, resource.Product, tenant, repo.Conditions{repo.NewEqualCondition("id", id)}, repo.NoOrderBy, &productEnt); err != nil {
   122  		return nil, err
   123  	}
   124  
   125  	productModel, err := r.conv.FromEntity(&productEnt)
   126  	if err != nil {
   127  		return nil, errors.Wrap(err, "while converting Product from Entity")
   128  	}
   129  
   130  	return productModel, nil
   131  }
   132  
   133  // GetByIDGlobal gets a product by its id without tenant isolation
   134  func (r *pgRepository) GetByIDGlobal(ctx context.Context, id string) (*model.Product, error) {
   135  	log.C(ctx).Debugf("Getting Product entity with id %q", id)
   136  	var productEnt Entity
   137  	if err := r.singleGetterGlobal.GetGlobal(ctx, repo.Conditions{repo.NewEqualCondition("id", id)}, repo.NoOrderBy, &productEnt); err != nil {
   138  		return nil, err
   139  	}
   140  
   141  	productModel, err := r.conv.FromEntity(&productEnt)
   142  	if err != nil {
   143  		return nil, errors.Wrap(err, "while converting Product from Entity")
   144  	}
   145  
   146  	return productModel, nil
   147  }
   148  
   149  // ListByResourceID gets all products for a given resource ID and type
   150  func (r *pgRepository) ListByResourceID(ctx context.Context, tenantID, resourceID string, resourceType resource.Type) ([]*model.Product, error) {
   151  	productCollection := productCollection{}
   152  
   153  	var err error
   154  	if resourceType == resource.Application {
   155  		condition := repo.NewEqualCondition("app_id", resourceID)
   156  		err = r.lister.ListWithSelectForUpdate(ctx, resource.Product, tenantID, &productCollection, condition)
   157  	} else {
   158  		condition := repo.NewEqualCondition("app_template_version_id", resourceID)
   159  		err = r.listerGlobal.ListGlobalWithSelectForUpdate(ctx, &productCollection, condition)
   160  	}
   161  	if err != nil {
   162  		return nil, err
   163  	}
   164  
   165  	products := make([]*model.Product, 0, productCollection.Len())
   166  	for _, product := range productCollection {
   167  		productModel, err := r.conv.FromEntity(&product)
   168  		if err != nil {
   169  			return nil, err
   170  		}
   171  		products = append(products, productModel)
   172  	}
   173  	return products, nil
   174  }
   175  
   176  // ListGlobal gets all global products (with NULL app_id) without tenant isolation
   177  func (r *pgRepository) ListGlobal(ctx context.Context) ([]*model.Product, error) {
   178  	productCollection := productCollection{}
   179  	if err := r.listerGlobal.ListGlobalWithSelectForUpdate(ctx, &productCollection, repo.NewNullCondition("app_id")); err != nil {
   180  		return nil, err
   181  	}
   182  	products := make([]*model.Product, 0, productCollection.Len())
   183  	for _, product := range productCollection {
   184  		productModel, err := r.conv.FromEntity(&product)
   185  		if err != nil {
   186  			return nil, err
   187  		}
   188  		products = append(products, productModel)
   189  	}
   190  	return products, nil
   191  }
   192  
   193  type productCollection []Entity
   194  
   195  // Len missing godoc
   196  func (pc productCollection) Len() int {
   197  	return len(pc)
   198  }