159 lines
4.2 KiB
Go
159 lines
4.2 KiB
Go
// internal/repositories/item_repo.go
|
|
package repositories
|
|
|
|
import (
|
|
"errors"
|
|
"lost-and-found/internal/models"
|
|
"time"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type ItemRepository struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
func NewItemRepository(db *gorm.DB) *ItemRepository {
|
|
return &ItemRepository{db: db}
|
|
}
|
|
|
|
// Create creates a new item
|
|
func (r *ItemRepository) Create(item *models.Item) error {
|
|
return r.db.Create(item).Error
|
|
}
|
|
|
|
// FindByID finds item by ID
|
|
func (r *ItemRepository) FindByID(id uint) (*models.Item, error) {
|
|
var item models.Item
|
|
err := r.db.Preload("Category").Preload("Reporter").Preload("Reporter.Role").First(&item, id).Error
|
|
if err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, errors.New("item not found")
|
|
}
|
|
return nil, err
|
|
}
|
|
return &item, nil
|
|
}
|
|
|
|
// FindAll returns all items with filters
|
|
func (r *ItemRepository) FindAll(page, limit int, status, category, search string) ([]models.Item, int64, error) {
|
|
var items []models.Item
|
|
var total int64
|
|
|
|
query := r.db.Model(&models.Item{})
|
|
|
|
// Apply filters
|
|
if status != "" {
|
|
query = query.Where("status = ?", status)
|
|
}
|
|
if category != "" {
|
|
query = query.Joins("JOIN categories ON categories.id = items.category_id").Where("categories.slug = ?", category)
|
|
}
|
|
if search != "" {
|
|
query = query.Where("name ILIKE ? OR location ILIKE ?", "%"+search+"%", "%"+search+"%")
|
|
}
|
|
|
|
// Count total
|
|
if err := query.Count(&total).Error; err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
// Get paginated results
|
|
offset := (page - 1) * limit
|
|
err := query.Preload("Category").Preload("Reporter").Preload("Reporter.Role").
|
|
Order("date_found DESC").
|
|
Offset(offset).Limit(limit).Find(&items).Error
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
return items, total, nil
|
|
}
|
|
|
|
// Update updates item data
|
|
func (r *ItemRepository) Update(item *models.Item) error {
|
|
return r.db.Save(item).Error
|
|
}
|
|
|
|
// UpdateStatus updates item status
|
|
func (r *ItemRepository) UpdateStatus(id uint, status string) error {
|
|
return r.db.Model(&models.Item{}).Where("id = ?", id).Update("status", status).Error
|
|
}
|
|
|
|
// Delete soft deletes an item
|
|
func (r *ItemRepository) Delete(id uint) error {
|
|
return r.db.Delete(&models.Item{}, id).Error
|
|
}
|
|
|
|
// FindExpired finds expired items
|
|
func (r *ItemRepository) FindExpired() ([]models.Item, error) {
|
|
var items []models.Item
|
|
now := time.Now()
|
|
err := r.db.Where("expires_at <= ? AND status = ?", now, models.ItemStatusUnclaimed).
|
|
Preload("Category").Find(&items).Error
|
|
return items, err
|
|
}
|
|
|
|
// ArchiveItem moves item to archive
|
|
func (r *ItemRepository) ArchiveItem(item *models.Item, reason string, claimedBy *uint) error {
|
|
return r.db.Transaction(func(tx *gorm.DB) error {
|
|
// Create archive record
|
|
archive := models.CreateFromItem(item, reason, claimedBy)
|
|
if err := tx.Create(archive).Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
// Update item status
|
|
if err := tx.Model(item).Updates(map[string]interface{}{
|
|
"status": models.ItemStatusExpired,
|
|
}).Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
// CountByStatus counts items by status
|
|
func (r *ItemRepository) CountByStatus(status string) (int64, error) {
|
|
var count int64
|
|
err := r.db.Model(&models.Item{}).Where("status = ?", status).Count(&count).Error
|
|
return count, err
|
|
}
|
|
|
|
// FindByReporter finds items by reporter ID
|
|
func (r *ItemRepository) FindByReporter(reporterID uint, page, limit int) ([]models.Item, int64, error) {
|
|
var items []models.Item
|
|
var total int64
|
|
|
|
query := r.db.Model(&models.Item{}).Where("reporter_id = ?", reporterID)
|
|
|
|
// Count total
|
|
if err := query.Count(&total).Error; err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
// Get paginated results
|
|
offset := (page - 1) * limit
|
|
err := query.Preload("Category").Order("date_found DESC").
|
|
Offset(offset).Limit(limit).Find(&items).Error
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
return items, total, nil
|
|
}
|
|
|
|
// SearchForMatching searches items for matching with lost items
|
|
func (r *ItemRepository) SearchForMatching(categoryID uint, name, color string) ([]models.Item, error) {
|
|
var items []models.Item
|
|
|
|
query := r.db.Where("status = ? AND category_id = ?", models.ItemStatusUnclaimed, categoryID)
|
|
|
|
if name != "" {
|
|
query = query.Where("name ILIKE ?", "%"+name+"%")
|
|
}
|
|
|
|
err := query.Preload("Category").Order("date_found DESC").Limit(10).Find(&items).Error
|
|
return items, err
|
|
} |