class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]

def change
  execute <<-SQL

    CREATE OR REPLACE FUNCTION jsonb_diff ( arg1 jsonb, arg2 jsonb ) RETURNS jsonb AS $$
      SELECT
        COALESCE(json_object_agg(key, value), '{}')::jsonb
      FROM
        jsonb_each(arg1)
      WHERE
        (arg1 -> key) <> (arg2 -> key)
        OR (arg2 -> key) IS NULL
    $$ LANGUAGE SQL;

    CREATE OR REPLACE FUNCTION notice_insert() RETURNS trigger AS $$
      DECLARE
        channel_name varchar DEFAULT (TG_TABLE_NAME || '<%= table_listeners %>');
      BEGIN
        PERFORM pg_notify(channel_name, json_build_object('action', TG_OP, 'model', NEW)::text);

        RETURN NEW;
      END;
    $$ LANGUAGE plpgsql;

    CREATE OR REPLACE FUNCTION notice_update() RETURNS trigger AS $$
      DECLARE
        channel_name varchar DEFAULT (TG_TABLE_NAME || '<%= table_listeners %>');
        js_new jsonb := row_to_json(NEW)::jsonb;
        js_old jsonb := row_to_json(OLD)::jsonb;
      BEGIN
        PERFORM pg_notify(channel_name, json_build_object('action', TG_OP, 'model', NEW, 'old_model', OLD, 'diff', jsonb_diff(js_new, js_old))::text);

        RETURN NEW;
      END;
    $$ LANGUAGE plpgsql;

    CREATE OR REPLACE FUNCTION notice_delete() RETURNS trigger as $$
      DECLARE
        channel_name varchar DEFAULT (TG_TABLE_NAME || '<%= table_listeners %>');
      BEGIN
        PERFORM pg_notify(channel_name, json_build_object('action', TG_OP, 'model', OLD)::text);

        RETURN OLD;
      END;
    $$ LANGUAGE plpgsql;

    <% tables.each do |table_name| %>
    CREATE TRIGGER notice_on_insert
      AFTER INSERT ON public.<%= table_name %> FOR EACH ROW
      EXECUTE PROCEDURE notice_insert();

    CREATE TRIGGER notice_on_update
      AFTER UPDATE ON public.<%= table_name %> FOR EACH ROW
      EXECUTE PROCEDURE notice_update();

    CREATE TRIGGER notice_on_delete
      AFTER DELETE ON public.<%= table_name %> FOR EACH ROW
      EXECUTE PROCEDURE notice_delete();
    <% end %>
  SQL
end

end