// Package file 提供文件元数据(files 表)的数据访问。 // 所有查询均参数化,杜绝 SQL 注入;仅负责持久化,不涉及存储后端 IO。 package file import ( "context" "gorm.io/gorm" "portal-mini-go/internal/model" "portal-mini-go/internal/pkg/errors" ) // Repository 文件元数据仓储。 type Repository struct { db *gorm.DB } func New(db *gorm.DB) *Repository { return &Repository{db: db} } // Create 写入文件记录。 func (r *Repository) Create(ctx context.Context, f *model.File) error { if err := r.db.WithContext(ctx).Create(f).Error; err != nil { return errors.Wrap(50000, "create file record", err) } return nil } // GetByID 按 ID 查询文件元数据,不存在返回 ErrNotFound。 func (r *Repository) GetByID(ctx context.Context, id uint64) (*model.File, error) { var f model.File if err := r.db.WithContext(ctx).Where("id = ?", id).First(&f).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, errors.ErrNotFound } return nil, errors.Wrap(50000, "query file", err) } return &f, nil } // Delete 按 ID 删除文件元数据,不存在返回 ErrNotFound。 func (r *Repository) Delete(ctx context.Context, id uint64) error { res := r.db.WithContext(ctx).Where("id = ?", id).Delete(&model.File{}) if res.Error != nil { return errors.Wrap(50000, "delete file", res.Error) } if res.RowsAffected == 0 { return errors.ErrNotFound } return nil } // ListFilter 文件列表过滤条件。 type ListFilter struct { UploaderType string // 上传者类型(admin/ma),为空表示不限 UploaderID uint64 // 上传者主键,0 表示不限 Keyword string // 模糊匹配 origin_name 或 filename,为空表示不限 Page int // 页码,从 1 开始 Size int // 每页条数 } // List 分页查询文件,所有条件均为可选。返回列表、总数与错误。 func (r *Repository) List(ctx context.Context, f ListFilter) ([]model.File, int64, error) { q := r.db.WithContext(ctx).Model(&model.File{}) if f.UploaderType != "" { q = q.Where("uploader_type = ?", f.UploaderType) } if f.UploaderID != 0 { q = q.Where("uploader_id = ?", f.UploaderID) } if f.Keyword != "" { kw := "%" + f.Keyword + "%" q = q.Where("origin_name LIKE ? OR filename LIKE ?", kw, kw) } var total int64 if err := q.Count(&total).Error; err != nil { return nil, 0, errors.Wrap(50000, "count files", err) } var list []model.File if err := q.Order("id DESC").Offset((f.Page - 1) * f.Size).Limit(f.Size).Find(&list).Error; err != nil { return nil, 0, errors.Wrap(50000, "list files", err) } return list, total, nil }