Merge pull request #1619 from GetStream/feat/persistence-message-local-remote-sync
This commit is contained in:
@@ -1,3 +1,7 @@
|
||||
## Upcoming
|
||||
|
||||
- Updated `stream_chat` dependency to [`Upcoming`](https://pub.dev/packages/stream_chat/changelog).
|
||||
|
||||
## 6.3.0
|
||||
|
||||
- Updated `stream_chat` dependency to [`6.3.0`](https://pub.dev/packages/stream_chat/changelog).
|
||||
|
||||
@@ -5,7 +5,6 @@ import 'package:stream_chat/stream_chat.dart';
|
||||
import 'package:stream_chat_persistence/src/db/drift_chat_database.dart';
|
||||
import 'package:stream_chat_persistence/src/entity/messages.dart';
|
||||
import 'package:stream_chat_persistence/src/entity/users.dart';
|
||||
|
||||
import 'package:stream_chat_persistence/src/mapper/mapper.dart';
|
||||
|
||||
part 'message_dao.g.dart';
|
||||
|
||||
@@ -49,7 +49,7 @@ class DriftChatDatabase extends _$DriftChatDatabase {
|
||||
|
||||
// you should bump this number whenever you change or add a table definition.
|
||||
@override
|
||||
int get schemaVersion => 11;
|
||||
int get schemaVersion => 12;
|
||||
|
||||
@override
|
||||
MigrationStrategy get migration => MigrationStrategy(
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -53,14 +53,52 @@ class Messages extends Table {
|
||||
/// A used command name.
|
||||
TextColumn get command => text().nullable()();
|
||||
|
||||
/// The DateTime when the message was created.
|
||||
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
|
||||
/// The DateTime on which the message was created.
|
||||
///
|
||||
/// Returns the latest between [localCreatedAt] and [remoteCreatedAt].
|
||||
/// If both are null, returns [currentDateAndTime].
|
||||
Expression<DateTime> get createdAt {
|
||||
return coalesce<DateTime>(
|
||||
[localCreatedAt, remoteCreatedAt, currentDateAndTime],
|
||||
);
|
||||
}
|
||||
|
||||
/// The DateTime when the message was updated last time.
|
||||
DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)();
|
||||
/// The DateTime on which the message was created on the client.
|
||||
DateTimeColumn get localCreatedAt => dateTime().nullable()();
|
||||
|
||||
/// The DateTime when the message was deleted.
|
||||
DateTimeColumn get deletedAt => dateTime().nullable()();
|
||||
/// The DateTime on which the message was created on the server.
|
||||
DateTimeColumn get remoteCreatedAt => dateTime().nullable()();
|
||||
|
||||
/// The DateTime on which the message was updated last time.
|
||||
///
|
||||
/// Returns the latest between [localUpdatedAt] and [remoteUpdatedAt].
|
||||
/// If both are null, returns [createdAt].
|
||||
Expression<DateTime> get updatedAt {
|
||||
return coalesce<DateTime>(
|
||||
[localUpdatedAt, remoteUpdatedAt, createdAt],
|
||||
);
|
||||
}
|
||||
|
||||
/// The DateTime on which the message was updated on the client.
|
||||
DateTimeColumn get localUpdatedAt => dateTime().nullable()();
|
||||
|
||||
/// The DateTime on which the message was updated on the server.
|
||||
DateTimeColumn get remoteUpdatedAt => dateTime().nullable()();
|
||||
|
||||
/// The DateTime on which the message was deleted.
|
||||
///
|
||||
/// Returns the latest between [localDeletedAt] and [remoteDeletedAt].
|
||||
Expression<DateTime> get deletedAt {
|
||||
return coalesce<DateTime>(
|
||||
[localDeletedAt, remoteDeletedAt],
|
||||
);
|
||||
}
|
||||
|
||||
/// The DateTime on which the message was deleted on the client.
|
||||
DateTimeColumn get localDeletedAt => dateTime().nullable()();
|
||||
|
||||
/// The DateTime on which the message was deleted on the server.
|
||||
DateTimeColumn get remoteDeletedAt => dateTime().nullable()();
|
||||
|
||||
/// Id of the User who sent the message
|
||||
TextColumn get userId => text().nullable()();
|
||||
|
||||
@@ -21,9 +21,13 @@ extension MessageEntityX on MessageEntity {
|
||||
final json = jsonDecode(it);
|
||||
return Attachment.fromData(json);
|
||||
}).toList(),
|
||||
createdAt: createdAt,
|
||||
extraData: extraData ?? <String, Object>{},
|
||||
updatedAt: updatedAt,
|
||||
createdAt: remoteCreatedAt,
|
||||
localCreatedAt: localCreatedAt,
|
||||
updatedAt: remoteUpdatedAt,
|
||||
localUpdatedAt: localUpdatedAt,
|
||||
deletedAt: remoteDeletedAt,
|
||||
localDeletedAt: localDeletedAt,
|
||||
id: id,
|
||||
type: type,
|
||||
status: status,
|
||||
@@ -37,7 +41,6 @@ extension MessageEntityX on MessageEntity {
|
||||
showInChannel: showInChannel,
|
||||
text: messageText,
|
||||
user: user,
|
||||
deletedAt: deletedAt,
|
||||
pinned: pinned,
|
||||
pinnedAt: pinnedAt,
|
||||
pinExpires: pinExpires,
|
||||
@@ -59,7 +62,8 @@ extension MessageX on Message {
|
||||
parentId: parentId,
|
||||
quotedMessageId: quotedMessageId,
|
||||
command: command,
|
||||
createdAt: createdAt,
|
||||
remoteCreatedAt: remoteCreatedAt,
|
||||
localCreatedAt: localCreatedAt,
|
||||
shadowed: shadowed,
|
||||
showInChannel: showInChannel,
|
||||
replyCount: replyCount,
|
||||
@@ -67,10 +71,12 @@ extension MessageX on Message {
|
||||
reactionCounts: reactionCounts,
|
||||
mentionedUsers: mentionedUsers.map(jsonEncode).toList(),
|
||||
status: status,
|
||||
updatedAt: updatedAt,
|
||||
remoteUpdatedAt: remoteUpdatedAt,
|
||||
localUpdatedAt: localUpdatedAt,
|
||||
extraData: extraData,
|
||||
userId: user?.id,
|
||||
deletedAt: deletedAt,
|
||||
remoteDeletedAt: remoteDeletedAt,
|
||||
localDeletedAt: localDeletedAt,
|
||||
messageText: text,
|
||||
pinned: pinned,
|
||||
pinnedAt: pinnedAt,
|
||||
|
||||
@@ -21,9 +21,13 @@ extension PinnedMessageEntityX on PinnedMessageEntity {
|
||||
final json = jsonDecode(it);
|
||||
return Attachment.fromData(json);
|
||||
}).toList(),
|
||||
createdAt: createdAt,
|
||||
extraData: extraData ?? <String, Object>{},
|
||||
updatedAt: updatedAt,
|
||||
createdAt: remoteCreatedAt,
|
||||
localCreatedAt: localCreatedAt,
|
||||
updatedAt: remoteUpdatedAt,
|
||||
localUpdatedAt: localUpdatedAt,
|
||||
deletedAt: remoteDeletedAt,
|
||||
localDeletedAt: localDeletedAt,
|
||||
id: id,
|
||||
type: type,
|
||||
status: status,
|
||||
@@ -37,7 +41,6 @@ extension PinnedMessageEntityX on PinnedMessageEntity {
|
||||
showInChannel: showInChannel,
|
||||
text: messageText,
|
||||
user: user,
|
||||
deletedAt: deletedAt,
|
||||
pinned: pinned,
|
||||
pinnedAt: pinnedAt,
|
||||
pinExpires: pinExpires,
|
||||
@@ -60,7 +63,8 @@ extension PMessageX on Message {
|
||||
parentId: parentId,
|
||||
quotedMessageId: quotedMessageId,
|
||||
command: command,
|
||||
createdAt: createdAt,
|
||||
remoteCreatedAt: remoteCreatedAt,
|
||||
localCreatedAt: localCreatedAt,
|
||||
shadowed: shadowed,
|
||||
showInChannel: showInChannel,
|
||||
replyCount: replyCount,
|
||||
@@ -68,10 +72,12 @@ extension PMessageX on Message {
|
||||
reactionCounts: reactionCounts,
|
||||
mentionedUsers: mentionedUsers.map(jsonEncode).toList(),
|
||||
status: status,
|
||||
updatedAt: updatedAt,
|
||||
remoteUpdatedAt: remoteUpdatedAt,
|
||||
localUpdatedAt: localUpdatedAt,
|
||||
extraData: extraData,
|
||||
userId: user?.id,
|
||||
deletedAt: deletedAt,
|
||||
remoteDeletedAt: remoteDeletedAt,
|
||||
localDeletedAt: localDeletedAt,
|
||||
messageText: text,
|
||||
pinned: pinned,
|
||||
pinnedAt: pinnedAt,
|
||||
|
||||
@@ -38,7 +38,8 @@ void main() {
|
||||
parentId: 'testParentId',
|
||||
quotedMessageId: quotedMessage.id,
|
||||
command: 'testCommand',
|
||||
createdAt: DateTime.now(),
|
||||
localCreatedAt: DateTime.now(),
|
||||
remoteCreatedAt: DateTime.now().add(const Duration(seconds: 1)),
|
||||
shadowed: math.Random().nextBool(),
|
||||
showInChannel: math.Random().nextBool(),
|
||||
replyCount: 33,
|
||||
@@ -52,10 +53,12 @@ void main() {
|
||||
jsonEncode(User(id: 'testuser')),
|
||||
],
|
||||
status: MessageSendingStatus.sent,
|
||||
updatedAt: DateTime.now(),
|
||||
localUpdatedAt: DateTime.now(),
|
||||
remoteUpdatedAt: DateTime.now().add(const Duration(seconds: 1)),
|
||||
extraData: {'extra_test_data': 'extraData'},
|
||||
userId: user.id,
|
||||
deletedAt: DateTime.now(),
|
||||
localDeletedAt: DateTime.now(),
|
||||
remoteDeletedAt: DateTime.now().add(const Duration(seconds: 1)),
|
||||
messageText: 'Hello',
|
||||
pinned: true,
|
||||
pinExpires: DateTime.now().toUtc(),
|
||||
@@ -81,7 +84,8 @@ void main() {
|
||||
expect(message.parentId, entity.parentId);
|
||||
expect(message.quotedMessageId, entity.quotedMessageId);
|
||||
expect(message.command, entity.command);
|
||||
expect(message.createdAt, isSameDateAs(entity.createdAt));
|
||||
expect(message.localCreatedAt, isSameDateAs(entity.localCreatedAt));
|
||||
expect(message.remoteCreatedAt, isSameDateAs(entity.remoteCreatedAt));
|
||||
expect(message.shadowed, entity.shadowed);
|
||||
expect(message.showInChannel, entity.showInChannel);
|
||||
for (var i = 0; i < message.mentionedUsers.length; i++) {
|
||||
@@ -93,10 +97,12 @@ void main() {
|
||||
expect(message.reactionScores, entity.reactionScores);
|
||||
expect(message.reactionCounts, entity.reactionCounts);
|
||||
expect(message.status, entity.status);
|
||||
expect(message.updatedAt, isSameDateAs(entity.updatedAt));
|
||||
expect(message.localUpdatedAt, isSameDateAs(entity.localUpdatedAt));
|
||||
expect(message.remoteUpdatedAt, isSameDateAs(entity.remoteUpdatedAt));
|
||||
expect(message.extraData, entity.extraData);
|
||||
expect(message.user!.id, entity.userId);
|
||||
expect(message.deletedAt, isSameDateAs(entity.deletedAt));
|
||||
expect(message.localDeletedAt, isSameDateAs(entity.localDeletedAt));
|
||||
expect(message.remoteDeletedAt, isSameDateAs(entity.remoteDeletedAt));
|
||||
expect(message.text, entity.messageText);
|
||||
expect(message.pinned, entity.pinned);
|
||||
expect(message.pinExpires, isSameDateAs(entity.pinExpires));
|
||||
@@ -144,7 +150,8 @@ void main() {
|
||||
parentId: 'testParentId',
|
||||
quotedMessageId: quotedMessage.id,
|
||||
command: 'testCommand',
|
||||
createdAt: DateTime.now(),
|
||||
localCreatedAt: DateTime.now(),
|
||||
createdAt: DateTime.now().add(const Duration(seconds: 1)),
|
||||
shadowed: math.Random().nextBool(),
|
||||
showInChannel: math.Random().nextBool(),
|
||||
replyCount: 33,
|
||||
@@ -157,10 +164,12 @@ void main() {
|
||||
(prev, curr) =>
|
||||
prev?..update(curr.type, (value) => value + 1, ifAbsent: () => 1),
|
||||
),
|
||||
updatedAt: DateTime.now(),
|
||||
localUpdatedAt: DateTime.now(),
|
||||
updatedAt: DateTime.now().add(const Duration(seconds: 1)),
|
||||
extraData: const {'extra_test_data': 'extraData'},
|
||||
user: user,
|
||||
deletedAt: DateTime.now(),
|
||||
localDeletedAt: DateTime.now(),
|
||||
deletedAt: DateTime.now().add(const Duration(seconds: 1)),
|
||||
text: 'Hello',
|
||||
pinned: true,
|
||||
pinExpires: DateTime.now(),
|
||||
@@ -179,7 +188,8 @@ void main() {
|
||||
expect(entity.parentId, message.parentId);
|
||||
expect(entity.quotedMessageId, message.quotedMessageId);
|
||||
expect(entity.command, message.command);
|
||||
expect(entity.createdAt, isSameDateAs(message.createdAt));
|
||||
expect(entity.localCreatedAt, isSameDateAs(message.localCreatedAt));
|
||||
expect(entity.remoteCreatedAt, isSameDateAs(message.remoteCreatedAt));
|
||||
expect(entity.shadowed, message.shadowed);
|
||||
expect(entity.showInChannel, message.showInChannel);
|
||||
expect(entity.replyCount, message.replyCount);
|
||||
@@ -188,10 +198,12 @@ void main() {
|
||||
expect(entity.reactionScores, message.reactionScores);
|
||||
expect(entity.reactionCounts, message.reactionCounts);
|
||||
expect(entity.status, message.status);
|
||||
expect(entity.updatedAt, isSameDateAs(message.updatedAt));
|
||||
expect(entity.localUpdatedAt, isSameDateAs(message.localUpdatedAt));
|
||||
expect(entity.remoteUpdatedAt, isSameDateAs(message.remoteUpdatedAt));
|
||||
expect(entity.extraData, message.extraData);
|
||||
expect(entity.userId, message.user!.id);
|
||||
expect(entity.deletedAt, isSameDateAs(message.deletedAt));
|
||||
expect(entity.localDeletedAt, isSameDateAs(message.localDeletedAt));
|
||||
expect(entity.remoteDeletedAt, isSameDateAs(message.remoteDeletedAt));
|
||||
expect(entity.messageText, message.text);
|
||||
expect(entity.pinned, message.pinned);
|
||||
expect(entity.pinExpires, isSameDateAs(message.pinExpires));
|
||||
|
||||
@@ -38,7 +38,8 @@ void main() {
|
||||
parentId: 'testParentId',
|
||||
quotedMessageId: quotedMessage.id,
|
||||
command: 'testCommand',
|
||||
createdAt: DateTime.now(),
|
||||
localCreatedAt: DateTime.now(),
|
||||
remoteCreatedAt: DateTime.now().add(const Duration(seconds: 1)),
|
||||
shadowed: math.Random().nextBool(),
|
||||
showInChannel: math.Random().nextBool(),
|
||||
replyCount: 33,
|
||||
@@ -48,12 +49,16 @@ void main() {
|
||||
(prev, curr) =>
|
||||
prev?..update(curr.type, (value) => value + 1, ifAbsent: () => 1),
|
||||
),
|
||||
mentionedUsers: [],
|
||||
mentionedUsers: [
|
||||
jsonEncode(User(id: 'testuser')),
|
||||
],
|
||||
status: MessageSendingStatus.sent,
|
||||
updatedAt: DateTime.now(),
|
||||
localUpdatedAt: DateTime.now(),
|
||||
remoteUpdatedAt: DateTime.now().add(const Duration(seconds: 1)),
|
||||
extraData: {'extra_test_data': 'extraData'},
|
||||
userId: user.id,
|
||||
deletedAt: DateTime.now(),
|
||||
localDeletedAt: DateTime.now(),
|
||||
remoteDeletedAt: DateTime.now().add(const Duration(seconds: 1)),
|
||||
messageText: 'Hello',
|
||||
pinned: true,
|
||||
pinExpires: DateTime.now().toUtc(),
|
||||
@@ -79,17 +84,25 @@ void main() {
|
||||
expect(message.parentId, entity.parentId);
|
||||
expect(message.quotedMessageId, entity.quotedMessageId);
|
||||
expect(message.command, entity.command);
|
||||
expect(message.createdAt, isSameDateAs(entity.createdAt));
|
||||
expect(message.localCreatedAt, isSameDateAs(entity.localCreatedAt));
|
||||
expect(message.remoteCreatedAt, isSameDateAs(entity.remoteCreatedAt));
|
||||
expect(message.shadowed, entity.shadowed);
|
||||
expect(message.showInChannel, entity.showInChannel);
|
||||
for (var i = 0; i < message.mentionedUsers.length; i++) {
|
||||
final entityMentionedUser =
|
||||
User.fromJson(jsonDecode(entity.mentionedUsers[i]));
|
||||
expect(message.mentionedUsers[i].id, entityMentionedUser.id);
|
||||
}
|
||||
expect(message.replyCount, entity.replyCount);
|
||||
expect(message.reactionScores, entity.reactionScores);
|
||||
expect(message.reactionCounts, entity.reactionCounts);
|
||||
expect(message.status, entity.status);
|
||||
expect(message.updatedAt, isSameDateAs(entity.updatedAt));
|
||||
expect(message.localUpdatedAt, isSameDateAs(entity.localUpdatedAt));
|
||||
expect(message.remoteUpdatedAt, isSameDateAs(entity.remoteUpdatedAt));
|
||||
expect(message.extraData, entity.extraData);
|
||||
expect(message.user!.id, entity.userId);
|
||||
expect(message.deletedAt, isSameDateAs(entity.deletedAt));
|
||||
expect(message.localDeletedAt, isSameDateAs(entity.localDeletedAt));
|
||||
expect(message.remoteDeletedAt, isSameDateAs(entity.remoteDeletedAt));
|
||||
expect(message.text, entity.messageText);
|
||||
expect(message.pinned, entity.pinned);
|
||||
expect(message.pinExpires, isSameDateAs(entity.pinExpires));
|
||||
@@ -108,7 +121,7 @@ void main() {
|
||||
}
|
||||
});
|
||||
|
||||
test('toPinnedEntity should map message into PinnedMessageEntity', () {
|
||||
test('toEntity should map message into MessageEntity', () {
|
||||
const cid = 'testCid';
|
||||
final user = User(id: 'testUserId');
|
||||
final quotedMessage = Message(id: 'testQuotedMessageId');
|
||||
@@ -137,20 +150,26 @@ void main() {
|
||||
parentId: 'testParentId',
|
||||
quotedMessageId: quotedMessage.id,
|
||||
command: 'testCommand',
|
||||
createdAt: DateTime.now(),
|
||||
localCreatedAt: DateTime.now(),
|
||||
createdAt: DateTime.now().add(const Duration(seconds: 1)),
|
||||
shadowed: math.Random().nextBool(),
|
||||
showInChannel: math.Random().nextBool(),
|
||||
replyCount: 33,
|
||||
mentionedUsers: [
|
||||
User(id: 'testuser'),
|
||||
],
|
||||
reactionScores: {for (final r in reactions) r.type: r.score},
|
||||
reactionCounts: reactions.fold(
|
||||
{},
|
||||
(prev, curr) =>
|
||||
prev?..update(curr.type, (value) => value + 1, ifAbsent: () => 1),
|
||||
),
|
||||
updatedAt: DateTime.now(),
|
||||
localUpdatedAt: DateTime.now(),
|
||||
updatedAt: DateTime.now().add(const Duration(seconds: 1)),
|
||||
extraData: const {'extra_test_data': 'extraData'},
|
||||
user: user,
|
||||
deletedAt: DateTime.now(),
|
||||
localDeletedAt: DateTime.now(),
|
||||
deletedAt: DateTime.now().add(const Duration(seconds: 1)),
|
||||
text: 'Hello',
|
||||
pinned: true,
|
||||
pinExpires: DateTime.now(),
|
||||
@@ -169,17 +188,22 @@ void main() {
|
||||
expect(entity.parentId, message.parentId);
|
||||
expect(entity.quotedMessageId, message.quotedMessageId);
|
||||
expect(entity.command, message.command);
|
||||
expect(entity.createdAt, isSameDateAs(message.createdAt));
|
||||
expect(entity.localCreatedAt, isSameDateAs(message.localCreatedAt));
|
||||
expect(entity.remoteCreatedAt, isSameDateAs(message.remoteCreatedAt));
|
||||
expect(entity.shadowed, message.shadowed);
|
||||
expect(entity.showInChannel, message.showInChannel);
|
||||
expect(entity.replyCount, message.replyCount);
|
||||
expect(
|
||||
entity.mentionedUsers, message.mentionedUsers.map(jsonEncode).toList());
|
||||
expect(entity.reactionScores, message.reactionScores);
|
||||
expect(entity.reactionCounts, message.reactionCounts);
|
||||
expect(entity.status, message.status);
|
||||
expect(entity.updatedAt, isSameDateAs(message.updatedAt));
|
||||
expect(entity.localUpdatedAt, isSameDateAs(message.localUpdatedAt));
|
||||
expect(entity.remoteUpdatedAt, isSameDateAs(message.remoteUpdatedAt));
|
||||
expect(entity.extraData, message.extraData);
|
||||
expect(entity.userId, message.user!.id);
|
||||
expect(entity.deletedAt, isSameDateAs(message.deletedAt));
|
||||
expect(entity.localDeletedAt, isSameDateAs(message.localDeletedAt));
|
||||
expect(entity.remoteDeletedAt, isSameDateAs(message.remoteDeletedAt));
|
||||
expect(entity.messageText, message.text);
|
||||
expect(entity.pinned, message.pinned);
|
||||
expect(entity.pinExpires, isSameDateAs(message.pinExpires));
|
||||
|
||||
Reference in New Issue
Block a user