Skip to content

Commit ad4ed9b

Browse files
Merge master to v10.0.0 (08.06.2026) (#2731)
* perf(persistence): Reduce the number of read message per channel from DB when paginating (part 1) (#2679) * refactor(dao): Filter reactions by userId at DB level. * refactor(dao): Filter reactions by userId at DB level (pinned messages). * refactor(dao): optimize message retrieval with SQL-side pagination filters * refactor(dao): fix formatting * refactor(dao): Update CHANGELOG.md * refactor(dao): Apply formatting * refactor(dao): enhance message pagination logic to support inclusive cursors * refactor(dao): Update docs * refactor(dao): Add message.id tiebreakier * refactor(dao): Add message.id tiebreaker * refactor(dao): Update CHANGELOG.md * perf(persistence): Reduce the number of read message per channel from DB when paginating (part 2) (#2681) * refactor(dao): Filter reactions by userId at DB level. * refactor(dao): Filter reactions by userId at DB level (pinned messages). * refactor(dao): optimize message retrieval with SQL-side pagination filters * refactor(dao): fix formatting * refactor(dao): Update CHANGELOG.md * refactor(dao): Apply formatting * refactor(dao): optimize message and reaction retrieval with grouped queries * refactor(dao): add tests for new methods * refactor(dao): enhance message pagination logic to support inclusive cursors * refactor(dao): Update docs * refactor(dao): Remove legacy method * refactor(dao): Remove legacy method * refactor(dao): Remove legacy method * refactor(dao): Fix warnings * refactor(dao): Add message.id tiebreakier * refactor(dao): Add message.id tiebreaker * refactor(dao): Update CHANGELOG.md * fix(persistence): Prevent fetching drafts/quotes for quoted messages. * chore(repo): release v9.25.0 (#2730) * feat(persistence): Add batched getLocationsByMessageIds. * Clean-up location dao. * Fix formatting. * Fix PR remarks. --------- Co-authored-by: Sahil Kumar <xdsahil@gmail.com>
1 parent 86d1c6d commit ad4ed9b

23 files changed

Lines changed: 2698 additions & 229 deletions

packages/stream_chat/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@
3434
- Fixed quoted poll messages losing their poll, shared-location, or nested-quote content when the server omits it from the `quoted_message` payload during channel re-sync.
3535
- Fixed a poll attached to a parent message disappearing when a thread reply was added; partial `message.updated` events no longer clobber locally-known `poll` / `sharedLocation` on the parent.
3636

37+
## 9.25.0
38+
39+
- Minor bug fixes and improvements
40+
3741
## 9.24.0
3842

3943
🔒 Security

packages/stream_chat_flutter/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@
155155
- Fixed tapping a quoted parent message inside a thread doing nothing (or kicking back to the channel). The thread message list now resolves the parent slot directly and scrolls/highlights it instead of falling through to `loadChannelAtMessage`.
156156
- Fixed the jump-to-message highlight starting before the scroll settled, which made the fade barely visible (or invisible if the target hadn't been mounted yet). The message list now awaits the scroll, then plays a 1s hold + 1s ease-out fade — closer to the highlight feel in Slack's permalink jump.
157157

158-
## Upcoming Changes
158+
## 9.25.0
159159

160160
🐞 Fixed
161161

packages/stream_chat_flutter_core/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
- Fixed `StreamChatCore` disconnecting the WebSocket immediately on background when no `onBackgroundEventReceived` handler was provided; the keep-alive timer now fires before the connection closes regardless of whether a handler is set.
3333
- Fixed `StreamMessageComposerController.cancelEditMessage` losing the pre-edit draft when a remote update arrived for the message being edited.
3434

35-
## Upcoming Changes
35+
## 9.25.0
3636

3737
✅ Added
3838

packages/stream_chat_localizations/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@
5858
- Reworded `flagLabel`, `cancelLabel` and `deleteLabel` defaults from uppercase to sentence case across all supported locales (e.g. English: `'FLAG'``'Flag'`, `'CANCEL'``'Cancel'`, `'DELETE'``'Delete'`) so dialog buttons render in the same case as the rest of the system.
5959
- Raised minimum Flutter to `>=3.41.0` and Dart SDK to `^3.11.0`.
6060

61+
## 9.25.0
62+
63+
- Updated `stream_chat_flutter` dependency to [`9.25.0`](https://pub.dev/packages/stream_chat_flutter/changelog).
64+
6165
## 9.24.0
6266

6367
- Updated `stream_chat_flutter` dependency to [`9.24.0`](https://pub.dev/packages/stream_chat_flutter/changelog).

packages/stream_chat_persistence/CHANGELOG.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,21 @@
99

1010
- Fixed channel list re-sorting on refresh or when returning from background.
1111

12-
# Upcoming
12+
## 9.25.0
1313

1414
🚀 Performance
1515

1616
- Reduce the number of DB reads in the `ChatPersistenceClient.getChannelStates` method.
17+
- Read only the messages matching the `PaginationParams` from DB when calling `MessageDao.getMessagesByCid` instead of reading all messages for the channel and applying pagination in memory.
18+
- Read only the reactions matching the `userId` from DB when calling `ReactionDao.getReactionsByUserId` instead of reading all reactions for the message and filtering in memory.
19+
- Read only the reactions matching the `userId` from DB when calling `PinnedMessageReactionDao.getReactionsByUserId` instead of reading all reactions for the message and filtering in memory.
20+
- Improve the message read times from DB.
1721

18-
🐛 Fixed
22+
🐞 Fixed
1923

24+
- `MessageDao.getMessagesByCid` now honours `PaginationParams.lessThanOrEqual` and `PaginationParams.greaterThanOrEqual` (inclusive of the cursor message), in addition to the existing strict `lessThan`/`greaterThan`.
25+
- `MessageDao.getMessagesByCid` now treats `PaginationParams.greaterThan` as strict (exclusive of the cursor), matching the `PaginationParams` contract and the existing `lessThan` behaviour.
26+
- `MessageDao.getMessagesByCid` with a forward cursor (`greaterThan`/`greaterThanOrEqual`) and a `limit` now returns the messages immediately AFTER the pivot, instead of the channel tail — mirroring how `lessThan` already returned the messages immediately before the pivot.
2027
- Fixed missing persistence of the `team` field on channel entities.
2128

2229
🔄 Changed

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import 'package:drift/drift.dart';
44
import 'package:stream_chat/stream_chat.dart';
55
import 'package:stream_chat_persistence/src/db/drift_chat_database.dart';
6+
import 'package:stream_chat_persistence/src/db/query_utils.dart';
67
import 'package:stream_chat_persistence/src/entity/entity.dart';
78
import 'package:stream_chat_persistence/src/mapper/mapper.dart';
89

@@ -74,6 +75,26 @@ class DraftMessageDao extends DatabaseAccessor<DriftChatDatabase> with _$DraftMe
7475
return _draftFromEntity(result);
7576
}
7677

78+
/// Returns thread drafts in [cid] for every parent message id in
79+
/// [parentIds], keyed by parent message id.
80+
Future<Map<String, Draft?>> getDraftMessagesByParentIds(
81+
String cid,
82+
List<String> parentIds,
83+
) async {
84+
if (parentIds.isEmpty) return const {};
85+
final result = <String, Draft?>{for (final id in parentIds) id: null};
86+
for (final chunk in chunked(parentIds)) {
87+
final query = select(draftMessages)..where((tbl) => tbl.channelCid.equals(cid) & tbl.parentId.isIn(chunk));
88+
final entities = await query.get();
89+
for (final entity in entities) {
90+
if (entity.parentId case final pid?) {
91+
result[pid] = await _draftFromEntity(entity);
92+
}
93+
}
94+
}
95+
return result;
96+
}
97+
7798
/// Updates the draft message data of a particular channel with
7899
/// the new [messageList] data.
79100
Future<void> updateDraftMessages(List<Draft> draftMessageList) {

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

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import 'package:drift/drift.dart';
44
import 'package:stream_chat/stream_chat.dart';
55
import 'package:stream_chat_persistence/src/db/drift_chat_database.dart';
6+
import 'package:stream_chat_persistence/src/db/query_utils.dart';
67
import 'package:stream_chat_persistence/src/entity/locations.dart';
78
import 'package:stream_chat_persistence/src/mapper/mapper.dart';
89

@@ -63,6 +64,38 @@ class LocationDao extends DatabaseAccessor<DriftChatDatabase> with _$LocationDao
6364
return _locationFromEntity(result);
6465
}
6566

67+
/// Returns the shared location for every id in [messageIds], keyed by
68+
/// message id. Messages with no associated location are absent from the
69+
/// map.
70+
///
71+
/// Returned `Location`s do not populate `Location.message` /
72+
/// `Location.channel`. The batched method is consumed by
73+
/// `MessageDao._messagesFromJoinRows`, which attaches the result as
74+
/// `Message.sharedLocation` on the message it is currently assembling —
75+
/// the linked fields would just be redundant copies of the parent Message
76+
/// and Channel. Hydrating them here would also re-enter
77+
/// `MessageDao.getMessageById` and open a cycle through quoted-message
78+
/// resolution whenever any link in the chain has a location. Consumers
79+
/// that need the linked `message` / `channel` should use
80+
/// [getLocationByMessageId] or [getLocationsByCid].
81+
Future<Map<String, Location>> getLocationsByMessageIds(
82+
List<String> messageIds,
83+
) async {
84+
if (messageIds.isEmpty) return const {};
85+
final result = <String, Location>{};
86+
for (final chunk in chunked(messageIds)) {
87+
final query = select(locations)..where((tbl) => tbl.messageId.isIn(chunk));
88+
final entities = await query.get();
89+
for (final entity in entities) {
90+
if (entity.messageId case final id?) {
91+
// Don't enrich message/channel (see method doc)
92+
result[id] = entity.toLocation();
93+
}
94+
}
95+
}
96+
return result;
97+
}
98+
6699
/// Update multiple locations
67100
Future<void> updateLocations(List<Location> locationList) {
68101
return batch(

0 commit comments

Comments
 (0)