github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/domain/formationconstraint/repository.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/internal/repo" 8 "github.com/kyma-incubator/compass/components/director/pkg/apperrors" 9 "github.com/kyma-incubator/compass/components/director/pkg/formationconstraint" 10 "github.com/kyma-incubator/compass/components/director/pkg/log" 11 "github.com/kyma-incubator/compass/components/director/pkg/resource" 12 "github.com/pkg/errors" 13 ) 14 15 const ( 16 tableName string = `public.formation_constraints` 17 idColumn string = "id" 18 resourceSubtypeANY string = "ANY" 19 ) 20 21 var ( 22 tableColumns = []string{"id", "name", "constraint_type", "target_operation", "operator", "resource_type", "resource_subtype", "input_template", "constraint_scope"} 23 updatableColumns = []string{"input_template"} 24 idColumns = []string{"id"} 25 ) 26 27 // EntityConverter converts between the internal model and entity 28 // 29 //go:generate mockery --name=EntityConverter --output=automock --outpkg=automock --case=underscore --disable-version-string 30 type EntityConverter interface { 31 ToEntity(in *model.FormationConstraint) *Entity 32 FromEntity(entity *Entity) *model.FormationConstraint 33 } 34 35 type repository struct { 36 conditionTreeLister repo.ConditionTreeListerGlobal 37 lister repo.ListerGlobal 38 creator repo.CreatorGlobal 39 singleGetter repo.SingleGetterGlobal 40 deleter repo.DeleterGlobal 41 updater repo.UpdaterGlobal 42 conv EntityConverter 43 } 44 45 // NewRepository creates a new FormationConstraint repository 46 func NewRepository(conv EntityConverter) *repository { 47 return &repository{ 48 conditionTreeLister: repo.NewConditionTreeListerGlobal(tableName, tableColumns), 49 lister: repo.NewListerGlobal(resource.FormationConstraint, tableName, tableColumns), 50 creator: repo.NewCreatorGlobal(resource.FormationConstraint, tableName, tableColumns), 51 singleGetter: repo.NewSingleGetterGlobal(resource.FormationConstraint, tableName, tableColumns), 52 deleter: repo.NewDeleterGlobal(resource.FormationConstraint, tableName), 53 updater: repo.NewUpdaterGlobal(resource.FormationConstraint, tableName, updatableColumns, idColumns), 54 conv: conv, 55 } 56 } 57 58 // Create stores new record in the database 59 func (r *repository) Create(ctx context.Context, item *model.FormationConstraint) error { 60 if item == nil { 61 return apperrors.NewInternalError("model can not be empty") 62 } 63 64 log.C(ctx).Debugf("Converting Formation Constraint with id %s to entity", item.ID) 65 entity := r.conv.ToEntity(item) 66 67 log.C(ctx).Debugf("Persisting Formation Constraint entity with id %s to db", item.ID) 68 return r.creator.Create(ctx, entity) 69 } 70 71 // Get fetches the formation constraint from the db by the provided id 72 func (r *repository) Get(ctx context.Context, id string) (*model.FormationConstraint, error) { 73 var entity Entity 74 if err := r.singleGetter.GetGlobal(ctx, repo.Conditions{repo.NewEqualCondition("id", id)}, repo.NoOrderBy, &entity); err != nil { 75 return nil, err 76 } 77 78 result := r.conv.FromEntity(&entity) 79 80 return result, nil 81 } 82 83 // ListAll lists all formation constraints 84 func (r *repository) ListAll(ctx context.Context) ([]*model.FormationConstraint, error) { 85 var entities EntityCollection 86 87 if err := r.lister.ListGlobal(ctx, &entities); err != nil { 88 return nil, err 89 } 90 91 return r.multipleFromEntities(entities) 92 } 93 94 // ListByIDs lists all formation constraints whose id is in formationConstraintIDs 95 func (r *repository) ListByIDs(ctx context.Context, formationConstraintIDs []string) ([]*model.FormationConstraint, error) { 96 if len(formationConstraintIDs) == 0 { 97 return nil, nil 98 } 99 100 var entities EntityCollection 101 102 if err := r.lister.ListGlobal(ctx, &entities, repo.NewInConditionForStringValues(idColumn, formationConstraintIDs)); err != nil { 103 return nil, err 104 } 105 106 return r.multipleFromEntities(entities) 107 } 108 109 // Delete deletes formation constraint from the database by id 110 func (r *repository) Delete(ctx context.Context, id string) error { 111 return r.deleter.DeleteOneGlobal(ctx, repo.Conditions{repo.NewEqualCondition(idColumn, id)}) 112 } 113 114 // ListMatchingFormationConstraints lists formationConstraints whose ID can be found in formationConstraintIDs or have constraint scope "global" that match on the join point location and matching details 115 func (r *repository) ListMatchingFormationConstraints(ctx context.Context, formationConstraintIDs []string, location formationconstraint.JoinPointLocation, details formationconstraint.MatchingDetails) ([]*model.FormationConstraint, error) { 116 var entityCollection EntityCollection 117 118 formationTypeRelevanceConditions := []repo.Condition{ 119 repo.NewEqualCondition("constraint_scope", model.GlobalFormationConstraintScope), 120 } 121 122 if len(formationConstraintIDs) > 0 { 123 formationTypeRelevanceConditions = append(formationTypeRelevanceConditions, repo.NewInConditionForStringValues("id", formationConstraintIDs)) 124 } 125 126 resourceSubtypeConditions := []repo.Condition{ 127 repo.NewEqualCondition("resource_subtype", details.ResourceSubtype), 128 repo.NewEqualCondition("resource_subtype", resourceSubtypeANY), 129 } 130 131 conditions := repo.And( 132 append( 133 repo.ConditionTreesFromConditions( 134 []repo.Condition{ 135 repo.NewEqualCondition("target_operation", location.OperationName), 136 repo.NewEqualCondition("constraint_type", location.ConstraintType), 137 repo.NewEqualCondition("resource_type", details.ResourceType), 138 }, 139 ), 140 repo.Or(repo.ConditionTreesFromConditions( 141 resourceSubtypeConditions, 142 )...), 143 repo.Or(repo.ConditionTreesFromConditions( 144 formationTypeRelevanceConditions, 145 )...), 146 )..., 147 ) 148 149 if err := r.conditionTreeLister.ListConditionTreeGlobal(ctx, resource.FormationConstraint, &entityCollection, conditions); err != nil { 150 return nil, errors.Wrap(err, "while listing constraints") 151 } 152 return r.multipleFromEntities(entityCollection) 153 } 154 155 // ListByIDsAndGlobal lists formationConstraints whose ID can be found in formationConstraintIDs or have constraint scope "global" 156 func (r *repository) ListByIDsAndGlobal(ctx context.Context, formationConstraintIDs []string) ([]*model.FormationConstraint, error) { 157 var entityCollection EntityCollection 158 159 formationTypeRelevanceConditions := []repo.Condition{ 160 repo.NewEqualCondition("constraint_scope", model.GlobalFormationConstraintScope), 161 } 162 163 if len(formationConstraintIDs) > 0 { 164 formationTypeRelevanceConditions = append(formationTypeRelevanceConditions, repo.NewInConditionForStringValues("id", formationConstraintIDs)) 165 } 166 167 conditions := repo.Or(repo.ConditionTreesFromConditions(formationTypeRelevanceConditions)...) 168 169 if err := r.conditionTreeLister.ListConditionTreeGlobal(ctx, resource.FormationConstraint, &entityCollection, conditions); err != nil { 170 return nil, errors.Wrap(err, "while listing constraints") 171 } 172 return r.multipleFromEntities(entityCollection) 173 } 174 175 // Update updates the FormationConstraint matching the ID of the input model 176 func (r *repository) Update(ctx context.Context, model *model.FormationConstraint) error { 177 if model == nil { 178 return apperrors.NewInternalError("model can not be empty") 179 } 180 181 entity := r.conv.ToEntity(model) 182 183 return r.updater.UpdateSingleGlobal(ctx, entity) 184 } 185 186 func (r *repository) multipleFromEntities(entities EntityCollection) ([]*model.FormationConstraint, error) { 187 items := make([]*model.FormationConstraint, 0, len(entities)) 188 for _, ent := range entities { 189 m := r.conv.FromEntity(&ent) 190 items = append(items, m) 191 } 192 return items, nil 193 }