fix(schema): fix migration ordering hazard and FK guard for table rebuild

Remove federated_id from addMissingColumns so it no longer races with
migrateDmChannelsFederatedId on installs that have canonical_pair_id.
Wrap the table rebuild in PRAGMA foreign_keys = OFF/ON with a transaction
so the DROP TABLE succeeds even when dm_members/dm_messages hold FK refs.
This commit is contained in:
Jannis Braun
2026-03-26 20:04:34 +01:00
parent d9dc33bd36
commit 3b16d9e2ce
+23 -17
View File
@@ -183,7 +183,6 @@ export function runMigrations(db: Database.Database): void {
{ {
name: 'dm_channels', name: 'dm_channels',
columns: [ columns: [
{ name: 'federated_id', type: 'TEXT' },
{ name: 'owner_home_user_id', type: 'TEXT' }, { name: 'owner_home_user_id', type: 'TEXT' },
{ name: 'owner_home_instance', type: 'TEXT' }, { name: 'owner_home_instance', type: 'TEXT' },
{ name: 'deleted_at', type: 'INTEGER' }, { name: 'deleted_at', type: 'INTEGER' },
@@ -1494,23 +1493,30 @@ function migrateDmChannelsFederatedId(db: Database.Database): void {
} }
if (hasOldCol && !hasNewCol) { if (hasOldCol && !hasNewCol) {
// Full table rebuild to rename column and add new columns in one atomic step // Full table rebuild to rename column — disable FK enforcement during DROP
console.log('Migrating: Renaming canonical_pair_id → federated_id in dm_channels and adding group DM columns...'); console.log('Migrating: Renaming canonical_pair_id → federated_id in dm_channels and adding group DM columns...');
db.exec(` db.exec(`PRAGMA foreign_keys = OFF`);
CREATE TABLE dm_channels_new ( try {
id TEXT PRIMARY KEY, db.transaction(() => {
owner_id TEXT, db.exec(`
federated_id TEXT, CREATE TABLE dm_channels_new (
owner_home_user_id TEXT, id TEXT PRIMARY KEY,
owner_home_instance TEXT, owner_id TEXT,
deleted_at INTEGER, federated_id TEXT,
created_at INTEGER NOT NULL owner_home_user_id TEXT,
); owner_home_instance TEXT,
INSERT INTO dm_channels_new (id, owner_id, federated_id, created_at) deleted_at INTEGER,
SELECT id, owner_id, canonical_pair_id, created_at FROM dm_channels; created_at INTEGER NOT NULL
DROP TABLE dm_channels; );
ALTER TABLE dm_channels_new RENAME TO dm_channels; INSERT INTO dm_channels_new (id, owner_id, federated_id, created_at)
`); SELECT id, owner_id, canonical_pair_id, created_at FROM dm_channels;
DROP TABLE dm_channels;
ALTER TABLE dm_channels_new RENAME TO dm_channels;
`);
})();
} finally {
db.exec(`PRAGMA foreign_keys = ON`);
}
db.exec(`DROP INDEX IF EXISTS idx_dm_canonical_pair`); db.exec(`DROP INDEX IF EXISTS idx_dm_canonical_pair`);
db.exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_dm_federated ON dm_channels(federated_id) WHERE federated_id IS NOT NULL`); db.exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_dm_federated ON dm_channels(federated_id) WHERE federated_id IS NOT NULL`);
console.log('Migrating: dm_channels rename complete.'); console.log('Migrating: dm_channels rename complete.');