FIX: simplify channel threads lookup for pagination ()

The previous query with subqueries was complicated to make right with pagination, this new query should be working correctly and is passing tests.
This commit is contained in:
Joffrey JAFFEUX 2023-07-13 16:44:22 +02:00 committed by GitHub
parent 110393e438
commit d7ef7b9c03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 41 additions and 100 deletions
plugins/chat
app/services/chat
assets/javascripts/discourse/services

View File

@ -72,37 +72,46 @@ module Chat
end
def fetch_threads(guardian:, channel:, **)
read_threads = []
unread_threads =
threads_query(guardian, channel)
.where(<<~SQL)
user_chat_thread_memberships_chat_threads.last_read_message_id IS NULL
OR tracked_threads_subquery.latest_message_id > user_chat_thread_memberships_chat_threads.last_read_message_id
SQL
.order("tracked_threads_subquery.latest_message_created_at DESC")
.limit(context.limit)
.offset(context.offset)
.to_a
# We do this to avoid having to query additional threads if the user
# already has a lot of unread threads.
if unread_threads.length < context.limit
final_limit = context.limit - unread_threads.length
final_offset = context.offset + unread_threads.length
read_threads =
threads_query(guardian, channel)
.where(<<~SQL)
tracked_threads_subquery.latest_message_id <= user_chat_thread_memberships_chat_threads.last_read_message_id
SQL
.order("tracked_threads_subquery.latest_message_created_at DESC")
.limit(final_limit)
.offset(final_offset)
.to_a
end
unread_threads + read_threads
::Chat::Thread
.strict_loading
.includes(
:channel,
:user_chat_thread_memberships,
original_message_user: :user_status,
last_message: [
:uploads,
:chat_webhook_event,
:chat_channel,
chat_mentions: {
user: :user_status,
},
user: :user_status,
],
original_message: [
:uploads,
:chat_webhook_event,
:chat_channel,
chat_mentions: {
user: :user_status,
},
user: :user_status,
],
)
.joins(:user_chat_thread_memberships, :last_message, :original_message)
.where("user_chat_thread_memberships.user_id = ?", guardian.user.id)
.where(
"user_chat_thread_memberships.notification_level IN (?)",
[
::Chat::UserChatThreadMembership.notification_levels[:normal],
::Chat::UserChatThreadMembership.notification_levels[:tracking],
],
)
.where("chat_threads.channel_id = ?", channel.id)
.limit(context.limit)
.offset(context.offset)
.order(
"CASE WHEN chat_threads.last_message_id > user_chat_thread_memberships.last_read_message_id THEN 0 ELSE 1 END, chat_messages.created_at DESC",
)
end
def fetch_tracking(guardian:, threads:, **)
@ -122,74 +131,6 @@ module Chat
)
end
def threads_query(guardian, channel)
::Chat::Thread
.strict_loading
.includes(
:channel,
:user_chat_thread_memberships,
original_message_user: :user_status,
last_message: [
:chat_webhook_event,
:chat_channel,
chat_mentions: {
user: :user_status,
},
user: :user_status,
],
original_message: [
:uploads,
:chat_webhook_event,
:chat_channel,
chat_mentions: {
user: :user_status,
},
user: :user_status,
],
)
.joins(
"JOIN (#{tracked_threads_subquery(guardian, channel)}) tracked_threads_subquery
ON tracked_threads_subquery.thread_id = chat_threads.id",
)
.joins(:user_chat_thread_memberships)
.joins(
"LEFT JOIN chat_messages original_messages ON chat_threads.original_message_id = original_messages.id",
)
.where("original_messages.deleted_at IS NULL")
.where(user_chat_thread_memberships_chat_threads: { user_id: guardian.user.id })
end
def tracked_threads_subquery(guardian, channel)
::Chat::Thread
.strict_loading
.joins(:chat_messages, :user_chat_thread_memberships)
.joins(
"LEFT JOIN chat_messages original_messages ON chat_threads.original_message_id = original_messages.id",
)
.joins(
"LEFT JOIN chat_messages last_message ON chat_threads.last_message_id = last_message.id",
)
.where(user_chat_thread_memberships: { user_id: guardian.user.id })
.where(
"chat_threads.channel_id = :channel_id AND chat_messages.chat_channel_id = :channel_id",
channel_id: channel.id,
)
.where(
"user_chat_thread_memberships.notification_level IN (?)",
[
::Chat::UserChatThreadMembership.notification_levels[:normal],
::Chat::UserChatThreadMembership.notification_levels[:tracking],
],
)
.where(
"original_messages.deleted_at IS NULL AND chat_messages.deleted_at IS NULL AND original_messages.id IS NOT NULL AND last_message.deleted_at IS NULL",
)
.select(
"chat_threads.id AS thread_id, last_message.created_at AS latest_message_created_at, last_message.id AS latest_message_id",
)
.to_sql
end
def build_load_more_url(contract:, **)
load_more_params = { offset: context.offset + context.limit }.to_query
context.load_more_url =

View File

@ -36,7 +36,7 @@ export default class ChatChannelPaneSubscriptionsManager extends ChatPaneBaseSub
handleThreadOriginalMessageUpdate(data) {
const message = this.messagesManager.findMessage(data.original_message_id);
if (message.thread) {
if (message?.thread) {
message.thread.preview = ChatThreadPreview.create(data.preview);
}
}