fix: add FK constraint to attachments.dm_message_id via table rebuild
Rebuilds the attachments table with ON DELETE CASCADE on dm_message_id. Dangling records are excluded during copy — their files become standard disk orphans detectable by the storage janitor. Also updates the raw SQL in index.ts to include width/height/duration columns for fresh installs.
This commit is contained in:
@@ -89,19 +89,6 @@ function createTables(db: Database.Database): void {
|
||||
created_at INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS attachments (
|
||||
id TEXT PRIMARY KEY,
|
||||
message_id TEXT REFERENCES messages(id) ON DELETE CASCADE,
|
||||
dm_message_id TEXT,
|
||||
uploader_id TEXT,
|
||||
filename TEXT NOT NULL,
|
||||
original_name TEXT NOT NULL,
|
||||
mimetype TEXT NOT NULL,
|
||||
size INTEGER NOT NULL,
|
||||
thumbnail_filename TEXT,
|
||||
created_at INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS dm_channels (
|
||||
id TEXT PRIMARY KEY,
|
||||
owner_id TEXT,
|
||||
@@ -125,6 +112,22 @@ function createTables(db: Database.Database): void {
|
||||
created_at INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS attachments (
|
||||
id TEXT PRIMARY KEY,
|
||||
message_id TEXT REFERENCES messages(id) ON DELETE CASCADE,
|
||||
dm_message_id TEXT REFERENCES dm_messages(id) ON DELETE CASCADE,
|
||||
uploader_id TEXT,
|
||||
filename TEXT NOT NULL,
|
||||
original_name TEXT NOT NULL,
|
||||
mimetype TEXT NOT NULL,
|
||||
size INTEGER NOT NULL,
|
||||
thumbnail_filename TEXT,
|
||||
width INTEGER,
|
||||
height INTEGER,
|
||||
duration REAL,
|
||||
created_at INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS friends (
|
||||
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
friend_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
|
||||
@@ -372,6 +372,9 @@ export function runMigrations(db: Database.Database): void {
|
||||
// ─── Add category_overrides table ────────────────────────────────────────
|
||||
migrateCategoryOverrides(db);
|
||||
|
||||
// ─── Add FK constraint to attachments.dm_message_id ─────────────────────
|
||||
migrateAttachmentsDmMessageFk(db);
|
||||
|
||||
console.log('Migrations complete.');
|
||||
}
|
||||
|
||||
@@ -1027,6 +1030,48 @@ function migrateCategoryOverrides(db: Database.Database): void {
|
||||
`);
|
||||
}
|
||||
|
||||
/** Add FK constraint to attachments.dm_message_id (SQLite requires table recreation) */
|
||||
function migrateAttachmentsDmMessageFk(db: Database.Database): void {
|
||||
const tableInfo = db.prepare(
|
||||
"SELECT sql FROM sqlite_master WHERE type='table' AND name='attachments'"
|
||||
).get() as { sql: string } | undefined;
|
||||
|
||||
// Only migrate if dm_message_id exists but has no FK reference
|
||||
if (!tableInfo) return;
|
||||
if (!tableInfo.sql.includes('dm_message_id')) return;
|
||||
if (tableInfo.sql.includes('REFERENCES dm_messages')) return;
|
||||
|
||||
console.log('Migrating: Adding FK constraint to attachments.dm_message_id...');
|
||||
|
||||
db.exec(`
|
||||
CREATE TABLE attachments_new (
|
||||
id TEXT PRIMARY KEY,
|
||||
message_id TEXT REFERENCES messages(id) ON DELETE CASCADE,
|
||||
dm_message_id TEXT REFERENCES dm_messages(id) ON DELETE CASCADE,
|
||||
uploader_id TEXT,
|
||||
filename TEXT NOT NULL,
|
||||
original_name TEXT NOT NULL,
|
||||
mimetype TEXT NOT NULL,
|
||||
size INTEGER NOT NULL,
|
||||
thumbnail_filename TEXT,
|
||||
width INTEGER,
|
||||
height INTEGER,
|
||||
duration REAL,
|
||||
created_at INTEGER NOT NULL
|
||||
);
|
||||
INSERT INTO attachments_new
|
||||
SELECT id, message_id, dm_message_id, uploader_id, filename, original_name,
|
||||
mimetype, size, thumbnail_filename, width, height, duration, created_at
|
||||
FROM attachments
|
||||
WHERE dm_message_id IS NULL
|
||||
OR dm_message_id IN (SELECT id FROM dm_messages);
|
||||
DROP TABLE attachments;
|
||||
ALTER TABLE attachments_new RENAME TO attachments;
|
||||
CREATE INDEX IF NOT EXISTS idx_attachments_message_id ON attachments(message_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_attachments_dm_message_id ON attachments(dm_message_id);
|
||||
`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Async backfill: generate thumbnails for all existing image attachments that
|
||||
* don't have one yet. Runs once after server startup, gated by a persistent
|
||||
|
||||
Reference in New Issue
Block a user