177 lines
4.8 KiB
Go
177 lines
4.8 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
|
|
"shop/internal/models"
|
|
)
|
|
|
|
type CartRepository struct {
|
|
pool *pgxpool.Pool
|
|
}
|
|
|
|
func NewCartRepository(pool *pgxpool.Pool) *CartRepository {
|
|
return &CartRepository{pool: pool}
|
|
}
|
|
|
|
func (r *CartRepository) GetOrCreate(ctx context.Context, sessionKey string, userID *int) (int, error) {
|
|
if userID != nil {
|
|
var cartID int
|
|
err := r.pool.QueryRow(ctx, `SELECT id FROM carts WHERE user_id = $1`, *userID).Scan(&cartID)
|
|
if err == nil {
|
|
return cartID, nil
|
|
}
|
|
if err != pgx.ErrNoRows {
|
|
return 0, err
|
|
}
|
|
err = r.pool.QueryRow(ctx, `
|
|
INSERT INTO carts (user_id, session_key) VALUES ($1, $2) RETURNING id
|
|
`, *userID, sessionKey).Scan(&cartID)
|
|
return cartID, err
|
|
}
|
|
|
|
var cartID int
|
|
err := r.pool.QueryRow(ctx, `
|
|
SELECT id FROM carts WHERE session_key = $1 AND user_id IS NULL
|
|
`, sessionKey).Scan(&cartID)
|
|
if err == nil {
|
|
return cartID, nil
|
|
}
|
|
if err != pgx.ErrNoRows {
|
|
return 0, err
|
|
}
|
|
err = r.pool.QueryRow(ctx, `
|
|
INSERT INTO carts (session_key) VALUES ($1) RETURNING id
|
|
`, sessionKey).Scan(&cartID)
|
|
return cartID, err
|
|
}
|
|
|
|
func (r *CartRepository) MergeToUser(ctx context.Context, sessionKey string, userID int) error {
|
|
tx, err := r.pool.Begin(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer tx.Rollback(ctx)
|
|
|
|
var guestCartID int
|
|
err = tx.QueryRow(ctx, `
|
|
SELECT id FROM carts WHERE session_key = $1 AND user_id IS NULL
|
|
`, sessionKey).Scan(&guestCartID)
|
|
if err == pgx.ErrNoRows {
|
|
return tx.Commit(ctx)
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var userCartID int
|
|
err = tx.QueryRow(ctx, `SELECT id FROM carts WHERE user_id = $1`, userID).Scan(&userCartID)
|
|
if err == pgx.ErrNoRows {
|
|
_, err = tx.Exec(ctx, `UPDATE carts SET user_id = $1 WHERE id = $2`, userID, guestCartID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return tx.Commit(ctx)
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = tx.Exec(ctx, `
|
|
INSERT INTO cart_items (cart_id, product_id, quantity)
|
|
SELECT $1, product_id, quantity FROM cart_items WHERE cart_id = $2
|
|
ON CONFLICT (cart_id, product_id) DO UPDATE
|
|
SET quantity = cart_items.quantity + EXCLUDED.quantity
|
|
`, userCartID, guestCartID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = tx.Exec(ctx, `DELETE FROM carts WHERE id = $1`, guestCartID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return tx.Commit(ctx)
|
|
}
|
|
|
|
func (r *CartRepository) AddItem(ctx context.Context, cartID, productID, qty int) error {
|
|
_, err := r.pool.Exec(ctx, `
|
|
INSERT INTO cart_items (cart_id, product_id, quantity)
|
|
VALUES ($1, $2, $3)
|
|
ON CONFLICT (cart_id, product_id) DO UPDATE
|
|
SET quantity = cart_items.quantity + EXCLUDED.quantity
|
|
`, cartID, productID, qty)
|
|
return err
|
|
}
|
|
|
|
func (r *CartRepository) UpdateItem(ctx context.Context, cartID, productID, qty int) error {
|
|
if qty <= 0 {
|
|
_, err := r.pool.Exec(ctx, `DELETE FROM cart_items WHERE cart_id = $1 AND product_id = $2`, cartID, productID)
|
|
return err
|
|
}
|
|
_, err := r.pool.Exec(ctx, `
|
|
UPDATE cart_items SET quantity = $3 WHERE cart_id = $1 AND product_id = $2
|
|
`, cartID, productID, qty)
|
|
return err
|
|
}
|
|
|
|
func (r *CartRepository) RemoveItem(ctx context.Context, cartID, productID int) error {
|
|
_, err := r.pool.Exec(ctx, `DELETE FROM cart_items WHERE cart_id = $1 AND product_id = $2`, cartID, productID)
|
|
return err
|
|
}
|
|
|
|
func (r *CartRepository) Clear(ctx context.Context, cartID int) error {
|
|
_, err := r.pool.Exec(ctx, `DELETE FROM cart_items WHERE cart_id = $1`, cartID)
|
|
return err
|
|
}
|
|
|
|
func (r *CartRepository) ItemCount(ctx context.Context, cartID int) (int, error) {
|
|
var count int
|
|
err := r.pool.QueryRow(ctx, `
|
|
SELECT COALESCE(SUM(quantity), 0) FROM cart_items WHERE cart_id = $1
|
|
`, cartID).Scan(&count)
|
|
return count, err
|
|
}
|
|
|
|
func (r *CartRepository) Items(ctx context.Context, cartID int) ([]models.CartItem, error) {
|
|
rows, err := r.pool.Query(ctx, `
|
|
SELECT ci.id, ci.cart_id, ci.product_id, ci.quantity,
|
|
p.id, p.name, p.description, p.details, p.price, p.image_url, p.category, p.is_active, p.created_at, p.updated_at
|
|
FROM cart_items ci
|
|
JOIN products p ON p.id = ci.product_id
|
|
WHERE ci.cart_id = $1 AND p.is_active = true
|
|
ORDER BY ci.id
|
|
`, cartID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var items []models.CartItem
|
|
for rows.Next() {
|
|
var ci models.CartItem
|
|
var p models.Product
|
|
if err := rows.Scan(
|
|
&ci.ID, &ci.CartID, &ci.ProductID, &ci.Quantity,
|
|
&p.ID, &p.Name, &p.Description, &p.Details, &p.Price, &p.ImageURL, &p.Category, &p.IsActive, &p.CreatedAt, &p.UpdatedAt,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
ci.Product = p
|
|
items = append(items, ci)
|
|
}
|
|
return items, rows.Err()
|
|
}
|
|
|
|
func (r *CartRepository) Total(ctx context.Context, cartID int) (float64, error) {
|
|
var total float64
|
|
err := r.pool.QueryRow(ctx, `
|
|
SELECT COALESCE(SUM(ci.quantity * p.price), 0)
|
|
FROM cart_items ci JOIN products p ON p.id = ci.product_id
|
|
WHERE ci.cart_id = $1
|
|
`, cartID).Scan(&total)
|
|
return total, err
|
|
}
|