From 35265d8ae8aa50c4919b77d58a8219adf0995284 Mon Sep 17 00:00:00 2001 From: Jack Kingsman Date: Wed, 1 Apr 2026 21:34:35 -0700 Subject: [PATCH] Back up all available files and remove dead else clause from contact prefix promotion --- app/migrations.py | 5 +- app/repository/contacts.py | 95 ++++++++++++++++++-------------------- 2 files changed, 49 insertions(+), 51 deletions(-) diff --git a/app/migrations.py b/app/migrations.py index add8ef1..61b1b23 100644 --- a/app/migrations.py +++ b/app/migrations.py @@ -2964,7 +2964,10 @@ async def _migrate_049_foreign_key_cascade(conn: aiosqlite.Connection) -> None: db_path = db_row[2] if db_row else "" if db_path and db_path != ":memory:" and Path(db_path).exists(): backup_path = db_path + ".pre-fk-migration.bak" - shutil.copy2(db_path, backup_path) + for suffix in ("", "-wal", "-shm"): + src = Path(db_path + suffix) + if src.exists(): + shutil.copy2(str(src), backup_path + suffix) logger.info("Database backed up to %s before FK migration", backup_path) # --- Phase 1: clean orphans (guard each table's existence) --- diff --git a/app/repository/contacts.py b/app/repository/contacts.py index 7b5e00e..ae5e310 100644 --- a/app/repository/contacts.py +++ b/app/repository/contacts.py @@ -484,7 +484,6 @@ class ContactRepository: return [] promoted_keys: list[str] = [] - full_exists = await ContactRepository.get_by_key(normalized_full_key) is not None for row in rows: old_key = row["public_key"] @@ -506,55 +505,51 @@ class ContactRepository: await migrate_child_rows(old_key, normalized_full_key) - if full_exists: - await db.conn.execute( - """ - UPDATE contacts - SET last_seen = CASE - WHEN contacts.last_seen IS NULL THEN ? - WHEN ? IS NULL THEN contacts.last_seen - WHEN ? > contacts.last_seen THEN ? - ELSE contacts.last_seen - END, - last_contacted = CASE - WHEN contacts.last_contacted IS NULL THEN ? - WHEN ? IS NULL THEN contacts.last_contacted - WHEN ? > contacts.last_contacted THEN ? - ELSE contacts.last_contacted - END, - first_seen = CASE - WHEN contacts.first_seen IS NULL THEN ? - WHEN ? IS NULL THEN contacts.first_seen - WHEN ? < contacts.first_seen THEN ? - ELSE contacts.first_seen - END, - last_read_at = COALESCE(contacts.last_read_at, ?) - WHERE public_key = ? - """, - ( - row["last_seen"], - row["last_seen"], - row["last_seen"], - row["last_seen"], - row["last_contacted"], - row["last_contacted"], - row["last_contacted"], - row["last_contacted"], - row["first_seen"], - row["first_seen"], - row["first_seen"], - row["first_seen"], - row["last_read_at"], - normalized_full_key, - ), - ) - await db.conn.execute("DELETE FROM contacts WHERE public_key = ?", (old_key,)) - else: - await db.conn.execute( - "UPDATE contacts SET public_key = ? WHERE public_key = ?", - (normalized_full_key, old_key), - ) - full_exists = True + # Merge timestamp metadata from the old prefix contact into the + # full-key contact (which all callers guarantee already exists), + # then delete the prefix placeholder. + await db.conn.execute( + """ + UPDATE contacts + SET last_seen = CASE + WHEN contacts.last_seen IS NULL THEN ? + WHEN ? IS NULL THEN contacts.last_seen + WHEN ? > contacts.last_seen THEN ? + ELSE contacts.last_seen + END, + last_contacted = CASE + WHEN contacts.last_contacted IS NULL THEN ? + WHEN ? IS NULL THEN contacts.last_contacted + WHEN ? > contacts.last_contacted THEN ? + ELSE contacts.last_contacted + END, + first_seen = CASE + WHEN contacts.first_seen IS NULL THEN ? + WHEN ? IS NULL THEN contacts.first_seen + WHEN ? < contacts.first_seen THEN ? + ELSE contacts.first_seen + END, + last_read_at = COALESCE(contacts.last_read_at, ?) + WHERE public_key = ? + """, + ( + row["last_seen"], + row["last_seen"], + row["last_seen"], + row["last_seen"], + row["last_contacted"], + row["last_contacted"], + row["last_contacted"], + row["last_contacted"], + row["first_seen"], + row["first_seen"], + row["first_seen"], + row["first_seen"], + row["last_read_at"], + normalized_full_key, + ), + ) + await db.conn.execute("DELETE FROM contacts WHERE public_key = ?", (old_key,)) promoted_keys.append(old_key)