Files
usenet-indexer/database/migrations/1768620764850_add_release_totals.ts
T

57 lines
2.3 KiB
TypeScript

import { BaseSchema } from '@adonisjs/lucid/schema'
/**
* Per-release totals for browsing and sorting (CONCEPT.md D22). A trigger on
* `files` keeps `releases.file_count` and `releases.size` current, whichever
* code path assigns files to releases.
*/
export default class extends BaseSchema {
async up() {
this.schema.alterTable('files', (table) => {
table.bigInteger('size')
})
this.schema.alterTable('releases', (table) => {
table.integer('file_count').notNullable().defaultTo(0).index()
table.bigInteger('size').notNullable().defaultTo(0).index()
})
this.defer(async (db) => {
await db.rawQuery(`
UPDATE files f SET size = s.size
FROM (SELECT id, (SELECT coalesce(sum((v->>'size')::bigint), 0) FROM jsonb_each(message_ids) e(k, v)) AS size FROM files) s
WHERE s.id = f.id`)
await db.rawQuery(`
UPDATE releases r SET file_count = t.n, size = t.size
FROM (SELECT release_id, count(*) AS n, coalesce(sum(size), 0) AS size FROM files
WHERE release_id IS NOT NULL GROUP BY release_id) t
WHERE t.release_id = r.id`)
await db.rawQuery(`
CREATE OR REPLACE FUNCTION files_release_totals() RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
IF TG_OP IN ('UPDATE', 'DELETE') AND OLD.release_id IS NOT NULL THEN
UPDATE releases SET file_count = file_count - 1, size = size - coalesce(OLD.size, 0) WHERE id = OLD.release_id;
END IF;
IF TG_OP IN ('UPDATE', 'INSERT') AND NEW.release_id IS NOT NULL THEN
UPDATE releases SET file_count = file_count + 1, size = size + coalesce(NEW.size, 0) WHERE id = NEW.release_id;
END IF;
RETURN NULL;
END $$`)
await db.rawQuery(`
CREATE TRIGGER files_release_totals
AFTER INSERT OR DELETE OR UPDATE OF release_id, size ON files
FOR EACH ROW EXECUTE FUNCTION files_release_totals()`)
})
}
async down() {
this.defer(async (db) => {
await db.rawQuery('DROP TRIGGER IF EXISTS files_release_totals ON files')
await db.rawQuery('DROP FUNCTION IF EXISTS files_release_totals()')
})
this.schema.alterTable('releases', (table) => {
table.dropColumn('size')
table.dropColumn('file_count')
})
this.schema.alterTable('files', (table) => table.dropColumn('size'))
}
}