Skip to content

Commit be53c06

Browse files
committed
DEV: Rewrite post-migration in pure SQL
1 parent 751483e commit be53c06

File tree

4 files changed

+83
-112
lines changed

4 files changed

+83
-112
lines changed

app/models/assignment.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,13 @@ def post
5656
target
5757
end
5858

59-
def create_missing_notifications!(mark_as_read: false)
59+
def create_missing_notifications!
6060
assigned_users.each do |user|
6161
next if user.notifications.for_assignment(self).exists?
6262
DiscourseAssign::CreateNotification.call(
6363
assignment: self,
6464
user: user,
65-
mark_as_read: mark_as_read || assigned_by_user == user,
65+
mark_as_read: assigned_by_user == user,
6666
)
6767
end
6868
end

db/post_migrate/20231011152903_ensure_notifications_consistency.rb

Lines changed: 70 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,78 @@
22

33
class EnsureNotificationsConsistency < ActiveRecord::Migration[7.0]
44
def up
5-
Notification
6-
.assigned
7-
.joins(
8-
"LEFT OUTER JOIN assignments ON assignments.id = ((notifications.data::jsonb)->'assignment_id')::int",
5+
DB.exec(<<~SQL)
6+
DELETE FROM notifications
7+
WHERE id IN (
8+
SELECT notifications.id FROM notifications
9+
LEFT OUTER JOIN assignments ON assignments.id = ((notifications.data::jsonb)->'assignment_id')::int
10+
WHERE (notification_type = 34 AND assignments.id IS NULL OR assignments.active = FALSE)
911
)
10-
.where(assignments: { id: nil })
11-
.or(Assignment.inactive)
12-
.destroy_all
12+
SQL
1313

14-
Assignment
15-
.active
16-
.left_joins(:topic)
17-
.where.not(topics: { id: nil })
18-
.find_each do |assignment|
19-
next if !assignment.target || !assignment.assigned_to
20-
assignment.create_missing_notifications!(mark_as_read: true)
21-
end
14+
DB.exec(<<~SQL)
15+
WITH tmp AS (
16+
SELECT
17+
assignments.assigned_to_id AS user_id,
18+
assignments.created_at,
19+
assignments.updated_at,
20+
assignments.topic_id,
21+
(
22+
CASE WHEN assignments.target_type = 'Topic' THEN 1
23+
ELSE (SELECT posts.post_number FROM posts WHERE posts.id = assignments.target_id)
24+
END
25+
) AS post_number,
26+
json_strip_nulls(json_build_object(
27+
'message', 'discourse_assign.assign_notification',
28+
'display_username', (SELECT users.username FROM users WHERE users.id = assignments.assigned_by_user_id),
29+
'topic_title', topics.title,
30+
'assignment_id', assignments.id
31+
))::text AS data
32+
FROM assignments
33+
LEFT OUTER JOIN topics ON topics.deleted_at IS NULL AND topics.id = assignments.topic_id
34+
LEFT OUTER JOIN users ON users.id = assignments.assigned_to_id AND assignments.assigned_to_type = 'User'
35+
LEFT OUTER JOIN notifications ON ((data::jsonb)->'assignment_id')::int = assignments.id
36+
WHERE assignments.active = TRUE
37+
AND NOT (topics.id IS NULL OR users.id IS NULL)
38+
AND assignments.assigned_to_type = 'User'
39+
AND notifications.id IS NULL
40+
)
41+
INSERT INTO notifications (notification_type, high_priority, read, user_id, created_at, updated_at, topic_id, post_number, data)
42+
SELECT 34, TRUE, TRUE, tmp.* FROM tmp
43+
SQL
44+
45+
DB.exec(<<~SQL)
46+
WITH tmp AS (
47+
SELECT
48+
users.id AS user_id,
49+
assignments.created_at,
50+
assignments.updated_at,
51+
assignments.topic_id,
52+
(
53+
CASE WHEN assignments.target_type = 'Topic' THEN 1
54+
ELSE (SELECT posts.post_number FROM posts WHERE posts.id = assignments.target_id)
55+
END
56+
) AS post_number,
57+
json_strip_nulls(json_build_object(
58+
'message', 'discourse_assign.assign_group_notification',
59+
'display_username', (SELECT groups.name FROM groups WHERE groups.id = assignments.assigned_to_id),
60+
'topic_title', topics.title,
61+
'assignment_id', assignments.id
62+
))::text AS data
63+
FROM assignments
64+
LEFT OUTER JOIN topics ON topics.deleted_at IS NULL AND topics.id = assignments.topic_id
65+
LEFT OUTER JOIN groups ON groups.id = assignments.assigned_to_id AND assignments.assigned_to_type = 'Group'
66+
LEFT OUTER JOIN group_users ON groups.id = group_users.group_id
67+
LEFT OUTER JOIN users ON users.id = group_users.user_id
68+
LEFT OUTER JOIN notifications ON ((data::jsonb)->'assignment_id')::int = assignments.id AND notifications.user_id = users.id
69+
WHERE assignments.active = TRUE
70+
AND NOT (topics.id IS NULL OR groups.id IS NULL)
71+
AND assignments.assigned_to_type = 'Group'
72+
AND notifications.id IS NULL
73+
)
74+
INSERT INTO notifications (notification_type, high_priority, read, user_id, created_at, updated_at, topic_id, post_number, data)
75+
SELECT 34, TRUE, TRUE, tmp.* FROM tmp
76+
SQL
2277
end
2378

2479
def down

spec/models/assignment_spec.rb

Lines changed: 11 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,11 @@
8383
end
8484

8585
describe "#create_missing_notifications!" do
86-
subject(:create_missing_notifications) do
87-
assignment.create_missing_notifications!(mark_as_read: mark_as_read)
88-
end
86+
subject(:create_missing_notifications) { assignment.create_missing_notifications! }
8987

9088
let(:assignment) do
9189
Fabricate(:topic_assignment, assigned_to: assigned_to, assigned_by_user: assigned_by_user)
9290
end
93-
let(:mark_as_read) { false }
9491
let(:assigned_by_user) { Fabricate(:user) }
9592

9693
context "when assigned to a user" do
@@ -113,8 +110,8 @@
113110
end
114111

115112
context "when notification does not exist yet" do
116-
context "when `mark_as_read` is true" do
117-
let(:mark_as_read) { true }
113+
context "when user is the one that assigned" do
114+
let(:assigned_by_user) { assigned_to }
118115

119116
it "creates the missing notification" do
120117
DiscourseAssign::CreateNotification.expects(:call).with(
@@ -126,29 +123,14 @@
126123
end
127124
end
128125

129-
context "when `mark_as_read` is false" do
130-
context "when user is the one that assigned" do
131-
let(:assigned_by_user) { assigned_to }
132-
133-
it "creates the missing notification" do
134-
DiscourseAssign::CreateNotification.expects(:call).with(
135-
assignment: assignment,
136-
user: assigned_to,
137-
mark_as_read: true,
138-
)
139-
create_missing_notifications
140-
end
141-
end
142-
143-
context "when user is not the one that assigned" do
144-
it "creates the missing notification" do
145-
DiscourseAssign::CreateNotification.expects(:call).with(
146-
assignment: assignment,
147-
user: assigned_to,
148-
mark_as_read: false,
149-
)
150-
create_missing_notifications
151-
end
126+
context "when user is not the one that assigned" do
127+
it "creates the missing notification" do
128+
DiscourseAssign::CreateNotification.expects(:call).with(
129+
assignment: assignment,
130+
user: assigned_to,
131+
mark_as_read: false,
132+
)
133+
create_missing_notifications
152134
end
153135
end
154136
end

spec/post_migrations/ensure_notifications_consistency_spec.rb

Lines changed: 0 additions & 66 deletions
This file was deleted.

0 commit comments

Comments
 (0)