57 lines
2.3 KiB
TypeScript
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'))
|
|
}
|
|
}
|