mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-01 03:56:38 +08:00
187 lines
6.6 KiB
Go
187 lines
6.6 KiB
Go
// Package repository — 阅读子系统仓储(书源 / 书架 / 章节 / 替换规则)。
|
|
package repository
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"gorm.io/gorm"
|
|
|
|
"github.com/truewhile/MeBox/internal/model"
|
|
)
|
|
|
|
// ReaderRepository 阅读子系统 GORM 封装。
|
|
type ReaderRepository struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
// ListSources 书源列表(按 customOrder 排序)。
|
|
func (r *ReaderRepository) ListSources(ctx context.Context) ([]model.ReaderBookSource, error) {
|
|
var out []model.ReaderBookSource
|
|
err := r.db.WithContext(ctx).Order("custom_order ASC, updated_at DESC").Find(&out).Error
|
|
return out, err
|
|
}
|
|
|
|
// GetSource 按 ID 取书源。
|
|
func (r *ReaderRepository) GetSource(ctx context.Context, id string) (*model.ReaderBookSource, error) {
|
|
var out model.ReaderBookSource
|
|
if err := r.db.WithContext(ctx).First(&out, "id = ?", id).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return &out, nil
|
|
}
|
|
|
|
// GetSourceByURL 按书源 URL 取书源(导入去重用)。
|
|
func (r *ReaderRepository) GetSourceByURL(ctx context.Context, sourceURL string) (*model.ReaderBookSource, error) {
|
|
var out model.ReaderBookSource
|
|
err := r.db.WithContext(ctx).First(&out, "source_url = ?", sourceURL).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &out, nil
|
|
}
|
|
|
|
// CreateSource 新增书源。
|
|
func (r *ReaderRepository) CreateSource(ctx context.Context, src *model.ReaderBookSource) error {
|
|
return r.db.WithContext(ctx).Create(src).Error
|
|
}
|
|
|
|
// UpdateSource 更新书源字段。
|
|
func (r *ReaderRepository) UpdateSource(ctx context.Context, src *model.ReaderBookSource) error {
|
|
return r.db.WithContext(ctx).Save(src).Error
|
|
}
|
|
|
|
// DeleteSource 删除书源(连带清理其会话状态)。
|
|
func (r *ReaderRepository) DeleteSource(ctx context.Context, id string) error {
|
|
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
|
src := &model.ReaderBookSource{}
|
|
if err := tx.First(src, "id = ?", id).Error; err == nil && src.SourceURL != "" {
|
|
if err := tx.Delete(&model.ReaderSourceState{}, "source_url = ?", src.SourceURL).Error; err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return tx.Delete(&model.ReaderBookSource{}, "id = ?", id).Error
|
|
})
|
|
}
|
|
|
|
// GetSourceState 取书源会话状态;不存在返回 (nil, nil)。
|
|
func (r *ReaderRepository) GetSourceState(ctx context.Context, sourceURL string) (*model.ReaderSourceState, error) {
|
|
var out model.ReaderSourceState
|
|
err := r.db.WithContext(ctx).First(&out, "source_url = ?", sourceURL).Error
|
|
if err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
return &out, nil
|
|
}
|
|
|
|
// SaveSourceState 覆盖保存书源会话状态(不存在则新建)。
|
|
func (r *ReaderRepository) SaveSourceState(ctx context.Context, st *model.ReaderSourceState) error {
|
|
var existing model.ReaderSourceState
|
|
err := r.db.WithContext(ctx).First(&existing, "source_url = ?", st.SourceURL).Error
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return r.db.WithContext(ctx).Create(st).Error
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
st.ID = existing.ID
|
|
st.CreatedAt = existing.CreatedAt
|
|
return r.db.WithContext(ctx).Save(st).Error
|
|
}
|
|
|
|
// ListBooks 用户书架(按 order 排序)。
|
|
func (r *ReaderRepository) ListBooks(ctx context.Context, userID string) ([]model.ReaderBook, error) {
|
|
var out []model.ReaderBook
|
|
err := r.db.WithContext(ctx).Where("user_id = ?", userID).Order("`order` ASC, updated_at DESC").Find(&out).Error
|
|
return out, err
|
|
}
|
|
|
|
// GetBook 按 ID 取书。
|
|
func (r *ReaderRepository) GetBook(ctx context.Context, id string) (*model.ReaderBook, error) {
|
|
var out model.ReaderBook
|
|
if err := r.db.WithContext(ctx).First(&out, "id = ?", id).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return &out, nil
|
|
}
|
|
|
|
// FindBookByURL 按用户 + 书源 + 书 URL 查书(加书架去重)。
|
|
func (r *ReaderRepository) FindBookByURL(ctx context.Context, userID, origin, bookURL string) (*model.ReaderBook, error) {
|
|
var out model.ReaderBook
|
|
err := r.db.WithContext(ctx).First(&out, "user_id = ? AND origin = ? AND book_url = ?", userID, origin, bookURL).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &out, nil
|
|
}
|
|
|
|
// CreateBook / UpdateBook / DeleteBook。
|
|
func (r *ReaderRepository) CreateBook(ctx context.Context, b *model.ReaderBook) error {
|
|
return r.db.WithContext(ctx).Create(b).Error
|
|
}
|
|
|
|
func (r *ReaderRepository) UpdateBook(ctx context.Context, b *model.ReaderBook) error {
|
|
return r.db.WithContext(ctx).Save(b).Error
|
|
}
|
|
|
|
func (r *ReaderRepository) DeleteBook(ctx context.Context, userID, id string) error {
|
|
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
|
if err := tx.Delete(&model.ReaderBook{}, "id = ? AND user_id = ?", id, userID).Error; err != nil {
|
|
return err
|
|
}
|
|
return tx.Delete(&model.ReaderChapter{}, "book_id = ?", id).Error
|
|
})
|
|
}
|
|
|
|
// ReplaceChapters 覆盖式刷新章节列表。
|
|
func (r *ReaderRepository) ReplaceChapters(ctx context.Context, bookID string, chapters []model.ReaderChapter) error {
|
|
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
|
if err := tx.Delete(&model.ReaderChapter{}, "book_id = ?", bookID).Error; err != nil {
|
|
return err
|
|
}
|
|
if len(chapters) == 0 {
|
|
return nil
|
|
}
|
|
return tx.CreateInBatches(chapters, 500).Error
|
|
})
|
|
}
|
|
|
|
// ListChapters 按序取章节。
|
|
func (r *ReaderRepository) ListChapters(ctx context.Context, bookID string) ([]model.ReaderChapter, error) {
|
|
var out []model.ReaderChapter
|
|
err := r.db.WithContext(ctx).Where("book_id = ?", bookID).Order("`index` ASC").Find(&out).Error
|
|
return out, err
|
|
}
|
|
|
|
// GetChapter 取指定章节。
|
|
func (r *ReaderRepository) GetChapter(ctx context.Context, bookID string, index int) (*model.ReaderChapter, error) {
|
|
var out model.ReaderChapter
|
|
if err := r.db.WithContext(ctx).First(&out, "book_id = ? AND `index` = ?", bookID, index).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return &out, nil
|
|
}
|
|
|
|
// ListReplaceRules 用户替换规则(按 order 排序)。
|
|
func (r *ReaderRepository) ListReplaceRules(ctx context.Context, userID string) ([]model.ReaderReplaceRule, error) {
|
|
var out []model.ReaderReplaceRule
|
|
err := r.db.WithContext(ctx).Where("user_id = ?", userID).Order("`order` DESC, created_at ASC").Find(&out).Error
|
|
return out, err
|
|
}
|
|
|
|
// CreateReplaceRule / UpdateReplaceRule / DeleteReplaceRule。
|
|
func (r *ReaderRepository) CreateReplaceRule(ctx context.Context, rule *model.ReaderReplaceRule) error {
|
|
return r.db.WithContext(ctx).Create(rule).Error
|
|
}
|
|
|
|
func (r *ReaderRepository) UpdateReplaceRule(ctx context.Context, rule *model.ReaderReplaceRule) error {
|
|
return r.db.WithContext(ctx).Save(rule).Error
|
|
}
|
|
|
|
func (r *ReaderRepository) DeleteReplaceRule(ctx context.Context, userID, id string) error {
|
|
return r.db.WithContext(ctx).Delete(&model.ReaderReplaceRule{}, "id = ? AND user_id = ?", id, userID).Error
|
|
}
|