Skip to content

Commit dcd373e

Browse files
authored
fix(llc, persistence): fix draft message persistence and retrieval issues (#2320)
1 parent 09bd4e4 commit dcd373e

15 files changed

+181
-181
lines changed

packages/stream_chat/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
🐞 Fixed
44

55
- Fixed `WebSocket` race condition where reconnection could access null user during disconnect.
6+
- Fixed draft message persistence issues where removed drafts were not properly deleted from the
7+
database.
68

79
## 9.14.0
810

packages/stream_chat/lib/src/db/chat_persistence_client.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,9 @@ abstract class ChatPersistenceClient {
240240
/// Deletes all the members by channel [cids]
241241
Future<void> deleteMembersByCids(List<String> cids);
242242

243+
/// Deletes all the draft messages by channel [cids]
244+
Future<void> deleteDraftMessagesByCids(List<String> cids);
245+
243246
/// Updates the channel [cid] threads data along with reactions and users.
244247
Future<void> updateChannelThreads(
245248
String cid,
@@ -277,7 +280,6 @@ abstract class ChatPersistenceClient {
277280
final channelWithPinnedMessages = <String, List<Message>?>{};
278281
final channelWithReads = <String, List<Read>?>{};
279282
final channelWithMembers = <String, List<Member>?>{};
280-
final drafts = <Draft>[];
281283

282284
final users = <User>[];
283285
final reactions = <Reaction>[];
@@ -287,6 +289,9 @@ abstract class ChatPersistenceClient {
287289
final pollVotes = <PollVote>[];
288290
final pollVotesToDelete = <String>[];
289291

292+
final drafts = <Draft>[];
293+
final draftsToDeleteCids = <String>[];
294+
290295
for (final state in channelStates) {
291296
final channel = state.channel;
292297
// Continue if channel is not available.
@@ -311,6 +316,7 @@ abstract class ChatPersistenceClient {
311316
membersToDelete.add(cid);
312317
reactionsToDelete.addAll(messages?.map((it) => it.id) ?? []);
313318
pinnedReactionsToDelete.addAll(pinnedMessages?.map((it) => it.id) ?? []);
319+
draftsToDeleteCids.add(cid);
314320

315321
// preparing addition data
316322
channelWithReads[cid] = reads;
@@ -356,6 +362,7 @@ abstract class ChatPersistenceClient {
356362
deleteReactionsByMessageId(reactionsToDelete),
357363
deletePinnedMessageReactionsByMessageId(pinnedReactionsToDelete),
358364
deletePollVotesByPollIds(pollVotesToDelete),
365+
deleteDraftMessagesByCids(draftsToDeleteCids),
359366
]);
360367

361368
// Updating first as does not depend on any other table.

packages/stream_chat/test/src/db/chat_persistence_client_test.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ class TestPersistenceClient extends ChatPersistenceClient {
3232
@override
3333
Future<void> deleteMembersByCids(List<String> cids) => Future.value();
3434

35+
@override
36+
Future<void> deleteDraftMessagesByCids(List<String> cids) => Future.value();
37+
3538
@override
3639
Future<void> deleteMessageByCids(List<String> cids) => Future.value();
3740

packages/stream_chat_persistence/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## Upcoming
2+
3+
🐞 Fixed
4+
5+
- Fixed draft message retrieval logic where channel drafts were incorrectly attached to all messages
6+
instead of only thread drafts being attached to their respective parent messages.
7+
18
## 9.14.0
29

310
- Updated `stream_chat` dependency to [`9.14.0`](https://pub.dev/packages/stream_chat/changelog).

packages/stream_chat_persistence/lib/src/dao/draft_message_dao.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,9 @@ class DraftMessageDao extends DatabaseAccessor<DriftChatDatabase>
102102

103103
return query.go();
104104
}
105+
106+
/// Deletes all the draft messages by matching [DraftMessages.channelCid]
107+
/// with the given list of [cids].
108+
Future<void> deleteDraftMessagesByCids(List<String> cids) =>
109+
(delete(draftMessages)..where((tbl) => tbl.channelCid.isIn(cids))).go();
105110
}

packages/stream_chat_persistence/lib/src/dao/message_dao.dart

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class MessageDao extends DatabaseAccessor<DriftChatDatabase>
3838

3939
Future<Message> _messageFromJoinRow(
4040
TypedResult rows, {
41-
bool fetchDraft = true,
41+
bool fetchDraft = false,
4242
}) async {
4343
final userEntity = rows.readTableOrNull(_users);
4444
final pinnedByEntity = rows.readTableOrNull(_pinnedByUsers);
@@ -62,7 +62,7 @@ class MessageDao extends DatabaseAccessor<DriftChatDatabase>
6262
final draft = await switch (fetchDraft) {
6363
true => _db.draftMessageDao.getDraftMessageByCid(
6464
msgEntity.channelCid,
65-
parentId: msgEntity.parentId,
65+
parentId: msgEntity.id,
6666
),
6767
_ => null,
6868
};
@@ -85,19 +85,24 @@ class MessageDao extends DatabaseAccessor<DriftChatDatabase>
8585
Future<Message?> getMessageById(
8686
String id, {
8787
bool fetchDraft = true,
88-
}) async =>
89-
await (select(messages).join(
90-
[
91-
leftOuterJoin(_users, messages.userId.equalsExp(_users.id)),
92-
leftOuterJoin(
93-
_pinnedByUsers,
94-
messages.pinnedByUserId.equalsExp(_pinnedByUsers.id),
95-
),
96-
],
97-
)..where(messages.id.equals(id)))
98-
.map((row) {
99-
return _messageFromJoinRow(row, fetchDraft: fetchDraft);
100-
}).getSingleOrNull();
88+
}) async {
89+
final query = select(messages).join([
90+
leftOuterJoin(_users, messages.userId.equalsExp(_users.id)),
91+
leftOuterJoin(
92+
_pinnedByUsers,
93+
messages.pinnedByUserId.equalsExp(_pinnedByUsers.id),
94+
),
95+
])
96+
..where(messages.id.equals(id));
97+
98+
final result = await query.getSingleOrNull();
99+
if (result == null) return null;
100+
101+
return _messageFromJoinRow(
102+
result,
103+
fetchDraft: fetchDraft,
104+
);
105+
}
101106

102107
/// Returns all the messages of a particular thread by matching
103108
/// [Messages.channelCid] with [cid]
@@ -163,22 +168,31 @@ class MessageDao extends DatabaseAccessor<DriftChatDatabase>
163168
/// [Messages.channelCid] with [parentId]
164169
Future<List<Message>> getMessagesByCid(
165170
String cid, {
171+
bool fetchDraft = true,
166172
PaginationParams? messagePagination,
167173
}) async {
168-
final msgList = await Future.wait(await (select(messages).join([
174+
final query = select(messages).join([
169175
leftOuterJoin(_users, messages.userId.equalsExp(_users.id)),
170176
leftOuterJoin(
171177
_pinnedByUsers,
172178
messages.pinnedByUserId.equalsExp(_pinnedByUsers.id),
173179
),
174180
])
175-
..where(messages.channelCid.equals(cid))
176-
..where(
177-
messages.parentId.isNull() | messages.showInChannel.equals(true),
178-
)
179-
..orderBy([OrderingTerm.asc(messages.createdAt)]))
180-
.map(_messageFromJoinRow)
181-
.get());
181+
..where(messages.channelCid.equals(cid))
182+
..where(messages.parentId.isNull() | messages.showInChannel.equals(true))
183+
..orderBy([OrderingTerm.asc(messages.createdAt)]);
184+
185+
final result = await query.get();
186+
if (result.isEmpty) return [];
187+
188+
final msgList = await Future.wait(
189+
result.map(
190+
(row) => _messageFromJoinRow(
191+
row,
192+
fetchDraft: fetchDraft,
193+
),
194+
),
195+
);
182196

183197
if (msgList.isNotEmpty) {
184198
if (messagePagination?.lessThan != null) {

packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart

Lines changed: 64 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,11 @@ class PinnedMessageDao extends DatabaseAccessor<DriftChatDatabase>
3535
Future<void> deleteMessageByCids(List<String> cids) async =>
3636
(delete(pinnedMessages)..where((tbl) => tbl.channelCid.isIn(cids))).go();
3737

38-
Future<Message> _messageFromJoinRow(TypedResult rows) async {
39-
final userEntity = rows.readTableOrNull(users);
38+
Future<Message> _messageFromJoinRow(
39+
TypedResult rows, {
40+
bool fetchDraft = false,
41+
}) async {
42+
final userEntity = rows.readTableOrNull(_users);
4043
final pinnedByEntity = rows.readTableOrNull(_pinnedByUsers);
4144
final msgEntity = rows.readTable(pinnedMessages);
4245
final latestReactions =
@@ -46,38 +49,58 @@ class PinnedMessageDao extends DatabaseAccessor<DriftChatDatabase>
4649
msgEntity.id,
4750
_db.userId,
4851
);
49-
Message? quotedMessage;
50-
final quotedMessageId = msgEntity.quotedMessageId;
51-
if (quotedMessageId != null) {
52-
quotedMessage = await getMessageById(quotedMessageId);
53-
}
54-
Poll? poll;
55-
final pollId = msgEntity.pollId;
56-
if (pollId != null) {
57-
poll = await _db.pollDao.getPollById(pollId);
58-
}
52+
53+
final quotedMessage = await switch (msgEntity.quotedMessageId) {
54+
final id? => getMessageById(id),
55+
_ => null,
56+
};
57+
58+
final poll = await switch (msgEntity.pollId) {
59+
final id? => _db.pollDao.getPollById(id),
60+
_ => null,
61+
};
62+
63+
final draft = await switch (fetchDraft) {
64+
true => _db.draftMessageDao.getDraftMessageByCid(
65+
msgEntity.channelCid,
66+
parentId: msgEntity.id,
67+
),
68+
_ => null,
69+
};
70+
5971
return msgEntity.toMessage(
6072
user: userEntity?.toUser(),
6173
pinnedBy: pinnedByEntity?.toUser(),
6274
latestReactions: latestReactions,
6375
ownReactions: ownReactions,
6476
quotedMessage: quotedMessage,
6577
poll: poll,
78+
draft: draft,
6679
);
6780
}
6881

6982
/// Returns a single message by matching the [PinnedMessages.id] with [id]
70-
Future<Message?> getMessageById(String id) async =>
71-
await (select(pinnedMessages).join([
72-
leftOuterJoin(_users, pinnedMessages.userId.equalsExp(_users.id)),
73-
leftOuterJoin(
74-
_pinnedByUsers,
75-
pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id),
76-
),
77-
])
78-
..where(pinnedMessages.id.equals(id)))
79-
.map(_messageFromJoinRow)
80-
.getSingleOrNull();
83+
Future<Message?> getMessageById(
84+
String id, {
85+
bool fetchDraft = true,
86+
}) async {
87+
final query = select(pinnedMessages).join([
88+
leftOuterJoin(_users, pinnedMessages.userId.equalsExp(_users.id)),
89+
leftOuterJoin(
90+
_pinnedByUsers,
91+
pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id),
92+
),
93+
])
94+
..where(pinnedMessages.id.equals(id));
95+
96+
final result = await query.getSingleOrNull();
97+
if (result == null) return null;
98+
99+
return _messageFromJoinRow(
100+
result,
101+
fetchDraft: fetchDraft,
102+
);
103+
}
81104

82105
/// Returns all the messages of a particular thread by matching
83106
/// [PinnedMessages.channelCid] with [cid]
@@ -142,21 +165,32 @@ class PinnedMessageDao extends DatabaseAccessor<DriftChatDatabase>
142165
/// [PinnedMessages.channelCid] with [parentId]
143166
Future<List<Message>> getMessagesByCid(
144167
String cid, {
168+
bool fetchDraft = true,
145169
PaginationParams? messagePagination,
146170
}) async {
147-
final msgList = await Future.wait(await (select(pinnedMessages).join([
171+
final query = select(pinnedMessages).join([
148172
leftOuterJoin(_users, pinnedMessages.userId.equalsExp(_users.id)),
149173
leftOuterJoin(
150174
_pinnedByUsers,
151175
pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id),
152176
),
153177
])
154-
..where(pinnedMessages.channelCid.equals(cid))
155-
..where(pinnedMessages.parentId.isNull() |
156-
pinnedMessages.showInChannel.equals(true))
157-
..orderBy([OrderingTerm.asc(pinnedMessages.createdAt)]))
158-
.map(_messageFromJoinRow)
159-
.get());
178+
..where(pinnedMessages.channelCid.equals(cid))
179+
..where(pinnedMessages.parentId.isNull() |
180+
pinnedMessages.showInChannel.equals(true))
181+
..orderBy([OrderingTerm.asc(pinnedMessages.createdAt)]);
182+
183+
final result = await query.get();
184+
if (result.isEmpty) return [];
185+
186+
final msgList = await Future.wait(
187+
result.map(
188+
(row) => _messageFromJoinRow(
189+
row,
190+
fetchDraft: fetchDraft,
191+
),
192+
),
193+
);
160194

161195
if (msgList.isNotEmpty) {
162196
if (messagePagination?.lessThan != null) {

packages/stream_chat_persistence/lib/src/db/drift_chat_database.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class DriftChatDatabase extends _$DriftChatDatabase {
5555

5656
// you should bump this number whenever you change or add a table definition.
5757
@override
58-
int get schemaVersion => 21;
58+
int get schemaVersion => 22;
5959

6060
@override
6161
MigrationStrategy get migration => MigrationStrategy(

0 commit comments

Comments
 (0)