Как реализовать обнаружение изменений на postgres таблице, чтобы УВЕДОМИТЬ гнездо js бэкэнда - PullRequest
0 голосов
/ 15 апреля 2020

Я хочу отобразить в приложении внешнего интерфейса (angular) все задачи, принадлежащие проекту и когда они были закрыты на графике. Я использую postgres в качестве БД с таблицей Todo, которая имеет внешний ключ (fk_project_id) для таблицы Project.

С помощью этой средней статьи я смог настроить postgres триггер уведомлений, который прослушивает мой бэкэнд js (см. Скрипт ниже). После каждого INSERT или UPDATE мой бэкэнд будет проверять, какой проект t todo изменился, и уведомлять об этом в канале socket.io для этого указанного c проекта.

Моя проблема теперь заключается в действии , что пользователь может удалить задачу из проекта. Текущий триггер выдаст удаленную задачу без fk_project_id, и я не могу выполнить sh обновление канала проекта, из которого была удалена задача.

Единственное решение, которое я могу придумать, - это добавьте второй триггер для задач с BEFORE UPDATE, который я считаю дорогим с единственной целью получить предыдущий fk_project_id.

Есть ли другие подходы, которые я могу использовать?

import { Pool } from 'pg';

interface NotificationTriggerConfig {
    trigger: string;
    channel: string;
    table: string;
    connectionString: string;
}

const getNotificationTrigger = (config: NotificationTriggerConfig) => `
CREATE OR REPLACE FUNCTION ${config.trigger}() 
    RETURNS trigger AS
$BODY$
    BEGIN
        PERFORM pg_notify('${config.channel}', row_to_json(NEW)::text);
        RETURN NULL;
    END;
$BODY$
    LANGUAGE plpgsql VOLATILE
    COST 100;

DROP TRIGGER IF EXISTS ${config.trigger} on "public"."${config.table}";

CREATE TRIGGER ${config.trigger}
    AFTER INSERT OR UPDATE  
    ON "${config.table}"
    FOR EACH ROW
    EXECUTE PROCEDURE ${config.trigger}();
`;

export function createNotificationTrigger<T = any>(
    cb: (payload: T) => any,
    config: NotificationTriggerConfig
) {
    const { connectionString, channel } = config;
    return new Promise(async (resolve, reject) => {
        const pool = new Pool({ connectionString, max: 10 });
        await pool.query(getNotificationTrigger(config));
        pool.connect((err, client) => {
            if (err) {
                console.log(err);
                return reject(err);
            }
            client.on('notification', (msg) => {
                if (msg.channel === channel) {
                    cb(JSON.parse(msg.payload));
                }
            });
            client.query(`LISTEN ${channel}`);
        });
        resolve(pool.end);
    });
}

...