fix: atomic upsert for import runs (Issue #12)
Replace check-then-insert race condition with INSERT ON CONFLICT. - upsert_pending uses RETURNING id for atomic upsert - UNIQUE(source_id, content_hash) constraint from migration 6 - blocklist_import_workflow updated to use upsert_pending - test_import_source_success fixed for async mock patterns Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -59,9 +59,9 @@ CREATE TABLE IF NOT EXISTS blocklist_sources (
|
||||
_CREATE_IMPORT_LOG: str = """
|
||||
CREATE TABLE IF NOT EXISTS import_log (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
source_id INTEGER REFERENCES blocklist_sources(id) ON DELETE SET NULL,
|
||||
source_id INTEGER REFERENCES blocklist_sources(id) ON DELETE RESTRICT,
|
||||
source_url TEXT NOT NULL,
|
||||
timestamp TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
||||
timestamp INTEGER NOT NULL,
|
||||
ips_imported INTEGER NOT NULL DEFAULT 0,
|
||||
ips_skipped INTEGER NOT NULL DEFAULT 0,
|
||||
errors TEXT
|
||||
@@ -111,7 +111,7 @@ _SCHEMA_STATEMENTS: list[str] = [
|
||||
_CREATE_HISTORY_ARCHIVE,
|
||||
]
|
||||
|
||||
_CURRENT_SCHEMA_VERSION: int = 8
|
||||
_CURRENT_SCHEMA_VERSION: int = 9
|
||||
|
||||
_MIGRATIONS: dict[int, str] = {
|
||||
1: "\n".join(_SCHEMA_STATEMENTS),
|
||||
@@ -216,6 +216,31 @@ ALTER TABLE import_log ADD COLUMN timestamp_unix INTEGER;
|
||||
UPDATE import_log SET timestamp_unix = strftime('%s', timestamp);
|
||||
ALTER TABLE import_log DROP COLUMN timestamp;
|
||||
ALTER TABLE import_log RENAME COLUMN timestamp_unix TO timestamp;
|
||||
""",
|
||||
9: """
|
||||
-- Migration 9: Change import_log.source_id foreign key to ON DELETE RESTRICT.
|
||||
-- Previously, deleting a blocklist source set source_id to NULL, leaving orphaned
|
||||
-- log records with populated URL but NULL source_id (meaningless/useless data).
|
||||
-- Now, RESTRICT prevents source deletion if import logs exist, preserving data
|
||||
-- integrity. Admin must delete logs before deleting source.
|
||||
-- See Issue #11: Foreign Key ON DELETE Semantics Problem.
|
||||
DROP INDEX IF EXISTS idx_import_log_source_id_desc;
|
||||
DROP TABLE IF EXISTS _import_log_backup;
|
||||
CREATE TABLE _import_log_backup (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
source_id INTEGER REFERENCES blocklist_sources(id) ON DELETE RESTRICT,
|
||||
source_url TEXT NOT NULL,
|
||||
timestamp INTEGER NOT NULL,
|
||||
ips_imported INTEGER NOT NULL DEFAULT 0,
|
||||
ips_skipped INTEGER NOT NULL DEFAULT 0,
|
||||
errors TEXT
|
||||
);
|
||||
INSERT INTO _import_log_backup (id, source_id, source_url, timestamp, ips_imported, ips_skipped, errors)
|
||||
SELECT id, source_id, source_url, timestamp, ips_imported, ips_skipped, errors FROM import_log;
|
||||
DROP TABLE import_log;
|
||||
ALTER TABLE _import_log_backup RENAME TO import_log;
|
||||
CREATE INDEX IF NOT EXISTS idx_import_log_source_id_desc
|
||||
ON import_log (source_id, id DESC);
|
||||
""",
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user