From 1405acfaed26748ade9feeb5715c7bb1ae10b283 Mon Sep 17 00:00:00 2001 From: Mattias Tall Date: Tue, 26 May 2026 16:10:24 +0200 Subject: [PATCH] Revert channel stats to correlated subqueries (CTE had a param binding bug) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CTE approach returned 0 rows — likely a SQLite/SQLAlchemy interaction with :user_id appearing in multiple CTEs. Reverted to the original correlated-subquery form which is proven correct. The 4 indexes added in the previous commit still apply and will make the per-channel subqueries faster once the DB is indexed on startup. Co-Authored-By: Claude Sonnet 4.6 --- backend/routers/channels.py | 67 ++++++++++++++----------------------- 1 file changed, 25 insertions(+), 42 deletions(-) diff --git a/backend/routers/channels.py b/backend/routers/channels.py index 261f0bb..4364814 100644 --- a/backend/routers/channels.py +++ b/backend/routers/channels.py @@ -67,48 +67,31 @@ class VideoOut(BaseModel): _CHANNEL_STATS_SELECT = """ - WITH followed AS ( - SELECT channel_id, last_seen_at - FROM user_channels - WHERE user_id = :user_id AND status = 'followed' - ), - vinfo AS ( - SELECT - v.channel_id, - COUNT(*) AS video_count, - MIN(v.published_at) AS oldest_published, - MAX(v.published_at) AS last_published_at, - SUM(CASE WHEN COALESCE(uv.watched, 0) = 0 THEN 1 ELSE 0 END) AS unwatched_count, - SUM(CASE WHEN uv.watched = 1 THEN 1 ELSE 0 END) AS watched_count, - SUM(CASE WHEN uv.downloaded = 1 THEN 1 ELSE 0 END) AS downloaded_count - FROM videos v - JOIN followed f ON f.channel_id = v.channel_id - LEFT JOIN user_videos uv ON uv.video_id = v.id AND uv.user_id = :user_id - GROUP BY v.channel_id - ), - nc AS ( - SELECT v.channel_id, COUNT(*) AS new_count - FROM videos v - JOIN followed f ON f.channel_id = v.channel_id - WHERE f.last_seen_at IS NULL OR v.indexed_at > f.last_seen_at - GROUP BY v.channel_id - ) - SELECT - c.*, uc.status, uc.auto_download, uc.muted_until, uc.notes, - COALESCE(vi.video_count, 0) AS video_count, - vi.last_published_at, - COALESCE(vi.unwatched_count, 0) AS unwatched_count, - COALESCE(vi.watched_count, 0) AS watched_count, - COALESCE(vi.downloaded_count, 0) AS downloaded_count, - COALESCE(nc.new_count, 0) AS new_count, - CASE WHEN COALESCE(vi.video_count, 0) < 2 THEN NULL - ELSE (julianday(vi.last_published_at) - julianday(vi.oldest_published)) - / (vi.video_count - 1.0) - END AS upload_frequency_days, - (SELECT v2.youtube_video_id FROM videos v2 - WHERE v2.channel_id = c.id ORDER BY v2.published_at DESC LIMIT 1) AS latest_video_id, - (SELECT v2.title FROM videos v2 - WHERE v2.channel_id = c.id ORDER BY v2.published_at DESC LIMIT 1) AS latest_video_title + SELECT c.*, uc.status, uc.auto_download, uc.muted_until, uc.notes, + (SELECT COUNT(*) FROM videos WHERE channel_id = c.id) AS video_count, + (SELECT MAX(v.published_at) FROM videos v WHERE v.channel_id = c.id) AS last_published_at, + (SELECT COUNT(*) FROM videos v + LEFT JOIN user_videos uv ON v.id = uv.video_id AND uv.user_id = :user_id + WHERE v.channel_id = c.id AND COALESCE(uv.watched, 0) = 0) AS unwatched_count, + (SELECT COUNT(*) FROM videos v + JOIN user_videos uv ON v.id = uv.video_id AND uv.user_id = :user_id + WHERE v.channel_id = c.id AND uv.watched = 1) AS watched_count, + (SELECT COUNT(*) FROM videos v + JOIN user_videos uv ON v.id = uv.video_id AND uv.user_id = :user_id + WHERE v.channel_id = c.id AND uv.downloaded = 1) AS downloaded_count, + (SELECT COUNT(*) FROM videos v + WHERE v.channel_id = c.id + AND (uc.last_seen_at IS NULL OR v.indexed_at > uc.last_seen_at)) AS new_count, + (SELECT v.youtube_video_id FROM videos v + WHERE v.channel_id = c.id ORDER BY v.published_at DESC LIMIT 1) AS latest_video_id, + (SELECT v.title FROM videos v + WHERE v.channel_id = c.id ORDER BY v.published_at DESC LIMIT 1) AS latest_video_title, + (SELECT + CASE WHEN COUNT(*) < 2 THEN NULL + ELSE CAST((julianday(MAX(sub.published_at)) - julianday(MIN(sub.published_at))) AS REAL) / (COUNT(*) - 1) + END + FROM (SELECT published_at FROM videos WHERE channel_id = c.id AND published_at IS NOT NULL ORDER BY published_at DESC LIMIT 15) sub + ) AS upload_frequency_days FROM channels c JOIN user_channels uc ON c.id = uc.channel_id WHERE uc.user_id = :user_id AND uc.status = 'followed'