package store import "context" func (s *Store) UpsertProgress(ctx context.Context, userID, libID int64, bookPath string, locator []byte, percent float64) error { _, err := s.p.Exec(ctx, `INSERT INTO reading_progress (user_id, library_id, book_path, locator, percent, updated_at) VALUES ($1,$2,$3,$4,$5,now()) ON CONFLICT (user_id, library_id, book_path) DO UPDATE SET locator=$4, percent=$5, updated_at=now()`, userID, libID, bookPath, locator, percent) return err } func (s *Store) GetProgress(ctx context.Context, userID, libID int64, bookPath string) (Progress, error) { var pr Progress err := s.p.QueryRow(ctx, `SELECT library_id, book_path, locator, percent, updated_at FROM reading_progress WHERE user_id=$1 AND library_id=$2 AND book_path=$3`, userID, libID, bookPath). Scan(&pr.LibraryID, &pr.BookPath, &pr.Locator, &pr.Percent, &pr.UpdatedAt) return pr, err } func (s *Store) ListProgress(ctx context.Context, userID int64) ([]Progress, error) { rows, err := s.p.Query(ctx, `SELECT p.library_id, l.name, p.book_path, COALESCE(b.title, ''), p.locator, p.percent, p.updated_at FROM reading_progress p JOIN libraries l ON l.id = p.library_id LEFT JOIN books b ON b.library_id = p.library_id AND b.path = p.book_path WHERE p.user_id = $1 ORDER BY p.updated_at DESC`, userID) if err != nil { return nil, err } defer rows.Close() var out []Progress for rows.Next() { var pr Progress if err := rows.Scan(&pr.LibraryID, &pr.LibraryName, &pr.BookPath, &pr.Title, &pr.Locator, &pr.Percent, &pr.UpdatedAt); err != nil { return nil, err } out = append(out, pr) } return out, rows.Err() }