package repository import ( "apskel-pos-be/internal/entities" "context" "database/sql" "github.com/google/uuid" ) type IngredientCompositionRepository struct { db *sql.DB } func NewIngredientCompositionRepository(db *sql.DB) *IngredientCompositionRepository { return &IngredientCompositionRepository{db: db} } func (r *IngredientCompositionRepository) Create(ctx context.Context, composition *entities.IngredientComposition) error { query := ` INSERT INTO ingredient_compositions (id, organization_id, outlet_id, parent_ingredient_id, child_ingredient_id, quantity, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) ` _, err := r.db.ExecContext(ctx, query, composition.ID, composition.OrganizationID, composition.OutletID, composition.ParentIngredientID, composition.ChildIngredientID, composition.Quantity, composition.CreatedAt, composition.UpdatedAt, ) return err } func (r *IngredientCompositionRepository) GetByID(ctx context.Context, id, organizationID uuid.UUID) (*entities.IngredientComposition, error) { query := ` SELECT ic.id, ic.organization_id, ic.outlet_id, ic.parent_ingredient_id, ic.child_ingredient_id, ic.quantity, ic.created_at, ic.updated_at, pi.id, pi.organization_id, pi.outlet_id, pi.name, pi.unit_id, pi.cost, pi.stock, pi.is_semi_finished, pi.is_active, pi.metadata, pi.created_at, pi.updated_at, ci.id, ci.organization_id, ci.outlet_id, ci.name, ci.unit_id, ci.cost, ci.stock, ci.is_semi_finished, ci.is_active, ci.metadata, ci.created_at, ci.updated_at FROM ingredient_compositions ic LEFT JOIN ingredients pi ON ic.parent_ingredient_id = pi.id LEFT JOIN ingredients ci ON ic.child_ingredient_id = ci.id WHERE ic.id = $1 AND ic.organization_id = $2 ` composition := &entities.IngredientComposition{} parentIngredient := &entities.Ingredient{} childIngredient := &entities.Ingredient{} err := r.db.QueryRowContext(ctx, query, id, organizationID).Scan( &composition.ID, &composition.OrganizationID, &composition.OutletID, &composition.ParentIngredientID, &composition.ChildIngredientID, &composition.Quantity, &composition.CreatedAt, &composition.UpdatedAt, &parentIngredient.ID, &parentIngredient.OrganizationID, &parentIngredient.OutletID, &parentIngredient.Name, &parentIngredient.UnitID, &parentIngredient.Cost, &parentIngredient.Stock, &parentIngredient.IsSemiFinished, &parentIngredient.IsActive, &parentIngredient.Metadata, &parentIngredient.CreatedAt, &parentIngredient.UpdatedAt, &childIngredient.ID, &childIngredient.OrganizationID, &childIngredient.OutletID, &childIngredient.Name, &childIngredient.UnitID, &childIngredient.Cost, &childIngredient.Stock, &childIngredient.IsSemiFinished, &childIngredient.IsActive, &childIngredient.Metadata, &childIngredient.CreatedAt, &childIngredient.UpdatedAt, ) if err != nil { return nil, err } composition.ParentIngredient = parentIngredient composition.ChildIngredient = childIngredient return composition, nil } func (r *IngredientCompositionRepository) GetByParentIngredientID(ctx context.Context, parentIngredientID, organizationID uuid.UUID) ([]*entities.IngredientComposition, error) { query := ` SELECT ic.id, ic.organization_id, ic.outlet_id, ic.parent_ingredient_id, ic.child_ingredient_id, ic.quantity, ic.created_at, ic.updated_at, pi.id, pi.organization_id, pi.outlet_id, pi.name, pi.unit_id, pi.cost, pi.stock, pi.is_semi_finished, pi.is_active, pi.metadata, pi.created_at, pi.updated_at, ci.id, ci.organization_id, ci.outlet_id, ci.name, ci.unit_id, ci.cost, ci.stock, ci.is_semi_finished, ci.is_active, ci.metadata, ci.created_at, ci.updated_at FROM ingredient_compositions ic LEFT JOIN ingredients pi ON ic.parent_ingredient_id = pi.id LEFT JOIN ingredients ci ON ic.child_ingredient_id = ci.id WHERE ic.parent_ingredient_id = $1 AND ic.organization_id = $2 ORDER BY ic.created_at DESC ` rows, err := r.db.QueryContext(ctx, query, parentIngredientID, organizationID) if err != nil { return nil, err } defer rows.Close() var compositions []*entities.IngredientComposition for rows.Next() { composition := &entities.IngredientComposition{} parentIngredient := &entities.Ingredient{} childIngredient := &entities.Ingredient{} err := rows.Scan( &composition.ID, &composition.OrganizationID, &composition.OutletID, &composition.ParentIngredientID, &composition.ChildIngredientID, &composition.Quantity, &composition.CreatedAt, &composition.UpdatedAt, &parentIngredient.ID, &parentIngredient.OrganizationID, &parentIngredient.OutletID, &parentIngredient.Name, &parentIngredient.UnitID, &parentIngredient.Cost, &parentIngredient.Stock, &parentIngredient.IsSemiFinished, &parentIngredient.IsActive, &parentIngredient.Metadata, &parentIngredient.CreatedAt, &parentIngredient.UpdatedAt, &childIngredient.ID, &childIngredient.OrganizationID, &childIngredient.OutletID, &childIngredient.Name, &childIngredient.UnitID, &childIngredient.Cost, &childIngredient.Stock, &childIngredient.IsSemiFinished, &childIngredient.IsActive, &childIngredient.Metadata, &childIngredient.CreatedAt, &childIngredient.UpdatedAt, ) if err != nil { return nil, err } composition.ParentIngredient = parentIngredient composition.ChildIngredient = childIngredient compositions = append(compositions, composition) } return compositions, nil } func (r *IngredientCompositionRepository) GetByChildIngredientID(ctx context.Context, childIngredientID, organizationID uuid.UUID) ([]*entities.IngredientComposition, error) { query := ` SELECT ic.id, ic.organization_id, ic.outlet_id, ic.parent_ingredient_id, ic.child_ingredient_id, ic.quantity, ic.created_at, ic.updated_at, pi.id, pi.organization_id, pi.outlet_id, pi.name, pi.unit_id, pi.cost, pi.stock, pi.is_semi_finished, pi.is_active, pi.metadata, pi.created_at, pi.updated_at, ci.id, ci.organization_id, ci.outlet_id, ci.name, ci.unit_id, ci.cost, ci.stock, ci.is_semi_finished, ci.is_active, ci.metadata, ci.created_at, ci.updated_at FROM ingredient_compositions ic LEFT JOIN ingredients pi ON ic.parent_ingredient_id = pi.id LEFT JOIN ingredients ci ON ic.child_ingredient_id = ci.id WHERE ic.child_ingredient_id = $1 AND ic.organization_id = $2 ORDER BY ic.created_at DESC ` rows, err := r.db.QueryContext(ctx, query, childIngredientID, organizationID) if err != nil { return nil, err } defer rows.Close() var compositions []*entities.IngredientComposition for rows.Next() { composition := &entities.IngredientComposition{} parentIngredient := &entities.Ingredient{} childIngredient := &entities.Ingredient{} err := rows.Scan( &composition.ID, &composition.OrganizationID, &composition.OutletID, &composition.ParentIngredientID, &composition.ChildIngredientID, &composition.Quantity, &composition.CreatedAt, &composition.UpdatedAt, &parentIngredient.ID, &parentIngredient.OrganizationID, &parentIngredient.OutletID, &parentIngredient.Name, &parentIngredient.UnitID, &parentIngredient.Cost, &parentIngredient.Stock, &parentIngredient.IsSemiFinished, &parentIngredient.IsActive, &parentIngredient.Metadata, &parentIngredient.CreatedAt, &parentIngredient.UpdatedAt, &childIngredient.ID, &childIngredient.OrganizationID, &childIngredient.OutletID, &childIngredient.Name, &childIngredient.UnitID, &childIngredient.Cost, &childIngredient.Stock, &childIngredient.IsSemiFinished, &childIngredient.IsActive, &childIngredient.Metadata, &childIngredient.CreatedAt, &childIngredient.UpdatedAt, ) if err != nil { return nil, err } composition.ParentIngredient = parentIngredient composition.ChildIngredient = childIngredient compositions = append(compositions, composition) } return compositions, nil } func (r *IngredientCompositionRepository) Update(ctx context.Context, composition *entities.IngredientComposition) error { query := ` UPDATE ingredient_compositions SET outlet_id = $1, quantity = $2, updated_at = $3 WHERE id = $4 AND organization_id = $5 ` result, err := r.db.ExecContext(ctx, query, composition.OutletID, composition.Quantity, composition.UpdatedAt, composition.ID, composition.OrganizationID, ) if err != nil { return err } rowsAffected, err := result.RowsAffected() if err != nil { return err } if rowsAffected == 0 { return sql.ErrNoRows } return nil } func (r *IngredientCompositionRepository) Delete(ctx context.Context, id, organizationID uuid.UUID) error { query := `DELETE FROM ingredient_compositions WHERE id = $1 AND organization_id = $2` result, err := r.db.ExecContext(ctx, query, id, organizationID) if err != nil { return err } rowsAffected, err := result.RowsAffected() if err != nil { return err } if rowsAffected == 0 { return sql.ErrNoRows } return nil }