Produkte und Properties im Server
This commit is contained in:
@@ -72,7 +72,7 @@ CREATE TABLE tabelle_a (
|
|||||||
|
|
||||||
- updateValueFromValueId
|
- updateValueFromValueId
|
||||||
|
|
||||||
- add
|
- addValueToPropertyType
|
||||||
|
|
||||||
- Produkte haben zusätzlich zur ID, Label und Beschreibung noch eine externalId.
|
- Produkte haben zusätzlich zur ID, Label und Beschreibung noch eine externalId.
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ CREATE TABLE IF NOT EXISTS values (
|
|||||||
id BIGINT PRIMARY KEY DEFAULT nextval('global_id_seq'),
|
id BIGINT PRIMARY KEY DEFAULT nextval('global_id_seq'),
|
||||||
Label TEXT,
|
Label TEXT,
|
||||||
description TEXT,
|
description TEXT,
|
||||||
propertyId BIGINT
|
propertyGroupId BIGINT
|
||||||
);
|
);
|
||||||
|
|
||||||
-- Property Table
|
-- Property Table
|
||||||
@@ -163,11 +163,8 @@ CREATE TABLE IF NOT EXISTS media (
|
|||||||
mediaType TEXT,
|
mediaType TEXT,
|
||||||
externalId BIGINT
|
externalId BIGINT
|
||||||
);
|
);
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Open Aufsetzen des Source Codes:
|
## Open Aufsetzen des Source Codes:
|
||||||
|
|
||||||
````
|
````
|
||||||
@@ -219,3 +216,46 @@ go get github.com/gin-contrib/cors
|
|||||||
## Server API
|
## Server API
|
||||||
|
|
||||||
Die Server-API baut auf HTTP und auf REST auf. Antworten werden im JSON Format gesendet,ebenso, wie neu anzulegende Daten oder zu aktualisierende Daten.
|
Die Server-API baut auf HTTP und auf REST auf. Antworten werden im JSON Format gesendet,ebenso, wie neu anzulegende Daten oder zu aktualisierende Daten.
|
||||||
|
|
||||||
|
Generell werden Daten im JSON Format ausgetauscht. Z.B. wird ein *Value* Objekt in From von *application/json Daten* übergeben:
|
||||||
|
|
||||||
|
```gettext
|
||||||
|
put: http://server:port/updatePropertyType
|
||||||
|
```
|
||||||
|
|
||||||
|
benötigt folgende Struktur im Anfragekörper:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": 1000003,
|
||||||
|
"label": "Colour",
|
||||||
|
"description": "System wide colors",
|
||||||
|
"propertyTypeGroupId": 100002
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
und liefert als Ergebnis (wenn kein Fehler auftritt):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"id": 1000003,
|
||||||
|
"label": "Colour",
|
||||||
|
"description": "System wide colors",
|
||||||
|
"propertyTypeGroupId": 100002
|
||||||
|
},
|
||||||
|
"message": "PropertyType updated"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Wenn Daten zurückkommen, so wie hier im Beispiel, dann werden sie im *"data"* Tag geschrieben. Meistens kommt auch noch eine Nachricht mit, die in *"message"* steht.
|
||||||
|
|
||||||
|
Im Falle eines Fehler kommt eine entsprechende Nachricht zurück (z.B. wenn es keinen PropertyType mit der entsprechenden *ID* gibt):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"error": "sql: no rows in result set"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Value und Property Funktionen
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"simplycpq/models"
|
||||||
|
"simplycpq/services"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProductController struct {
|
||||||
|
productService *services.ProductService
|
||||||
|
productGroupService *services.ProductGroupService
|
||||||
|
valueService *services.ValueService
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewProductController(productService *services.ProductService, productGroupService *services.ProductGroupService, valueService *services.ValueService) *ProductController {
|
||||||
|
return &ProductController{
|
||||||
|
productService: productService,
|
||||||
|
productGroupService: productGroupService,
|
||||||
|
valueService: valueService,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pc *ProductController) CreateProduct(c *gin.Context) {
|
||||||
|
var product models.Product
|
||||||
|
if err := c.ShouldBindJSON(&product); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
createdProduct, err := pc.productService.CreateProduct(&product)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, gin.H{"status": "product created successfully", "data": createdProduct})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pc *ProductController) UpdateProduct(c *gin.Context) {
|
||||||
|
var product models.Product
|
||||||
|
if err := c.ShouldBindJSON(&product); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := pc.productService.UpdateProduct(&product); err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, gin.H{"status": "product updated successfully"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pc *ProductController) DeleteProduct(c *gin.Context) {
|
||||||
|
id, err := strconv.Atoi(c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid product id"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := pc.productService.DeleteProduct(id); err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, gin.H{"status": "product deleted successfully"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pc *ProductController) GetProduct(c *gin.Context) {
|
||||||
|
id, err := strconv.Atoi(c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid product id"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
product, err := pc.productService.GetProductById(id)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, gin.H{"status": "product retrieved successfully", "product": product})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pc *ProductController) GetProductsByGroupId(c *gin.Context) {
|
||||||
|
groupId, err := strconv.Atoi(c.Param("groupId"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid group id"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
products, err := pc.productService.GetProductsByGroupId(groupId)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, gin.H{"status": "products retrieved successfully", "groupId": groupId, "products": products})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pc *ProductController) AddPropertyToProductId(c *gin.Context) {
|
||||||
|
productId, err := strconv.Atoi(c.Param("productId"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid product id"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
propertyId, err := strconv.Atoi(c.Param("propertyId"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid property id"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := pc.productService.AddPropertyToProduct(productId, propertyId); err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, gin.H{"status": "property added to product successfully", "productId": productId, "propertyId": propertyId})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pc *ProductController) DeletePropertyFromProductId(c *gin.Context) {
|
||||||
|
productId, err := strconv.Atoi(c.Param("productId"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid product id"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
propertyId, err := strconv.Atoi(c.Param("propertyId"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid property id"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := pc.productService.DeletePropertyFromProduct(productId, propertyId); err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, gin.H{"status": "property deleted from product successfully", "productId": productId, "propertyId": propertyId})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pc *ProductController) GetPropertiesFromProductId(c *gin.Context) {
|
||||||
|
productId, err := strconv.Atoi(c.Param("productId"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid product id"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
properties, err := pc.productService.GetPropertiesFromProduct(productId)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, gin.H{"status": "properties retrieved from product successfully", "productId": productId, "properties": properties})
|
||||||
|
}
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"simplycpq/models"
|
||||||
|
"simplycpq/services"
|
||||||
|
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProductGroupController struct {
|
||||||
|
productGroupService *services.ProductGroupService
|
||||||
|
valueService *services.ValueService
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewProductGroupController(productGroupService *services.ProductGroupService, valueService *services.ValueService) *ProductGroupController {
|
||||||
|
return &ProductGroupController{
|
||||||
|
productGroupService: productGroupService,
|
||||||
|
valueService: valueService,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pgc *ProductGroupController) CreateProductGroup(c *gin.Context) {
|
||||||
|
var productGroup models.ProductGroup
|
||||||
|
if err := c.ShouldBindJSON(&productGroup); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
createdProductGroup, err := pgc.productGroupService.CreateProductGroup(&productGroup)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, createdProductGroup)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pgc *ProductGroupController) UpdateProductGroup(c *gin.Context) {
|
||||||
|
var productGroup models.ProductGroup
|
||||||
|
if err := c.ShouldBindJSON(&productGroup); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
updatedProductGroup, err := pgc.productGroupService.UpdateProductGroup(&productGroup)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, updatedProductGroup)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pgc *ProductGroupController) DeleteProductGroup(c *gin.Context) {
|
||||||
|
id, err := strconv.Atoi(c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = pgc.productGroupService.DeleteProductGroup(id)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, gin.H{"message": "ProductGroup deleted successfully"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pgc *ProductGroupController) GetProductGroup(c *gin.Context) {
|
||||||
|
id, err := strconv.Atoi(c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
productGroup, err := pgc.productGroupService.GetProductGroup(id)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, productGroup)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pgc *ProductGroupController) GetProductGroupsByParentId(c *gin.Context) {
|
||||||
|
parentId, err := strconv.Atoi(c.Param("parentId"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid parent ID"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
productGroups, err := pgc.productGroupService.GetProductGroupsByParentId(parentId)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, productGroups)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pgc *ProductGroupController) DeleteProductFromProductGroupId(c *gin.Context) {
|
||||||
|
productId, err := strconv.Atoi(c.Param("productId"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid product ID"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = pgc.productGroupService.DeleteProductFromProductGroupId(productId)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, gin.H{"message": "Product deleted from product group successfully"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pgc *ProductGroupController) GetPropertiesFromProductGroupId(c *gin.Context) {
|
||||||
|
productGroupId, err := strconv.Atoi(c.Param("productGroupId"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid product group ID"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
properties, err := pgc.productGroupService.GetPropertiesFromProductGroupId(productGroupId)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, properties)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pgc *ProductGroupController) DeletePropertyFromProductGroupId(c *gin.Context) {
|
||||||
|
propertyId, err := strconv.Atoi(c.Param("propertyId"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid property ID"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
productGroupId, err := strconv.Atoi(c.Param("productGroupId"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid product group ID"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = pgc.productGroupService.DeletePropertyFromProductGroup(productGroupId, propertyId)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, gin.H{"message": "Property deleted from product group successfully"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pgc *ProductGroupController) CreatePropertyToProductGroupId(c *gin.Context) {
|
||||||
|
var property models.Property
|
||||||
|
if err := c.ShouldBindJSON(&property); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
productGroupId, err := strconv.Atoi(c.Param("productGroupId"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid product group ID"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
property2, err := pgc.productGroupService.CreatePropertyToProductGroupId(productGroupId, &property)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, property2)
|
||||||
|
}
|
||||||
@@ -19,6 +19,8 @@ type Property struct {
|
|||||||
Label string `json:"label"`
|
Label string `json:"label"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
PropertyTypeID int `json:"propertyTypeId"`
|
PropertyTypeID int `json:"propertyTypeId"`
|
||||||
|
ProductID int `json:"productId"`
|
||||||
|
ProductGroupID int `json:"productGroupId"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Value struct {
|
type Value struct {
|
||||||
|
|||||||
@@ -0,0 +1,152 @@
|
|||||||
|
package repositories
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"simplycpq/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProductGroupRepository struct {
|
||||||
|
db *sql.DB
|
||||||
|
valueRepository *ValueRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewProductGroupRepository(db *sql.DB, valueRepository *ValueRepository) *ProductGroupRepository {
|
||||||
|
return &ProductGroupRepository{
|
||||||
|
db: db,
|
||||||
|
valueRepository: valueRepository,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ProductGroupRepository) CreateProductGroup(productGroup *models.ProductGroup) (*models.ProductGroup, error) {
|
||||||
|
// Insert the product group into the database
|
||||||
|
query := "INSERT INTO product_groups (label, description, parentgroupid) VALUES($1,$2,$3) RETURNING id"
|
||||||
|
err := r.db.QueryRow(query, productGroup.Label, productGroup.Description, productGroup.ParentGroupID).Scan(&productGroup.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// get all properties from parent group and copy them to the new group
|
||||||
|
if productGroup.ParentGroupID != 0 {
|
||||||
|
properties, err := r.GetPropertiesFromProductGroupId(productGroup.ParentGroupID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, prop := range properties {
|
||||||
|
_, err := r.valueRepository.createPropertyFromProperty(productGroup.ID, 0, prop)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return productGroup, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ProductGroupRepository) UpdateProductGroup(productGroup *models.ProductGroup) (*models.ProductGroup, error) {
|
||||||
|
query := "UPDATE product_groups SET label=$1, description=$2, parentgroupid=$3 WHERE id=$4"
|
||||||
|
_, err := r.db.Exec(query, productGroup.Label, productGroup.Description, productGroup.ParentGroupID, productGroup.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return productGroup, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ProductGroupRepository) DeleteProductGroup(id int) error {
|
||||||
|
query := "DELETE FROM product_groups WHERE id=$1"
|
||||||
|
_, err := r.db.Exec(query, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ProductGroupRepository) GetProductGroup(id int) (*models.ProductGroup, error) {
|
||||||
|
query := "SELECT id, label, description, parentgroupid FROM product_groups WHERE id=$1"
|
||||||
|
row := r.db.QueryRow(query, id)
|
||||||
|
productGroup := &models.ProductGroup{}
|
||||||
|
err := row.Scan(&productGroup.ID, &productGroup.Label, &productGroup.Description, &productGroup.ParentGroupID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return productGroup, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ProductGroupRepository) GetProductGroupsByParentId(parentId int) ([]*models.ProductGroup, error) {
|
||||||
|
query := "SELECT id, label, description, parentgroupid FROM product_groups WHERE parentgroupid=$1"
|
||||||
|
rows, err := r.db.Query(query, parentId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var productGroups []*models.ProductGroup
|
||||||
|
for rows.Next() {
|
||||||
|
var productGroup models.ProductGroup
|
||||||
|
err := rows.Scan(&productGroup.ID, &productGroup.Label, &productGroup.Description, &productGroup.ParentGroupID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
productGroups = append(productGroups, &productGroup)
|
||||||
|
}
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return productGroups, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ProductGroupRepository) DeleteProductFromProductGroupId(productGroupId int) error {
|
||||||
|
query := "DELETE FROM products WHERE productgroupid=$1"
|
||||||
|
_, err := r.db.Exec(query, productGroupId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ProductGroupRepository) GetPropertiesFromProductGroupId(productGroupId int) ([]*models.Property, error) {
|
||||||
|
query := "SELECT id, label, description, propertytypeid, productid, productgroupid FROM properties WHERE productgroupid=$1"
|
||||||
|
rows, err := r.db.Query(query, productGroupId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var properties []*models.Property
|
||||||
|
for rows.Next() {
|
||||||
|
var property models.Property
|
||||||
|
err := rows.Scan(&property.ID, &property.Label, &property.Description, &property.PropertyTypeID, &property.ProductID, &property.ProductGroupID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
properties = append(properties, &property)
|
||||||
|
}
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return properties, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ProductGroupRepository) DeletePropertyFromProductGroup(productGroupId int, propertyId int) error {
|
||||||
|
query := "DELETE FROM properties WHERE productgroupid=$1 AND id=$2"
|
||||||
|
_, err := r.db.Exec(query, productGroupId, propertyId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ProductGroupRepository) CreatePropertyFromProductGroup(productGroupId int, property *models.Property) (*models.Property, error) {
|
||||||
|
query := "INSERT INTO properties (label, description, propertytypeid, productid, productgroupid) VALUES($1,$2,$3,$4,$5) RETURNING id"
|
||||||
|
err := r.db.QueryRow(query, property.Label, property.Description, property.PropertyTypeID, property.ProductID, productGroupId).Scan(&property.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy property values from parent group to new property
|
||||||
|
if productGroupId != 0 {
|
||||||
|
err := r.valueRepository.copyValuesFromPropertyTypeToProperty(property.ID, property.PropertyTypeID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return property, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
package repositories
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"simplycpq/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProductRepository struct {
|
||||||
|
dbHandler *sql.DB
|
||||||
|
productGroupRepository *ProductGroupRepository
|
||||||
|
valueRepository *ValueRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewProductRepository(dbHandler *sql.DB, productGroupRepository *ProductGroupRepository, valueRepository *ValueRepository) *ProductRepository {
|
||||||
|
return &ProductRepository{
|
||||||
|
dbHandler: dbHandler,
|
||||||
|
productGroupRepository: productGroupRepository,
|
||||||
|
valueRepository: valueRepository,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pr *ProductRepository) CreateProduct(product *models.Product) (*models.Product, error) {
|
||||||
|
// Implement the logic to insert a new product into the database
|
||||||
|
query := "INSERT INTO products (label, externalId, description, productGroupId) VALUES ($1, $2, $3, $4) RETURNING id"
|
||||||
|
err := pr.dbHandler.QueryRow(query, product.Label, product.ExternalID, product.Description, product.ProductGroupID).Scan(&product.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy Properties from ProductGroup to Product
|
||||||
|
properties, err := pr.productGroupRepository.GetPropertiesFromProductGroupId(product.ProductGroupID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, property := range properties {
|
||||||
|
_, err := pr.valueRepository.createPropertyFromProperty(0, product.ID, property)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return product, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pr *ProductRepository) GetProductById(id int) (*models.Product, error) {
|
||||||
|
// Implement the logic to retrieve a product by its ID from the database
|
||||||
|
query := "SELECT id, label, externalId, description, productGroupId FROM products WHERE id = $1"
|
||||||
|
row := pr.dbHandler.QueryRow(query, id)
|
||||||
|
product := &models.Product{}
|
||||||
|
err := row.Scan(&product.ID, &product.Label, &product.ExternalID, &product.Description, &product.ProductGroupID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return product, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pr *ProductRepository) UpdateProduct(product *models.Product) error {
|
||||||
|
// Implement the logic to update an existing product in the database
|
||||||
|
query := "UPDATE products SET label = $1, externalId = $2, description = $3, productGroupId = $4 WHERE id = $5"
|
||||||
|
_, err := pr.dbHandler.Exec(query, product.Label, product.ExternalID, product.Description, product.ProductGroupID, product.ID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pr *ProductRepository) DeleteProduct(id int) error {
|
||||||
|
// Implement the logic to delete a product from the database
|
||||||
|
query := "DELETE FROM products WHERE id = $1"
|
||||||
|
_, err := pr.dbHandler.Exec(query, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pr *ProductRepository) GetProductsByGroupId(groupId int) ([]*models.Product, error) {
|
||||||
|
// Implement the logic to retrieve all products by their group ID from the database
|
||||||
|
query := "SELECT id, label, externalId, description, productGroupId FROM products WHERE productGroupId = $1"
|
||||||
|
rows, err := pr.dbHandler.Query(query, groupId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
products := []*models.Product{}
|
||||||
|
for rows.Next() {
|
||||||
|
product := &models.Product{}
|
||||||
|
err := rows.Scan(&product.ID, &product.Label, &product.ExternalID, &product.Description, &product.ProductGroupID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
products = append(products, product)
|
||||||
|
}
|
||||||
|
return products, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pr *ProductRepository) AddPropertyToProduct(productId int, propertyId int) error {
|
||||||
|
// Implement the logic to add a property to a product in the database
|
||||||
|
query := "INSERT INTO product_properties (productId, propertyId) VALUES ($1, $2)"
|
||||||
|
_, err := pr.dbHandler.Exec(query, productId, propertyId)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pr *ProductRepository) DeletePropertyFromProduct(productId int, propertyId int) error {
|
||||||
|
// Implement the logic to delete a property from a product in the database
|
||||||
|
query := "DELETE FROM product_properties WHERE productId = $1 AND propertyId = $2"
|
||||||
|
_, err := pr.dbHandler.Exec(query, productId, propertyId)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pr *ProductRepository) GetPropertiesFromProduct(productId int) ([]*models.Property, error) {
|
||||||
|
// Implement the logic to retrieve all properties from a product in the database
|
||||||
|
query := "SELECT id, label, description, propertyTypeId, productId, productGroupId FROM properties WHERE productId = $1"
|
||||||
|
rows, err := pr.dbHandler.Query(query, productId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
properties := []*models.Property{}
|
||||||
|
for rows.Next() {
|
||||||
|
property := &models.Property{}
|
||||||
|
err := rows.Scan(&property.ID, &property.Label, &property.Description, &property.PropertyTypeID, &property.ProductID, &property.ProductGroupID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
properties = append(properties, property)
|
||||||
|
}
|
||||||
|
return properties, nil
|
||||||
|
}
|
||||||
@@ -267,6 +267,48 @@ func (vr *ValueRepository) GetValue(id int) (*models.Value, error) {
|
|||||||
return &value, nil
|
return &value, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (vr *ValueRepository) createPropertyFromPropertyType(productGroupId int, productId int, propertyType *models.PropertyType) (*models.Property, error) {
|
||||||
|
query := `INSERT INTO properties (label, description, propertytypeid, productid, productgroupid) VALUES ($1, $2, $3, $4, $5) RETURNING id`
|
||||||
|
var property models.Property
|
||||||
|
err := vr.db.QueryRow(query, propertyType.Label, propertyType.Description, propertyType.ID, productId, productGroupId).Scan(&property.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
property.Label = propertyType.Label
|
||||||
|
property.Description = propertyType.Description
|
||||||
|
property.PropertyTypeID = propertyType.ID
|
||||||
|
property.ProductID = productId
|
||||||
|
property.ProductGroupID = productGroupId
|
||||||
|
|
||||||
|
// Copy values from property type to property
|
||||||
|
err = vr.copyValuesFromPropertyTypeToProperty(propertyType.ID, property.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &property, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vr *ValueRepository) createPropertyFromProperty(productGroupId int, productId int, property *models.Property) (*models.Property, error) {
|
||||||
|
query := `INSERT INTO properties (label, description, propertytypeid, productid, productgroupid) VALUES ($1, $2, $3, $4, $5) RETURNING id`
|
||||||
|
var newProperty models.Property
|
||||||
|
err := vr.db.QueryRow(query, property.Label, property.Description, property.PropertyTypeID, productId, productGroupId).Scan(&newProperty.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
newProperty.Label = property.Label
|
||||||
|
newProperty.Description = property.Description
|
||||||
|
newProperty.PropertyTypeID = property.PropertyTypeID
|
||||||
|
newProperty.ProductID = productId
|
||||||
|
newProperty.ProductGroupID = productGroupId
|
||||||
|
|
||||||
|
// Copy values from property type to property
|
||||||
|
err = vr.copyValuesFromPropertyToProperty(property.ID, newProperty.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &newProperty, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (vr *ValueRepository) copyValuesFromPropertyTypeToProperty(propertyTypeId int, propertyId int) error {
|
func (vr *ValueRepository) copyValuesFromPropertyTypeToProperty(propertyTypeId int, propertyId int) error {
|
||||||
// Implement the logic to copy values from a property type to a property
|
// Implement the logic to copy values from a property type to a property
|
||||||
query := `INSERT INTO values (propertyId, label, description) SELECT $1, label, description FROM values WHERE propertytypeid=$2`
|
query := `INSERT INTO values (propertyId, label, description) SELECT $1, label, description FROM values WHERE propertytypeid=$2`
|
||||||
|
|||||||
@@ -15,20 +15,30 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type HttpServer struct {
|
type HttpServer struct {
|
||||||
config *viper.Viper
|
config *viper.Viper
|
||||||
router *gin.Engine
|
router *gin.Engine
|
||||||
dbHandler *sql.DB
|
dbHandler *sql.DB
|
||||||
valueController *controller.ValueController
|
valueController *controller.ValueController
|
||||||
|
productGroupController *controller.ProductGroupController
|
||||||
|
productController *controller.ProductController
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitHttpServer(config *viper.Viper, dbHandler *sql.DB) HttpServer {
|
func InitHttpServer(config *viper.Viper, dbHandler *sql.DB) HttpServer {
|
||||||
|
|
||||||
// repository initialisation:
|
// repository initialisation:
|
||||||
valueRepository := repositories.NewValueRepository(dbHandler)
|
valueRepository := repositories.NewValueRepository(dbHandler)
|
||||||
|
productGroupRepository := repositories.NewProductGroupRepository(dbHandler, valueRepository)
|
||||||
|
productRepository := repositories.NewProductRepository(dbHandler, productGroupRepository, valueRepository)
|
||||||
|
|
||||||
// service initialisation:
|
// service initialisation:
|
||||||
valueService := services.NewValueService(valueRepository)
|
valueService := services.NewValueService(valueRepository)
|
||||||
|
productGroupService := services.NewProductGroupService(productGroupRepository)
|
||||||
|
productService := services.NewProductService(productRepository)
|
||||||
|
|
||||||
// controller initialisation:
|
// controller initialisation:
|
||||||
valueController := controller.NewValueController(valueService)
|
valueController := controller.NewValueController(valueService)
|
||||||
|
productGroupController := controller.NewProductGroupController(productGroupService, valueService)
|
||||||
|
productController := controller.NewProductController(productService, productGroupService, valueService)
|
||||||
|
|
||||||
// Service API
|
// Service API
|
||||||
router := gin.Default()
|
router := gin.Default()
|
||||||
@@ -55,13 +65,34 @@ func InitHttpServer(config *viper.Viper, dbHandler *sql.DB) HttpServer {
|
|||||||
router.GET("/getValue/:id", valueController.GetValue) // get Value by id
|
router.GET("/getValue/:id", valueController.GetValue) // get Value by id
|
||||||
|
|
||||||
// Product centric routing
|
// Product centric routing
|
||||||
|
// ProductGroup
|
||||||
|
router.POST("/createProductGroup", productGroupController.CreateProductGroup) // create ProductGroup
|
||||||
|
router.PUT("/updateProductGroup", productGroupController.UpdateProductGroup) // update ProductGroup
|
||||||
|
router.DELETE("/deleteProductGroup/:id", productGroupController.DeleteProductGroup) // delete ProductGroup
|
||||||
|
router.GET("/getProductGroup/:id", productGroupController.GetProductGroup) // get ProductGroup by id
|
||||||
|
router.GET("/getProductGroupsByParentId/:parentId", productGroupController.GetProductGroupsByParentId) // get all ProductGroups by parent ID
|
||||||
|
router.DELETE("/deleteProductFromProductGroupId/:productId", productGroupController.DeleteProductFromProductGroupId) // delete Product from ProductGroup by ID
|
||||||
|
router.POST("/getPropertiesFromProductGroupId/:productGroupId", productGroupController.GetPropertiesFromProductGroupId) // get Properties from ProductGroup by ID
|
||||||
|
router.DELETE("/deletePropertyFromProductGroupId/:propertyId/:productGroupId", productGroupController.DeletePropertyFromProductGroupId) // delete Property from ProductGroup by ID
|
||||||
|
router.POST("/createPropertyToProductGroupId/:propertyTypeId/:productGroupId", productGroupController.CreatePropertyToProductGroupId) // add Property to ProductGroup by ID
|
||||||
|
|
||||||
|
// Product
|
||||||
|
router.POST("/createProduct", productController.CreateProduct) // create Product
|
||||||
|
router.PUT("/updateProduct", productController.UpdateProduct) // update Product
|
||||||
|
router.DELETE("/deleteProduct/:id", productController.DeleteProduct) // delete Product
|
||||||
|
router.GET("/getProduct/:id", productController.GetProduct) // get Product by id
|
||||||
|
router.GET("/getProductsByGroupId/:groupId", productController.GetProductsByGroupId) // get all Products by group ID
|
||||||
|
router.POST("/addPropertyToProductId/:productId", productController.AddPropertyToProductId) // add Property to Product by ID
|
||||||
|
router.DELETE("/deletePropertyFromProductId/:productId", productController.DeletePropertyFromProductId) // delete Property from Product by ID
|
||||||
|
|
||||||
// server
|
// server
|
||||||
return HttpServer{
|
return HttpServer{
|
||||||
config: config,
|
config: config,
|
||||||
router: router,
|
router: router,
|
||||||
dbHandler: dbHandler,
|
dbHandler: dbHandler,
|
||||||
valueController: valueController,
|
valueController: valueController,
|
||||||
|
productGroupController: productGroupController,
|
||||||
|
productController: productController,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"simplycpq/models"
|
||||||
|
"simplycpq/repositories"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProductGroupService struct {
|
||||||
|
productGroupRepository *repositories.ProductGroupRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewProductGroupService(productGroupRepository *repositories.ProductGroupRepository) *ProductGroupService {
|
||||||
|
return &ProductGroupService{
|
||||||
|
productGroupRepository: productGroupRepository,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProductGroupService) CreateProductGroup(productGroup *models.ProductGroup) (*models.ProductGroup, error) {
|
||||||
|
return s.productGroupRepository.CreateProductGroup(productGroup)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProductGroupService) UpdateProductGroup(productGroup *models.ProductGroup) (*models.ProductGroup, error) {
|
||||||
|
return s.productGroupRepository.UpdateProductGroup(productGroup)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProductGroupService) DeleteProductGroup(id int) error {
|
||||||
|
return s.productGroupRepository.DeleteProductGroup(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProductGroupService) GetProductGroup(id int) (*models.ProductGroup, error) {
|
||||||
|
return s.productGroupRepository.GetProductGroup(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProductGroupService) GetPropertiesFromProductGroupId(id int) ([]*models.Property, error) {
|
||||||
|
return s.productGroupRepository.GetPropertiesFromProductGroupId(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProductGroupService) GetProductGroupsByParentId(parentId int) ([]*models.ProductGroup, error) {
|
||||||
|
return s.productGroupRepository.GetProductGroupsByParentId(parentId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProductGroupService) DeleteProductFromProductGroupId(productGroupId int) error {
|
||||||
|
return s.productGroupRepository.DeleteProductFromProductGroupId(productGroupId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProductGroupService) GetPropertiesFromProductGroup(productGroupId int) ([]*models.Property, error) {
|
||||||
|
return s.productGroupRepository.GetPropertiesFromProductGroupId(productGroupId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProductGroupService) DeletePropertyFromProductGroup(productGroupId int, propertyId int) error {
|
||||||
|
return s.productGroupRepository.DeletePropertyFromProductGroup(productGroupId, propertyId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProductGroupService) CreatePropertyToProductGroupId(productGroupId int, property *models.Property) (*models.Property, error) {
|
||||||
|
return s.productGroupRepository.CreatePropertyFromProductGroup(productGroupId, property)
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"simplycpq/models"
|
||||||
|
"simplycpq/repositories"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProductService struct {
|
||||||
|
productRepository *repositories.ProductRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewProductService(productRepository *repositories.ProductRepository) *ProductService {
|
||||||
|
return &ProductService{
|
||||||
|
productRepository: productRepository,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProductService) CreateProduct(product *models.Product) (*models.Product, error) {
|
||||||
|
return s.productRepository.CreateProduct(product)
|
||||||
|
}
|
||||||
|
func (s *ProductService) UpdateProduct(product *models.Product) error {
|
||||||
|
return s.productRepository.UpdateProduct(product)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProductService) DeleteProduct(id int) error {
|
||||||
|
return s.productRepository.DeleteProduct(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProductService) GetProduct(id int) (*models.Product, error) {
|
||||||
|
return s.productRepository.GetProductById(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProductService) GetProductById(id int) (*models.Product, error) {
|
||||||
|
return s.productRepository.GetProductById(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProductService) GetProductsByGroupId(groupId int) ([]*models.Product, error) {
|
||||||
|
return s.productRepository.GetProductsByGroupId(groupId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProductService) AddPropertyToProduct(productId int, propertyId int) error {
|
||||||
|
return s.productRepository.AddPropertyToProduct(productId, propertyId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProductService) DeletePropertyFromProduct(productId int, propertyId int) error {
|
||||||
|
return s.productRepository.DeletePropertyFromProduct(productId, propertyId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProductService) GetPropertiesFromProduct(productId int) ([]*models.Property, error) {
|
||||||
|
return s.productRepository.GetPropertiesFromProduct(productId)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user