From 37349900fd018a164af0be6d2f27efbca4b15bba Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 22 Jul 2025 17:54:28 +0200 Subject: [PATCH 01/10] fix: delete removed drafts from database in updateChannelStates - Modified updateChannelStates to delete all drafts for a channel before updating - Added deleteDraftMessagesByCids method to DAO and persistence client - Updated test client with mock implementation - Ensures drafts that are no longer present in channel state are properly removed - Follows same pattern used for reactions, members, and poll votes --- .../stream_chat/lib/src/db/chat_persistence_client.dart | 9 ++++++++- .../test/src/db/chat_persistence_client_test.dart | 3 +++ .../lib/src/dao/draft_message_dao.dart | 5 +++++ .../lib/src/stream_chat_persistence_client.dart | 7 +++++++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/stream_chat/lib/src/db/chat_persistence_client.dart b/packages/stream_chat/lib/src/db/chat_persistence_client.dart index ade11ffab..2353a847f 100644 --- a/packages/stream_chat/lib/src/db/chat_persistence_client.dart +++ b/packages/stream_chat/lib/src/db/chat_persistence_client.dart @@ -240,6 +240,9 @@ abstract class ChatPersistenceClient { /// Deletes all the members by channel [cids] Future deleteMembersByCids(List cids); + /// Deletes all the draft messages by channel [cids] + Future deleteDraftMessagesByCids(List cids); + /// Updates the channel [cid] threads data along with reactions and users. Future updateChannelThreads( String cid, @@ -277,7 +280,6 @@ abstract class ChatPersistenceClient { final channelWithPinnedMessages = ?>{}; final channelWithReads = ?>{}; final channelWithMembers = ?>{}; - final drafts = []; final users = []; final reactions = []; @@ -287,6 +289,9 @@ abstract class ChatPersistenceClient { final pollVotes = []; final pollVotesToDelete = []; + final drafts = []; + final draftsToDelete = []; + for (final state in channelStates) { final channel = state.channel; // Continue if channel is not available. @@ -311,6 +316,7 @@ abstract class ChatPersistenceClient { membersToDelete.add(cid); reactionsToDelete.addAll(messages?.map((it) => it.id) ?? []); pinnedReactionsToDelete.addAll(pinnedMessages?.map((it) => it.id) ?? []); + draftsToDelete.add(cid); // preparing addition data channelWithReads[cid] = reads; @@ -356,6 +362,7 @@ abstract class ChatPersistenceClient { deleteReactionsByMessageId(reactionsToDelete), deletePinnedMessageReactionsByMessageId(pinnedReactionsToDelete), deletePollVotesByPollIds(pollVotesToDelete), + deleteDraftMessagesByCids(draftsToDelete), ]); // Updating first as does not depend on any other table. diff --git a/packages/stream_chat/test/src/db/chat_persistence_client_test.dart b/packages/stream_chat/test/src/db/chat_persistence_client_test.dart index 00adbe668..a3036a2fd 100644 --- a/packages/stream_chat/test/src/db/chat_persistence_client_test.dart +++ b/packages/stream_chat/test/src/db/chat_persistence_client_test.dart @@ -32,6 +32,9 @@ class TestPersistenceClient extends ChatPersistenceClient { @override Future deleteMembersByCids(List cids) => Future.value(); + @override + Future deleteDraftMessagesByCids(List cids) => Future.value(); + @override Future deleteMessageByCids(List cids) => Future.value(); diff --git a/packages/stream_chat_persistence/lib/src/dao/draft_message_dao.dart b/packages/stream_chat_persistence/lib/src/dao/draft_message_dao.dart index 1c69c3165..4caa740db 100644 --- a/packages/stream_chat_persistence/lib/src/dao/draft_message_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/draft_message_dao.dart @@ -102,4 +102,9 @@ class DraftMessageDao extends DatabaseAccessor return query.go(); } + + /// Deletes all the poll votes whose [DraftMessages.channelCid] is + /// present in [cids] + Future deleteDraftMessagesByCids(List cids) => + (delete(draftMessages)..where((tbl) => tbl.channelCid.isIn(cids))).go(); } diff --git a/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart index c76991948..f136a9fe5 100644 --- a/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart +++ b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart @@ -424,6 +424,13 @@ class StreamChatPersistenceClient extends ChatPersistenceClient { return db!.memberDao.deleteMemberByCids(cids); } + @override + Future deleteDraftMessagesByCids(List cids) { + assert(_debugIsConnected, ''); + _logger.info('deleteDraftMessagesByCids'); + return db!.draftMessageDao.deleteDraftMessagesByCids(cids); + } + @override Future deleteDraftMessageByCid( String cid, { From 531a90284088bc93be2f8f86253953e912f896d4 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 22 Jul 2025 17:54:42 +0200 Subject: [PATCH 02/10] refactor: improve draft retrieval logic and remove deprecated draft fields - Fixed draft fetching to only retrieve thread drafts for messages with parentId - Changed default fetchDraft to false to avoid unnecessary queries - Enabled draft fetching for getMessagesByCid to attach thread drafts to parent messages - Removed deprecated draftMessageId column from Messages entity and related mappers - Updated generated database files and DAO methods accordingly - Prevents channel drafts from being incorrectly attached to all messages --- .../lib/src/dao/message_dao.dart | 64 +++++---- .../lib/src/dao/pinned_message_dao.dart | 94 +++++++++----- .../lib/src/db/drift_chat_database.g.dart | 122 ------------------ .../lib/src/entity/messages.dart | 3 - .../lib/src/mapper/message_mapper.dart | 1 - .../lib/src/mapper/pinned_message_mapper.dart | 2 + 6 files changed, 105 insertions(+), 181 deletions(-) diff --git a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart index 3d11267a6..570bbe6c9 100644 --- a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart @@ -38,7 +38,7 @@ class MessageDao extends DatabaseAccessor Future _messageFromJoinRow( TypedResult rows, { - bool fetchDraft = true, + bool fetchDraft = false, }) async { final userEntity = rows.readTableOrNull(_users); final pinnedByEntity = rows.readTableOrNull(_pinnedByUsers); @@ -59,10 +59,10 @@ class MessageDao extends DatabaseAccessor _ => null, }; - final draft = await switch (fetchDraft) { - true => _db.draftMessageDao.getDraftMessageByCid( + final draft = await switch ((fetchDraft, msgEntity.parentId)) { + (true, final parentId?) => _db.draftMessageDao.getDraftMessageByCid( msgEntity.channelCid, - parentId: msgEntity.parentId, + parentId: parentId, ), _ => null, }; @@ -85,19 +85,24 @@ class MessageDao extends DatabaseAccessor Future getMessageById( String id, { bool fetchDraft = true, - }) async => - await (select(messages).join( - [ - leftOuterJoin(_users, messages.userId.equalsExp(_users.id)), - leftOuterJoin( - _pinnedByUsers, - messages.pinnedByUserId.equalsExp(_pinnedByUsers.id), - ), - ], - )..where(messages.id.equals(id))) - .map((row) { - return _messageFromJoinRow(row, fetchDraft: fetchDraft); - }).getSingleOrNull(); + }) async { + final query = select(messages).join([ + leftOuterJoin(_users, messages.userId.equalsExp(_users.id)), + leftOuterJoin( + _pinnedByUsers, + messages.pinnedByUserId.equalsExp(_pinnedByUsers.id), + ), + ]) + ..where(messages.id.equals(id)); + + final result = await query.getSingleOrNull(); + if (result == null) return null; + + return _messageFromJoinRow( + result, + fetchDraft: fetchDraft, + ); + } /// Returns all the messages of a particular thread by matching /// [Messages.channelCid] with [cid] @@ -163,22 +168,31 @@ class MessageDao extends DatabaseAccessor /// [Messages.channelCid] with [parentId] Future> getMessagesByCid( String cid, { + bool fetchDraft = true, PaginationParams? messagePagination, }) async { - final msgList = await Future.wait(await (select(messages).join([ + final query = select(messages).join([ leftOuterJoin(_users, messages.userId.equalsExp(_users.id)), leftOuterJoin( _pinnedByUsers, messages.pinnedByUserId.equalsExp(_pinnedByUsers.id), ), ]) - ..where(messages.channelCid.equals(cid)) - ..where( - messages.parentId.isNull() | messages.showInChannel.equals(true), - ) - ..orderBy([OrderingTerm.asc(messages.createdAt)])) - .map(_messageFromJoinRow) - .get()); + ..where(messages.channelCid.equals(cid)) + ..where(messages.parentId.isNull() | messages.showInChannel.equals(true)) + ..orderBy([OrderingTerm.asc(messages.createdAt)]); + + final result = await query.get(); + if (result.isEmpty) return []; + + final msgList = await Future.wait( + result.map( + (row) => _messageFromJoinRow( + row, + fetchDraft: fetchDraft, + ), + ), + ); if (msgList.isNotEmpty) { if (messagePagination?.lessThan != null) { diff --git a/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart b/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart index bf7b45b12..9addb92ec 100644 --- a/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart @@ -35,8 +35,11 @@ class PinnedMessageDao extends DatabaseAccessor Future deleteMessageByCids(List cids) async => (delete(pinnedMessages)..where((tbl) => tbl.channelCid.isIn(cids))).go(); - Future _messageFromJoinRow(TypedResult rows) async { - final userEntity = rows.readTableOrNull(users); + Future _messageFromJoinRow( + TypedResult rows, { + bool fetchDraft = false, + }) async { + final userEntity = rows.readTableOrNull(_users); final pinnedByEntity = rows.readTableOrNull(_pinnedByUsers); final msgEntity = rows.readTable(pinnedMessages); final latestReactions = @@ -46,16 +49,25 @@ class PinnedMessageDao extends DatabaseAccessor msgEntity.id, _db.userId, ); - Message? quotedMessage; - final quotedMessageId = msgEntity.quotedMessageId; - if (quotedMessageId != null) { - quotedMessage = await getMessageById(quotedMessageId); - } - Poll? poll; - final pollId = msgEntity.pollId; - if (pollId != null) { - poll = await _db.pollDao.getPollById(pollId); - } + + final quotedMessage = await switch (msgEntity.quotedMessageId) { + final id? => getMessageById(id), + _ => null, + }; + + final poll = await switch (msgEntity.pollId) { + final id? => _db.pollDao.getPollById(id), + _ => null, + }; + + final draft = await switch ((fetchDraft, msgEntity.parentId)) { + (true, final parentId?) => _db.draftMessageDao.getDraftMessageByCid( + msgEntity.channelCid, + parentId: parentId, + ), + _ => null, + }; + return msgEntity.toMessage( user: userEntity?.toUser(), pinnedBy: pinnedByEntity?.toUser(), @@ -63,21 +75,32 @@ class PinnedMessageDao extends DatabaseAccessor ownReactions: ownReactions, quotedMessage: quotedMessage, poll: poll, + draft: draft, ); } /// Returns a single message by matching the [PinnedMessages.id] with [id] - Future getMessageById(String id) async => - await (select(pinnedMessages).join([ - leftOuterJoin(_users, pinnedMessages.userId.equalsExp(_users.id)), - leftOuterJoin( - _pinnedByUsers, - pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id), - ), - ]) - ..where(pinnedMessages.id.equals(id))) - .map(_messageFromJoinRow) - .getSingleOrNull(); + Future getMessageById( + String id, { + bool fetchDraft = true, + }) async { + final query = select(pinnedMessages).join([ + leftOuterJoin(_users, pinnedMessages.userId.equalsExp(_users.id)), + leftOuterJoin( + _pinnedByUsers, + pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id), + ), + ]) + ..where(pinnedMessages.id.equals(id)); + + final result = await query.getSingleOrNull(); + if (result == null) return null; + + return _messageFromJoinRow( + result, + fetchDraft: fetchDraft, + ); + } /// Returns all the messages of a particular thread by matching /// [PinnedMessages.channelCid] with [cid] @@ -142,21 +165,32 @@ class PinnedMessageDao extends DatabaseAccessor /// [PinnedMessages.channelCid] with [parentId] Future> getMessagesByCid( String cid, { + bool fetchDraft = true, PaginationParams? messagePagination, }) async { - final msgList = await Future.wait(await (select(pinnedMessages).join([ + final query = select(pinnedMessages).join([ leftOuterJoin(_users, pinnedMessages.userId.equalsExp(_users.id)), leftOuterJoin( _pinnedByUsers, pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id), ), ]) - ..where(pinnedMessages.channelCid.equals(cid)) - ..where(pinnedMessages.parentId.isNull() | - pinnedMessages.showInChannel.equals(true)) - ..orderBy([OrderingTerm.asc(pinnedMessages.createdAt)])) - .map(_messageFromJoinRow) - .get()); + ..where(pinnedMessages.channelCid.equals(cid)) + ..where(pinnedMessages.parentId.isNull() | + pinnedMessages.showInChannel.equals(true)) + ..orderBy([OrderingTerm.asc(pinnedMessages.createdAt)]); + + final result = await query.get(); + if (result.isEmpty) return []; + + final msgList = await Future.wait( + result.map( + (row) => _messageFromJoinRow( + row, + fetchDraft: fetchDraft, + ), + ), + ); if (msgList.isNotEmpty) { if (messagePagination?.lessThan != null) { diff --git a/packages/stream_chat_persistence/lib/src/db/drift_chat_database.g.dart b/packages/stream_chat_persistence/lib/src/db/drift_chat_database.g.dart index 62b81b61e..fdf044d67 100644 --- a/packages/stream_chat_persistence/lib/src/db/drift_chat_database.g.dart +++ b/packages/stream_chat_persistence/lib/src/db/drift_chat_database.g.dart @@ -846,12 +846,6 @@ class $MessagesTable extends Messages type: DriftSqlType.string, requiredDuringInsert: false) .withConverter?>( $MessagesTable.$converterrestrictedVisibilityn); - static const VerificationMeta _draftMessageIdMeta = - const VerificationMeta('draftMessageId'); - @override - late final GeneratedColumn draftMessageId = GeneratedColumn( - 'draft_message_id', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); @override late final GeneratedColumnWithTypeConverter?, String> extraData = GeneratedColumn('extra_data', aliasedName, true, @@ -889,7 +883,6 @@ class $MessagesTable extends Messages channelCid, i18n, restrictedVisibility, - draftMessageId, extraData ]; @override @@ -1031,12 +1024,6 @@ class $MessagesTable extends Messages } else if (isInserting) { context.missing(_channelCidMeta); } - if (data.containsKey('draft_message_id')) { - context.handle( - _draftMessageIdMeta, - draftMessageId.isAcceptableOrUnknown( - data['draft_message_id']!, _draftMessageIdMeta)); - } return context; } @@ -1109,8 +1096,6 @@ class $MessagesTable extends Messages restrictedVisibility: $MessagesTable.$converterrestrictedVisibilityn .fromSql(attachedDatabase.typeMapping.read(DriftSqlType.string, data['${effectivePrefix}restricted_visibility'])), - draftMessageId: attachedDatabase.typeMapping.read( - DriftSqlType.string, data['${effectivePrefix}draft_message_id']), extraData: $MessagesTable.$converterextraDatan.fromSql(attachedDatabase .typeMapping .read(DriftSqlType.string, data['${effectivePrefix}extra_data'])), @@ -1232,9 +1217,6 @@ class MessageEntity extends DataClass implements Insertable { /// The list of user ids that should be able to see the message. final List? restrictedVisibility; - /// Id of the draft message if this message is a parent message. - final String? draftMessageId; - /// Message custom extraData final Map? extraData; const MessageEntity( @@ -1267,7 +1249,6 @@ class MessageEntity extends DataClass implements Insertable { required this.channelCid, this.i18n, this.restrictedVisibility, - this.draftMessageId, this.extraData}); @override Map toColumns(bool nullToAbsent) { @@ -1352,9 +1333,6 @@ class MessageEntity extends DataClass implements Insertable { .$converterrestrictedVisibilityn .toSql(restrictedVisibility)); } - if (!nullToAbsent || draftMessageId != null) { - map['draft_message_id'] = Variable(draftMessageId); - } if (!nullToAbsent || extraData != null) { map['extra_data'] = Variable( $MessagesTable.$converterextraDatan.toSql(extraData)); @@ -1398,7 +1376,6 @@ class MessageEntity extends DataClass implements Insertable { i18n: serializer.fromJson?>(json['i18n']), restrictedVisibility: serializer.fromJson?>(json['restrictedVisibility']), - draftMessageId: serializer.fromJson(json['draftMessageId']), extraData: serializer.fromJson?>(json['extraData']), ); } @@ -1438,7 +1415,6 @@ class MessageEntity extends DataClass implements Insertable { 'i18n': serializer.toJson?>(i18n), 'restrictedVisibility': serializer.toJson?>(restrictedVisibility), - 'draftMessageId': serializer.toJson(draftMessageId), 'extraData': serializer.toJson?>(extraData), }; } @@ -1474,7 +1450,6 @@ class MessageEntity extends DataClass implements Insertable { String? channelCid, Value?> i18n = const Value.absent(), Value?> restrictedVisibility = const Value.absent(), - Value draftMessageId = const Value.absent(), Value?> extraData = const Value.absent()}) => MessageEntity( id: id ?? this.id, @@ -1524,8 +1499,6 @@ class MessageEntity extends DataClass implements Insertable { restrictedVisibility: restrictedVisibility.present ? restrictedVisibility.value : this.restrictedVisibility, - draftMessageId: - draftMessageId.present ? draftMessageId.value : this.draftMessageId, extraData: extraData.present ? extraData.value : this.extraData, ); MessageEntity copyWithCompanion(MessagesCompanion data) { @@ -1590,9 +1563,6 @@ class MessageEntity extends DataClass implements Insertable { restrictedVisibility: data.restrictedVisibility.present ? data.restrictedVisibility.value : this.restrictedVisibility, - draftMessageId: data.draftMessageId.present - ? data.draftMessageId.value - : this.draftMessageId, extraData: data.extraData.present ? data.extraData.value : this.extraData, ); } @@ -1629,7 +1599,6 @@ class MessageEntity extends DataClass implements Insertable { ..write('channelCid: $channelCid, ') ..write('i18n: $i18n, ') ..write('restrictedVisibility: $restrictedVisibility, ') - ..write('draftMessageId: $draftMessageId, ') ..write('extraData: $extraData') ..write(')')) .toString(); @@ -1666,7 +1635,6 @@ class MessageEntity extends DataClass implements Insertable { channelCid, i18n, restrictedVisibility, - draftMessageId, extraData ]); @override @@ -1702,7 +1670,6 @@ class MessageEntity extends DataClass implements Insertable { other.channelCid == this.channelCid && other.i18n == this.i18n && other.restrictedVisibility == this.restrictedVisibility && - other.draftMessageId == this.draftMessageId && other.extraData == this.extraData); } @@ -1736,7 +1703,6 @@ class MessagesCompanion extends UpdateCompanion { final Value channelCid; final Value?> i18n; final Value?> restrictedVisibility; - final Value draftMessageId; final Value?> extraData; final Value rowid; const MessagesCompanion({ @@ -1769,7 +1735,6 @@ class MessagesCompanion extends UpdateCompanion { this.channelCid = const Value.absent(), this.i18n = const Value.absent(), this.restrictedVisibility = const Value.absent(), - this.draftMessageId = const Value.absent(), this.extraData = const Value.absent(), this.rowid = const Value.absent(), }); @@ -1803,7 +1768,6 @@ class MessagesCompanion extends UpdateCompanion { required String channelCid, this.i18n = const Value.absent(), this.restrictedVisibility = const Value.absent(), - this.draftMessageId = const Value.absent(), this.extraData = const Value.absent(), this.rowid = const Value.absent(), }) : id = Value(id), @@ -1841,7 +1805,6 @@ class MessagesCompanion extends UpdateCompanion { Expression? channelCid, Expression? i18n, Expression? restrictedVisibility, - Expression? draftMessageId, Expression? extraData, Expression? rowid, }) { @@ -1877,7 +1840,6 @@ class MessagesCompanion extends UpdateCompanion { if (i18n != null) 'i18n': i18n, if (restrictedVisibility != null) 'restricted_visibility': restrictedVisibility, - if (draftMessageId != null) 'draft_message_id': draftMessageId, if (extraData != null) 'extra_data': extraData, if (rowid != null) 'rowid': rowid, }); @@ -1913,7 +1875,6 @@ class MessagesCompanion extends UpdateCompanion { Value? channelCid, Value?>? i18n, Value?>? restrictedVisibility, - Value? draftMessageId, Value?>? extraData, Value? rowid}) { return MessagesCompanion( @@ -1946,7 +1907,6 @@ class MessagesCompanion extends UpdateCompanion { channelCid: channelCid ?? this.channelCid, i18n: i18n ?? this.i18n, restrictedVisibility: restrictedVisibility ?? this.restrictedVisibility, - draftMessageId: draftMessageId ?? this.draftMessageId, extraData: extraData ?? this.extraData, rowid: rowid ?? this.rowid, ); @@ -2049,9 +2009,6 @@ class MessagesCompanion extends UpdateCompanion { .$converterrestrictedVisibilityn .toSql(restrictedVisibility.value)); } - if (draftMessageId.present) { - map['draft_message_id'] = Variable(draftMessageId.value); - } if (extraData.present) { map['extra_data'] = Variable( $MessagesTable.$converterextraDatan.toSql(extraData.value)); @@ -2094,7 +2051,6 @@ class MessagesCompanion extends UpdateCompanion { ..write('channelCid: $channelCid, ') ..write('i18n: $i18n, ') ..write('restrictedVisibility: $restrictedVisibility, ') - ..write('draftMessageId: $draftMessageId, ') ..write('extraData: $extraData, ') ..write('rowid: $rowid') ..write(')')) @@ -2998,12 +2954,6 @@ class $PinnedMessagesTable extends PinnedMessages type: DriftSqlType.string, requiredDuringInsert: false) .withConverter?>( $PinnedMessagesTable.$converterrestrictedVisibilityn); - static const VerificationMeta _draftMessageIdMeta = - const VerificationMeta('draftMessageId'); - @override - late final GeneratedColumn draftMessageId = GeneratedColumn( - 'draft_message_id', aliasedName, true, - type: DriftSqlType.string, requiredDuringInsert: false); @override late final GeneratedColumnWithTypeConverter?, String> extraData = GeneratedColumn('extra_data', aliasedName, true, @@ -3041,7 +2991,6 @@ class $PinnedMessagesTable extends PinnedMessages channelCid, i18n, restrictedVisibility, - draftMessageId, extraData ]; @override @@ -3184,12 +3133,6 @@ class $PinnedMessagesTable extends PinnedMessages } else if (isInserting) { context.missing(_channelCidMeta); } - if (data.containsKey('draft_message_id')) { - context.handle( - _draftMessageIdMeta, - draftMessageId.isAcceptableOrUnknown( - data['draft_message_id']!, _draftMessageIdMeta)); - } return context; } @@ -3263,8 +3206,6 @@ class $PinnedMessagesTable extends PinnedMessages restrictedVisibility: $PinnedMessagesTable.$converterrestrictedVisibilityn .fromSql(attachedDatabase.typeMapping.read(DriftSqlType.string, data['${effectivePrefix}restricted_visibility'])), - draftMessageId: attachedDatabase.typeMapping.read( - DriftSqlType.string, data['${effectivePrefix}draft_message_id']), extraData: $PinnedMessagesTable.$converterextraDatan.fromSql( attachedDatabase.typeMapping .read(DriftSqlType.string, data['${effectivePrefix}extra_data'])), @@ -3387,9 +3328,6 @@ class PinnedMessageEntity extends DataClass /// The list of user ids that should be able to see the message. final List? restrictedVisibility; - /// Id of the draft message if this message is a parent message. - final String? draftMessageId; - /// Message custom extraData final Map? extraData; const PinnedMessageEntity( @@ -3422,7 +3360,6 @@ class PinnedMessageEntity extends DataClass required this.channelCid, this.i18n, this.restrictedVisibility, - this.draftMessageId, this.extraData}); @override Map toColumns(bool nullToAbsent) { @@ -3508,9 +3445,6 @@ class PinnedMessageEntity extends DataClass .$converterrestrictedVisibilityn .toSql(restrictedVisibility)); } - if (!nullToAbsent || draftMessageId != null) { - map['draft_message_id'] = Variable(draftMessageId); - } if (!nullToAbsent || extraData != null) { map['extra_data'] = Variable( $PinnedMessagesTable.$converterextraDatan.toSql(extraData)); @@ -3554,7 +3488,6 @@ class PinnedMessageEntity extends DataClass i18n: serializer.fromJson?>(json['i18n']), restrictedVisibility: serializer.fromJson?>(json['restrictedVisibility']), - draftMessageId: serializer.fromJson(json['draftMessageId']), extraData: serializer.fromJson?>(json['extraData']), ); } @@ -3594,7 +3527,6 @@ class PinnedMessageEntity extends DataClass 'i18n': serializer.toJson?>(i18n), 'restrictedVisibility': serializer.toJson?>(restrictedVisibility), - 'draftMessageId': serializer.toJson(draftMessageId), 'extraData': serializer.toJson?>(extraData), }; } @@ -3630,7 +3562,6 @@ class PinnedMessageEntity extends DataClass String? channelCid, Value?> i18n = const Value.absent(), Value?> restrictedVisibility = const Value.absent(), - Value draftMessageId = const Value.absent(), Value?> extraData = const Value.absent()}) => PinnedMessageEntity( id: id ?? this.id, @@ -3680,8 +3611,6 @@ class PinnedMessageEntity extends DataClass restrictedVisibility: restrictedVisibility.present ? restrictedVisibility.value : this.restrictedVisibility, - draftMessageId: - draftMessageId.present ? draftMessageId.value : this.draftMessageId, extraData: extraData.present ? extraData.value : this.extraData, ); PinnedMessageEntity copyWithCompanion(PinnedMessagesCompanion data) { @@ -3746,9 +3675,6 @@ class PinnedMessageEntity extends DataClass restrictedVisibility: data.restrictedVisibility.present ? data.restrictedVisibility.value : this.restrictedVisibility, - draftMessageId: data.draftMessageId.present - ? data.draftMessageId.value - : this.draftMessageId, extraData: data.extraData.present ? data.extraData.value : this.extraData, ); } @@ -3785,7 +3711,6 @@ class PinnedMessageEntity extends DataClass ..write('channelCid: $channelCid, ') ..write('i18n: $i18n, ') ..write('restrictedVisibility: $restrictedVisibility, ') - ..write('draftMessageId: $draftMessageId, ') ..write('extraData: $extraData') ..write(')')) .toString(); @@ -3822,7 +3747,6 @@ class PinnedMessageEntity extends DataClass channelCid, i18n, restrictedVisibility, - draftMessageId, extraData ]); @override @@ -3858,7 +3782,6 @@ class PinnedMessageEntity extends DataClass other.channelCid == this.channelCid && other.i18n == this.i18n && other.restrictedVisibility == this.restrictedVisibility && - other.draftMessageId == this.draftMessageId && other.extraData == this.extraData); } @@ -3892,7 +3815,6 @@ class PinnedMessagesCompanion extends UpdateCompanion { final Value channelCid; final Value?> i18n; final Value?> restrictedVisibility; - final Value draftMessageId; final Value?> extraData; final Value rowid; const PinnedMessagesCompanion({ @@ -3925,7 +3847,6 @@ class PinnedMessagesCompanion extends UpdateCompanion { this.channelCid = const Value.absent(), this.i18n = const Value.absent(), this.restrictedVisibility = const Value.absent(), - this.draftMessageId = const Value.absent(), this.extraData = const Value.absent(), this.rowid = const Value.absent(), }); @@ -3959,7 +3880,6 @@ class PinnedMessagesCompanion extends UpdateCompanion { required String channelCid, this.i18n = const Value.absent(), this.restrictedVisibility = const Value.absent(), - this.draftMessageId = const Value.absent(), this.extraData = const Value.absent(), this.rowid = const Value.absent(), }) : id = Value(id), @@ -3997,7 +3917,6 @@ class PinnedMessagesCompanion extends UpdateCompanion { Expression? channelCid, Expression? i18n, Expression? restrictedVisibility, - Expression? draftMessageId, Expression? extraData, Expression? rowid, }) { @@ -4033,7 +3952,6 @@ class PinnedMessagesCompanion extends UpdateCompanion { if (i18n != null) 'i18n': i18n, if (restrictedVisibility != null) 'restricted_visibility': restrictedVisibility, - if (draftMessageId != null) 'draft_message_id': draftMessageId, if (extraData != null) 'extra_data': extraData, if (rowid != null) 'rowid': rowid, }); @@ -4069,7 +3987,6 @@ class PinnedMessagesCompanion extends UpdateCompanion { Value? channelCid, Value?>? i18n, Value?>? restrictedVisibility, - Value? draftMessageId, Value?>? extraData, Value? rowid}) { return PinnedMessagesCompanion( @@ -4102,7 +4019,6 @@ class PinnedMessagesCompanion extends UpdateCompanion { channelCid: channelCid ?? this.channelCid, i18n: i18n ?? this.i18n, restrictedVisibility: restrictedVisibility ?? this.restrictedVisibility, - draftMessageId: draftMessageId ?? this.draftMessageId, extraData: extraData ?? this.extraData, rowid: rowid ?? this.rowid, ); @@ -4207,9 +4123,6 @@ class PinnedMessagesCompanion extends UpdateCompanion { .$converterrestrictedVisibilityn .toSql(restrictedVisibility.value)); } - if (draftMessageId.present) { - map['draft_message_id'] = Variable(draftMessageId.value); - } if (extraData.present) { map['extra_data'] = Variable( $PinnedMessagesTable.$converterextraDatan.toSql(extraData.value)); @@ -4252,7 +4165,6 @@ class PinnedMessagesCompanion extends UpdateCompanion { ..write('channelCid: $channelCid, ') ..write('i18n: $i18n, ') ..write('restrictedVisibility: $restrictedVisibility, ') - ..write('draftMessageId: $draftMessageId, ') ..write('extraData: $extraData, ') ..write('rowid: $rowid') ..write(')')) @@ -9107,7 +9019,6 @@ typedef $$MessagesTableCreateCompanionBuilder = MessagesCompanion Function({ required String channelCid, Value?> i18n, Value?> restrictedVisibility, - Value draftMessageId, Value?> extraData, Value rowid, }); @@ -9141,7 +9052,6 @@ typedef $$MessagesTableUpdateCompanionBuilder = MessagesCompanion Function({ Value channelCid, Value?> i18n, Value?> restrictedVisibility, - Value draftMessageId, Value?> extraData, Value rowid, }); @@ -9310,10 +9220,6 @@ class $$MessagesTableFilterComposer column: $table.restrictedVisibility, builder: (column) => ColumnWithTypeConverterFilters(column)); - ColumnFilters get draftMessageId => $composableBuilder( - column: $table.draftMessageId, - builder: (column) => ColumnFilters(column)); - ColumnWithTypeConverterFilters?, Map, String> get extraData => $composableBuilder( @@ -9489,10 +9395,6 @@ class $$MessagesTableOrderingComposer column: $table.restrictedVisibility, builder: (column) => ColumnOrderings(column)); - ColumnOrderings get draftMessageId => $composableBuilder( - column: $table.draftMessageId, - builder: (column) => ColumnOrderings(column)); - ColumnOrderings get extraData => $composableBuilder( column: $table.extraData, builder: (column) => ColumnOrderings(column)); @@ -9614,9 +9516,6 @@ class $$MessagesTableAnnotationComposer get restrictedVisibility => $composableBuilder( column: $table.restrictedVisibility, builder: (column) => column); - GeneratedColumn get draftMessageId => $composableBuilder( - column: $table.draftMessageId, builder: (column) => column); - GeneratedColumnWithTypeConverter?, String> get extraData => $composableBuilder( column: $table.extraData, builder: (column) => column); @@ -9738,7 +9637,6 @@ class $$MessagesTableTableManager extends RootTableManager< Value channelCid = const Value.absent(), Value?> i18n = const Value.absent(), Value?> restrictedVisibility = const Value.absent(), - Value draftMessageId = const Value.absent(), Value?> extraData = const Value.absent(), Value rowid = const Value.absent(), }) => @@ -9772,7 +9670,6 @@ class $$MessagesTableTableManager extends RootTableManager< channelCid: channelCid, i18n: i18n, restrictedVisibility: restrictedVisibility, - draftMessageId: draftMessageId, extraData: extraData, rowid: rowid, ), @@ -9807,7 +9704,6 @@ class $$MessagesTableTableManager extends RootTableManager< required String channelCid, Value?> i18n = const Value.absent(), Value?> restrictedVisibility = const Value.absent(), - Value draftMessageId = const Value.absent(), Value?> extraData = const Value.absent(), Value rowid = const Value.absent(), }) => @@ -9841,7 +9737,6 @@ class $$MessagesTableTableManager extends RootTableManager< channelCid: channelCid, i18n: i18n, restrictedVisibility: restrictedVisibility, - draftMessageId: draftMessageId, extraData: extraData, rowid: rowid, ), @@ -10466,7 +10361,6 @@ typedef $$PinnedMessagesTableCreateCompanionBuilder = PinnedMessagesCompanion required String channelCid, Value?> i18n, Value?> restrictedVisibility, - Value draftMessageId, Value?> extraData, Value rowid, }); @@ -10501,7 +10395,6 @@ typedef $$PinnedMessagesTableUpdateCompanionBuilder = PinnedMessagesCompanion Value channelCid, Value?> i18n, Value?> restrictedVisibility, - Value draftMessageId, Value?> extraData, Value rowid, }); @@ -10648,10 +10541,6 @@ class $$PinnedMessagesTableFilterComposer column: $table.restrictedVisibility, builder: (column) => ColumnWithTypeConverterFilters(column)); - ColumnFilters get draftMessageId => $composableBuilder( - column: $table.draftMessageId, - builder: (column) => ColumnFilters(column)); - ColumnWithTypeConverterFilters?, Map, String> get extraData => $composableBuilder( @@ -10791,10 +10680,6 @@ class $$PinnedMessagesTableOrderingComposer column: $table.restrictedVisibility, builder: (column) => ColumnOrderings(column)); - ColumnOrderings get draftMessageId => $composableBuilder( - column: $table.draftMessageId, - builder: (column) => ColumnOrderings(column)); - ColumnOrderings get extraData => $composableBuilder( column: $table.extraData, builder: (column) => ColumnOrderings(column)); } @@ -10899,9 +10784,6 @@ class $$PinnedMessagesTableAnnotationComposer get restrictedVisibility => $composableBuilder( column: $table.restrictedVisibility, builder: (column) => column); - GeneratedColumn get draftMessageId => $composableBuilder( - column: $table.draftMessageId, builder: (column) => column); - GeneratedColumnWithTypeConverter?, String> get extraData => $composableBuilder( column: $table.extraData, builder: (column) => column); @@ -10984,7 +10866,6 @@ class $$PinnedMessagesTableTableManager extends RootTableManager< Value channelCid = const Value.absent(), Value?> i18n = const Value.absent(), Value?> restrictedVisibility = const Value.absent(), - Value draftMessageId = const Value.absent(), Value?> extraData = const Value.absent(), Value rowid = const Value.absent(), }) => @@ -11018,7 +10899,6 @@ class $$PinnedMessagesTableTableManager extends RootTableManager< channelCid: channelCid, i18n: i18n, restrictedVisibility: restrictedVisibility, - draftMessageId: draftMessageId, extraData: extraData, rowid: rowid, ), @@ -11053,7 +10933,6 @@ class $$PinnedMessagesTableTableManager extends RootTableManager< required String channelCid, Value?> i18n = const Value.absent(), Value?> restrictedVisibility = const Value.absent(), - Value draftMessageId = const Value.absent(), Value?> extraData = const Value.absent(), Value rowid = const Value.absent(), }) => @@ -11087,7 +10966,6 @@ class $$PinnedMessagesTableTableManager extends RootTableManager< channelCid: channelCid, i18n: i18n, restrictedVisibility: restrictedVisibility, - draftMessageId: draftMessageId, extraData: extraData, rowid: rowid, ), diff --git a/packages/stream_chat_persistence/lib/src/entity/messages.dart b/packages/stream_chat_persistence/lib/src/entity/messages.dart index 766bbe599..caf11a1a1 100644 --- a/packages/stream_chat_persistence/lib/src/entity/messages.dart +++ b/packages/stream_chat_persistence/lib/src/entity/messages.dart @@ -129,9 +129,6 @@ class Messages extends Table { TextColumn get restrictedVisibility => text().nullable().map(ListConverter())(); - /// Id of the draft message if this message is a parent message. - TextColumn get draftMessageId => text().nullable()(); - /// Message custom extraData TextColumn get extraData => text().nullable().map(MapConverter())(); diff --git a/packages/stream_chat_persistence/lib/src/mapper/message_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/message_mapper.dart index 8e4d9d544..323592516 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/message_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/message_mapper.dart @@ -91,6 +91,5 @@ extension MessageX on Message { pinnedByUserId: pinnedBy?.id, i18n: i18n, restrictedVisibility: restrictedVisibility, - draftMessageId: draft?.message.id, ); } diff --git a/packages/stream_chat_persistence/lib/src/mapper/pinned_message_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/pinned_message_mapper.dart index a87b716ec..c6cbf1941 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/pinned_message_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/pinned_message_mapper.dart @@ -13,6 +13,7 @@ extension PinnedMessageEntityX on PinnedMessageEntity { List? ownReactions, Message? quotedMessage, Poll? poll, + Draft? draft, }) => Message( shadowed: shadowed, @@ -52,6 +53,7 @@ extension PinnedMessageEntityX on PinnedMessageEntity { mentionedUsers.map((e) => User.fromJson(jsonDecode(e))).toList(), i18n: i18n, restrictedVisibility: restrictedVisibility, + draft: draft, ); } From 6c0bcaa82dbefb14441a9cd6b60f77731993b00b Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 22 Jul 2025 17:56:58 +0200 Subject: [PATCH 03/10] chore: update CHANGELOG.md --- packages/stream_chat/CHANGELOG.md | 88 ++++++++++++------- packages/stream_chat_persistence/CHANGELOG.md | 34 +++++-- 2 files changed, 83 insertions(+), 39 deletions(-) diff --git a/packages/stream_chat/CHANGELOG.md b/packages/stream_chat/CHANGELOG.md index 298468ba2..e25261de4 100644 --- a/packages/stream_chat/CHANGELOG.md +++ b/packages/stream_chat/CHANGELOG.md @@ -3,6 +3,8 @@ 🐞 Fixed - Fixed `WebSocket` race condition where reconnection could access null user during disconnect. +- Fixed draft message persistence issues where removed drafts were not properly deleted from the + database. ## 9.14.0 @@ -47,6 +49,7 @@ `message.reactionGroups`. 🐞 Fixed + - `Null check operator used on a null value` in Websocket connect. - Ensure query cache is cleared when refreshing channel queries. @@ -54,7 +57,8 @@ 🐞 Fixed -- [[#2013]](https://github.com/GetStream/stream-chat-flutter/issues/2013) Fix pinned message get duplicated. +- [[#2013]](https://github.com/GetStream/stream-chat-flutter/issues/2013) Fix pinned message get + duplicated. 🔄 Changed @@ -102,9 +106,10 @@ - Added support for message moderation feature. - Improved user blocking functionality by updating client state when blocking/unblocking users: - - `client.blockUser` now updates `currentUser.blockedUserIds` list with newly blocked user IDs. - - `client.unblockUser` now removes the unblocked user ID from `currentUser.blockedUserIds` list. - - `client.queryBlockedUsers` now updates `currentUser.blockedUserIds` with the latest blocked users data. + - `client.blockUser` now updates `currentUser.blockedUserIds` list with newly blocked user IDs. + - `client.unblockUser` now removes the unblocked user ID from `currentUser.blockedUserIds` list. + - `client.queryBlockedUsers` now updates `currentUser.blockedUserIds` with the latest blocked + users data. 🐞 Fixed @@ -122,24 +127,30 @@ 🐞 Fixed -- [[#1775]](https://github.com/GetStream/stream-chat-flutter/issues/1775) Fix incorrect message order. +- [[#1775]](https://github.com/GetStream/stream-chat-flutter/issues/1775) Fix incorrect message + order. ## 9.5.0 ✅ Added -- [[#2101]](https://github.com/GetStream/stream-chat-flutter/issues/2101) Added support for system messages not updating `channel.lastMessageAt`. +- [[#2101]](https://github.com/GetStream/stream-chat-flutter/issues/2101) Added support for system + messages not updating `channel.lastMessageAt`. - Added support for sending private or restricted visibility messages. - Add `member.extraData` field. 🐞 Fixed -- [[#1774]](https://github.com/GetStream/stream-chat-flutter/issues/1774) Fixed failed to execute 'close' on 'WebSocket'. -- [[#2016]](https://github.com/GetStream/stream-chat-flutter/issues/2016) Fix muted channel's unreadCount incorrectly updated. - +- [[#1774]](https://github.com/GetStream/stream-chat-flutter/issues/1774) Fixed failed to execute ' + close' on 'WebSocket'. +- [[#2016]](https://github.com/GetStream/stream-chat-flutter/issues/2016) Fix muted channel's + unreadCount incorrectly updated. + 🔄 Changed -- Refactored identifying the `Attachment.uploadState` logic for local and remote attachments. Also updated the logic for determining the attachment type to check for ogScrapeUrl instead of `AttachmentType.giphy`. +- Refactored identifying the `Attachment.uploadState` logic for local and remote attachments. Also + updated the logic for determining the attachment type to check for ogScrapeUrl instead of + `AttachmentType.giphy`. - Improved the `x-stream-client` header generation for better client identification and analytics. ## 9.4.0 @@ -247,7 +258,7 @@ 🐞 Fixed -- [[#1837]](https://github.com/GetStream/stream-chat-flutter/issues/1837) Delete image and file +- [[#1837]](https://github.com/GetStream/stream-chat-flutter/issues/1837) Delete image and file attachments from the CDN, when the message get's hard deleted. - [[#1819]](https://github.com/GetStream/stream-chat-flutter/issues/1819) Handle network errors with String payload. @@ -256,8 +267,10 @@ 🐞 Fixed -- [[#1811]](https://github.com/GetStream/stream-chat-flutter/issues/1811) Bumped `UUID` dependency to `^4.2.1`. This - **might** produce a **breaking change** if you your code depends in `UUID` `3.x.x` directly or indirectly. +- [[#1811]](https://github.com/GetStream/stream-chat-flutter/issues/1811) Bumped `UUID` dependency + to `^4.2.1`. This + **might** produce a **breaking change** if you your code depends in `UUID` `3.x.x` directly or + indirectly. ## 7.0.0 @@ -265,19 +278,20 @@ - Removed deprecated `channelQuery.sort` property. Use `channelStateSort` instead. - Removed deprecated `RetryPolicy.retryTimeout` property. Use `delayFactor` instead. -- Removed deprecated `StreamChatNetworkError.fromDioError` constructor. Use `StreamChatNetworkError.fromDioException` +- Removed deprecated `StreamChatNetworkError.fromDioError` constructor. Use + `StreamChatNetworkError.fromDioException` instead. - Removed deprecated `MessageSendingStatus` enum. Use `MessageState` instead. 🔄 Changed - Updated minimum supported `SDK` version to Flutter 3.13/Dart 3.1 - + # 6.10.0 🐞 Fixed -- [[#1753]](https://github.com/GetStream/stream-chat-flutter/issues/1753) Fixed Unhandled null +- [[#1753]](https://github.com/GetStream/stream-chat-flutter/issues/1753) Fixed Unhandled null check operator exception when user is removed from a channel. ## 6.9.0 @@ -297,7 +311,8 @@ ✅ Added -- Added support for `channel.countUnreadMentions()` to get the count of unread messages mentioning the current user on a +- Added support for `channel.countUnreadMentions()` to get the count of unread messages mentioning + the current user on a channel. [#1692](https://github.com/GetStream/stream-chat-flutter/issues/1692) 🔄 Changed @@ -308,7 +323,8 @@ ✅ Added -- Added support for setting `Message.type`. [#1682](https://github.com/GetStream/stream-chat-flutter/issues/1682) +- Added support for setting + `Message.type`. [#1682](https://github.com/GetStream/stream-chat-flutter/issues/1682) ``` It is now possible to send system messages. System messages differ from normal messages in the way they are presented to the user. Like the name says, system messages are normally send from the system itself, but a user is @@ -333,16 +349,19 @@ 🐞 Fixed -- [[#1293]](https://github.com/GetStream/stream-chat-flutter/issues/1293) Fixed wrong message order when sending +- [[#1293]](https://github.com/GetStream/stream-chat-flutter/issues/1293) Fixed wrong message order + when sending messages quickly. -- [[#1612]](https://github.com/GetStream/stream-chat-flutter/issues/1612) Fixed `Channel.isMutedStream` does not emit +- [[#1612]](https://github.com/GetStream/stream-chat-flutter/issues/1612) Fixed + `Channel.isMutedStream` does not emit when channel mute expires. ## 6.3.0 🐞 Fixed -- [[#1585]](https://github.com/GetStream/stream-chat-flutter/issues/1585) Fixed channels left not being removed from +- [[#1585]](https://github.com/GetStream/stream-chat-flutter/issues/1585) Fixed channels left not + being removed from the persistent storage. 🔄 Changed @@ -353,23 +372,28 @@ 🐞 Fixed -- [[#1422]](https://github.com/GetStream/stream-chat-flutter/issues/1422) Fixed `User.createdAt` property using +- [[#1422]](https://github.com/GetStream/stream-chat-flutter/issues/1422) Fixed `User.createdAt` + property using currentTime when the ws connection is not established. ✅ Added -- Added support for `ChatPersistenceClient.isConnected` for checking if the client is connected to the database. +- Added support for `ChatPersistenceClient.isConnected` for checking if the client is connected to + the database. - Added support for `ChatPersistenceClient.userId` for getting the current connected user id. -- Added two new methods `ChatPersistenceClient.disconnect` and `ChatPersistenceClient.connect` for disconnecting and +- Added two new methods `ChatPersistenceClient.disconnect` and `ChatPersistenceClient.connect` for + disconnecting and connecting to the database. ## 6.1.0 🐞 Fixed -- [[#1355]](https://github.com/GetStream/stream-chat-flutter/issues/1355) Fixed error while hiding channel and clearing +- [[#1355]](https://github.com/GetStream/stream-chat-flutter/issues/1355) Fixed error while hiding + channel and clearing message history. -- [[#1525]](https://github.com/GetStream/stream-chat-flutter/issues/1525) Fixed removing message not removing quoted +- [[#1525]](https://github.com/GetStream/stream-chat-flutter/issues/1525) Fixed removing message not + removing quoted message reference. ✅ Added @@ -377,7 +401,8 @@ - Expose `ChannelMute` class. [#1473](https://github.com/GetStream/stream-chat-flutter/issues/1473) - Added synchronization to the `StreamChatClient.sync` api. [#1392](https://github.com/GetStream/stream-chat-flutter/issues/1392) -- Added support for `StreamChatClient.chatApiInterceptors` to add custom interceptors to the API client. +- Added support for `StreamChatClient.chatApiInterceptors` to add custom interceptors to the API + client. [#1265](https://github.com/GetStream/stream-chat-flutter/issues/1265). ```dart @@ -409,7 +434,8 @@ 🐞 Fixed -- Fixed streamWatchers. Before it was always new, now it is possible to follow the watchers of a channel. +- Fixed streamWatchers. Before it was always new, now it is possible to follow the watchers of a + channel. - Make `Message.i18n` field read-only. 🔄 Changed @@ -839,7 +865,8 @@ the [V4 Migration Guide](https://getstream.io/chat/docs/sdk/flutter/guides/migra - `StreamChatError` -> parent type for all the stream errors. - `StreamWebSocketError` -> for user web socket related errors. - `StreamChatNetworkError` -> for network related errors. -- `client.queryChannels()`, `channel.query()` options parameter is removed in favor of individual parameters +- `client.queryChannels()`, `channel.query()` options parameter is removed in favor of individual + parameters - `option.state` -> bool state - `option.watch` -> bool watch - `option.presence` -> bool presence @@ -887,7 +914,8 @@ the [V4 Migration Guide](https://getstream.io/chat/docs/sdk/flutter/guides/migra - `StreamChatError` -> parent type for all the stream errors. - `StreamWebSocketError` -> for user web socket related errors. - `StreamChatNetworkError` -> for network related errors. -- `client.queryChannels()`, `channel.query()` options parameter is removed in favor of individual parameters +- `client.queryChannels()`, `channel.query()` options parameter is removed in favor of individual + parameters - `option.state` -> bool state - `option.watch` -> bool watch - `option.presence` -> bool presence diff --git a/packages/stream_chat_persistence/CHANGELOG.md b/packages/stream_chat_persistence/CHANGELOG.md index a8259e2f5..72d4cabcd 100644 --- a/packages/stream_chat_persistence/CHANGELOG.md +++ b/packages/stream_chat_persistence/CHANGELOG.md @@ -1,3 +1,10 @@ +## Upcoming + +🐞 Fixed + +- Fixed draft message retrieval logic where channel drafts were incorrectly attached to all messages + instead of only thread drafts being attached to their respective parent messages. + ## 9.14.0 - Updated `stream_chat` dependency to [`9.14.0`](https://pub.dev/packages/stream_chat/changelog). @@ -95,7 +102,8 @@ ## 7.2.0-hotfix.1 -- Updated `stream_chat` dependency to [`7.2.0-hotfix.1`](https://pub.dev/packages/stream_chat/changelog). +- Updated `stream_chat` dependency to [ + `7.2.0-hotfix.1`](https://pub.dev/packages/stream_chat/changelog). ## 7.2.0 @@ -116,7 +124,8 @@ ## 7.0.0 - Updated minimum supported `SDK` version to Flutter 3.13/Dart 3.1 -- 🛑 **BREAKING** Removed deprecated `getChannelStates.sort` parameter. Use `getChannelStates.channelStateSort` instead. +- 🛑 **BREAKING** Removed deprecated `getChannelStates.sort` parameter. Use + `getChannelStates.channelStateSort` instead. ## 6.10.0 @@ -133,7 +142,8 @@ ## 6.7.0 -- [[#1683]](https://github.com/GetStream/stream-chat-flutter/issues/1683) Fixed SqliteException no such column `messages.state`. +- [[#1683]](https://github.com/GetStream/stream-chat-flutter/issues/1683) Fixed SqliteException no + such column `messages.state`. - Updated `stream_chat` dependency to [`6.7.0`](https://pub.dev/packages/stream_chat/changelog). ## 6.6.0 @@ -154,12 +164,14 @@ ## 6.2.0 -- Added support for `StreamChatPersistenceClient.isConnected` for checking if the client is connected to the database. +- Added support for `StreamChatPersistenceClient.isConnected` for checking if the client is + connected to the database. - [[#1422]](https://github.com/GetStream/stream-chat-flutter/issues/1422) Removed default values from `UserEntity` `createdAt` and `updatedAt` fields. - Updated `stream_chat` dependency to [`6.2.0`](https://pub.dev/packages/stream_chat/changelog). - Added support for `StreamChatPersistenceClient.openPersistenceConnection` - and `StreamChatPersistenceClient.closePersistenceConnection` for opening and closing the database connection. + and `StreamChatPersistenceClient.closePersistenceConnection` for opening and closing the database + connection. ## 6.1.0 @@ -187,7 +199,8 @@ ## 5.0.0-beta.1 -- Updated `stream_chat` dependency to [`5.0.0-beta.1`](https://pub.dev/packages/stream_chat/changelog). +- Updated `stream_chat` dependency to [ + `5.0.0-beta.1`](https://pub.dev/packages/stream_chat/changelog). ## 4.4.0 @@ -219,7 +232,8 @@ ## 4.0.0-beta.0 -- Updated `stream_chat` dependency to [`4.0.0-beta.0`](https://pub.dev/packages/stream_chat/changelog). +- Updated `stream_chat` dependency to [ + `4.0.0-beta.0`](https://pub.dev/packages/stream_chat/changelog). ## 3.1.0 @@ -228,8 +242,10 @@ ## 3.0.0 - Updated `stream_chat` dependency to [`3.0.0`](https://pub.dev/packages/stream_chat/changelog). -- [[#604]](https://github.com/GetStream/stream-chat-flutter/issues/604) Fix cascade deletion by enabling `pragma foreign_keys`. -- Added a new table `PinnedMessageReactions` and dao `PinnedMessageReactionDao` specifically for pinned messages. +- [[#604]](https://github.com/GetStream/stream-chat-flutter/issues/604) Fix cascade deletion by + enabling `pragma foreign_keys`. +- Added a new table `PinnedMessageReactions` and dao `PinnedMessageReactionDao` specifically for + pinned messages. ## 2.2.0 From b51ba7dfb7f697b51eaea7101fc02b996fe3a723 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 22 Jul 2025 17:57:55 +0200 Subject: [PATCH 04/10] test: add test --- .../test/stream_chat_persistence_client_test.dart | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/stream_chat_persistence/test/stream_chat_persistence_client_test.dart b/packages/stream_chat_persistence/test/stream_chat_persistence_client_test.dart index 0a8cfc678..3b0cb7314 100644 --- a/packages/stream_chat_persistence/test/stream_chat_persistence_client_test.dart +++ b/packages/stream_chat_persistence/test/stream_chat_persistence_client_test.dart @@ -631,6 +631,16 @@ void main() { verify(() => mockDatabase.memberDao.deleteMemberByCids(cids)).called(1); }); + test('deleteDraftMessagesByCids', () async { + final cids = []; + when(() => mockDatabase.draftMessageDao.deleteDraftMessagesByCids(cids)) + .thenAnswer((_) => Future.value()); + + await client.deleteDraftMessagesByCids(cids); + verify(() => mockDatabase.draftMessageDao.deleteDraftMessagesByCids(cids)) + .called(1); + }); + test('getDraftMessageByCid', () async { const cid = 'testCid'; const parentId = 'testParentId'; From c8b2f47b9079b72328599b3d74b6403398bc4049 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 22 Jul 2025 18:05:22 +0200 Subject: [PATCH 05/10] chore: remove extra changes --- packages/stream_chat/CHANGELOG.md | 86 +++++++------------ packages/stream_chat_persistence/CHANGELOG.md | 27 ++---- 2 files changed, 39 insertions(+), 74 deletions(-) diff --git a/packages/stream_chat/CHANGELOG.md b/packages/stream_chat/CHANGELOG.md index e25261de4..5e37a3984 100644 --- a/packages/stream_chat/CHANGELOG.md +++ b/packages/stream_chat/CHANGELOG.md @@ -49,7 +49,6 @@ `message.reactionGroups`. 🐞 Fixed - - `Null check operator used on a null value` in Websocket connect. - Ensure query cache is cleared when refreshing channel queries. @@ -57,8 +56,7 @@ 🐞 Fixed -- [[#2013]](https://github.com/GetStream/stream-chat-flutter/issues/2013) Fix pinned message get - duplicated. +- [[#2013]](https://github.com/GetStream/stream-chat-flutter/issues/2013) Fix pinned message get duplicated. 🔄 Changed @@ -106,10 +104,9 @@ - Added support for message moderation feature. - Improved user blocking functionality by updating client state when blocking/unblocking users: - - `client.blockUser` now updates `currentUser.blockedUserIds` list with newly blocked user IDs. - - `client.unblockUser` now removes the unblocked user ID from `currentUser.blockedUserIds` list. - - `client.queryBlockedUsers` now updates `currentUser.blockedUserIds` with the latest blocked - users data. + - `client.blockUser` now updates `currentUser.blockedUserIds` list with newly blocked user IDs. + - `client.unblockUser` now removes the unblocked user ID from `currentUser.blockedUserIds` list. + - `client.queryBlockedUsers` now updates `currentUser.blockedUserIds` with the latest blocked users data. 🐞 Fixed @@ -127,30 +124,24 @@ 🐞 Fixed -- [[#1775]](https://github.com/GetStream/stream-chat-flutter/issues/1775) Fix incorrect message - order. +- [[#1775]](https://github.com/GetStream/stream-chat-flutter/issues/1775) Fix incorrect message order. ## 9.5.0 ✅ Added -- [[#2101]](https://github.com/GetStream/stream-chat-flutter/issues/2101) Added support for system - messages not updating `channel.lastMessageAt`. +- [[#2101]](https://github.com/GetStream/stream-chat-flutter/issues/2101) Added support for system messages not updating `channel.lastMessageAt`. - Added support for sending private or restricted visibility messages. - Add `member.extraData` field. 🐞 Fixed -- [[#1774]](https://github.com/GetStream/stream-chat-flutter/issues/1774) Fixed failed to execute ' - close' on 'WebSocket'. -- [[#2016]](https://github.com/GetStream/stream-chat-flutter/issues/2016) Fix muted channel's - unreadCount incorrectly updated. - +- [[#1774]](https://github.com/GetStream/stream-chat-flutter/issues/1774) Fixed failed to execute 'close' on 'WebSocket'. +- [[#2016]](https://github.com/GetStream/stream-chat-flutter/issues/2016) Fix muted channel's unreadCount incorrectly updated. + 🔄 Changed -- Refactored identifying the `Attachment.uploadState` logic for local and remote attachments. Also - updated the logic for determining the attachment type to check for ogScrapeUrl instead of - `AttachmentType.giphy`. +- Refactored identifying the `Attachment.uploadState` logic for local and remote attachments. Also updated the logic for determining the attachment type to check for ogScrapeUrl instead of `AttachmentType.giphy`. - Improved the `x-stream-client` header generation for better client identification and analytics. ## 9.4.0 @@ -258,7 +249,7 @@ 🐞 Fixed -- [[#1837]](https://github.com/GetStream/stream-chat-flutter/issues/1837) Delete image and file +- [[#1837]](https://github.com/GetStream/stream-chat-flutter/issues/1837) Delete image and file attachments from the CDN, when the message get's hard deleted. - [[#1819]](https://github.com/GetStream/stream-chat-flutter/issues/1819) Handle network errors with String payload. @@ -267,10 +258,8 @@ 🐞 Fixed -- [[#1811]](https://github.com/GetStream/stream-chat-flutter/issues/1811) Bumped `UUID` dependency - to `^4.2.1`. This - **might** produce a **breaking change** if you your code depends in `UUID` `3.x.x` directly or - indirectly. +- [[#1811]](https://github.com/GetStream/stream-chat-flutter/issues/1811) Bumped `UUID` dependency to `^4.2.1`. This + **might** produce a **breaking change** if you your code depends in `UUID` `3.x.x` directly or indirectly. ## 7.0.0 @@ -278,20 +267,19 @@ - Removed deprecated `channelQuery.sort` property. Use `channelStateSort` instead. - Removed deprecated `RetryPolicy.retryTimeout` property. Use `delayFactor` instead. -- Removed deprecated `StreamChatNetworkError.fromDioError` constructor. Use - `StreamChatNetworkError.fromDioException` +- Removed deprecated `StreamChatNetworkError.fromDioError` constructor. Use `StreamChatNetworkError.fromDioException` instead. - Removed deprecated `MessageSendingStatus` enum. Use `MessageState` instead. 🔄 Changed - Updated minimum supported `SDK` version to Flutter 3.13/Dart 3.1 - + # 6.10.0 🐞 Fixed -- [[#1753]](https://github.com/GetStream/stream-chat-flutter/issues/1753) Fixed Unhandled null +- [[#1753]](https://github.com/GetStream/stream-chat-flutter/issues/1753) Fixed Unhandled null check operator exception when user is removed from a channel. ## 6.9.0 @@ -311,8 +299,7 @@ ✅ Added -- Added support for `channel.countUnreadMentions()` to get the count of unread messages mentioning - the current user on a +- Added support for `channel.countUnreadMentions()` to get the count of unread messages mentioning the current user on a channel. [#1692](https://github.com/GetStream/stream-chat-flutter/issues/1692) 🔄 Changed @@ -323,8 +310,7 @@ ✅ Added -- Added support for setting - `Message.type`. [#1682](https://github.com/GetStream/stream-chat-flutter/issues/1682) +- Added support for setting `Message.type`. [#1682](https://github.com/GetStream/stream-chat-flutter/issues/1682) ``` It is now possible to send system messages. System messages differ from normal messages in the way they are presented to the user. Like the name says, system messages are normally send from the system itself, but a user is @@ -349,19 +335,16 @@ 🐞 Fixed -- [[#1293]](https://github.com/GetStream/stream-chat-flutter/issues/1293) Fixed wrong message order - when sending +- [[#1293]](https://github.com/GetStream/stream-chat-flutter/issues/1293) Fixed wrong message order when sending messages quickly. -- [[#1612]](https://github.com/GetStream/stream-chat-flutter/issues/1612) Fixed - `Channel.isMutedStream` does not emit +- [[#1612]](https://github.com/GetStream/stream-chat-flutter/issues/1612) Fixed `Channel.isMutedStream` does not emit when channel mute expires. ## 6.3.0 🐞 Fixed -- [[#1585]](https://github.com/GetStream/stream-chat-flutter/issues/1585) Fixed channels left not - being removed from +- [[#1585]](https://github.com/GetStream/stream-chat-flutter/issues/1585) Fixed channels left not being removed from the persistent storage. 🔄 Changed @@ -372,28 +355,23 @@ 🐞 Fixed -- [[#1422]](https://github.com/GetStream/stream-chat-flutter/issues/1422) Fixed `User.createdAt` - property using +- [[#1422]](https://github.com/GetStream/stream-chat-flutter/issues/1422) Fixed `User.createdAt` property using currentTime when the ws connection is not established. ✅ Added -- Added support for `ChatPersistenceClient.isConnected` for checking if the client is connected to - the database. +- Added support for `ChatPersistenceClient.isConnected` for checking if the client is connected to the database. - Added support for `ChatPersistenceClient.userId` for getting the current connected user id. -- Added two new methods `ChatPersistenceClient.disconnect` and `ChatPersistenceClient.connect` for - disconnecting and +- Added two new methods `ChatPersistenceClient.disconnect` and `ChatPersistenceClient.connect` for disconnecting and connecting to the database. ## 6.1.0 🐞 Fixed -- [[#1355]](https://github.com/GetStream/stream-chat-flutter/issues/1355) Fixed error while hiding - channel and clearing +- [[#1355]](https://github.com/GetStream/stream-chat-flutter/issues/1355) Fixed error while hiding channel and clearing message history. -- [[#1525]](https://github.com/GetStream/stream-chat-flutter/issues/1525) Fixed removing message not - removing quoted +- [[#1525]](https://github.com/GetStream/stream-chat-flutter/issues/1525) Fixed removing message not removing quoted message reference. ✅ Added @@ -401,8 +379,7 @@ - Expose `ChannelMute` class. [#1473](https://github.com/GetStream/stream-chat-flutter/issues/1473) - Added synchronization to the `StreamChatClient.sync` api. [#1392](https://github.com/GetStream/stream-chat-flutter/issues/1392) -- Added support for `StreamChatClient.chatApiInterceptors` to add custom interceptors to the API - client. +- Added support for `StreamChatClient.chatApiInterceptors` to add custom interceptors to the API client. [#1265](https://github.com/GetStream/stream-chat-flutter/issues/1265). ```dart @@ -434,8 +411,7 @@ 🐞 Fixed -- Fixed streamWatchers. Before it was always new, now it is possible to follow the watchers of a - channel. +- Fixed streamWatchers. Before it was always new, now it is possible to follow the watchers of a channel. - Make `Message.i18n` field read-only. 🔄 Changed @@ -865,8 +841,7 @@ the [V4 Migration Guide](https://getstream.io/chat/docs/sdk/flutter/guides/migra - `StreamChatError` -> parent type for all the stream errors. - `StreamWebSocketError` -> for user web socket related errors. - `StreamChatNetworkError` -> for network related errors. -- `client.queryChannels()`, `channel.query()` options parameter is removed in favor of individual - parameters +- `client.queryChannels()`, `channel.query()` options parameter is removed in favor of individual parameters - `option.state` -> bool state - `option.watch` -> bool watch - `option.presence` -> bool presence @@ -914,8 +889,7 @@ the [V4 Migration Guide](https://getstream.io/chat/docs/sdk/flutter/guides/migra - `StreamChatError` -> parent type for all the stream errors. - `StreamWebSocketError` -> for user web socket related errors. - `StreamChatNetworkError` -> for network related errors. -- `client.queryChannels()`, `channel.query()` options parameter is removed in favor of individual - parameters +- `client.queryChannels()`, `channel.query()` options parameter is removed in favor of individual parameters - `option.state` -> bool state - `option.watch` -> bool watch - `option.presence` -> bool presence diff --git a/packages/stream_chat_persistence/CHANGELOG.md b/packages/stream_chat_persistence/CHANGELOG.md index 72d4cabcd..bd5a53354 100644 --- a/packages/stream_chat_persistence/CHANGELOG.md +++ b/packages/stream_chat_persistence/CHANGELOG.md @@ -102,8 +102,7 @@ ## 7.2.0-hotfix.1 -- Updated `stream_chat` dependency to [ - `7.2.0-hotfix.1`](https://pub.dev/packages/stream_chat/changelog). +- Updated `stream_chat` dependency to [`7.2.0-hotfix.1`](https://pub.dev/packages/stream_chat/changelog). ## 7.2.0 @@ -124,8 +123,7 @@ ## 7.0.0 - Updated minimum supported `SDK` version to Flutter 3.13/Dart 3.1 -- 🛑 **BREAKING** Removed deprecated `getChannelStates.sort` parameter. Use - `getChannelStates.channelStateSort` instead. +- 🛑 **BREAKING** Removed deprecated `getChannelStates.sort` parameter. Use `getChannelStates.channelStateSort` instead. ## 6.10.0 @@ -142,8 +140,7 @@ ## 6.7.0 -- [[#1683]](https://github.com/GetStream/stream-chat-flutter/issues/1683) Fixed SqliteException no - such column `messages.state`. +- [[#1683]](https://github.com/GetStream/stream-chat-flutter/issues/1683) Fixed SqliteException no such column `messages.state`. - Updated `stream_chat` dependency to [`6.7.0`](https://pub.dev/packages/stream_chat/changelog). ## 6.6.0 @@ -164,14 +161,12 @@ ## 6.2.0 -- Added support for `StreamChatPersistenceClient.isConnected` for checking if the client is - connected to the database. +- Added support for `StreamChatPersistenceClient.isConnected` for checking if the client is connected to the database. - [[#1422]](https://github.com/GetStream/stream-chat-flutter/issues/1422) Removed default values from `UserEntity` `createdAt` and `updatedAt` fields. - Updated `stream_chat` dependency to [`6.2.0`](https://pub.dev/packages/stream_chat/changelog). - Added support for `StreamChatPersistenceClient.openPersistenceConnection` - and `StreamChatPersistenceClient.closePersistenceConnection` for opening and closing the database - connection. + and `StreamChatPersistenceClient.closePersistenceConnection` for opening and closing the database connection. ## 6.1.0 @@ -199,8 +194,7 @@ ## 5.0.0-beta.1 -- Updated `stream_chat` dependency to [ - `5.0.0-beta.1`](https://pub.dev/packages/stream_chat/changelog). +- Updated `stream_chat` dependency to [`5.0.0-beta.1`](https://pub.dev/packages/stream_chat/changelog). ## 4.4.0 @@ -232,8 +226,7 @@ ## 4.0.0-beta.0 -- Updated `stream_chat` dependency to [ - `4.0.0-beta.0`](https://pub.dev/packages/stream_chat/changelog). +- Updated `stream_chat` dependency to [`4.0.0-beta.0`](https://pub.dev/packages/stream_chat/changelog). ## 3.1.0 @@ -242,10 +235,8 @@ ## 3.0.0 - Updated `stream_chat` dependency to [`3.0.0`](https://pub.dev/packages/stream_chat/changelog). -- [[#604]](https://github.com/GetStream/stream-chat-flutter/issues/604) Fix cascade deletion by - enabling `pragma foreign_keys`. -- Added a new table `PinnedMessageReactions` and dao `PinnedMessageReactionDao` specifically for - pinned messages. +- [[#604]](https://github.com/GetStream/stream-chat-flutter/issues/604) Fix cascade deletion by enabling `pragma foreign_keys`. +- Added a new table `PinnedMessageReactions` and dao `PinnedMessageReactionDao` specifically for pinned messages. ## 2.2.0 From 404ea7881cc4501ed6a2ef35d75c9d9c2818ed07 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 22 Jul 2025 18:06:37 +0200 Subject: [PATCH 06/10] chore: update doc --- .../lib/src/dao/draft_message_dao.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/stream_chat_persistence/lib/src/dao/draft_message_dao.dart b/packages/stream_chat_persistence/lib/src/dao/draft_message_dao.dart index 4caa740db..b5a5cb6fc 100644 --- a/packages/stream_chat_persistence/lib/src/dao/draft_message_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/draft_message_dao.dart @@ -103,8 +103,8 @@ class DraftMessageDao extends DatabaseAccessor return query.go(); } - /// Deletes all the poll votes whose [DraftMessages.channelCid] is - /// present in [cids] + /// Deletes all the draft messages by matching [DraftMessages.channelCid] + /// with the given list of [cids]. Future deleteDraftMessagesByCids(List cids) => (delete(draftMessages)..where((tbl) => tbl.channelCid.isIn(cids))).go(); } From 9fe01ca86e4b50c36dc49189a1413a3e1f4420e5 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 22 Jul 2025 18:09:26 +0200 Subject: [PATCH 07/10] chore: update schemaVersion --- .../stream_chat_persistence/lib/src/db/drift_chat_database.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat_persistence/lib/src/db/drift_chat_database.dart b/packages/stream_chat_persistence/lib/src/db/drift_chat_database.dart index c1aa21797..7aaeee4b2 100644 --- a/packages/stream_chat_persistence/lib/src/db/drift_chat_database.dart +++ b/packages/stream_chat_persistence/lib/src/db/drift_chat_database.dart @@ -55,7 +55,7 @@ class DriftChatDatabase extends _$DriftChatDatabase { // you should bump this number whenever you change or add a table definition. @override - int get schemaVersion => 21; + int get schemaVersion => 22; @override MigrationStrategy get migration => MigrationStrategy( From dfddf05f5b203eea269cee5bc143eec164847d4b Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 22 Jul 2025 19:07:11 +0200 Subject: [PATCH 08/10] test: add focused test for deleteDraftMessagesByCids method - Added single comprehensive test case for draft deletion by channel CIDs - Tests verify deletion of specified channels while preserving others - Covers core functionality without excessive test cases - All 13 tests in draft_message_dao_test.dart now passing --- .../test/src/dao/draft_message_dao_test.dart | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/packages/stream_chat_persistence/test/src/dao/draft_message_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/draft_message_dao_test.dart index 5ac947b87..15c8e48b2 100644 --- a/packages/stream_chat_persistence/test/src/dao/draft_message_dao_test.dart +++ b/packages/stream_chat_persistence/test/src/dao/draft_message_dao_test.dart @@ -343,6 +343,41 @@ void main() { ); }); + group('deleteDraftMessagesByCids', () { + test('should delete drafts for specified channel cids', () async { + const cid1 = 'test:deleteByCids1'; + const cid2 = 'test:deleteByCids2'; + const cid3 = 'test:deleteByCids3'; + + // Create drafts for multiple channels + await _prepareTestData(cid1, count: 1); + await _prepareTestData(cid2, count: 1); + await _prepareTestData(cid3, count: 1); + + // Verify all drafts exist + final draft1Before = await draftMessageDao.getDraftMessageByCid(cid1); + final draft2Before = await draftMessageDao.getDraftMessageByCid(cid2); + final draft3Before = await draftMessageDao.getDraftMessageByCid(cid3); + expect(draft1Before, isNotNull); + expect(draft2Before, isNotNull); + expect(draft3Before, isNotNull); + + // Delete drafts for cid1 and cid2 + await draftMessageDao.deleteDraftMessagesByCids([cid1, cid2]); + + // Verify drafts for cid1 and cid2 are deleted + final draft1After = await draftMessageDao.getDraftMessageByCid(cid1); + final draft2After = await draftMessageDao.getDraftMessageByCid(cid2); + expect(draft1After, isNull); + expect(draft2After, isNull); + + // Verify draft for cid3 still exists + final draft3After = await draftMessageDao.getDraftMessageByCid(cid3); + expect(draft3After, isNotNull); + expect(draft3After!.channelCid, cid3); + }); + }); + group('DraftMessages entity references', () { test( 'should delete draft messages when referenced channel is deleted', From bfba2878fbf14dcca450d78c5cbe220b5e38d066 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 22 Jul 2025 19:59:33 +0200 Subject: [PATCH 09/10] chore: revert some changes --- .../stream_chat_persistence/lib/src/dao/message_dao.dart | 6 +++--- .../lib/src/dao/pinned_message_dao.dart | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart index 570bbe6c9..8a947a742 100644 --- a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart @@ -59,10 +59,10 @@ class MessageDao extends DatabaseAccessor _ => null, }; - final draft = await switch ((fetchDraft, msgEntity.parentId)) { - (true, final parentId?) => _db.draftMessageDao.getDraftMessageByCid( + final draft = await switch (fetchDraft) { + true => _db.draftMessageDao.getDraftMessageByCid( msgEntity.channelCid, - parentId: parentId, + parentId: msgEntity.id, ), _ => null, }; diff --git a/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart b/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart index 9addb92ec..ac8576b33 100644 --- a/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart @@ -60,10 +60,10 @@ class PinnedMessageDao extends DatabaseAccessor _ => null, }; - final draft = await switch ((fetchDraft, msgEntity.parentId)) { - (true, final parentId?) => _db.draftMessageDao.getDraftMessageByCid( + final draft = await switch (fetchDraft) { + true => _db.draftMessageDao.getDraftMessageByCid( msgEntity.channelCid, - parentId: parentId, + parentId: msgEntity.id, ), _ => null, }; From cf2739c3aaaa398447c99f935c9cf6d929af4259 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 23 Jul 2025 14:57:18 +0200 Subject: [PATCH 10/10] chore: rename draftsToDelete variable for clarity --- .../stream_chat/lib/src/db/chat_persistence_client.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/stream_chat/lib/src/db/chat_persistence_client.dart b/packages/stream_chat/lib/src/db/chat_persistence_client.dart index 2353a847f..95439d574 100644 --- a/packages/stream_chat/lib/src/db/chat_persistence_client.dart +++ b/packages/stream_chat/lib/src/db/chat_persistence_client.dart @@ -290,7 +290,7 @@ abstract class ChatPersistenceClient { final pollVotesToDelete = []; final drafts = []; - final draftsToDelete = []; + final draftsToDeleteCids = []; for (final state in channelStates) { final channel = state.channel; @@ -316,7 +316,7 @@ abstract class ChatPersistenceClient { membersToDelete.add(cid); reactionsToDelete.addAll(messages?.map((it) => it.id) ?? []); pinnedReactionsToDelete.addAll(pinnedMessages?.map((it) => it.id) ?? []); - draftsToDelete.add(cid); + draftsToDeleteCids.add(cid); // preparing addition data channelWithReads[cid] = reads; @@ -362,7 +362,7 @@ abstract class ChatPersistenceClient { deleteReactionsByMessageId(reactionsToDelete), deletePinnedMessageReactionsByMessageId(pinnedReactionsToDelete), deletePollVotesByPollIds(pollVotesToDelete), - deleteDraftMessagesByCids(draftsToDelete), + deleteDraftMessagesByCids(draftsToDeleteCids), ]); // Updating first as does not depend on any other table.