v0.30: product pages, categories, sale prices and order status timeline
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
|
||||
"shop/internal/models"
|
||||
)
|
||||
|
||||
type CategoryRepository struct {
|
||||
pool *pgxpool.Pool
|
||||
}
|
||||
|
||||
func NewCategoryRepository(pool *pgxpool.Pool) *CategoryRepository {
|
||||
return &CategoryRepository{pool: pool}
|
||||
}
|
||||
|
||||
var slugRe = regexp.MustCompile(`[^a-z0-9]+`)
|
||||
|
||||
func Slugify(name string) string {
|
||||
translit := map[rune]string{
|
||||
'а': "a", 'б': "b", 'в': "v", 'г': "g", 'д': "d", 'е': "e", 'ё': "e",
|
||||
'ж': "zh", 'з': "z", 'и': "i", 'й': "y", 'к': "k", 'л': "l", 'м': "m",
|
||||
'н': "n", 'о': "o", 'п': "p", 'р': "r", 'с': "s", 'т': "t", 'у': "u",
|
||||
'ф': "f", 'х': "h", 'ц': "ts", 'ч': "ch", 'ш': "sh", 'щ': "sch",
|
||||
'ъ': "", 'ы': "y", 'ь': "", 'э': "e", 'ю': "yu", 'я': "ya",
|
||||
}
|
||||
var b strings.Builder
|
||||
for _, r := range strings.ToLower(name) {
|
||||
if t, ok := translit[r]; ok {
|
||||
b.WriteString(t)
|
||||
} else if (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') {
|
||||
b.WriteRune(r)
|
||||
} else if r == ' ' || r == '-' {
|
||||
b.WriteRune('-')
|
||||
}
|
||||
}
|
||||
s := slugRe.ReplaceAllString(b.String(), "-")
|
||||
return strings.Trim(s, "-")
|
||||
}
|
||||
|
||||
func (r *CategoryRepository) All(ctx context.Context) ([]models.Category, error) {
|
||||
rows, err := r.pool.Query(ctx, `
|
||||
SELECT c.id, c.name, c.slug, c.description, c.sort_order,
|
||||
COUNT(p.id) FILTER (WHERE p.is_active = true) AS cnt
|
||||
FROM categories c
|
||||
LEFT JOIN products p ON p.category_id = c.id
|
||||
GROUP BY c.id
|
||||
ORDER BY c.sort_order, c.name
|
||||
`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var list []models.Category
|
||||
for rows.Next() {
|
||||
var c models.Category
|
||||
if err := rows.Scan(&c.ID, &c.Name, &c.Slug, &c.Description, &c.SortOrder, &c.Count); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
list = append(list, c)
|
||||
}
|
||||
return list, rows.Err()
|
||||
}
|
||||
|
||||
func (r *CategoryRepository) GetBySlug(ctx context.Context, slug string) (models.Category, error) {
|
||||
var c models.Category
|
||||
err := r.pool.QueryRow(ctx, `
|
||||
SELECT id, name, slug, description, sort_order FROM categories WHERE slug = $1
|
||||
`, slug).Scan(&c.ID, &c.Name, &c.Slug, &c.Description, &c.SortOrder)
|
||||
return c, err
|
||||
}
|
||||
|
||||
func (r *CategoryRepository) GetByID(ctx context.Context, id int) (models.Category, error) {
|
||||
var c models.Category
|
||||
err := r.pool.QueryRow(ctx, `
|
||||
SELECT id, name, slug, description, sort_order FROM categories WHERE id = $1
|
||||
`, id).Scan(&c.ID, &c.Name, &c.Slug, &c.Description, &c.SortOrder)
|
||||
return c, err
|
||||
}
|
||||
|
||||
func (r *CategoryRepository) Create(ctx context.Context, name, description string) (models.Category, error) {
|
||||
slug := Slugify(name)
|
||||
var c models.Category
|
||||
err := r.pool.QueryRow(ctx, `
|
||||
INSERT INTO categories (name, slug, description)
|
||||
VALUES ($1, $2, $3)
|
||||
ON CONFLICT (slug) DO UPDATE SET name = EXCLUDED.name
|
||||
RETURNING id, name, slug, description, sort_order
|
||||
`, name, slug, description).Scan(&c.ID, &c.Name, &c.Slug, &c.Description, &c.SortOrder)
|
||||
return c, err
|
||||
}
|
||||
|
||||
func (r *CategoryRepository) Update(ctx context.Context, c *models.Category) error {
|
||||
tag, err := r.pool.Exec(ctx, `
|
||||
UPDATE categories SET name = $1, slug = $2, description = $3, sort_order = $4 WHERE id = $5
|
||||
`, c.Name, c.Slug, c.Description, c.SortOrder, c.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tag.RowsAffected() == 0 {
|
||||
return pgx.ErrNoRows
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *CategoryRepository) Delete(ctx context.Context, id int) error {
|
||||
_, err := r.pool.Exec(ctx, `UPDATE products SET category_id = NULL WHERE category_id = $1`, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tag, err := r.pool.Exec(ctx, `DELETE FROM categories WHERE id = $1`, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tag.RowsAffected() == 0 {
|
||||
return pgx.ErrNoRows
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user