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

     1  package product
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/kyma-incubator/compass/components/director/pkg/resource"
     7  
     8  	"github.com/kyma-incubator/compass/components/director/internal/domain/tenant"
     9  	"github.com/kyma-incubator/compass/components/director/internal/model"
    10  	"github.com/kyma-incubator/compass/components/director/pkg/log"
    11  	"github.com/pkg/errors"
    12  )
    13  
    14  // ProductRepository missing godoc
    15  //
    16  //go:generate mockery --name=ProductRepository --output=automock --outpkg=automock --case=underscore --disable-version-string
    17  type ProductRepository interface {
    18  	Create(ctx context.Context, tenant string, item *model.Product) error
    19  	CreateGlobal(ctx context.Context, model *model.Product) error
    20  	Update(ctx context.Context, tenant string, item *model.Product) error
    21  	UpdateGlobal(ctx context.Context, model *model.Product) error
    22  	Delete(ctx context.Context, tenant, id string) error
    23  	DeleteGlobal(ctx context.Context, id string) error
    24  	Exists(ctx context.Context, tenant, id string) (bool, error)
    25  	GetByID(ctx context.Context, tenant, id string) (*model.Product, error)
    26  	GetByIDGlobal(ctx context.Context, id string) (*model.Product, error)
    27  	ListByResourceID(ctx context.Context, tenantID, appID string, resourceType resource.Type) ([]*model.Product, error)
    28  	ListGlobal(ctx context.Context) ([]*model.Product, error)
    29  }
    30  
    31  // UIDService missing godoc
    32  //
    33  //go:generate mockery --name=UIDService --output=automock --outpkg=automock --case=underscore --disable-version-string
    34  type UIDService interface {
    35  	Generate() string
    36  }
    37  
    38  type service struct {
    39  	productRepo ProductRepository
    40  	uidService  UIDService
    41  }
    42  
    43  // NewService creates a new instance of Product Service.
    44  func NewService(productRepo ProductRepository, uidService UIDService) *service {
    45  	return &service{
    46  		productRepo: productRepo,
    47  		uidService:  uidService,
    48  	}
    49  }
    50  
    51  // Create creates a new product.
    52  func (s *service) Create(ctx context.Context, resourceType resource.Type, resourceID string, in model.ProductInput) (string, error) {
    53  	id := s.uidService.Generate()
    54  	product := in.ToProduct(id, resourceType, resourceID)
    55  
    56  	if err := s.createProduct(ctx, product, resourceType); err != nil {
    57  		return "", errors.Wrapf(err, "error occurred while creating a Product with id %s and title %s for %v with id %s", id, product.Title, resourceType, resourceID)
    58  	}
    59  
    60  	log.C(ctx).Debugf("Successfully created a Product with id %s and title %s for %s with id %s", id, product.Title, resourceType, resourceID)
    61  
    62  	return product.OrdID, nil
    63  }
    64  
    65  // CreateGlobal creates a new global product (with NULL app_id).
    66  func (s *service) CreateGlobal(ctx context.Context, in model.ProductInput) (string, error) {
    67  	id := s.uidService.Generate()
    68  	product := in.ToProduct(id, "", "")
    69  
    70  	if err := s.productRepo.CreateGlobal(ctx, product); err != nil {
    71  		return "", errors.Wrapf(err, "error occurred while creating Global Product with id %s and title %s", id, product.Title)
    72  	}
    73  	log.C(ctx).Debugf("Successfully created a Global Product with id %s and title %s", id, product.Title)
    74  
    75  	return product.OrdID, nil
    76  }
    77  
    78  // Update updates an existing product.
    79  func (s *service) Update(ctx context.Context, resourceType resource.Type, id string, in model.ProductInput) error {
    80  	product, err := s.getProduct(ctx, id, resourceType)
    81  	if err != nil {
    82  		return errors.Wrapf(err, "while getting Product with id %s", id)
    83  	}
    84  
    85  	product.SetFromUpdateInput(in)
    86  
    87  	if err = s.updateProduct(ctx, product, resourceType); err != nil {
    88  		return errors.Wrapf(err, "while updating Product with id %s", id)
    89  	}
    90  
    91  	return nil
    92  }
    93  
    94  // UpdateGlobal updates an existing product without tenant isolation.
    95  func (s *service) UpdateGlobal(ctx context.Context, id string, in model.ProductInput) error {
    96  	product, err := s.productRepo.GetByIDGlobal(ctx, id)
    97  	if err != nil {
    98  		return errors.Wrapf(err, "while getting Product with id %s", id)
    99  	}
   100  
   101  	product.SetFromUpdateInput(in)
   102  
   103  	if err = s.productRepo.UpdateGlobal(ctx, product); err != nil {
   104  		return errors.Wrapf(err, "while updating Product with id %s", id)
   105  	}
   106  	return nil
   107  }
   108  
   109  // Delete deletes an existing product.
   110  func (s *service) Delete(ctx context.Context, resourceType resource.Type, id string) error {
   111  	if err := s.deleteProduct(ctx, id, resourceType); err != nil {
   112  		return errors.Wrapf(err, "while deleting Product with id %s", id)
   113  	}
   114  
   115  	log.C(ctx).Infof("Successfully deleted Product with id %s", id)
   116  
   117  	return nil
   118  }
   119  
   120  // DeleteGlobal deletes an existing product without tenant isolation.
   121  func (s *service) DeleteGlobal(ctx context.Context, id string) error {
   122  	if err := s.productRepo.DeleteGlobal(ctx, id); err != nil {
   123  		return errors.Wrapf(err, "while deleting Product with id %s", id)
   124  	}
   125  
   126  	return nil
   127  }
   128  
   129  // Exist checks if a product exists.
   130  func (s *service) Exist(ctx context.Context, id string) (bool, error) {
   131  	tnt, err := tenant.LoadFromContext(ctx)
   132  	if err != nil {
   133  		return false, errors.Wrap(err, "while loading tenant from context")
   134  	}
   135  
   136  	exist, err := s.productRepo.Exists(ctx, tnt, id)
   137  	if err != nil {
   138  		return false, errors.Wrapf(err, "while getting Product with ID: %q", id)
   139  	}
   140  
   141  	return exist, nil
   142  }
   143  
   144  // Get returns a product by its ID.
   145  func (s *service) Get(ctx context.Context, id string) (*model.Product, error) {
   146  	tnt, err := tenant.LoadFromContext(ctx)
   147  	if err != nil {
   148  		return nil, errors.Wrap(err, "while loading tenant from context")
   149  	}
   150  
   151  	product, err := s.productRepo.GetByID(ctx, tnt, id)
   152  	if err != nil {
   153  		return nil, errors.Wrapf(err, "while getting Product with ID: %q", id)
   154  	}
   155  
   156  	return product, nil
   157  }
   158  
   159  // ListByApplicationID returns a list of products for a given application ID.
   160  func (s *service) ListByApplicationID(ctx context.Context, appID string) ([]*model.Product, error) {
   161  	tnt, err := tenant.LoadFromContext(ctx)
   162  	if err != nil {
   163  		return nil, err
   164  	}
   165  
   166  	return s.productRepo.ListByResourceID(ctx, tnt, appID, resource.Application)
   167  }
   168  
   169  // ListByApplicationTemplateVersionID returns a list of products for a given application ID.
   170  func (s *service) ListByApplicationTemplateVersionID(ctx context.Context, appID string) ([]*model.Product, error) {
   171  	return s.productRepo.ListByResourceID(ctx, "", appID, resource.ApplicationTemplateVersion)
   172  }
   173  
   174  // ListGlobal returns a list of global products (with NULL app_id).
   175  func (s *service) ListGlobal(ctx context.Context) ([]*model.Product, error) {
   176  	return s.productRepo.ListGlobal(ctx)
   177  }
   178  
   179  func (s *service) createProduct(ctx context.Context, product *model.Product, resourceType resource.Type) error {
   180  	if resourceType.IsTenantIgnorable() {
   181  		return s.productRepo.CreateGlobal(ctx, product)
   182  	}
   183  
   184  	tnt, err := tenant.LoadFromContext(ctx)
   185  	if err != nil {
   186  		return err
   187  	}
   188  
   189  	return s.productRepo.Create(ctx, tnt, product)
   190  }
   191  
   192  func (s *service) getProduct(ctx context.Context, id string, resourceType resource.Type) (*model.Product, error) {
   193  	if resourceType.IsTenantIgnorable() {
   194  		return s.productRepo.GetByIDGlobal(ctx, id)
   195  	}
   196  
   197  	return s.Get(ctx, id)
   198  }
   199  
   200  func (s *service) updateProduct(ctx context.Context, product *model.Product, resourceType resource.Type) error {
   201  	if resourceType.IsTenantIgnorable() {
   202  		return s.productRepo.UpdateGlobal(ctx, product)
   203  	}
   204  
   205  	tnt, err := tenant.LoadFromContext(ctx)
   206  	if err != nil {
   207  		return err
   208  	}
   209  
   210  	return s.productRepo.Update(ctx, tnt, product)
   211  }
   212  
   213  func (s *service) deleteProduct(ctx context.Context, id string, resourceType resource.Type) error {
   214  	if resourceType.IsTenantIgnorable() {
   215  		return s.productRepo.DeleteGlobal(ctx, id)
   216  	}
   217  
   218  	tnt, err := tenant.LoadFromContext(ctx)
   219  	if err != nil {
   220  		return errors.Wrap(err, "while loading tenant from context")
   221  	}
   222  
   223  	return s.productRepo.Delete(ctx, tnt, id)
   224  }