Files
rmser/internal/infrastructure/repository/ocr/postgres.go
2025-12-11 05:20:53 +03:00

109 lines
3.0 KiB
Go

package ocr
import (
"strings"
"time"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"rmser/internal/domain/ocr"
"github.com/google/uuid"
"github.com/shopspring/decimal"
)
type pgRepository struct {
db *gorm.DB
}
func NewRepository(db *gorm.DB) ocr.Repository {
return &pgRepository{db: db}
}
func (r *pgRepository) SaveMatch(rawName string, productID uuid.UUID, quantity decimal.Decimal, containerID *uuid.UUID) error {
normalized := strings.ToLower(strings.TrimSpace(rawName))
match := ocr.ProductMatch{
RawName: normalized,
ProductID: productID,
Quantity: quantity,
ContainerID: containerID,
}
return r.db.Transaction(func(tx *gorm.DB) error {
if err := tx.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "raw_name"}},
DoUpdates: clause.AssignmentColumns([]string{"product_id", "quantity", "container_id", "updated_at"}),
}).Create(&match).Error; err != nil {
return err
}
if err := tx.Where("raw_name = ?", normalized).Delete(&ocr.UnmatchedItem{}).Error; err != nil {
return err
}
return nil
})
}
func (r *pgRepository) FindMatch(rawName string) (*ocr.ProductMatch, error) {
normalized := strings.ToLower(strings.TrimSpace(rawName))
var match ocr.ProductMatch
// Preload Container на случай, если нам сразу нужна инфа
err := r.db.Preload("Container").Where("raw_name = ?", normalized).First(&match).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
}
return nil, err
}
return &match, nil
}
func (r *pgRepository) GetAllMatches() ([]ocr.ProductMatch, error) {
var matches []ocr.ProductMatch
// Подгружаем Товар, Единицу и Фасовку
err := r.db.
Preload("Product").
Preload("Product.MainUnit").
Preload("Container").
Order("updated_at DESC").
Find(&matches).Error
return matches, err
}
// UpsertUnmatched увеличивает счетчик встречаемости
func (r *pgRepository) UpsertUnmatched(rawName string) error {
normalized := strings.ToLower(strings.TrimSpace(rawName))
if normalized == "" {
return nil
}
// Используем сырой SQL или GORM upsert expression
// PostgreSQL: INSERT ... ON CONFLICT DO UPDATE SET count = count + 1
item := ocr.UnmatchedItem{
RawName: normalized,
Count: 1,
LastSeen: time.Now(),
}
return r.db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "raw_name"}},
DoUpdates: clause.Assignments(map[string]interface{}{
"count": gorm.Expr("unmatched_items.count + 1"),
"last_seen": time.Now(),
}),
}).Create(&item).Error
}
func (r *pgRepository) GetTopUnmatched(limit int) ([]ocr.UnmatchedItem, error) {
var items []ocr.UnmatchedItem
err := r.db.Order("count DESC, last_seen DESC").Limit(limit).Find(&items).Error
return items, err
}
func (r *pgRepository) DeleteUnmatched(rawName string) error {
normalized := strings.ToLower(strings.TrimSpace(rawName))
return r.db.Where("raw_name = ?", normalized).Delete(&ocr.UnmatchedItem{}).Error
}