Ahoi
I'm developing an auditing mechanism where table contents are logged as JSON (github.com/fxku/audit).
At first I just logged the whole row everytime my triggers were fired.
Now I'm trying to log only the old state of values that have changed.
Therefore I compare the OLD and NEW entry by using json_each(json).
SELECT old.key, old.value
FROM json_each(row_to_json(OLD)) old
LEFT OUTER JOIN json_each(row_to_json(NEW)) new ON old.key = new.key
WHERE new.value::text <> old.value::text OR new.key IS NULL;
FROM json_each(row_to_json(OLD)) old
LEFT OUTER JOIN json_each(row_to_json(NEW)) new ON old.key = new.key
WHERE new.value::text <> old.value::text OR new.key IS NULL;
Now I aggregate the result to arrays of JSON and call this function, that I've written:
CREATE OR REPLACE FUNCTION audit.build_json(json_keys ANYARRAY, json_values ANYARRAY) RETURNS JSON AS
$$
DECLARE
json_string TEXT := '{';
delimeter TEXT := '';
json_result JSON;
BEGIN
FOR i IN array_lower(json_keys, 1)..array_upper(json_keys, 1) LOOP
json_string := json_string || delimeter || json_keys[i] || ':' || json_values[i];
delimeter := ',';
END LOOP;
$$
DECLARE
json_string TEXT := '{';
delimeter TEXT := '';
json_result JSON;
BEGIN
FOR i IN array_lower(json_keys, 1)..array_upper(json_keys, 1) LOOP
json_string := json_string || delimeter || json_keys[i] || ':' || json_values[i];
delimeter := ',';
END LOOP;
json_string := json_string || '}';
EXECUTE format('SELECT %L::json', json_string) INTO json_result;
RETURN json_result;
END
$$
LANGUAGE plpgsql;
RETURN json_result;
END
$$
LANGUAGE plpgsql;
In the end the call looks like this:
SELECT audit.build_json(array_agg(to_json(old.key)), array_agg(old.value))
FROM json_each(row_to_json(OLD)) old
LEFT OUTER JOIN json_each(row_to_json(NEW)) new ON old.key = new.key
WHERE new.value::text <> old.value::text OR new.key IS NULL;
LEFT OUTER JOIN json_each(row_to_json(NEW)) new ON old.key = new.key
WHERE new.value::text <> old.value::text OR new.key IS NULL;
Everything works as expected, but it feels kinda ugly to me.
Any PG-JSON experts around to tell me a better solution?
Did i trapped into some "YouShouldNot"s?
Regards!
Felix Kunde