package postgres import ( "fmt" "photography-backend/internal/models" "gorm.io/gorm" ) // PhotoRepository 照片仓库接口 type PhotoRepository interface { Create(photo *models.Photo) error GetByID(id uint) (*models.Photo, error) Update(photo *models.Photo) error Delete(id uint) error List(params *models.PhotoListParams) ([]*models.Photo, int64, error) GetByCategory(categoryID uint, page, limit int) ([]*models.Photo, int64, error) GetByTag(tagID uint, page, limit int) ([]*models.Photo, int64, error) GetByUser(userID uint, page, limit int) ([]*models.Photo, int64, error) Search(query string, page, limit int) ([]*models.Photo, int64, error) IncrementViewCount(id uint) error IncrementLikeCount(id uint) error UpdateStatus(id uint, status string) error GetStats() (*PhotoStats, error) } // PhotoStats 照片统计 type PhotoStats struct { Total int64 `json:"total"` Published int64 `json:"published"` Draft int64 `json:"draft"` Archived int64 `json:"archived"` } // photoRepository 照片仓库实现 type photoRepository struct { db *gorm.DB } // NewPhotoRepository 创建照片仓库 func NewPhotoRepository(db *gorm.DB) PhotoRepository { return &photoRepository{db: db} } // Create 创建照片 func (r *photoRepository) Create(photo *models.Photo) error { if err := r.db.Create(photo).Error; err != nil { return fmt.Errorf("failed to create photo: %w", err) } return nil } // GetByID 根据ID获取照片 func (r *photoRepository) GetByID(id uint) (*models.Photo, error) { var photo models.Photo if err := r.db.Preload("Category").Preload("Tags").Preload("User"). First(&photo, id).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, nil } return nil, fmt.Errorf("failed to get photo by id: %w", err) } return &photo, nil } // Update 更新照片 func (r *photoRepository) Update(photo *models.Photo) error { if err := r.db.Save(photo).Error; err != nil { return fmt.Errorf("failed to update photo: %w", err) } return nil } // Delete 删除照片 func (r *photoRepository) Delete(id uint) error { if err := r.db.Delete(&models.Photo{}, id).Error; err != nil { return fmt.Errorf("failed to delete photo: %w", err) } return nil } // List 获取照片列表 func (r *photoRepository) List(params *models.PhotoListParams) ([]*models.Photo, int64, error) { var photos []*models.Photo var total int64 query := r.db.Model(&models.Photo{}). Preload("Category"). Preload("Tags"). Preload("User") // 添加过滤条件 if params.CategoryID > 0 { query = query.Where("category_id = ?", params.CategoryID) } if params.TagID > 0 { query = query.Joins("JOIN photo_tags ON photos.id = photo_tags.photo_id"). Where("photo_tags.tag_id = ?", params.TagID) } if params.UserID > 0 { query = query.Where("user_id = ?", params.UserID) } if params.Status != "" { query = query.Where("status = ?", params.Status) } if params.Search != "" { query = query.Where("title ILIKE ? OR description ILIKE ?", "%"+params.Search+"%", "%"+params.Search+"%") } if params.Year > 0 { query = query.Where("EXTRACT(YEAR FROM taken_at) = ?", params.Year) } if params.Month > 0 { query = query.Where("EXTRACT(MONTH FROM taken_at) = ?", params.Month) } // 计算总数 if err := query.Count(&total).Error; err != nil { return nil, 0, fmt.Errorf("failed to count photos: %w", err) } // 排序 orderClause := fmt.Sprintf("%s %s", params.SortBy, params.SortOrder) // 分页查询 offset := (params.Page - 1) * params.Limit if err := query.Offset(offset).Limit(params.Limit). Order(orderClause). Find(&photos).Error; err != nil { return nil, 0, fmt.Errorf("failed to list photos: %w", err) } return photos, total, nil } // GetByCategory 根据分类获取照片 func (r *photoRepository) GetByCategory(categoryID uint, page, limit int) ([]*models.Photo, int64, error) { var photos []*models.Photo var total int64 query := r.db.Model(&models.Photo{}). Where("category_id = ? AND is_public = ?", categoryID, true). Preload("Category"). Preload("Tags") // 计算总数 if err := query.Count(&total).Error; err != nil { return nil, 0, fmt.Errorf("failed to count photos by category: %w", err) } // 分页查询 offset := (page - 1) * limit if err := query.Offset(offset).Limit(limit). Order("created_at DESC"). Find(&photos).Error; err != nil { return nil, 0, fmt.Errorf("failed to get photos by category: %w", err) } return photos, total, nil } // GetByTag 根据标签获取照片 func (r *photoRepository) GetByTag(tagID uint, page, limit int) ([]*models.Photo, int64, error) { var photos []*models.Photo var total int64 query := r.db.Model(&models.Photo{}). Joins("JOIN photo_tags ON photos.id = photo_tags.photo_id"). Where("photo_tags.tag_id = ? AND photos.is_public = ?", tagID, true). Preload("Category"). Preload("Tags") // 计算总数 if err := query.Count(&total).Error; err != nil { return nil, 0, fmt.Errorf("failed to count photos by tag: %w", err) } // 分页查询 offset := (page - 1) * limit if err := query.Offset(offset).Limit(limit). Order("photos.created_at DESC"). Find(&photos).Error; err != nil { return nil, 0, fmt.Errorf("failed to get photos by tag: %w", err) } return photos, total, nil } // GetByUser 根据用户获取照片 func (r *photoRepository) GetByUser(userID uint, page, limit int) ([]*models.Photo, int64, error) { var photos []*models.Photo var total int64 query := r.db.Model(&models.Photo{}). Where("user_id = ?", userID). Preload("Category"). Preload("Tags") // 计算总数 if err := query.Count(&total).Error; err != nil { return nil, 0, fmt.Errorf("failed to count photos by user: %w", err) } // 分页查询 offset := (page - 1) * limit if err := query.Offset(offset).Limit(limit). Order("created_at DESC"). Find(&photos).Error; err != nil { return nil, 0, fmt.Errorf("failed to get photos by user: %w", err) } return photos, total, nil } // Search 搜索照片 func (r *photoRepository) Search(query string, page, limit int) ([]*models.Photo, int64, error) { var photos []*models.Photo var total int64 searchQuery := r.db.Model(&models.Photo{}). Where("title ILIKE ? OR description ILIKE ? OR location ILIKE ?", "%"+query+"%", "%"+query+"%", "%"+query+"%"). Where("is_public = ?", true). Preload("Category"). Preload("Tags") // 计算总数 if err := searchQuery.Count(&total).Error; err != nil { return nil, 0, fmt.Errorf("failed to count search results: %w", err) } // 分页查询 offset := (page - 1) * limit if err := searchQuery.Offset(offset).Limit(limit). Order("created_at DESC"). Find(&photos).Error; err != nil { return nil, 0, fmt.Errorf("failed to search photos: %w", err) } return photos, total, nil } // IncrementViewCount 增加浏览次数 func (r *photoRepository) IncrementViewCount(id uint) error { if err := r.db.Model(&models.Photo{}).Where("id = ?", id). Update("view_count", gorm.Expr("view_count + 1")).Error; err != nil { return fmt.Errorf("failed to increment view count: %w", err) } return nil } // IncrementLikeCount 增加点赞次数 func (r *photoRepository) IncrementLikeCount(id uint) error { if err := r.db.Model(&models.Photo{}).Where("id = ?", id). Update("like_count", gorm.Expr("like_count + 1")).Error; err != nil { return fmt.Errorf("failed to increment like count: %w", err) } return nil } // UpdateStatus 更新状态 func (r *photoRepository) UpdateStatus(id uint, status string) error { if err := r.db.Model(&models.Photo{}).Where("id = ?", id). Update("status", status).Error; err != nil { return fmt.Errorf("failed to update status: %w", err) } return nil } // GetStats 获取照片统计 func (r *photoRepository) GetStats() (*PhotoStats, error) { var stats PhotoStats // 总数 if err := r.db.Model(&models.Photo{}).Count(&stats.Total).Error; err != nil { return nil, fmt.Errorf("failed to count total photos: %w", err) } // 已发布 if err := r.db.Model(&models.Photo{}).Where("status = ?", models.StatusPublished). Count(&stats.Published).Error; err != nil { return nil, fmt.Errorf("failed to count published photos: %w", err) } // 草稿 if err := r.db.Model(&models.Photo{}).Where("status = ?", models.StatusDraft). Count(&stats.Draft).Error; err != nil { return nil, fmt.Errorf("failed to count draft photos: %w", err) } // 已归档 if err := r.db.Model(&models.Photo{}).Where("status = ?", models.StatusArchived). Count(&stats.Archived).Error; err != nil { return nil, fmt.Errorf("failed to count archived photos: %w", err) } return &stats, nil }