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

     1  package formationconstraint
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/kyma-incubator/compass/components/director/internal/model"
     7  	"github.com/kyma-incubator/compass/components/director/pkg/formationconstraint"
     8  	"github.com/kyma-incubator/compass/components/director/pkg/log"
     9  	"github.com/pkg/errors"
    10  )
    11  
    12  //go:generate mockery --exported --name=formationConstraintRepository --output=automock --outpkg=automock --case=underscore --disable-version-string
    13  type formationConstraintRepository interface {
    14  	Create(ctx context.Context, item *model.FormationConstraint) error
    15  	Get(ctx context.Context, id string) (*model.FormationConstraint, error)
    16  	ListAll(ctx context.Context) ([]*model.FormationConstraint, error)
    17  	ListByIDs(ctx context.Context, formationConstraintIDs []string) ([]*model.FormationConstraint, error)
    18  	Delete(ctx context.Context, id string) error
    19  	Update(ctx context.Context, model *model.FormationConstraint) error
    20  	ListMatchingFormationConstraints(ctx context.Context, formationConstraintIDs []string, location formationconstraint.JoinPointLocation, details formationconstraint.MatchingDetails) ([]*model.FormationConstraint, error)
    21  	ListByIDsAndGlobal(ctx context.Context, formationConstraintIDs []string) ([]*model.FormationConstraint, error)
    22  }
    23  
    24  //go:generate mockery --exported --name=formationTemplateConstraintReferenceRepository --output=automock --outpkg=automock --case=underscore --disable-version-string
    25  type formationTemplateConstraintReferenceRepository interface {
    26  	ListByFormationTemplateID(ctx context.Context, formationTemplateID string) ([]*model.FormationTemplateConstraintReference, error)
    27  	ListByFormationTemplateIDs(ctx context.Context, formationTemplateIDs []string) ([]*model.FormationTemplateConstraintReference, error)
    28  }
    29  
    30  //go:generate mockery --exported --name=uidService --output=automock --outpkg=automock --case=underscore --disable-version-string
    31  type uidService interface {
    32  	Generate() string
    33  }
    34  
    35  type service struct {
    36  	repo                                     formationConstraintRepository
    37  	formationTemplateConstraintReferenceRepo formationTemplateConstraintReferenceRepository
    38  	converter                                formationConstraintConverter
    39  	uidSvc                                   uidService
    40  }
    41  
    42  // NewService creates a FormationConstraint service
    43  func NewService(repo formationConstraintRepository, formationTemplateConstraintReferenceRepo formationTemplateConstraintReferenceRepository, uidSvc uidService, converter formationConstraintConverter) *service {
    44  	return &service{
    45  		repo:                                     repo,
    46  		formationTemplateConstraintReferenceRepo: formationTemplateConstraintReferenceRepo,
    47  		uidSvc:                                   uidSvc,
    48  		converter:                                converter,
    49  	}
    50  }
    51  
    52  // Create creates formation constraint using the provided input
    53  func (s *service) Create(ctx context.Context, in *model.FormationConstraintInput) (string, error) {
    54  	formationConstraintID := s.uidSvc.Generate()
    55  
    56  	log.C(ctx).Debugf("ID %s generated for Formation Constraint with name %s", formationConstraintID, in.Name)
    57  
    58  	err := s.repo.Create(ctx, s.converter.FromModelInputToModel(in, formationConstraintID))
    59  	if err != nil {
    60  		return "", errors.Wrapf(err, "while creating Formation Constraint with name %s", in.Name)
    61  	}
    62  
    63  	return formationConstraintID, nil
    64  }
    65  
    66  // Get fetches formation constraint by id
    67  func (s *service) Get(ctx context.Context, id string) (*model.FormationConstraint, error) {
    68  	formationConstraint, err := s.repo.Get(ctx, id)
    69  	if err != nil {
    70  		return nil, errors.Wrapf(err, "while getting Formation Constraint with id %s", id)
    71  	}
    72  
    73  	return formationConstraint, nil
    74  }
    75  
    76  // List lists all formation constraints
    77  func (s *service) List(ctx context.Context) ([]*model.FormationConstraint, error) {
    78  	formationConstraints, err := s.repo.ListAll(ctx)
    79  	if err != nil {
    80  		return nil, errors.Wrapf(err, "while listing all Formation Constraints")
    81  	}
    82  	return formationConstraints, nil
    83  }
    84  
    85  // ListByFormationTemplateID lists all formation constraints associated with the formation template
    86  func (s *service) ListByFormationTemplateID(ctx context.Context, formationTemplateID string) ([]*model.FormationConstraint, error) {
    87  	constraintReferences, err := s.formationTemplateConstraintReferenceRepo.ListByFormationTemplateID(ctx, formationTemplateID)
    88  	if err != nil {
    89  		return nil, errors.Wrapf(err, "while listing Formation Constraint References for FormationTemplate with ID: %s", formationTemplateID)
    90  	}
    91  
    92  	formationConstraintIDs := make([]string, 0, len(constraintReferences))
    93  	for _, cr := range constraintReferences {
    94  		formationConstraintIDs = append(formationConstraintIDs, cr.ConstraintID)
    95  	}
    96  
    97  	formationConstraints, err := s.repo.ListByIDs(ctx, formationConstraintIDs)
    98  	if err != nil {
    99  		return nil, errors.Wrapf(err, "while listing Formation Constraints for FormationTemplate with ID: %s", formationTemplateID)
   100  	}
   101  	return formationConstraints, nil
   102  }
   103  
   104  // ListByFormationTemplateIDs lists all formation constraints associated with the formation templates
   105  func (s *service) ListByFormationTemplateIDs(ctx context.Context, formationTemplateIDs []string) ([][]*model.FormationConstraint, error) {
   106  	constraintRefs, err := s.formationTemplateConstraintReferenceRepo.ListByFormationTemplateIDs(ctx, formationTemplateIDs)
   107  	if err != nil {
   108  		return nil, errors.Wrapf(err, "while listing Formation Constraint References for FormationTemplates with IDs: %q", formationTemplateIDs)
   109  	}
   110  
   111  	constraintIDs := make([]string, 0, len(constraintRefs))
   112  	formationTemplateIDToConstraintIDsMap := make(map[string][]string, len(constraintRefs))
   113  
   114  	for _, cr := range constraintRefs {
   115  		constraintIDs = append(constraintIDs, cr.ConstraintID)
   116  
   117  		formationTemplateIDToConstraintIDsMap[cr.FormationTemplateID] = append(formationTemplateIDToConstraintIDsMap[cr.FormationTemplateID], cr.ConstraintID)
   118  	}
   119  
   120  	formationConstraints, err := s.repo.ListByIDsAndGlobal(ctx, constraintIDs)
   121  	if err != nil {
   122  		return nil, errors.Wrapf(err, "while listing Formation Constraints by IDs %q and the global ones", formationTemplateIDs)
   123  	}
   124  
   125  	globalConstraints := make([]*model.FormationConstraint, 0, len(formationConstraints))
   126  	attachedConstraintsMap := make(map[string]*model.FormationConstraint, len(formationConstraints))
   127  
   128  	for _, constraint := range formationConstraints {
   129  		if constraint.ConstraintScope == model.GlobalFormationConstraintScope {
   130  			globalConstraints = append(globalConstraints, constraint)
   131  		} else {
   132  			attachedConstraintsMap[constraint.ID] = constraint
   133  		}
   134  	}
   135  
   136  	formationConstraintsPerFormationTemplate := make([][]*model.FormationConstraint, len(formationTemplateIDs))
   137  
   138  	for i, ftID := range formationTemplateIDs {
   139  		// Add attached constraints
   140  		constraintIDsPerFT := formationTemplateIDToConstraintIDsMap[ftID]
   141  		for _, constraintID := range constraintIDsPerFT {
   142  			formationConstraintsPerFormationTemplate[i] = append(formationConstraintsPerFormationTemplate[i], attachedConstraintsMap[constraintID])
   143  		}
   144  
   145  		// Add global constraints
   146  		formationConstraintsPerFormationTemplate[i] = append(formationConstraintsPerFormationTemplate[i], globalConstraints...)
   147  	}
   148  
   149  	return formationConstraintsPerFormationTemplate, nil
   150  }
   151  
   152  // Delete deletes formation constraint by id
   153  func (s *service) Delete(ctx context.Context, id string) error {
   154  	if err := s.repo.Delete(ctx, id); err != nil {
   155  		return errors.Wrapf(err, "while deleting Formation Constraint with ID %s", id)
   156  	}
   157  
   158  	return nil
   159  }
   160  
   161  // ListMatchingConstraints lists formation constraints that math the provided JoinPointLocation and JoinPointDetails
   162  func (s *service) ListMatchingConstraints(ctx context.Context, formationTemplateID string, location formationconstraint.JoinPointLocation, details formationconstraint.MatchingDetails) ([]*model.FormationConstraint, error) {
   163  	formationTemplateConstraintReferences, err := s.formationTemplateConstraintReferenceRepo.ListByFormationTemplateID(ctx, formationTemplateID)
   164  	if err != nil {
   165  		return nil, err
   166  	}
   167  
   168  	constraintIDs := make([]string, 0, len(formationTemplateConstraintReferences))
   169  	for _, reference := range formationTemplateConstraintReferences {
   170  		constraintIDs = append(constraintIDs, reference.ConstraintID)
   171  	}
   172  
   173  	constraints, err := s.repo.ListMatchingFormationConstraints(ctx, constraintIDs, location, details)
   174  	if err != nil {
   175  		return nil, errors.Wrapf(err, "while listing matching formation constraints for formation template with ID %q, target operation %q, constraint type %q, resource type %q and resource subtype %q", formationTemplateID, location.OperationName, location.ConstraintType, details.ResourceType, details.ResourceSubtype)
   176  	}
   177  
   178  	return constraints, nil
   179  }
   180  
   181  // Update updates a FormationConstraint matching ID `id` using `in`
   182  func (s *service) Update(ctx context.Context, id string, in *model.FormationConstraintInput) error {
   183  	err := s.repo.Update(ctx, s.converter.FromModelInputToModel(in, id))
   184  	if err != nil {
   185  		return errors.Wrapf(err, "while updating Formation Constraint with ID %s", id)
   186  	}
   187  
   188  	return nil
   189  }