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 }