Count a Signal's items and unread in one pass (#348)

signal_rows ran the same correlated subquery over signal_verdicts,
entries, subscriptions and entry_state twice a Signal, once for items
and once for unread. One grouped subquery now gives both: count(*) and
a sum of the unread, joined to the person's Signals. Same results on
SQLite and Postgres (the existing counts test runs on both).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-23 15:30:30 +00:00
parent 21fa0ae476
commit c4878731c6
2 changed files with 19 additions and 16 deletions

View File

@@ -2804,23 +2804,25 @@ impl Db {
let mut a = Args::default();
let user = a.p(user_id);
let one = id.map(|i| format!("AND g.id = {}", a.p(i))).unwrap_or_default();
// The items it shows, and of those the unread: what its list counts, by the same rules.
let hits = |unread: &str| {
format!(
"(SELECT count(*) FROM signal_verdicts v
JOIN entries e ON e.feed_id = v.feed_id AND e.guid = v.guid
JOIN subscriptions s ON s.user_id = g.user_id AND s.feed_id = v.feed_id
LEFT JOIN entry_state st ON st.user_id = g.user_id AND st.feed_id = v.feed_id AND st.guid = v.guid
WHERE v.signal_id = g.id AND v.hit AND {unread} AND {} AND {})",
not_hidden(&user),
shown_in("hide_from_signals", "s")
)
};
// The items it shows, and of those the unread: what its list counts, by the same rules. One
// pass for both; they were two copies of the same subquery (#348).
let sql = format!(
"SELECT g.id, g.name, g.keywords, g.description, g.icon, {} AS items, {} AS unread
FROM signals g WHERE g.user_id = {user} {one} ORDER BY lower(g.name), g.id",
hits("true"),
hits("NOT coalesce(st.read, false)")
"SELECT g.id, g.name, g.keywords, g.description, g.icon,
coalesce(c.items, 0) AS items, coalesce(c.unread, 0) AS unread
FROM signals g
LEFT JOIN (SELECT v.signal_id, count(*) AS items,
sum(CASE WHEN NOT coalesce(st.read, false) THEN 1 ELSE 0 END) AS unread
FROM signal_verdicts v
JOIN signals vg ON vg.id = v.signal_id
JOIN entries e ON e.feed_id = v.feed_id AND e.guid = v.guid
JOIN subscriptions s ON s.user_id = vg.user_id AND s.feed_id = v.feed_id
LEFT JOIN entry_state st
ON st.user_id = vg.user_id AND st.feed_id = v.feed_id AND st.guid = v.guid
WHERE vg.user_id = {user} AND v.hit AND {} AND {}
GROUP BY v.signal_id) c ON c.signal_id = g.id
WHERE g.user_id = {user} {one} ORDER BY lower(g.name), g.id",
not_hidden(&user),
shown_in("hide_from_signals", "s")
);
self.rows(&sql, a.0)
.await?