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')) } }