Skip to content

Commit

Permalink
Merge pull request #1361 from alphagov/more-selective-router-notifica…
Browse files Browse the repository at this point in the history
…tiosn

Notify Router only on specific column updates
  • Loading branch information
theseanything authored Dec 10, 2024
2 parents ef5074d + d00c048 commit c453cfa
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
class UpdateNotifyTriggerForRouteChanges < ActiveRecord::Migration[7.2]
def up
execute <<-SQL
CREATE OR REPLACE FUNCTION notify_route_change() RETURNS trigger AS $$
BEGIN
-- Trigger on INSERT or DELETE
IF (TG_OP = 'INSERT' OR TG_OP = 'DELETE') THEN
PERFORM pg_notify('route_changes', '');
RETURN COALESCE(NEW, OLD);
END IF;
-- Trigger on UPDATE for specific columns
IF (TG_OP = 'UPDATE') THEN
IF TG_TABLE_NAME = 'content_items' THEN
-- Specific column checks for the content_items table
IF (NEW.routes IS DISTINCT FROM OLD.routes OR
NEW.redirects IS DISTINCT FROM OLD.redirects OR
NEW.schema_name IS DISTINCT FROM OLD.schema_name OR
NEW.rendering_app IS DISTINCT FROM OLD.rendering_app) THEN
PERFORM pg_notify('route_changes', '');
END IF;
ELSIF TG_TABLE_NAME = 'publish_intents' THEN
-- Specific column checks for publish_intents table
IF (NEW.routes IS DISTINCT FROM OLD.routes OR
NEW.rendering_app IS DISTINCT FROM OLD.rendering_app) THEN
PERFORM pg_notify('route_changes', '');
END IF;
END IF;
END IF;
RETURN COALESCE(NEW, OLD);
END;
$$ LANGUAGE plpgsql;
SQL
end

def down
execute <<-SQL
CREATE OR REPLACE FUNCTION notify_route_change() RETURNS trigger AS $$
BEGIN
PERFORM pg_notify('route_changes', '');
RETURN OLD;
END;
$$ LANGUAGE plpgsql;
SQL
end
end
29 changes: 27 additions & 2 deletions db/structure.sql
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,32 @@ CREATE FUNCTION public.notify_route_change() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
PERFORM pg_notify('route_changes', '');
RETURN OLD;
-- Trigger on INSERT or DELETE
IF (TG_OP = 'INSERT' OR TG_OP = 'DELETE') THEN
PERFORM pg_notify('route_changes', '');
RETURN COALESCE(NEW, OLD);
END IF;

-- Trigger on UPDATE for specific columns
IF (TG_OP = 'UPDATE') THEN
IF TG_TABLE_NAME = 'content_items' THEN
-- Specific column checks for the content_items table
IF (NEW.routes IS DISTINCT FROM OLD.routes OR
NEW.redirects IS DISTINCT FROM OLD.redirects OR
NEW.schema_name IS DISTINCT FROM OLD.schema_name OR
NEW.rendering_app IS DISTINCT FROM OLD.rendering_app) THEN
PERFORM pg_notify('route_changes', '');
END IF;
ELSIF TG_TABLE_NAME = 'publish_intents' THEN
-- Specific column checks for publish_intents table
IF (NEW.routes IS DISTINCT FROM OLD.routes OR
NEW.rendering_app IS DISTINCT FROM OLD.rendering_app) THEN
PERFORM pg_notify('route_changes', '');
END IF;
END IF;
END IF;

RETURN COALESCE(NEW, OLD);
END;
$$;

Expand Down Expand Up @@ -437,6 +461,7 @@ CREATE TRIGGER publish_intent_change_trigger AFTER INSERT OR DELETE OR UPDATE ON
SET search_path TO "$user", public;

INSERT INTO "schema_migrations" (version) VALUES
('20241209132444'),
('20241105135438'),
('20240312132747'),
('20240220151333'),
Expand Down
46 changes: 43 additions & 3 deletions spec/integration/notify_route_change_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,55 @@ def postgres_listener(channel)
expect(listener.pop).to eq("route_changes")
end

it "sends a notification when content item updated" do
it "sends a notification when content item's routes are updated" do
content_item = create(:content_item)

listener = postgres_listener("route_changes")
content_item.update!(base_path: "/foo")
content_item.update!(
routes: [{ "path" => content_item.base_path, "type" => "prefix" }],
)

expect(listener.pop).to eq("route_changes")
end

it "sends a notification when content item's redirects are updated" do
content_item = create(:content_item)

listener = postgres_listener("route_changes")
content_item.update!(
redirects: [{ "path" => content_item.base_path, "type" => "exact", "destination" => "/new" }],
)

expect(listener.pop).to eq("route_changes")
end

it "sends a notification when content item's schema name is updated" do
content_item = create(:content_item)

listener = postgres_listener("route_changes")
content_item.update!(schema_name: "gone")

expect(listener.pop).to eq("route_changes")
end

it "sends a notification when content item's rendering_app is updated" do
content_item = create(:content_item)

listener = postgres_listener("route_changes")
content_item.update!(rendering_app: "new-frontend")

expect(listener.pop).to eq("route_changes")
end

it "does not send a notification when content item's details are updated" do
content_item = create(:content_item)

listener = postgres_listener("route_changes")
content_item.update!(details: { "body" => "change" })

expect(listener).to be_empty
end

it "sends a notification when content item destroyed" do
content_item = create(:content_item)
listener = postgres_listener("route_changes")
Expand All @@ -62,7 +102,7 @@ def postgres_listener(channel)
it "sends a notification when publish intent updated" do
publish_intent = create(:publish_intent)
listener = postgres_listener("route_changes")
publish_intent.update!(publish_time: 10.minutes.from_now)
publish_intent.update!(rendering_app: "updated")

expect(listener.pop).to eq("route_changes")
end
Expand Down

0 comments on commit c453cfa

Please sign in to comment.