CREATE OR REPLACE FUNCTION acl.add_journaling(table_name text) RETURNS text
LANGUAGE plpgsql
AS $$
BEGIN
    EXECUTE format('
        CREATE OR REPLACE FUNCTION acl.journal_%1$s_update() RETURNS TRIGGER
        LANGUAGE plpgsql
        AS $body$
        BEGIN
          PERFORM acl.update_journal(''%1$s''::text, row_to_json(OLD.*), row_to_json(NEW.*));
          RETURN NEW;
        END
        $body$;

        CREATE OR REPLACE FUNCTION acl.journal_%1$s_delete() RETURNS TRIGGER
        LANGUAGE plpgsql
        AS $body$
        BEGIN
          PERFORM acl.update_journal(''%1$s''::text, row_to_json(OLD.*), NULL);
          RETURN NEW;
        END
        $body$;

        CREATE OR REPLACE FUNCTION acl.journal_%1$s_insert() RETURNS TRIGGER
        LANGUAGE plpgsql
        AS $body$
        BEGIN
          PERFORM acl.update_journal(''%1$s''::text, NULL, row_to_json(NEW.*));
          RETURN NEW;
        END
        $body$;

        DROP TRIGGER IF EXISTS acl_%1$s_update ON acl.%1$s;
        CREATE TRIGGER acl_%1$s_update
            AFTER UPDATE ON acl.%1$s
            FOR EACH ROW
            WHEN (OLD.* IS DISTINCT FROM NEW.*)
            EXECUTE PROCEDURE acl.journal_%1$s_update();

        DROP TRIGGER IF EXISTS acl_%1$s_delete ON acl.%1$s;
        CREATE TRIGGER acl_%1$s_delete
            AFTER DELETE ON acl.%1$s
            FOR EACH ROW
            EXECUTE PROCEDURE acl.journal_%1$s_delete();

        DROP TRIGGER IF EXISTS acl_%1$s_insert ON acl.%1$s;
        CREATE TRIGGER acl_%1$s_insert
            AFTER INSERT ON acl.%1$s
            FOR EACH ROW
            EXECUTE PROCEDURE acl.journal_%1$s_insert();',
        table_name);
    RETURN table_name;
END;
$$;

SELECT acl.add_journaling('ban_record');
SELECT acl.add_journaling('group');
SELECT acl.add_journaling('group_user');
SELECT acl.add_journaling('policy');
SELECT acl.add_journaling('restricted_users');
SELECT acl.add_journaling('role');
SELECT acl.add_journaling('role_permission');
SELECT acl.add_journaling('user');

UPDATE acl.journal SET data_after=NULL WHERE data_after = '{}';
UPDATE acl.journal SET data_before=NULL WHERE data_before = '{}';
