exports.up = async function(knex) { await knex.schema.alterTable('notifications', (table) => { table.datetime('seen_at'); }); await knex.schema.alterTable('alerts', (table) => { table.boolean('is_expired') .notNullable() .defaultTo(false); }); await knex.schema.createMaterializedView('alerts_users_scenes', (view) => { view.columns('user_id', 'scene_id', 'alert_ids'); view.as( knex('alerts_scenes') .select( 'alerts.user_id', 'alerts_scenes.scene_id', knex.raw('array_agg(distinct alerts.id) as alert_ids'), knex.raw('(alerts_tags.id is null and alerts_entities.id is null and alerts_matches.id is null and related_scenes.id is null) as is_only'), ) .leftJoin('alerts', 'alerts.id', 'alerts_scenes.alert_id') .leftJoin('alerts_entities', 'alerts_entities.alert_id', 'alerts_scenes.alert_id') .leftJoin('alerts_tags', 'alerts_tags.alert_id', 'alerts_scenes.alert_id') .leftJoin('alerts_matches', 'alerts_matches.alert_id', 'alerts_scenes.alert_id') .leftJoin('alerts_scenes as related_scenes', (joinBuilder) => { joinBuilder .on('related_scenes.alert_id', 'alerts_scenes.alert_id') .on('related_scenes.scene_id', '!=', 'alerts_scenes.scene_id'); }) .where('alerts.is_expired', false) .groupBy(['user_id', 'alerts_scenes.scene_id', 'is_only']), ); }); }; exports.down = async function(knex) { await knex.schema.dropMaterializedView('alerts_users_scenes'); await knex.schema.alterTable('alerts', (table) => { table.dropColumn('is_expired'); }); await knex.schema.alterTable('notifications', (table) => { table.dropColumn('seen_at'); }); };