-- Setup
DROPTABLEIFEXISTSarticles_example;DROPTABLEIFEXISTSarticles_audit;CREATETABLEarticles_example(idbigintGENERATEDALWAYSASIDENTITYPRIMARYKEY,titletextNOTNULL,bodytextNOTNULL,created_attimestamptzNOTNULLDEFAULTcurrent_timestamp,updated_attimestamptzNOTNULLDEFAULTcurrent_timestamp);CREATETABLEarticles_audit(idbigintGENERATEDALWAYSASIDENTITYPRIMARYKEY,article_idbigintNOTNULL,actiontextNOTNULL,by_usertextNOTNULLDEFAULTcurrent_user,attimestamptzNOTNULLDEFAULTcurrent_timestamp,old_rowjsonb,new_rowjsonb);-- Trigger function: bump updated_at before every UPDATE
CREATEORREPLACEFUNCTIONset_updated_at()RETURNStriggerLANGUAGEplpgsqlAS$$BEGINNEW.updated_at:=current_timestamp;RETURNNEW;END;$$;CREATETRIGGERarticles_updated_atBEFOREUPDATEONarticles_exampleFOREACHROWEXECUTEFUNCTIONset_updated_at();-- Trigger function: write to the audit log after every change
CREATEORREPLACEFUNCTIONaudit_article_change()RETURNStriggerLANGUAGEplpgsqlAS$$BEGININSERTINTOarticles_audit(article_id,action,old_row,new_row)VALUES(COALESCE(NEW.id,OLD.id),TG_OP,CASEWHENTG_OPIN('UPDATE','DELETE')THENto_jsonb(OLD)END,CASEWHENTG_OPIN('INSERT','UPDATE')THENto_jsonb(NEW)END);RETURNNULL;-- AFTER trigger return value is ignored
END;$$;CREATETRIGGERarticles_auditAFTERINSERTORUPDATEORDELETEONarticles_exampleFOREACHROWEXECUTEFUNCTIONaudit_article_change();-- Exercise the triggers
INSERTINTOarticles_example(title,body)VALUES('Hello','world');UPDATEarticles_exampleSETbody='edited world'WHEREtitle='Hello';DELETEFROMarticles_example;SELECT*FROMarticles_auditORDERBYid;-- Cleanup
DROPTRIGGERIFEXISTSarticles_updated_atONarticles_example;DROPTRIGGERIFEXISTSarticles_auditONarticles_example;DROPFUNCTIONIFEXISTSset_updated_at();DROPFUNCTIONIFEXISTSaudit_article_change();DROPTABLEIFEXISTSarticles_example;DROPTABLEIFEXISTSarticles_audit;