mirror of
https://github.com/truewhile/MeBox.git
synced 2026-09-28 03:06:38 +08:00
43 lines
1.5 KiB
Go
43 lines
1.5 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/clause"
|
|
|
|
"github.com/truewhile/MeBox/internal/model"
|
|
)
|
|
|
|
// HistoryRepository persists model.PlaybackHistory entries. The application
|
|
// upserts on (UserID, MediaID) so resume always reads the latest position.
|
|
type HistoryRepository struct{ db *gorm.DB }
|
|
|
|
// Upsert atomically inserts/updates the resume position in a single statement,
|
|
// relying on the uniq_user_history composite unique index. Concurrent progress
|
|
// reports for the same (user, media) can no longer double-insert.
|
|
func (r *HistoryRepository) Upsert(ctx context.Context, h *model.PlaybackHistory) error {
|
|
return r.db.WithContext(ctx).Clauses(clause.OnConflict{
|
|
Columns: []clause.Column{{Name: "user_id"}, {Name: "media_id"}},
|
|
DoUpdates: clause.Assignments(map[string]any{
|
|
"position_ms": h.PositionMs,
|
|
// 沿用旧语义:未知时长(0)不覆盖已记录的时长。
|
|
"duration_ms": gorm.Expr(
|
|
"CASE WHEN ? > 0 THEN ? ELSE playback_histories.duration_ms END",
|
|
h.DurationMs, h.DurationMs,
|
|
),
|
|
"watched_at": h.WatchedAt,
|
|
"completed": h.Completed,
|
|
"deleted_at": nil,
|
|
}),
|
|
}).Create(h).Error
|
|
}
|
|
|
|
// ListByUser returns the most recent history rows for the user.
|
|
func (r *HistoryRepository) ListByUser(ctx context.Context, userID string, limit int) ([]model.PlaybackHistory, error) {
|
|
var rows []model.PlaybackHistory
|
|
err := r.db.WithContext(ctx).Where("user_id = ?", userID).
|
|
Order("watched_at desc").Limit(limit).Find(&rows).Error
|
|
return rows, err
|
|
}
|