This commit is contained in:
John Doty 2024-07-22 15:58:30 -07:00
parent abd70e2ad3
commit 5a834d5d26
2 changed files with 203 additions and 33 deletions

View file

@ -45,6 +45,60 @@ SCHEMA_STATEMENTS = [
ELSE status
END
""",
# The "clock" is a number that increments as we make changes. We use this
# to do reconciliation, and track which versions of other databases we
# have reconciled already.
"""
INSERT INTO properties (name, value) VALUES ('clock', 1);
CREATE TRIGGER update_clock_on_feed_insert
AFTER INSERT ON feeds
BEGIN
UPDATE properties SET value=value + 1 WHERE name='clock';
END;
CREATE TRIGGER update_clock_on_feed_delete
AFTER DELETE ON feeds
BEGIN
UPDATE properties SET value=value + 1 WHERE name='clock';
END;
CREATE TRIGGER update_clock_on_feed_update
AFTER UPDATE ON feeds
WHEN (NEW.last_fetched_ts IS NOT OLD.last_fetched_ts)
OR (NEW.retry_after_ts IS NOT OLD.retry_after_ts)
OR (NEW.status IS NOT OLD.status)
OR (NEW.etag IS NOT OLD.etag)
OR (NEW.modified IS NOT OLD.modified)
OR (NEW.title IS NOT OLD.title)
OR (NEW.link IS NOT OLD.link)
BEGIN
UPDATE properties SET value=value + 1 WHERE name='clock';
END;
CREATE TRIGGER update_clock_on_entries_insert
AFTER INSERT ON entries
BEGIN
UPDATE properties SET value=value + 1 WHERE name='clock';
END;
CREATE TRIGGER update_clock_on_entries_delete
AFTER DELETE ON entries
BEGIN
UPDATE properties SET value=value + 1 WHERE name='clock';
END;
CREATE TRIGGER update_clock_on_entries_update
AFTER UPDATE ON entries
WHEN (NEW.id IS NOT OLD.id)
OR (NEW.inserted_at IS NOT OLD.inserted_at)
OR (NEW.feed_url IS NOT OLD.feed_url)
OR (NEW.title IS NOT OLD.title)
OR (NEW.link IS NOT OLD.link)
BEGIN
UPDATE properties SET value=value + 1 WHERE name='clock';
END;
""",
]
@ -121,6 +175,9 @@ class Database:
with self.db:
return self._set_property(prop, value)
def get_clock(self) -> int:
return int(self.get_property("clock", 0))
def ensure_database_schema(self):
with self.db:
self.db.execute(
@ -133,11 +190,10 @@ class Database:
)
version = int(self._get_property("version", 0))
for script in SCHEMA_STATEMENTS[version:]:
for statement in script.split(";"):
try:
self.db.execute(statement)
except Exception as e:
raise Exception(f"Error executing:\n{statement}") from e
try:
self.db.executescript(script)
except Exception as e:
raise Exception(f"Error executing:\n{script}") from e
self._set_property("version", len(SCHEMA_STATEMENTS))
self._set_property("origin", self.origin)
@ -248,33 +304,7 @@ class Database:
def load_meta(self, url: str) -> feed.FeedMeta | None:
with self.db:
cursor = self.db.execute(
"""
SELECT
last_fetched_ts,
retry_after_ts,
status,
etag,
modified
FROM feeds
WHERE url=?
""",
[url],
)
row = cursor.fetchone()
if row is None:
return None
last_fetched_ts, retry_after_ts, status, etag, modified = row
return feed.FeedMeta(
url=url,
last_fetched_ts=last_fetched_ts,
retry_after_ts=retry_after_ts,
status=status,
etag=etag,
modified=modified,
)
return self._load_meta(url)
def update_meta(self, f: feed.FeedMeta):
with self.db:
@ -475,3 +505,32 @@ class Database:
[status, new_ts, meta.url],
)
return cursor.rowcount
def _load_meta(self, url: str) -> feed.FeedMeta | None:
cursor = self.db.execute(
"""
SELECT
last_fetched_ts,
retry_after_ts,
status,
etag,
modified
FROM feeds
WHERE url=?
""",
[url],
)
row = cursor.fetchone()
if row is None:
return None
last_fetched_ts, retry_after_ts, status, etag, modified = row
return feed.FeedMeta(
url=url,
last_fetched_ts=last_fetched_ts,
retry_after_ts=retry_after_ts,
status=status,
etag=etag,
modified=modified,
)