DEV: Ensure unique notification level per tag user (#28638)

TagUser.rb is used to set user notification levels for a tag, we don't have a unique index on the notification level itself. This means that there might be some weird case where a user may have multiple of the same notification level on a tag.

This PR adds a migration which de-duplicates this based on defaults, where we keep the earliest record in the event there is multiple notification level per-user-per-tag.
This commit is contained in:
Natalie Tay 2024-09-03 15:43:02 +08:00 committed by GitHub
parent 74c9b5c11c
commit cc873977ec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 45 additions and 2 deletions

View File

@ -259,6 +259,7 @@ end
#
# Indexes
#
# idx_tag_users_ix1 (user_id,tag_id,notification_level) UNIQUE
# idx_tag_users_ix2 (tag_id,user_id,notification_level) UNIQUE
# index_tag_users_on_tag_id_and_user_id_and_notification_level (tag_id,user_id,notification_level)
# index_tag_users_on_user_id_and_tag_id (user_id,tag_id) UNIQUE
# index_tag_users_on_user_id_and_tag_id_and_notification_level (user_id,tag_id,notification_level)
#

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
class EnsureUniqueTagUserNotificationLevel < ActiveRecord::Migration[7.1]
def up
execute <<-SQL
DELETE FROM tag_users
USING tag_users AS dupe
WHERE tag_users.id > dupe.id
AND tag_users.user_id = dupe.user_id
AND tag_users.tag_id = dupe.tag_id;
SQL
add_index :tag_users, %i[user_id tag_id], unique: true
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
class RemoveUniqueConstraintFromTagUsersIndexes < ActiveRecord::Migration[7.1]
disable_ddl_transaction!
def up
remove_index :tag_users, name: :idx_tag_users_ix1, algorithm: :concurrently
remove_index :tag_users, name: :idx_tag_users_ix2, algorithm: :concurrently
add_index :tag_users, %i[user_id tag_id notification_level], algorithm: :concurrently
add_index :tag_users, %i[tag_id user_id notification_level], algorithm: :concurrently
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
Fabricator(:tag_user) do
user
tag
notification_level { TagUser.notification_levels[:tracking] }
end