pub async fn upsert_feed(pool: &SqlitePool, feed: &NewFeed) -> Result<i64>Expand description
Insert a feed by URL, or update its metadata if the URL already exists. Returns the feed’s row id (existing or newly assigned).
EVERY updatable column is COALESCE’d, so None means “leave alone” for all
of them and a partial upsert cannot clobber a field it never mentioned.
etag/last_modified were the exception until now, and the exception was
silently disabling conditional GET for the entire instance. set_next_poll
in the scheduler supplies only url + next_poll after every single poll,
which wrote both validators back to NULL — so 304 Not Modified was
unreachable and every feed was re-downloaded, re-parsed, re-sanitised and
re-inserted in full, hourly, forever. feed::touch_polled had discovered the
same trap earlier and worked around it in its own caller by re-reading the
row first; that local fix is what let the next caller walk into it.
A stale validator is not a hazard: if the origin no longer issues one it
ignores our If-None-Match and returns 200, and if it still matches then
304 was the correct answer anyway.