FloorVisualizer/internal/repository/brand_view_repo.go

71 lines
1.8 KiB
Go
Raw Normal View History

package repository
import (
"database/sql"
)
// RecordBrandView inserts a brand view record.
func RecordBrandView(d *sql.DB, userID, brand string) error {
_, err := d.Exec(`
INSERT INTO user_brand_views (user_id, brand) VALUES ($1, $2)
`, userID, brand)
return err
}
// FrequentBrand represents a brand the user interacts with frequently.
type FrequentBrand struct {
Brand string `json:"brand"`
ViewCount int `json:"view_count"`
FavCount int `json:"fav_count"`
LogoURL string `json:"logo_url,omitempty"`
StyleCount int `json:"style_count,omitempty"`
}
// GetFrequentBrands returns brands where user has views≥3 or favorites≥2.
func GetFrequentBrands(d *sql.DB, userID string) ([]FrequentBrand, error) {
rows, err := d.Query(`
SELECT brand,
COALESCE(v.cnt, 0) AS view_count,
COALESCE(f.cnt, 0) AS fav_count
FROM (
SELECT brand, COUNT(*) AS cnt
FROM user_brand_views
WHERE user_id = $1
GROUP BY brand
HAVING COUNT(*) >= 3
) v
FULL OUTER JOIN (
SELECT brand, COUNT(*) AS cnt
FROM favorites
WHERE user_id = $1
GROUP BY brand
HAVING COUNT(*) >= 2
) f USING (brand)
ORDER BY COALESCE(v.cnt, 0) + COALESCE(f.cnt, 0) * 2 DESC
`, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var out []FrequentBrand
for rows.Next() {
var fb FrequentBrand
if err := rows.Scan(&fb.Brand, &fb.ViewCount, &fb.FavCount); err != nil {
continue
}
// Load brand logo and stats
logoMap := loadBrandLogos()
if u, ok := logoMap[fb.Brand]; ok {
fb.LogoURL = u
}
// Get style count from products
var sc int
d.QueryRow(`SELECT COUNT(DISTINCT style_name) FROM products WHERE brand = $1`, fb.Brand).Scan(&sc)
fb.StyleCount = sc
out = append(out, fb)
}
return out, rows.Err()
}