update
This commit is contained in:
142
internal/repository/street_snap_repository.go
Normal file
142
internal/repository/street_snap_repository.go
Normal file
@ -0,0 +1,142 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"fashionapi/internal/dto"
|
||||
"fashionapi/internal/model"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// StreetSnapRepository 街拍数据访问接口。
|
||||
type StreetSnapRepository interface {
|
||||
// List 按筛选条件分页查询街拍,同时返回符合条件的总数。
|
||||
List(ctx context.Context, q dto.StreetSnapQuery) ([]model.StreetSnap, int64, error)
|
||||
// FindByID 查询单条街拍;不存在时返回 ErrNotFound。
|
||||
FindByID(ctx context.Context, id string) (*model.StreetSnap, error)
|
||||
// ListImages 查询某条街拍的全部图片,按排序值升序。
|
||||
ListImages(ctx context.Context, snapID string) ([]model.StreetSnapImage, error)
|
||||
// ImagesBySnapIDs 批量查询多条街拍的图片,单次 IN 查询避免 N+1。
|
||||
ImagesBySnapIDs(ctx context.Context, ids []uint32) (map[uint32][]model.StreetSnapImage, error)
|
||||
// Popular 按图片数降序返回热度前 N 个街拍,供 SSG 首页热门街拍使用。
|
||||
Popular(ctx context.Context, limit int) ([]model.StreetSnap, error)
|
||||
}
|
||||
|
||||
type streetSnapRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
// NewStreetSnapRepository 创建街拍仓储。
|
||||
func NewStreetSnapRepository(db *gorm.DB) StreetSnapRepository {
|
||||
return &streetSnapRepository{db: db}
|
||||
}
|
||||
|
||||
// filterScope 把查询条件编译为 GORM Scope(白名单化,杜绝 SQL 注入)。
|
||||
func snapFilterScope(q dto.StreetSnapQuery) func(*gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
db = db.Where("is_deleted = 0")
|
||||
if q.Year != 0 {
|
||||
db = db.Where("year = ?", q.Year)
|
||||
}
|
||||
return db
|
||||
}
|
||||
}
|
||||
|
||||
// snapOrderBy 把 sort 参数映射为 ORDER BY(白名单,杜绝注入)。
|
||||
func snapOrderBy(sort string) string {
|
||||
switch sort {
|
||||
case "year_asc":
|
||||
return "street_snap.year ASC, street_snap.id ASC"
|
||||
case "year_desc":
|
||||
return "street_snap.year DESC, street_snap.id DESC"
|
||||
default: // image_count
|
||||
return "street_snap.image_count DESC, street_snap.id DESC"
|
||||
}
|
||||
}
|
||||
|
||||
func (r *streetSnapRepository) List(ctx context.Context, q dto.StreetSnapQuery) ([]model.StreetSnap, int64, error) {
|
||||
scope := snapFilterScope(q)
|
||||
|
||||
var total int64
|
||||
if err := r.db.WithContext(ctx).
|
||||
Model(&model.StreetSnap{}).
|
||||
Scopes(scope).
|
||||
Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
if total == 0 {
|
||||
return []model.StreetSnap{}, 0, nil
|
||||
}
|
||||
|
||||
var rows []model.StreetSnap
|
||||
if err := r.db.WithContext(ctx).
|
||||
Model(&model.StreetSnap{}).
|
||||
Scopes(scope).
|
||||
Order(snapOrderBy(q.Sort)).
|
||||
Offset(q.Offset()).
|
||||
Limit(q.Size).
|
||||
Find(&rows).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return rows, total, nil
|
||||
}
|
||||
|
||||
func (r *streetSnapRepository) FindByID(ctx context.Context, id string) (*model.StreetSnap, error) {
|
||||
var snap model.StreetSnap
|
||||
err := r.db.WithContext(ctx).
|
||||
Where("id = ? AND is_deleted = 0", id).
|
||||
First(&snap).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &snap, nil
|
||||
}
|
||||
|
||||
func (r *streetSnapRepository) ListImages(ctx context.Context, snapID string) ([]model.StreetSnapImage, error) {
|
||||
var imgs []model.StreetSnapImage
|
||||
err := r.db.WithContext(ctx).
|
||||
Where("snap_id = ? AND is_deleted = 0", snapID).
|
||||
Order("sort_order ASC, id ASC").
|
||||
Find(&imgs).Error
|
||||
return imgs, err
|
||||
}
|
||||
|
||||
func (r *streetSnapRepository) ImagesBySnapIDs(ctx context.Context, ids []uint32) (map[uint32][]model.StreetSnapImage, error) {
|
||||
result := make(map[uint32][]model.StreetSnapImage, len(ids))
|
||||
if len(ids) == 0 {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
var imgs []model.StreetSnapImage
|
||||
err := r.db.WithContext(ctx).
|
||||
Select("snap_id, image, name, sort_order").
|
||||
Where("snap_id IN ? AND is_deleted = 0", ids).
|
||||
Order("sort_order ASC, id ASC").
|
||||
Find(&imgs).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, im := range imgs {
|
||||
result[im.SnapID] = append(result[im.SnapID], im)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// IDs 返回全部未删除街拍的 id(升序),供 SSG 构建期枚举详情页路径。
|
||||
// Popular 按图片数降序返回热度前 N 个街拍(SSG 首页热门街拍用)。
|
||||
func (r *streetSnapRepository) Popular(ctx context.Context, limit int) ([]model.StreetSnap, error) {
|
||||
var rows []model.StreetSnap
|
||||
if err := r.db.WithContext(ctx).
|
||||
Where("is_deleted = 0").
|
||||
Order("image_count DESC, id DESC").
|
||||
Limit(limit).
|
||||
Find(&rows).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rows, nil
|
||||
}
|
||||
Reference in New Issue
Block a user