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 }