Skip to main content

Overview

Recipe Room uses PostgreSQL triggers to maintain denormalized counters and create notifications automatically. This avoids manual counter management in application code and ensures data consistency.

Counter Triggers

Counter triggers maintain denormalized counts in sync. Most fire on INSERT and DELETE; profile counters also fire on UPDATE to handle soft deletes.

Profile Counters

TriggerTableEventsUpdates
trigger_update_follow_countsfollowsINSERT, DELETEprofiles.follower_count, profiles.following_count
trigger_update_profile_recipe_countrecipesINSERT, UPDATE, DELETEprofiles.recipe_count
trigger_update_profile_post_countpostsINSERT, UPDATE, DELETEprofiles.post_count
trigger_update_profile_collection_countcollectionsINSERT, UPDATE, DELETEprofiles.collection_count
Recipe, post, and collection count triggers fire on UPDATE as well as INSERT/DELETE because soft deletes (is_deleted = true) are implemented as UPDATEs. The trigger functions check the is_deleted flag to correctly adjust counts.

Content Counters

TriggerTableUpdates
trigger_update_recipe_favorite_countrecipe_favoritesrecipes.favorite_count
trigger_update_recipe_comment_countrecipe_commentsrecipes.comment_count
trigger_update_recipe_repost_countrecipe_repostsrecipes.repost_count
trigger_update_post_favorite_countpost_favoritesposts.favorite_count
trigger_update_post_comment_countpost_commentsposts.comment_count
trigger_update_post_repost_countpost_repostsposts.repost_count
trigger_update_collection_item_countcollection_saved_itemscollections.item_count

Timestamp Triggers

Each table has its own named trigger, all calling the same update_updated_at_column() function:
TriggerTableTimingUpdates
update_profiles_updated_atprofilesBEFORE UPDATEupdated_at
update_recipes_updated_atrecipesBEFORE UPDATEupdated_at
posts_updated_atpostsBEFORE UPDATEupdated_at
update_collections_updated_atcollectionsBEFORE UPDATEupdated_at
update_lightroom_settings_updated_atlightroom_settingsBEFORE UPDATEupdated_at

Notification Triggers

Notifications are created automatically when users are tagged, mentioned, or followed.
TriggerFires OnNotification Type
trigger_post_tag_notificationpost_tagged_users INSERTtag_post
trigger_recipe_tag_notificationrecipe_tagged_users INSERTtag_recipe
trigger_post_comment_mention_notificationpost_comment_mentions INSERTmention_post_comment
trigger_recipe_comment_mention_notificationrecipe_comment_mentions INSERTmention_recipe_comment
follows INSERT triggerfollows INSERTfollow
Collection notification types were removed from the allowed notification set. Follow notifications point at the follower’s profile.

Cleanup Triggers

TriggerFires OnAction
trigger_delete_post_tag_notificationpost_tagged_users DELETERemoves associated notification
trigger_delete_recipe_tag_notificationrecipe_tagged_users DELETERemoves associated notification
trigger_delete_saved_items_on_post_deleteposts BEFORE DELETERemoves saved items for hard-deleted post
trigger_delete_saved_items_on_post_soft_deleteposts AFTER UPDATERemoves saved items when is_deleted set to true
trigger_delete_saved_items_on_recipe_deleterecipes BEFORE DELETERemoves saved items for hard-deleted recipe
trigger_delete_saved_items_on_recipe_soft_deleterecipes AFTER UPDATERemoves saved items when is_deleted set to true
The soft-delete cleanup triggers (trigger_delete_saved_items_on_post_soft_delete and trigger_delete_saved_items_on_recipe_soft_delete) call the same function as their hard-delete counterparts (delete_saved_items_on_post_delete() and delete_saved_items_on_recipe_delete() respectively). The function handles both cases.

Auth Trigger

TriggerFires OnAction
on_auth_user_createdauth.users AFTER INSERTCalls handle_new_user() — creates a profiles row for new signups

Counter Validation

Use the validate_all_counters() function to check for drift between denormalized counters and actual counts:
SELECT * FROM validate_all_counters();
Returns rows only where counter_value != actual_value, making it easy to spot and fix inconsistencies.