Merge pull request #401 from GetStream/persistence-nnbd

feat: migrate persistence to nnbd
This commit is contained in:
Salvatore Giordano
2021-04-21 11:06:24 +02:00
committed by GitHub
69 changed files with 2003 additions and 2071 deletions
@@ -620,7 +620,7 @@ class Channel {
Future<SendReactionResponse> sendReaction( Future<SendReactionResponse> sendReaction(
Message message, Message message,
String type, { String type, {
Map<String, dynamic> extraData = const {}, Map<String, Object> extraData = const {},
bool enforceUnique = false, bool enforceUnique = false,
}) async { }) async {
_checkInitialized(); _checkInitialized();
@@ -209,7 +209,7 @@ class GetMessageResponse extends _BaseResponse {
final res = _$GetMessageResponseFromJson(json); final res = _$GetMessageResponseFromJson(json);
final jsonChannel = res.message.extraData.remove('channel'); final jsonChannel = res.message.extraData.remove('channel');
if (jsonChannel != null) { if (jsonChannel != null) {
res.channel = ChannelModel.fromJson(jsonChannel); res.channel = ChannelModel.fromJson(jsonChannel as Map<String, dynamic>);
} }
return res; return res;
} }
@@ -7,6 +7,7 @@ import 'package:stream_chat/src/models/message.dart';
import 'package:stream_chat/src/models/reaction.dart'; import 'package:stream_chat/src/models/reaction.dart';
import 'package:stream_chat/src/models/read.dart'; import 'package:stream_chat/src/models/read.dart';
import 'package:stream_chat/src/models/user.dart'; import 'package:stream_chat/src/models/user.dart';
import 'package:stream_chat/src/extensions/iterable_extension.dart';
/// A simple client used for persisting chat data locally. /// A simple client used for persisting chat data locally.
abstract class ChatPersistenceClient { abstract class ChatPersistenceClient {
@@ -24,10 +25,10 @@ abstract class ChatPersistenceClient {
}); });
/// Get stored connection event /// Get stored connection event
Future<Event> getConnectionInfo(); Future<Event?> getConnectionInfo();
/// Get stored lastSyncAt /// Get stored lastSyncAt
Future<DateTime> getLastSyncAt(); Future<DateTime?> getLastSyncAt();
/// Update stored connection event /// Update stored connection event
Future<void> updateConnectionInfo(Event event); Future<void> updateConnectionInfo(Event event);
@@ -39,7 +40,7 @@ abstract class ChatPersistenceClient {
Future<List<String>> getChannelCids(); Future<List<String>> getChannelCids();
/// Get stored [ChannelModel]s by providing channel [cid] /// Get stored [ChannelModel]s by providing channel [cid]
Future<ChannelModel> getChannelByCid(String cid); Future<ChannelModel?> getChannelByCid(String cid);
/// Get stored channel [Member]s by providing channel [cid] /// Get stored channel [Member]s by providing channel [cid]
Future<List<Member>> getMembersByCid(String cid); Future<List<Member>> getMembersByCid(String cid);
@@ -78,7 +79,7 @@ abstract class ChatPersistenceClient {
return ChannelState( return ChannelState(
members: data[0] as List<Member>, members: data[0] as List<Member>,
read: data[1] as List<Read>, read: data[1] as List<Read>,
channel: data[2] as ChannelModel, channel: data[2] as ChannelModel?,
messages: data[3] as List<Message>, messages: data[3] as List<Message>,
pinnedMessages: data[4] as List<Message>, pinnedMessages: data[4] as List<Message>,
); );
@@ -90,7 +91,7 @@ abstract class ChatPersistenceClient {
/// for filtering out states. /// for filtering out states.
Future<List<ChannelState>> getChannelStates({ Future<List<ChannelState>> getChannelStates({
Map<String, dynamic>? filter, Map<String, dynamic>? filter,
List<SortOption<ChannelModel>>? sort = const [], List<SortOption<ChannelModel>>? sort,
PaginationParams? paginationParams, PaginationParams? paginationParams,
}); });
@@ -192,17 +193,17 @@ abstract class ChatPersistenceClient {
deleteMembers, deleteMembers,
]); ]);
final channels = cleanedChannelStates final channels = cleanedChannelStates.map((it) => it.channel).withNullifyer;
.map((it) => it.channel)
.where((it) => it != null) as Iterable<ChannelModel>;
final reactions = final reactions = cleanedChannelStates
cleanedChannelStates.expand((it) => it.messages).expand((it) => [ .expand((it) => it.messages)
.expand((it) => [
if (it.ownReactions != null) if (it.ownReactions != null)
...it.ownReactions!.where((r) => r.userId != null), ...it.ownReactions!.where((r) => r.userId != null),
if (it.latestReactions != null) if (it.latestReactions != null)
...it.latestReactions!.where((r) => r.userId != null), ...it.latestReactions!.where((r) => r.userId != null),
]); ])
.withNullifyer;
final users = cleanedChannelStates final users = cleanedChannelStates
.map((cs) => [ .map((cs) => [
@@ -220,7 +221,7 @@ abstract class ChatPersistenceClient {
...cs.members.map((m) => m.user), ...cs.members.map((m) => m.user),
]) ])
.expand((it) => it) .expand((it) => it)
.where((it) => it != null) as Iterable<User>; .withNullifyer;
final updateMessagesFuture = cleanedChannelStates.map((it) { final updateMessagesFuture = cleanedChannelStates.map((it) {
final cid = it.channel!.cid; final cid = it.channel!.cid;
@@ -0,0 +1,9 @@
/// Useful extension functions for [Iterable]
extension IterableX<T> on Iterable<T?> {
/// Removes all the null values
/// and converts `Iterable<T?>` into `Iterable<T>`
Iterable<T> get withNullifyer => [
for (final item in this)
if (item != null) item
];
}
@@ -111,7 +111,7 @@ class Attachment extends Equatable {
/// Map of custom channel extraData /// Map of custom channel extraData
@JsonKey(includeIfNull: false) @JsonKey(includeIfNull: false)
final Map<String, dynamic>? extraData; final Map<String, Object>? extraData;
/// The attachment ID. /// The attachment ID.
/// ///
@@ -180,7 +180,7 @@ class Attachment extends Equatable {
List<Action>? actions, List<Action>? actions,
AttachmentFile? file, AttachmentFile? file,
UploadState? uploadState, UploadState? uploadState,
Map<String, dynamic>? extraData, Map<String, Object>? extraData,
}) => }) =>
Attachment( Attachment(
id: id ?? this.id, id: id ?? this.id,
@@ -30,7 +30,9 @@ Attachment _$AttachmentFromJson(Map<String, dynamic> json) {
?.map((e) => Action.fromJson(e as Map<String, dynamic>)) ?.map((e) => Action.fromJson(e as Map<String, dynamic>))
.toList() ?? .toList() ??
[], [],
extraData: json['extra_data'] as Map<String, dynamic>?, extraData: (json['extra_data'] as Map<String, dynamic>?)?.map(
(k, e) => MapEntry(k, e as Object),
),
file: json['file'] == null file: json['file'] == null
? null ? null
: AttachmentFile.fromJson(json['file'] as Map<String, dynamic>), : AttachmentFile.fromJson(json['file'] as Map<String, dynamic>),
@@ -84,7 +84,7 @@ class ChannelModel {
/// Map of custom channel extraData /// Map of custom channel extraData
@JsonKey(includeIfNull: false) @JsonKey(includeIfNull: false)
final Map<String, dynamic>? extraData; final Map<String, Object>? extraData;
/// The team the channel belongs to /// The team the channel belongs to
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly) @JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
@@ -108,8 +108,9 @@ class ChannelModel {
]; ];
/// Shortcut for channel name /// Shortcut for channel name
String? get name => String get name => extraData?.containsKey('name') == true
extraData?.containsKey('name') == true ? extraData!['name'] : cid; ? extraData!['name'] as String
: cid;
/// Serialize to json /// Serialize to json
Map<String, dynamic> toJson() => Serialization.moveFromExtraDataToRoot( Map<String, dynamic> toJson() => Serialization.moveFromExtraDataToRoot(
@@ -129,7 +130,7 @@ class ChannelModel {
DateTime? updatedAt, DateTime? updatedAt,
DateTime? deletedAt, DateTime? deletedAt,
int? memberCount, int? memberCount,
Map<String, dynamic>? extraData, Map<String, Object>? extraData,
String? team, String? team,
}) => }) =>
ChannelModel( ChannelModel(
@@ -31,7 +31,9 @@ ChannelModel _$ChannelModelFromJson(Map<String, dynamic> json) {
? null ? null
: DateTime.parse(json['deleted_at'] as String), : DateTime.parse(json['deleted_at'] as String),
memberCount: json['member_count'] as int? ?? 0, memberCount: json['member_count'] as int? ?? 0,
extraData: json['extra_data'] as Map<String, dynamic>?, extraData: (json['extra_data'] as Map<String, dynamic>?)?.map(
(k, e) => MapEntry(k, e as Object),
),
team: json['team'] as String?, team: json['team'] as String?,
); );
} }
@@ -93,7 +93,7 @@ class Event {
/// Map of custom channel extraData /// Map of custom channel extraData
@JsonKey(defaultValue: {}) @JsonKey(defaultValue: {})
final Map<String, dynamic> extraData; final Map<String, Object> extraData;
/// Known top level fields. /// Known top level fields.
/// Useful for [Serialization] methods. /// Useful for [Serialization] methods.
@@ -140,7 +140,7 @@ class Event {
int? unreadChannels, int? unreadChannels,
bool? online, bool? online,
String? parentId, String? parentId,
Map<String, dynamic>? extraData, Map<String, Object>? extraData,
}) => }) =>
Event( Event(
type: type ?? this.type, type: type ?? this.type,
@@ -180,7 +180,7 @@ class EventChannel extends ChannelModel {
required DateTime updatedAt, required DateTime updatedAt,
DateTime? deletedAt, DateTime? deletedAt,
required int memberCount, required int memberCount,
Map<String, dynamic>? extraData, Map<String, Object>? extraData,
}) : super( }) : super(
id: id, id: id,
type: type, type: type,
@@ -38,7 +38,10 @@ Event _$EventFromJson(Map<String, dynamic> json) {
channelId: json['channel_id'] as String?, channelId: json['channel_id'] as String?,
channelType: json['channel_type'] as String?, channelType: json['channel_type'] as String?,
parentId: json['parent_id'] as String?, parentId: json['parent_id'] as String?,
extraData: json['extra_data'] as Map<String, dynamic>? ?? {}, extraData: (json['extra_data'] as Map<String, dynamic>?)?.map(
(k, e) => MapEntry(k, e as Object),
) ??
{},
isLocal: json['is_local'] as bool? ?? false, isLocal: json['is_local'] as bool? ?? false,
); );
} }
@@ -86,7 +89,9 @@ EventChannel _$EventChannelFromJson(Map<String, dynamic> json) {
? null ? null
: DateTime.parse(json['deleted_at'] as String), : DateTime.parse(json['deleted_at'] as String),
memberCount: json['member_count'] as int? ?? 0, memberCount: json['member_count'] as int? ?? 0,
extraData: json['extra_data'] as Map<String, dynamic>?, extraData: (json['extra_data'] as Map<String, dynamic>?)?.map(
(k, e) => MapEntry(k, e as Object),
),
); );
} }
@@ -208,7 +208,7 @@ class Message extends Equatable {
includeIfNull: false, includeIfNull: false,
defaultValue: {}, defaultValue: {},
) )
final Map<String, dynamic> extraData; final Map<String, Object> extraData;
/// True if the message is a system info /// True if the message is a system info
bool get isSystem => type == 'system'; bool get isSystem => type == 'system';
@@ -289,7 +289,7 @@ class Message extends Equatable {
DateTime? pinnedAt, DateTime? pinnedAt,
Object? pinExpires = _pinExpires, Object? pinExpires = _pinExpires,
User? pinnedBy, User? pinnedBy,
Map<String, dynamic>? extraData, Map<String, Object>? extraData,
MessageSendingStatus? status, MessageSendingStatus? status,
bool? skipPush, bool? skipPush,
}) { }) {
@@ -63,7 +63,10 @@ Message _$MessageFromJson(Map<String, dynamic> json) {
pinnedBy: json['pinned_by'] == null pinnedBy: json['pinned_by'] == null
? null ? null
: User.fromJson(json['pinned_by'] as Map<String, dynamic>), : User.fromJson(json['pinned_by'] as Map<String, dynamic>),
extraData: json['extra_data'] as Map<String, dynamic>? ?? {}, extraData: (json['extra_data'] as Map<String, dynamic>?)?.map(
(k, e) => MapEntry(k, e as Object),
) ??
{},
deletedAt: json['deleted_at'] == null deletedAt: json['deleted_at'] == null
? null ? null
: DateTime.parse(json['deleted_at'] as String), : DateTime.parse(json['deleted_at'] as String),
@@ -23,7 +23,7 @@ class OwnUser extends User {
DateTime? updatedAt, DateTime? updatedAt,
DateTime? lastActive, DateTime? lastActive,
bool online = false, bool online = false,
Map<String, dynamic> extraData = const {}, Map<String, Object> extraData = const {},
bool banned = false, bool banned = false,
}) : super( }) : super(
id: id, id: id,
@@ -34,7 +34,9 @@ OwnUser _$OwnUserFromJson(Map<String, dynamic> json) {
? null ? null
: DateTime.parse(json['last_active'] as String), : DateTime.parse(json['last_active'] as String),
online: json['online'] as bool? ?? false, online: json['online'] as bool? ?? false,
extraData: json['extra_data'] as Map<String, dynamic>, extraData: (json['extra_data'] as Map<String, dynamic>).map(
(k, e) => MapEntry(k, e as Object),
),
banned: json['banned'] as bool? ?? false, banned: json['banned'] as bool? ?? false,
); );
} }
@@ -50,7 +50,7 @@ class Reaction {
/// Reaction custom extraData /// Reaction custom extraData
@JsonKey(includeIfNull: false) @JsonKey(includeIfNull: false)
final Map<String, dynamic>? extraData; final Map<String, Object>? extraData;
/// Map of custom user extraData /// Map of custom user extraData
static const topLevelFields = [ static const topLevelFields = [
@@ -75,7 +75,7 @@ class Reaction {
User? user, User? user,
String? userId, String? userId,
int? score, int? score,
Map<String, dynamic>? extraData, Map<String, Object>? extraData,
}) => }) =>
Reaction( Reaction(
messageId: messageId ?? this.messageId, messageId: messageId ?? this.messageId,
@@ -18,7 +18,9 @@ Reaction _$ReactionFromJson(Map<String, dynamic> json) {
: User.fromJson(json['user'] as Map<String, dynamic>), : User.fromJson(json['user'] as Map<String, dynamic>),
userId: json['user_id'] as String?, userId: json['user_id'] as String?,
score: json['score'] as int? ?? 0, score: json['score'] as int? ?? 0,
extraData: json['extra_data'] as Map<String, dynamic>?, extraData: (json['extra_data'] as Map<String, dynamic>?)?.map(
(k, e) => MapEntry(k, e as Object),
),
); );
} }
@@ -75,16 +75,19 @@ class User {
/// Map of custom user extraData /// Map of custom user extraData
@JsonKey(includeIfNull: false) @JsonKey(includeIfNull: false)
final Map<String, dynamic> extraData; final Map<String, Object> extraData;
@override @override
int get hashCode => id.hashCode; int get hashCode => id.hashCode;
/// Shortcut for user name /// Shortcut for user name
String get name => String get name {
(extraData.containsKey('name') == true && extraData['name'] != '') if (extraData.containsKey('name')) {
? extraData['name'] final name = extraData['name'] as String;
: id; if (name.isNotEmpty) return name;
}
return id;
}
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
@@ -104,7 +107,7 @@ class User {
DateTime? updatedAt, DateTime? updatedAt,
DateTime? lastActive, DateTime? lastActive,
bool? online, bool? online,
Map<String, dynamic>? extraData, Map<String, Object>? extraData,
bool? banned, bool? banned,
List<String>? teams, List<String>? teams,
}) => }) =>
@@ -20,7 +20,9 @@ User _$UserFromJson(Map<String, dynamic> json) {
? null ? null
: DateTime.parse(json['last_active'] as String), : DateTime.parse(json['last_active'] as String),
online: json['online'] as bool? ?? false, online: json['online'] as bool? ?? false,
extraData: json['extra_data'] as Map<String, dynamic>, extraData: (json['extra_data'] as Map<String, dynamic>).map(
(k, e) => MapEntry(k, e as Object),
),
banned: json['banned'] as bool? ?? false, banned: json['banned'] as bool? ?? false,
teams: teams:
(json['teams'] as List<dynamic>?)?.map((e) => e as String).toList() ?? (json['teams'] as List<dynamic>?)?.map((e) => e as String).toList() ??
@@ -1,11 +1,10 @@
analyzer: analyzer:
exclude: exclude:
- lib/**/*.g.dart - lib/**/*.g.dart
- lib/**/*.freezed.dart - lib/**/*.freezed.dart
- example/* - example/*
- test/* linter:
linter: rules:
rules:
- always_use_package_imports - always_use_package_imports
- avoid_empty_else - avoid_empty_else
- avoid_relative_lib_imports - avoid_relative_lib_imports
@@ -50,15 +50,16 @@ Future<void> main() async {
/// Example using Stream's Low Level Dart client. /// Example using Stream's Low Level Dart client.
class StreamExample extends StatelessWidget { class StreamExample extends StatelessWidget {
/// To initialize this example, an instance of [client] and [channel] is required. /// To initialize this example, an instance of
/// [client] and [channel] is required.
const StreamExample({ const StreamExample({
Key key, Key? key,
@required this.client, required this.client,
@required this.channel, required this.channel,
}) : super(key: key); }) : super(key: key);
/// Instance of [StreamChatClient] we created earlier. This contains information about /// Instance of [StreamChatClient] we created earlier.
/// our application and connection state. /// This contains information about our application and connection state.
final StreamChatClient client; final StreamChatClient client;
/// The channel we'd like to observe and participate. /// The channel we'd like to observe and participate.
@@ -77,28 +78,31 @@ class StreamExample extends StatelessWidget {
/// containing the channel name and a [MessageView] displaying recent messages. /// containing the channel name and a [MessageView] displaying recent messages.
class HomeScreen extends StatelessWidget { class HomeScreen extends StatelessWidget {
/// [HomeScreen] is constructed using the [Channel] we defined earlier. /// [HomeScreen] is constructed using the [Channel] we defined earlier.
const HomeScreen({Key key, @required this.channel}) : super(key: key); const HomeScreen({
Key? key,
required this.channel,
}) : super(key: key);
/// Channel object containing the [Channel.id] we'd like to observe. /// Channel object containing the [Channel.id] we'd like to observe.
final Channel channel; final Channel channel;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final messages = channel.state.channelStateStream; final messages = channel.state!.channelStateStream;
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text('Channel: ${channel.id}'), title: Text('Channel: ${channel.id}'),
), ),
body: SafeArea( body: SafeArea(
child: StreamBuilder<ChannelState>( child: StreamBuilder<ChannelState?>(
stream: messages, stream: messages,
builder: ( builder: (
BuildContext context, BuildContext context,
AsyncSnapshot<ChannelState> snapshot, AsyncSnapshot<ChannelState?> snapshot,
) { ) {
if (snapshot.hasData && snapshot.data != null) { if (snapshot.hasData && snapshot.data != null) {
return MessageView( return MessageView(
messages: snapshot.data.messages.reversed.toList(), messages: snapshot.data!.messages.reversed.toList(),
channel: channel, channel: channel,
); );
} else if (snapshot.hasError) { } else if (snapshot.hasError) {
@@ -110,8 +114,8 @@ class HomeScreen extends StatelessWidget {
} }
return const Center( return const Center(
child: SizedBox( child: SizedBox(
width: 100.0, width: 100,
height: 100.0, height: 100,
child: CircularProgressIndicator(), child: CircularProgressIndicator(),
), ),
); );
@@ -127,9 +131,9 @@ class HomeScreen extends StatelessWidget {
class MessageView extends StatefulWidget { class MessageView extends StatefulWidget {
/// Message takes the latest list of messages and the current channel. /// Message takes the latest list of messages and the current channel.
const MessageView({ const MessageView({
Key key, Key? key,
@required this.messages, required this.messages,
@required this.channel, required this.channel,
}) : super(key: key); }) : super(key: key);
/// List of messages sent in the given channel. /// List of messages sent in the given channel.
@@ -143,8 +147,8 @@ class MessageView extends StatefulWidget {
} }
class _MessageViewState extends State<MessageView> { class _MessageViewState extends State<MessageView> {
TextEditingController _controller; late final TextEditingController _controller;
ScrollController _scrollController; late final ScrollController _scrollController;
List<Message> get _messages => widget.messages; List<Message> get _messages => widget.messages;
@@ -182,20 +186,20 @@ class _MessageViewState extends State<MessageView> {
reverse: true, reverse: true,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
final item = _messages[index]; final item = _messages[index];
if (item.user.id == widget.channel.client.uid) { if (item.user?.id == widget.channel.client.uid) {
return Align( return Align(
alignment: Alignment.centerRight, alignment: Alignment.centerRight,
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: Text(item.text), child: Text(item.text ?? ''),
), ),
); );
} else { } else {
return Align( return Align(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: Text(item.text), child: Text(item.text ?? ''),
), ),
); );
} }
@@ -203,7 +207,7 @@ class _MessageViewState extends State<MessageView> {
), ),
), ),
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: Row( child: Row(
children: [ children: [
Expanded( Expanded(
@@ -251,7 +255,8 @@ class _MessageViewState extends State<MessageView> {
} }
} }
/// Helper extension for quickly retrieving the current user id from a [StreamChatClient]. /// Helper extension for quickly retrieving
/// the current user id from a [StreamChatClient].
extension on StreamChatClient { extension on StreamChatClient {
String get uid => state.user.id; String get uid => state.user!.id;
} }
@@ -5,7 +5,7 @@ publish_to: 'none'
version: 1.0.0+1 version: 1.0.0+1
environment: environment:
sdk: ">=2.7.0 <3.0.0" sdk: ">=2.12.0 <3.0.0"
dependencies: dependencies:
flutter: flutter:
@@ -6,7 +6,7 @@ import 'package:moor/moor.dart';
/// by the sqlite backend. /// by the sqlite backend.
class ListConverter<T> extends TypeConverter<List<T>, String> { class ListConverter<T> extends TypeConverter<List<T>, String> {
@override @override
List<T> mapToDart(String fromDb) { List<T>? mapToDart(String? fromDb) {
if (fromDb == null) { if (fromDb == null) {
return null; return null;
} }
@@ -14,7 +14,7 @@ class ListConverter<T> extends TypeConverter<List<T>, String> {
} }
@override @override
String mapToSql(List<T> value) { String? mapToSql(List<T>? value) {
if (value == null) { if (value == null) {
return null; return null;
} }
@@ -6,7 +6,7 @@ import 'package:moor/moor.dart';
/// by the sqlite backend. /// by the sqlite backend.
class MapConverter<T> extends TypeConverter<Map<String, T>, String> { class MapConverter<T> extends TypeConverter<Map<String, T>, String> {
@override @override
Map<String, T> mapToDart(String fromDb) { Map<String, T>? mapToDart(String? fromDb) {
if (fromDb == null) { if (fromDb == null) {
return null; return null;
} }
@@ -14,7 +14,7 @@ class MapConverter<T> extends TypeConverter<Map<String, T>, String> {
} }
@override @override
String mapToSql(Map<String, T> value) { String? mapToSql(Map<String, T>? value) {
if (value == null) { if (value == null) {
return null; return null;
} }
@@ -6,7 +6,7 @@ import 'package:stream_chat/stream_chat.dart';
class MessageSendingStatusConverter class MessageSendingStatusConverter
extends TypeConverter<MessageSendingStatus, int> { extends TypeConverter<MessageSendingStatus, int> {
@override @override
MessageSendingStatus mapToDart(int fromDb) { MessageSendingStatus? mapToDart(int? fromDb) {
switch (fromDb) { switch (fromDb) {
case 0: case 0:
return MessageSendingStatus.sending; return MessageSendingStatus.sending;
@@ -28,7 +28,7 @@ class MessageSendingStatusConverter
} }
@override @override
int mapToSql(MessageSendingStatus value) { int? mapToSql(MessageSendingStatus? value) {
switch (value) { switch (value) {
case MessageSendingStatus.sending: case MessageSendingStatus.sending:
return 0; return 0;
@@ -15,11 +15,11 @@ class ChannelDao extends DatabaseAccessor<MoorChatDatabase>
ChannelDao(MoorChatDatabase db) : super(db); ChannelDao(MoorChatDatabase db) : super(db);
/// Get channel by cid /// Get channel by cid
Future<ChannelModel> getChannelByCid(String cid) async => Future<ChannelModel?> getChannelByCid(String cid) async =>
(select(channels)..where((c) => c.cid.equals(cid))).join([ (select(channels)..where((c) => c.cid.equals(cid))).join([
leftOuterJoin(users, channels.createdById.equalsExp(users.id)), leftOuterJoin(users, channels.createdById.equalsExp(users.id)),
]).map((rows) { ]).map((rows) {
final channel = rows.readTableOrNull(channels); final channel = rows.readTable(channels);
final createdBy = rows.readTableOrNull(users); final createdBy = rows.readTableOrNull(users);
return channel.toChannelModel(createdBy: createdBy?.toUser()); return channel.toChannelModel(createdBy: createdBy?.toUser());
}).getSingleOrNull(); }).getSingleOrNull();
@@ -30,7 +30,7 @@ class ChannelDao extends DatabaseAccessor<MoorChatDatabase>
/// 1. Channel Reads /// 1. Channel Reads
/// 2. Channel Members /// 2. Channel Members
/// 3. Channel Messages -> Messages Reactions /// 3. Channel Messages -> Messages Reactions
Future<void> deleteChannelByCids(List<String> cids) async => Future<int> deleteChannelByCids(List<String> cids) async =>
(delete(channels)..where((tbl) => tbl.cid.isIn(cids))).go(); (delete(channels)..where((tbl) => tbl.cid.isIn(cids))).go();
/// Get the channel cids saved in the storage /// Get the channel cids saved in the storage
@@ -18,7 +18,7 @@ class ChannelQueryDao extends DatabaseAccessor<MoorChatDatabase>
/// Creates a new channel query dao instance /// Creates a new channel query dao instance
ChannelQueryDao(MoorChatDatabase db) : super(db); ChannelQueryDao(MoorChatDatabase db) : super(db);
String _computeHash(Map<String, dynamic> filter) { String _computeHash(Map<String, dynamic>? filter) {
if (filter == null) { if (filter == null) {
return 'allchannels'; return 'allchannels';
} }
@@ -58,7 +58,7 @@ class ChannelQueryDao extends DatabaseAccessor<MoorChatDatabase>
}); });
/// ///
Future<List<String>> getCachedChannelCids(Map<String, dynamic> filter) { Future<List<String>> getCachedChannelCids(Map<String, dynamic>? filter) {
final hash = _computeHash(filter); final hash = _computeHash(filter);
return (select(channelQueries)..where((c) => c.queryHash.equals(hash))) return (select(channelQueries)..where((c) => c.queryHash.equals(hash)))
.map((c) => c.channelCid) .map((c) => c.channelCid)
@@ -67,9 +67,9 @@ class ChannelQueryDao extends DatabaseAccessor<MoorChatDatabase>
/// Get list of channels by filter, sort and paginationParams /// Get list of channels by filter, sort and paginationParams
Future<List<ChannelModel>> getChannels({ Future<List<ChannelModel>> getChannels({
Map<String, dynamic> filter, Map<String, dynamic>? filter,
List<SortOption<ChannelModel>> sort = const [], List<SortOption<ChannelModel>>? sort,
PaginationParams paginationParams, PaginationParams? paginationParams,
}) async { }) async {
assert(() { assert(() {
if (sort != null && sort.any((it) => it.comparator == null)) { if (sort != null && sort.any((it) => it.comparator == null)) {
@@ -86,20 +86,21 @@ class ChannelQueryDao extends DatabaseAccessor<MoorChatDatabase>
final cachedChannels = await (query.join([ final cachedChannels = await (query.join([
leftOuterJoin(users, channels.createdById.equalsExp(users.id)), leftOuterJoin(users, channels.createdById.equalsExp(users.id)),
]).map((row) { ]).map((row) {
final createdByEntity = row.readTable(users); final createdByEntity = row.readTableOrNull(users);
final channelEntity = row.readTable(channels); final channelEntity = row.readTable(channels);
return channelEntity.toChannelModel(createdBy: createdByEntity?.toUser()); return channelEntity.toChannelModel(createdBy: createdByEntity?.toUser());
})).get(); })).get();
final possibleSortingFields = cachedChannels.fold<List<String>>( final possibleSortingFields = cachedChannels.fold<List<String>>(
ChannelModel.topLevelFields, ChannelModel.topLevelFields, (previousValue, element) {
(previousValue, element) => final extraData = element.extraData ?? {};
{...previousValue, ...element.extraData.keys}.toList()); return {...previousValue, ...extraData.keys}.toList();
});
// ignore: parameter_assignments // ignore: parameter_assignments
sort = sort sort = sort
?.where((s) => possibleSortingFields.contains(s.field)) ?.where((s) => possibleSortingFields.contains(s.field))
?.toList(growable: false); .toList(growable: false);
var chainedComparator = (ChannelModel a, ChannelModel b) { var chainedComparator = (ChannelModel a, ChannelModel b) {
final dateA = a.lastMessageAt ?? a.createdAt; final dateA = a.lastMessageAt ?? a.createdAt;
@@ -110,9 +111,9 @@ class ChannelQueryDao extends DatabaseAccessor<MoorChatDatabase>
if (sort != null && sort.isNotEmpty) { if (sort != null && sort.isNotEmpty) {
chainedComparator = (a, b) { chainedComparator = (a, b) {
int result; int result;
for (final comparator in sort.map((it) => it.comparator)) { for (final comparator in sort!.map((it) => it.comparator)) {
try { try {
result = comparator(a, b); result = comparator!(a, b);
} catch (e) { } catch (e) {
result = 0; result = 0;
} }
@@ -125,11 +126,11 @@ class ChannelQueryDao extends DatabaseAccessor<MoorChatDatabase>
cachedChannels.sort(chainedComparator); cachedChannels.sort(chainedComparator);
if (paginationParams?.offset != null && cachedChannels.isNotEmpty) { if (paginationParams?.offset != null && cachedChannels.isNotEmpty) {
cachedChannels.removeRange(0, paginationParams.offset); cachedChannels.removeRange(0, paginationParams!.offset);
} }
if (paginationParams?.limit != null) { if (paginationParams?.limit != null) {
return cachedChannels.take(paginationParams.limit).toList(); return cachedChannels.take(paginationParams!.limit).toList();
} }
return cachedChannels; return cachedChannels;
@@ -15,19 +15,18 @@ class ConnectionEventDao extends DatabaseAccessor<MoorChatDatabase>
ConnectionEventDao(MoorChatDatabase db) : super(db); ConnectionEventDao(MoorChatDatabase db) : super(db);
/// Get the latest stored connection event /// Get the latest stored connection event
Future<Event> get connectionEvent => select(connectionEvents) Future<Event?> get connectionEvent => select(connectionEvents)
.map((eventEntity) => eventEntity.toEvent()) .map((eventEntity) => eventEntity.toEvent())
.getSingleOrNull(); .getSingleOrNull();
/// Get the latest stored lastSyncAt /// Get the latest stored lastSyncAt
Future<DateTime> get lastSyncAt => Future<DateTime?> get lastSyncAt =>
select(connectionEvents).getSingleOrNull().then((r) => r?.lastSyncAt); select(connectionEvents).getSingleOrNull().then((r) => r?.lastSyncAt);
/// Update stored connection event with latest data /// Update stored connection event with latest data
Future<void> updateConnectionEvent(Event event) async => Future<int> updateConnectionEvent(Event event) => transaction(() async {
transaction(() async {
final connectionInfo = await select(connectionEvents).getSingleOrNull(); final connectionInfo = await select(connectionEvents).getSingleOrNull();
await into(connectionEvents).insert( return into(connectionEvents).insert(
ConnectionEventEntity( ConnectionEventEntity(
id: 1, id: 1,
lastSyncAt: connectionInfo?.lastSyncAt, lastSyncAt: connectionInfo?.lastSyncAt,
@@ -26,7 +26,7 @@ class MemberDao extends DatabaseAccessor<MoorChatDatabase>
.map((row) { .map((row) {
final userEntity = row.readTable(users); final userEntity = row.readTable(users);
final memberEntity = row.readTable(members); final memberEntity = row.readTable(members);
return memberEntity.toMember(user: userEntity?.toUser()); return memberEntity.toMember(user: userEntity.toUser());
}).get(); }).get();
/// Updates all the members using the new [memberList] data /// Updates all the members using the new [memberList] data
@@ -25,7 +25,7 @@ class MessageDao extends DatabaseAccessor<MoorChatDatabase>
/// ///
/// This will automatically delete the following linked records /// This will automatically delete the following linked records
/// 1. Message Reactions /// 1. Message Reactions
Future<void> deleteMessageByIds(List<String> messageIds) => Future<int> deleteMessageByIds(List<String> messageIds) =>
(delete(messages)..where((tbl) => tbl.id.isIn(messageIds))).go(); (delete(messages)..where((tbl) => tbl.id.isIn(messageIds))).go();
/// Removes all the messages by matching [Messages.channelCid] in [cids] /// Removes all the messages by matching [Messages.channelCid] in [cids]
@@ -38,15 +38,16 @@ class MessageDao extends DatabaseAccessor<MoorChatDatabase>
Future<Message> _messageFromJoinRow(TypedResult rows) async { Future<Message> _messageFromJoinRow(TypedResult rows) async {
final userEntity = rows.readTableOrNull(_users); final userEntity = rows.readTableOrNull(_users);
final pinnedByEntity = rows.readTableOrNull(_pinnedByUsers); final pinnedByEntity = rows.readTableOrNull(_pinnedByUsers);
final msgEntity = rows.readTableOrNull(messages); final msgEntity = rows.readTable(messages);
final latestReactions = await _db.reactionDao.getReactions(msgEntity.id); final latestReactions = await _db.reactionDao.getReactions(msgEntity.id);
final ownReactions = await _db.reactionDao.getReactionsByUserId( final ownReactions = await _db.reactionDao.getReactionsByUserId(
msgEntity.id, msgEntity.id,
_db.userId, _db.userId,
); );
Message quotedMessage; Message? quotedMessage;
if (msgEntity.quotedMessageId != null) { final quotedMessageId = msgEntity.quotedMessageId;
quotedMessage = await getMessageById(msgEntity.quotedMessageId); if (quotedMessageId != null) {
quotedMessage = await getMessageById(quotedMessageId);
} }
return msgEntity.toMessage( return msgEntity.toMessage(
user: userEntity?.toUser(), user: userEntity?.toUser(),
@@ -58,7 +59,7 @@ class MessageDao extends DatabaseAccessor<MoorChatDatabase>
} }
/// Returns a single message by matching the [Messages.id] with [id] /// Returns a single message by matching the [Messages.id] with [id]
Future<Message> getMessageById(String id) async => Future<Message?> getMessageById(String id) async =>
await (select(messages).join([ await (select(messages).join([
leftOuterJoin(_users, messages.userId.equalsExp(_users.id)), leftOuterJoin(_users, messages.userId.equalsExp(_users.id)),
leftOuterJoin(_pinnedByUsers, leftOuterJoin(_pinnedByUsers,
@@ -86,7 +87,7 @@ class MessageDao extends DatabaseAccessor<MoorChatDatabase>
/// [Messages.parentId] with [parentId] /// [Messages.parentId] with [parentId]
Future<List<Message>> getThreadMessagesByParentId( Future<List<Message>> getThreadMessagesByParentId(
String parentId, { String parentId, {
PaginationParams options, PaginationParams? options,
}) async { }) async {
final msgList = await Future.wait(await (select(messages).join([ final msgList = await Future.wait(await (select(messages).join([
leftOuterJoin(_users, messages.userId.equalsExp(_users.id)), leftOuterJoin(_users, messages.userId.equalsExp(_users.id)),
@@ -102,7 +103,7 @@ class MessageDao extends DatabaseAccessor<MoorChatDatabase>
if (msgList.isNotEmpty) { if (msgList.isNotEmpty) {
if (options?.lessThan != null) { if (options?.lessThan != null) {
final lessThanIndex = msgList.indexWhere( final lessThanIndex = msgList.indexWhere(
(m) => m.id == options.lessThan, (m) => m.id == options!.lessThan,
); );
if (lessThanIndex != -1) { if (lessThanIndex != -1) {
msgList.removeRange(lessThanIndex, msgList.length); msgList.removeRange(lessThanIndex, msgList.length);
@@ -110,14 +111,14 @@ class MessageDao extends DatabaseAccessor<MoorChatDatabase>
} }
if (options?.greaterThanOrEqual != null) { if (options?.greaterThanOrEqual != null) {
final greaterThanIndex = msgList.indexWhere( final greaterThanIndex = msgList.indexWhere(
(m) => m.id == options.greaterThanOrEqual, (m) => m.id == options!.greaterThanOrEqual,
); );
if (greaterThanIndex != -1) { if (greaterThanIndex != -1) {
msgList.removeRange(0, greaterThanIndex); msgList.removeRange(0, greaterThanIndex);
} }
} }
if (options?.limit != null) { if (options?.limit != null) {
return msgList.take(options.limit).toList(); return msgList.take(options!.limit).toList();
} }
} }
return msgList; return msgList;
@@ -127,7 +128,7 @@ class MessageDao extends DatabaseAccessor<MoorChatDatabase>
/// [Messages.channelCid] with [parentId] /// [Messages.channelCid] with [parentId]
Future<List<Message>> getMessagesByCid( Future<List<Message>> getMessagesByCid(
String cid, { String cid, {
PaginationParams messagePagination, PaginationParams? messagePagination,
}) async { }) async {
final msgList = await Future.wait(await (select(messages).join([ final msgList = await Future.wait(await (select(messages).join([
leftOuterJoin(_users, messages.userId.equalsExp(_users.id)), leftOuterJoin(_users, messages.userId.equalsExp(_users.id)),
@@ -145,7 +146,7 @@ class MessageDao extends DatabaseAccessor<MoorChatDatabase>
if (msgList.isNotEmpty) { if (msgList.isNotEmpty) {
if (messagePagination?.lessThan != null) { if (messagePagination?.lessThan != null) {
final lessThanIndex = msgList.indexWhere( final lessThanIndex = msgList.indexWhere(
(m) => m.id == messagePagination.lessThan, (m) => m.id == messagePagination!.lessThan,
); );
if (lessThanIndex != -1) { if (lessThanIndex != -1) {
msgList.removeRange(lessThanIndex, msgList.length); msgList.removeRange(lessThanIndex, msgList.length);
@@ -153,14 +154,14 @@ class MessageDao extends DatabaseAccessor<MoorChatDatabase>
} }
if (messagePagination?.greaterThanOrEqual != null) { if (messagePagination?.greaterThanOrEqual != null) {
final greaterThanIndex = msgList.indexWhere( final greaterThanIndex = msgList.indexWhere(
(m) => m.id == messagePagination.greaterThanOrEqual, (m) => m.id == messagePagination!.greaterThanOrEqual,
); );
if (greaterThanIndex != -1) { if (greaterThanIndex != -1) {
msgList.removeRange(0, greaterThanIndex); msgList.removeRange(0, greaterThanIndex);
} }
} }
if (messagePagination?.limit != null) { if (messagePagination?.limit != null) {
return msgList.take(messagePagination.limit).toList(); return msgList.take(messagePagination!.limit).toList();
} }
} }
return msgList; return msgList;
@@ -168,17 +169,13 @@ class MessageDao extends DatabaseAccessor<MoorChatDatabase>
/// Updates the message data of a particular channel with /// Updates the message data of a particular channel with
/// the new [messageList] data /// the new [messageList] data
Future<void> updateMessages(String cid, List<Message> messageList) async { Future<void> updateMessages(String cid, List<Message> messageList) => batch(
if (messageList == null) { (batch) {
return; batch.insertAll(
} messages,
messageList.map((it) => it.toEntity(cid: cid)).toList(),
return batch((batch) { mode: InsertMode.insertOrReplace,
batch.insertAll( );
messages, },
messageList.map((it) => it.toEntity(cid: cid)).toList(),
mode: InsertMode.insertOrReplace,
); );
});
}
} }
@@ -38,15 +38,16 @@ class PinnedMessageDao extends DatabaseAccessor<MoorChatDatabase>
Future<Message> _messageFromJoinRow(TypedResult rows) async { Future<Message> _messageFromJoinRow(TypedResult rows) async {
final userEntity = rows.readTableOrNull(users); final userEntity = rows.readTableOrNull(users);
final pinnedByEntity = rows.readTableOrNull(_pinnedByUsers); final pinnedByEntity = rows.readTableOrNull(_pinnedByUsers);
final msgEntity = rows.readTableOrNull(pinnedMessages); final msgEntity = rows.readTable(pinnedMessages);
final latestReactions = await _db.reactionDao.getReactions(msgEntity.id); final latestReactions = await _db.reactionDao.getReactions(msgEntity.id);
final ownReactions = await _db.reactionDao.getReactionsByUserId( final ownReactions = await _db.reactionDao.getReactionsByUserId(
msgEntity.id, msgEntity.id,
_db.userId, _db.userId,
); );
Message quotedMessage; Message? quotedMessage;
if (msgEntity.quotedMessageId != null) { final quotedMessageId = msgEntity.quotedMessageId;
quotedMessage = await getMessageById(msgEntity.quotedMessageId); if (quotedMessageId != null) {
quotedMessage = await getMessageById(quotedMessageId);
} }
return msgEntity.toMessage( return msgEntity.toMessage(
user: userEntity?.toUser(), user: userEntity?.toUser(),
@@ -58,7 +59,7 @@ class PinnedMessageDao extends DatabaseAccessor<MoorChatDatabase>
} }
/// Returns a single message by matching the [PinnedMessages.id] with [id] /// Returns a single message by matching the [PinnedMessages.id] with [id]
Future<Message> getMessageById(String id) async => Future<Message?> getMessageById(String id) async =>
await (select(pinnedMessages).join([ await (select(pinnedMessages).join([
leftOuterJoin(_users, pinnedMessages.userId.equalsExp(_users.id)), leftOuterJoin(_users, pinnedMessages.userId.equalsExp(_users.id)),
leftOuterJoin(_pinnedByUsers, leftOuterJoin(_pinnedByUsers,
@@ -86,7 +87,7 @@ class PinnedMessageDao extends DatabaseAccessor<MoorChatDatabase>
/// [PinnedMessages.parentId] with [parentId] /// [PinnedMessages.parentId] with [parentId]
Future<List<Message>> getThreadMessagesByParentId( Future<List<Message>> getThreadMessagesByParentId(
String parentId, { String parentId, {
PaginationParams options, PaginationParams? options,
}) async { }) async {
final msgList = await Future.wait(await (select(pinnedMessages).join([ final msgList = await Future.wait(await (select(pinnedMessages).join([
leftOuterJoin(_users, pinnedMessages.userId.equalsExp(_users.id)), leftOuterJoin(_users, pinnedMessages.userId.equalsExp(_users.id)),
@@ -102,7 +103,7 @@ class PinnedMessageDao extends DatabaseAccessor<MoorChatDatabase>
if (msgList.isNotEmpty) { if (msgList.isNotEmpty) {
if (options?.lessThan != null) { if (options?.lessThan != null) {
final lessThanIndex = msgList.indexWhere( final lessThanIndex = msgList.indexWhere(
(m) => m.id == options.lessThan, (m) => m.id == options!.lessThan,
); );
if (lessThanIndex != -1) { if (lessThanIndex != -1) {
msgList.removeRange(lessThanIndex, msgList.length); msgList.removeRange(lessThanIndex, msgList.length);
@@ -110,14 +111,14 @@ class PinnedMessageDao extends DatabaseAccessor<MoorChatDatabase>
} }
if (options?.greaterThanOrEqual != null) { if (options?.greaterThanOrEqual != null) {
final greaterThanIndex = msgList.indexWhere( final greaterThanIndex = msgList.indexWhere(
(m) => m.id == options.greaterThanOrEqual, (m) => m.id == options!.greaterThanOrEqual,
); );
if (greaterThanIndex != -1) { if (greaterThanIndex != -1) {
msgList.removeRange(0, greaterThanIndex); msgList.removeRange(0, greaterThanIndex);
} }
} }
if (options?.limit != null) { if (options?.limit != null) {
return msgList.take(options.limit).toList(); return msgList.take(options!.limit).toList();
} }
} }
return msgList; return msgList;
@@ -127,7 +128,7 @@ class PinnedMessageDao extends DatabaseAccessor<MoorChatDatabase>
/// [PinnedMessages.channelCid] with [parentId] /// [PinnedMessages.channelCid] with [parentId]
Future<List<Message>> getMessagesByCid( Future<List<Message>> getMessagesByCid(
String cid, { String cid, {
PaginationParams messagePagination, PaginationParams? messagePagination,
}) async { }) async {
final msgList = await Future.wait(await (select(pinnedMessages).join([ final msgList = await Future.wait(await (select(pinnedMessages).join([
leftOuterJoin(_users, pinnedMessages.userId.equalsExp(_users.id)), leftOuterJoin(_users, pinnedMessages.userId.equalsExp(_users.id)),
@@ -144,7 +145,7 @@ class PinnedMessageDao extends DatabaseAccessor<MoorChatDatabase>
if (msgList.isNotEmpty) { if (msgList.isNotEmpty) {
if (messagePagination?.lessThan != null) { if (messagePagination?.lessThan != null) {
final lessThanIndex = msgList.indexWhere( final lessThanIndex = msgList.indexWhere(
(m) => m.id == messagePagination.lessThan, (m) => m.id == messagePagination!.lessThan,
); );
if (lessThanIndex != -1) { if (lessThanIndex != -1) {
msgList.removeRange(lessThanIndex, msgList.length); msgList.removeRange(lessThanIndex, msgList.length);
@@ -152,14 +153,14 @@ class PinnedMessageDao extends DatabaseAccessor<MoorChatDatabase>
} }
if (messagePagination?.greaterThanOrEqual != null) { if (messagePagination?.greaterThanOrEqual != null) {
final greaterThanIndex = msgList.indexWhere( final greaterThanIndex = msgList.indexWhere(
(m) => m.id == messagePagination.greaterThanOrEqual, (m) => m.id == messagePagination!.greaterThanOrEqual,
); );
if (greaterThanIndex != -1) { if (greaterThanIndex != -1) {
msgList.removeRange(0, greaterThanIndex); msgList.removeRange(0, greaterThanIndex);
} }
} }
if (messagePagination?.limit != null) { if (messagePagination?.limit != null) {
return msgList.take(messagePagination.limit).toList(); return msgList.take(messagePagination!.limit).toList();
} }
} }
return msgList; return msgList;
@@ -167,17 +168,13 @@ class PinnedMessageDao extends DatabaseAccessor<MoorChatDatabase>
/// Updates the message data of a particular channel with /// Updates the message data of a particular channel with
/// the new [messageList] data /// the new [messageList] data
Future<void> updateMessages(String cid, List<Message> messageList) async { Future<void> updateMessages(String cid, List<Message> messageList) => batch(
if (messageList == null) { (batch) {
return; batch.insertAll(
} pinnedMessages,
messageList.map((it) => it.toPinnedEntity(cid: cid)).toList(),
return batch((batch) { mode: InsertMode.insertOrReplace,
batch.insertAll( );
pinnedMessages, },
messageList.map((it) => it.toPinnedEntity(cid: cid)).toList(),
mode: InsertMode.insertOrReplace,
); );
});
}
} }
@@ -24,7 +24,7 @@ class ReactionDao extends DatabaseAccessor<MoorChatDatabase>
..orderBy([OrderingTerm.asc(reactions.createdAt)])) ..orderBy([OrderingTerm.asc(reactions.createdAt)]))
.map((rows) { .map((rows) {
final userEntity = rows.readTableOrNull(users); final userEntity = rows.readTableOrNull(users);
final reactionEntity = rows.readTableOrNull(reactions); final reactionEntity = rows.readTable(reactions);
return reactionEntity.toReaction(user: userEntity?.toUser()); return reactionEntity.toReaction(user: userEntity?.toUser());
}).get(); }).get();
@@ -24,7 +24,7 @@ class ReadDao extends DatabaseAccessor<MoorChatDatabase> with _$ReadDaoMixin {
.map((row) { .map((row) {
final userEntity = row.readTable(users); final userEntity = row.readTable(users);
final readEntity = row.readTable(reads); final readEntity = row.readTable(reads);
return readEntity.toRead(user: userEntity?.toUser()); return readEntity.toRead(user: userEntity.toUser());
}).get(); }).get();
/// Updates the read data of a particular channel with /// Updates the read data of a particular channel with
@@ -72,6 +72,13 @@ class MoorChatDatabase extends _$MoorChatDatabase {
}, },
); );
/// Deletes all the tables
Future<void> flush() => batch((batch) {
allTables.forEach((table) {
delete(table).go();
});
});
/// Closes the database instance /// Closes the database instance
Future<void> disconnect() => close(); Future<void> disconnect() => close();
} }
File diff suppressed because it is too large Load Diff
@@ -15,7 +15,7 @@ class Channels extends Table {
TextColumn get cid => text()(); TextColumn get cid => text()();
/// The channel configuration data /// The channel configuration data
TextColumn get config => text().map(MapConverter<Object>())(); TextColumn get config => text().map(MapConverter())();
/// True if this channel entity is frozen /// True if this channel entity is frozen
BoolColumn get frozen => boolean().withDefault(const Constant(false))(); BoolColumn get frozen => boolean().withDefault(const Constant(false))();
@@ -24,16 +24,16 @@ class Channels extends Table {
DateTimeColumn get lastMessageAt => dateTime().nullable()(); DateTimeColumn get lastMessageAt => dateTime().nullable()();
/// The date of channel creation /// The date of channel creation
DateTimeColumn get createdAt => dateTime().nullable()(); DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
/// The date of the last channel update /// The date of the last channel update
DateTimeColumn get updatedAt => dateTime().nullable()(); DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)();
/// The date of channel deletion /// The date of channel deletion
DateTimeColumn get deletedAt => dateTime().nullable()(); DateTimeColumn get deletedAt => dateTime().nullable()();
/// The count of this channel members /// The count of this channel members
IntColumn get memberCount => integer().nullable()(); IntColumn get memberCount => integer().withDefault(const Constant(0))();
/// The id of the user that created this channel /// The id of the user that created this channel
TextColumn get createdById => text().nullable()(); TextColumn get createdById => text().nullable()();
@@ -9,7 +9,7 @@ class ConnectionEvents extends Table {
IntColumn get id => integer()(); IntColumn get id => integer()();
/// User object of the current user /// User object of the current user
TextColumn get ownUser => text().nullable().map(MapConverter<Object>())(); TextColumn get ownUser => text().nullable().map(MapConverter())();
/// The number of unread messages for current user /// The number of unread messages for current user
IntColumn get totalUnreadCount => integer().nullable()(); IntColumn get totalUnreadCount => integer().nullable()();
@@ -21,22 +21,22 @@ class Members extends Table {
DateTimeColumn get inviteRejectedAt => dateTime().nullable()(); DateTimeColumn get inviteRejectedAt => dateTime().nullable()();
/// True if the user has been invited to the channel /// True if the user has been invited to the channel
BoolColumn get invited => boolean().nullable()(); BoolColumn get invited => boolean().withDefault(const Constant(false))();
/// True if the member is banned from the channel /// True if the member is banned from the channel
BoolColumn get banned => boolean().nullable()(); BoolColumn get banned => boolean().withDefault(const Constant(false))();
/// True if the member is shadow banned from the channel /// True if the member is shadow banned from the channel
BoolColumn get shadowBanned => boolean().nullable()(); BoolColumn get shadowBanned => boolean().withDefault(const Constant(false))();
/// True if the user is a moderator of the channel /// True if the user is a moderator of the channel
BoolColumn get isModerator => boolean().nullable()(); BoolColumn get isModerator => boolean().withDefault(const Constant(false))();
/// The date of creation /// The date of creation
DateTimeColumn get createdAt => dateTime()(); DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
/// The last date of update /// The last date of update
DateTimeColumn get updatedAt => dateTime().nullable()(); DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)();
@override @override
Set<Column> get primaryKey => { Set<Column> get primaryKey => {
@@ -15,19 +15,18 @@ class Messages extends Table {
/// The list of attachments, either provided by the user /// The list of attachments, either provided by the user
/// or generated from a command or as a result of URL scraping. /// or generated from a command or as a result of URL scraping.
TextColumn get attachments => TextColumn get attachments => text().map(ListConverter<String>())();
text().nullable().map(ListConverter<String>())();
/// The status of a sending message /// The status of a sending message
IntColumn get status => IntColumn get status => integer()
integer().nullable().map(MessageSendingStatusConverter())(); .withDefault(const Constant(1))
.map(MessageSendingStatusConverter())();
/// The message type /// The message type
TextColumn get type => text().nullable()(); TextColumn get type => text().withDefault(const Constant('regular'))();
/// The list of user mentioned in the message /// The list of user mentioned in the message
TextColumn get mentionedUsers => TextColumn get mentionedUsers => text().map(ListConverter<String>())();
text().nullable().map(ListConverter<String>())();
/// A map describing the count of number of every reaction /// A map describing the count of number of every reaction
TextColumn get reactionCounts => text().nullable().map(MapConverter<int>())(); TextColumn get reactionCounts => text().nullable().map(MapConverter<int>())();
@@ -48,16 +47,16 @@ class Messages extends Table {
BoolColumn get showInChannel => boolean().nullable()(); BoolColumn get showInChannel => boolean().nullable()();
/// If true the message is shadowed /// If true the message is shadowed
BoolColumn get shadowed => boolean().nullable()(); BoolColumn get shadowed => boolean().withDefault(const Constant(false))();
/// A used command name. /// A used command name.
TextColumn get command => text().nullable()(); TextColumn get command => text().nullable()();
/// The DateTime when the message was created. /// The DateTime when the message was created.
DateTimeColumn get createdAt => dateTime()(); DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
/// The DateTime when the message was updated last time. /// The DateTime when the message was updated last time.
DateTimeColumn get updatedAt => dateTime().nullable()(); DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)();
/// The DateTime when the message was deleted. /// The DateTime when the message was deleted.
DateTimeColumn get deletedAt => dateTime().nullable()(); DateTimeColumn get deletedAt => dateTime().nullable()();
@@ -16,10 +16,10 @@ class Reactions extends Table {
TextColumn get type => text()(); TextColumn get type => text()();
/// The DateTime on which the reaction is created /// The DateTime on which the reaction is created
DateTimeColumn get createdAt => dateTime()(); DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
/// The score of the reaction (ie. number of reactions sent) /// The score of the reaction (ie. number of reactions sent)
IntColumn get score => integer().nullable()(); IntColumn get score => integer().withDefault(const Constant(0))();
/// Reaction custom extraData /// Reaction custom extraData
TextColumn get extraData => text().nullable().map(MapConverter<Object>())(); TextColumn get extraData => text().nullable().map(MapConverter<Object>())();
@@ -15,7 +15,7 @@ class Reads extends Table {
text().customConstraint('REFERENCES channels(cid) ON DELETE CASCADE')(); text().customConstraint('REFERENCES channels(cid) ON DELETE CASCADE')();
/// Number of unread messages /// Number of unread messages
IntColumn get unreadMessages => integer().nullable()(); IntColumn get unreadMessages => integer().withDefault(const Constant(0))();
@override @override
Set<Column> get primaryKey => { Set<Column> get primaryKey => {
@@ -12,22 +12,22 @@ class Users extends Table {
TextColumn get role => text().nullable()(); TextColumn get role => text().nullable()();
/// Date of user creation /// Date of user creation
DateTimeColumn get createdAt => dateTime().nullable()(); DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
/// Date of last user update /// Date of last user update
DateTimeColumn get updatedAt => dateTime().nullable()(); DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)();
/// Date of last user connection /// Date of last user connection
DateTimeColumn get lastActive => dateTime().nullable()(); DateTimeColumn get lastActive => dateTime().nullable()();
/// True if user is online /// True if user is online
BoolColumn get online => boolean().nullable()(); BoolColumn get online => boolean().withDefault(const Constant(false))();
/// True if user is banned from the chat /// True if user is banned from the chat
BoolColumn get banned => boolean().nullable()(); BoolColumn get banned => boolean().withDefault(const Constant(false))();
/// Map of custom user extraData /// Map of custom user extraData
TextColumn get extraData => text().nullable().map(MapConverter<Object>())(); TextColumn get extraData => text().map(MapConverter<Object>())();
@override @override
Set<Column> get primaryKey => {id}; Set<Column> get primaryKey => {id};
@@ -4,8 +4,8 @@ import 'package:stream_chat_persistence/src/db/moor_chat_database.dart';
/// Useful mapping functions for [ChannelEntity] /// Useful mapping functions for [ChannelEntity]
extension ChannelEntityX on ChannelEntity { extension ChannelEntityX on ChannelEntity {
/// Maps a [ChannelEntity] into [ChannelModel] /// Maps a [ChannelEntity] into [ChannelModel]
ChannelModel toChannelModel({User createdBy}) { ChannelModel toChannelModel({User? createdBy}) {
final config = ChannelConfig.fromJson(this.config ?? {}); final config = ChannelConfig.fromJson(this.config);
return ChannelModel( return ChannelModel(
id: id, id: id,
config: config, config: config,
@@ -24,11 +24,11 @@ extension ChannelEntityX on ChannelEntity {
/// Maps a [ChannelEntity] into [ChannelState] /// Maps a [ChannelEntity] into [ChannelState]
ChannelState toChannelState({ ChannelState toChannelState({
User createdBy, User? createdBy,
List<Member> members, List<Member> members = const [],
List<Read> reads, List<Read> reads = const [],
List<Message> messages, List<Message> messages = const [],
List<Message> pinnedMessages, List<Message> pinnedMessages = const [],
}) => }) =>
ChannelState( ChannelState(
members: members, members: members,
@@ -46,7 +46,7 @@ extension ChannelModelX on ChannelModel {
id: id, id: id,
type: type, type: type,
cid: cid, cid: cid,
config: config?.toJson(), config: config.toJson(),
frozen: frozen, frozen: frozen,
lastMessageAt: lastMessageAt, lastMessageAt: lastMessageAt,
createdAt: createdAt, createdAt: createdAt,
@@ -5,7 +5,7 @@ import 'package:stream_chat_persistence/src/db/moor_chat_database.dart';
extension ConnectionEventX on ConnectionEventEntity { extension ConnectionEventX on ConnectionEventEntity {
/// Maps a [ConnectionEventEntity] into [Event] /// Maps a [ConnectionEventEntity] into [Event]
Event toEvent() => Event( Event toEvent() => Event(
me: ownUser != null ? OwnUser.fromJson(ownUser) : null, me: ownUser != null ? OwnUser.fromJson(ownUser!) : null,
totalUnreadCount: totalUnreadCount, totalUnreadCount: totalUnreadCount,
unreadChannels: unreadChannels, unreadChannels: unreadChannels,
); );
@@ -4,7 +4,7 @@ import 'package:stream_chat_persistence/src/db/moor_chat_database.dart';
/// Useful mapping functions for [MemberEntity] /// Useful mapping functions for [MemberEntity]
extension MemberEntityX on MemberEntity { extension MemberEntityX on MemberEntity {
/// Maps a [MemberEntity] into [Member] /// Maps a [MemberEntity] into [Member]
Member toMember({User user}) => Member( Member toMember({User? user}) => Member(
user: user, user: user,
userId: userId, userId: userId,
banned: banned, banned: banned,
@@ -22,8 +22,8 @@ extension MemberEntityX on MemberEntity {
/// Useful mapping functions for [Member] /// Useful mapping functions for [Member]
extension MemberX on Member { extension MemberX on Member {
/// Maps a [Member] into [MemberEntity] /// Maps a [Member] into [MemberEntity]
MemberEntity toEntity({String cid}) => MemberEntity( MemberEntity toEntity({required String cid}) => MemberEntity(
userId: user?.id, userId: user!.id,
banned: banned, banned: banned,
shadowBanned: shadowBanned, shadowBanned: shadowBanned,
channelCid: cid, channelCid: cid,
@@ -7,22 +7,22 @@ import 'package:stream_chat_persistence/src/db/moor_chat_database.dart';
extension MessageEntityX on MessageEntity { extension MessageEntityX on MessageEntity {
/// Maps a [MessageEntity] into [Message] /// Maps a [MessageEntity] into [Message]
Message toMessage({ Message toMessage({
User user, User? user,
User pinnedBy, User? pinnedBy,
List<Reaction> latestReactions, List<Reaction>? latestReactions,
List<Reaction> ownReactions, List<Reaction>? ownReactions,
Message quotedMessage, Message? quotedMessage,
}) => }) =>
Message( Message(
shadowed: shadowed, shadowed: shadowed,
latestReactions: latestReactions, latestReactions: latestReactions,
ownReactions: ownReactions, ownReactions: ownReactions,
attachments: attachments?.map((it) { attachments: attachments.map((it) {
final json = jsonDecode(it); final json = jsonDecode(it);
return Attachment.fromData(json); return Attachment.fromData(json);
})?.toList(), }).toList(),
createdAt: createdAt, createdAt: createdAt,
extraData: extraData, extraData: extraData ?? <String, Object>{},
updatedAt: updatedAt, updatedAt: updatedAt,
id: id, id: id,
type: type, type: type,
@@ -48,10 +48,9 @@ extension MessageEntityX on MessageEntity {
/// Useful mapping functions for [Message] /// Useful mapping functions for [Message]
extension MessageX on Message { extension MessageX on Message {
/// Maps a [Message] into [MessageEntity] /// Maps a [Message] into [MessageEntity]
MessageEntity toEntity({String cid}) => MessageEntity( MessageEntity toEntity({String? cid}) => MessageEntity(
id: id, id: id,
attachments: attachments: attachments.map((it) => jsonEncode(it.toData())).toList(),
attachments?.map((it) => jsonEncode(it.toData()))?.toList(),
channelCid: cid, channelCid: cid,
type: type, type: type,
parentId: parentId, parentId: parentId,
@@ -63,6 +62,7 @@ extension MessageX on Message {
replyCount: replyCount, replyCount: replyCount,
reactionScores: reactionScores, reactionScores: reactionScores,
reactionCounts: reactionCounts, reactionCounts: reactionCounts,
mentionedUsers: mentionedUsers.map(jsonEncode).toList(),
status: status, status: status,
updatedAt: updatedAt, updatedAt: updatedAt,
extraData: extraData, extraData: extraData,
@@ -7,22 +7,22 @@ import 'package:stream_chat_persistence/src/db/moor_chat_database.dart';
extension PinnedMessageEntityX on PinnedMessageEntity { extension PinnedMessageEntityX on PinnedMessageEntity {
/// Maps a [PinnedMessageEntity] into [Message] /// Maps a [PinnedMessageEntity] into [Message]
Message toMessage({ Message toMessage({
User user, User? user,
User pinnedBy, User? pinnedBy,
List<Reaction> latestReactions, List<Reaction>? latestReactions,
List<Reaction> ownReactions, List<Reaction>? ownReactions,
Message quotedMessage, Message? quotedMessage,
}) => }) =>
Message( Message(
shadowed: shadowed, shadowed: shadowed,
latestReactions: latestReactions, latestReactions: latestReactions,
ownReactions: ownReactions, ownReactions: ownReactions,
attachments: attachments?.map((it) { attachments: attachments.map((it) {
final json = jsonDecode(it); final json = jsonDecode(it);
return Attachment.fromData(json); return Attachment.fromData(json);
})?.toList(), }).toList(),
createdAt: createdAt, createdAt: createdAt,
extraData: extraData, extraData: extraData ?? <String, Object>{},
updatedAt: updatedAt, updatedAt: updatedAt,
id: id, id: id,
type: type, type: type,
@@ -48,10 +48,9 @@ extension PinnedMessageEntityX on PinnedMessageEntity {
/// Useful mapping functions for [Message] /// Useful mapping functions for [Message]
extension PMessageX on Message { extension PMessageX on Message {
/// Maps a [Message] into [PinnedMessageEntity] /// Maps a [Message] into [PinnedMessageEntity]
PinnedMessageEntity toPinnedEntity({String cid}) => PinnedMessageEntity( PinnedMessageEntity toPinnedEntity({String? cid}) => PinnedMessageEntity(
id: id, id: id,
attachments: attachments: attachments.map((it) => jsonEncode(it.toData())).toList(),
attachments?.map((it) => jsonEncode(it.toData()))?.toList(),
channelCid: cid, channelCid: cid,
type: type, type: type,
parentId: parentId, parentId: parentId,
@@ -63,6 +62,7 @@ extension PMessageX on Message {
replyCount: replyCount, replyCount: replyCount,
reactionScores: reactionScores, reactionScores: reactionScores,
reactionCounts: reactionCounts, reactionCounts: reactionCounts,
mentionedUsers: mentionedUsers.map(jsonEncode).toList(),
status: status, status: status,
updatedAt: updatedAt, updatedAt: updatedAt,
extraData: extraData, extraData: extraData,
@@ -4,7 +4,7 @@ import 'package:stream_chat_persistence/src/db/moor_chat_database.dart';
/// Useful mapping functions for [ReactionEntity] /// Useful mapping functions for [ReactionEntity]
extension ReactionEntityX on ReactionEntity { extension ReactionEntityX on ReactionEntity {
/// Maps a [ReactionEntity] into [Reaction] /// Maps a [ReactionEntity] into [Reaction]
Reaction toReaction({User user}) => Reaction( Reaction toReaction({User? user}) => Reaction(
extraData: extraData, extraData: extraData,
type: type, type: type,
createdAt: createdAt, createdAt: createdAt,
@@ -22,8 +22,8 @@ extension ReactionX on Reaction {
extraData: extraData, extraData: extraData,
type: type, type: type,
createdAt: createdAt, createdAt: createdAt,
userId: userId, userId: userId!,
messageId: messageId, messageId: messageId!,
score: score, score: score,
); );
} }
@@ -4,7 +4,7 @@ import 'package:stream_chat_persistence/src/db/moor_chat_database.dart';
/// Useful mapping functions for [ReadEntity] /// Useful mapping functions for [ReadEntity]
extension ReadEntityX on ReadEntity { extension ReadEntityX on ReadEntity {
/// Maps a [ReadEntity] into [Read] /// Maps a [ReadEntity] into [Read]
Read toRead({User user}) => Read( Read toRead({required User user}) => Read(
user: user, user: user,
lastRead: lastRead, lastRead: lastRead,
unreadMessages: unreadMessages, unreadMessages: unreadMessages,
@@ -14,9 +14,9 @@ extension ReadEntityX on ReadEntity {
/// Useful mapping functions for [Read] /// Useful mapping functions for [Read]
extension ReadX on Read { extension ReadX on Read {
/// Maps a [Read] into [ReadEntity] /// Maps a [Read] into [ReadEntity]
ReadEntity toEntity({String cid}) => ReadEntity( ReadEntity toEntity({required String cid}) => ReadEntity(
lastRead: lastRead, lastRead: lastRead,
userId: user?.id, userId: user.id,
channelCid: cid, channelCid: cid,
unreadMessages: unreadMessages, unreadMessages: unreadMessages,
); );
@@ -1,3 +1,4 @@
import 'package:flutter/foundation.dart';
import 'package:logging/logging.dart' show LogRecord; import 'package:logging/logging.dart' show LogRecord;
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:mutex/mutex.dart'; import 'package:mutex/mutex.dart';
@@ -30,17 +31,15 @@ class StreamChatPersistenceClient extends ChatPersistenceClient {
/// Connection mode on which the client will work /// Connection mode on which the client will work
ConnectionMode connectionMode = ConnectionMode.regular, ConnectionMode connectionMode = ConnectionMode.regular,
Level logLevel = Level.WARNING, Level logLevel = Level.WARNING,
LogHandlerFunction logHandlerFunction, LogHandlerFunction? logHandlerFunction,
}) : assert(connectionMode != null, 'ConnectionMode cannot be null'), }) : _connectionMode = connectionMode,
assert(logLevel != null, 'LogLevel cannot be null'),
_connectionMode = connectionMode,
_logger = Logger.detached('💽')..level = logLevel { _logger = Logger.detached('💽')..level = logLevel {
_logger.onRecord.listen(logHandlerFunction ?? _defaultLogHandler); _logger.onRecord.listen(logHandlerFunction ?? _defaultLogHandler);
} }
/// [MoorChatDatabase] instance used by this client. /// [MoorChatDatabase] instance used by this client.
@visibleForTesting @visibleForTesting
MoorChatDatabase db; MoorChatDatabase? db;
final Logger _logger; final Logger _logger;
final ConnectionMode _connectionMode; final ConnectionMode _connectionMode;
@@ -55,15 +54,20 @@ class StreamChatPersistenceClient extends ChatPersistenceClient {
if (record.stackTrace != null) print(record.stackTrace); if (record.stackTrace != null) print(record.stackTrace);
} }
Future<T> _readProtected<T>(Future<T> Function() f) async { Future<T> _readProtected<T>(AsyncValueGetter<T> func) =>
T ret; _mutex.protectRead(func);
await _mutex.protectRead(() async {
bool get _debugIsConnected {
assert(() {
if (db == null) { if (db == null) {
return; throw StateError('''
$runtimeType hasn't been connected yet or used after `disconnect`
was called. Consider calling `connect` to create a connection.
''');
} }
ret = await f(); return true;
}); }(), '');
return ret; return true;
} }
MoorChatDatabase _defaultDatabaseProvider( MoorChatDatabase _defaultDatabaseProvider(
@@ -75,7 +79,7 @@ class StreamChatPersistenceClient extends ChatPersistenceClient {
@override @override
Future<void> connect( Future<void> connect(
String userId, { String userId, {
DatabaseProvider databaseProvider, // Used only for testing DatabaseProvider? databaseProvider, // Used only for testing
}) async { }) async {
if (db != null) { if (db != null) {
throw Exception( throw Exception(
@@ -88,239 +92,281 @@ class StreamChatPersistenceClient extends ChatPersistenceClient {
} }
@override @override
Future<Event> getConnectionInfo() => _readProtected(() { Future<Event?> getConnectionInfo() {
_logger.info('getConnectionInfo'); assert(_debugIsConnected, '');
return db.connectionEventDao.connectionEvent; _logger.info('getConnectionInfo');
}); return _readProtected(() => db!.connectionEventDao.connectionEvent);
}
@override @override
Future<void> updateConnectionInfo(Event event) => _readProtected(() { Future<void> updateConnectionInfo(Event event) {
_logger.info('updateConnectionInfo'); assert(_debugIsConnected, '');
return db.connectionEventDao.updateConnectionEvent(event); _logger.info('updateConnectionInfo');
}); return _readProtected(
() => db!.connectionEventDao.updateConnectionEvent(event),
);
}
@override @override
Future<void> updateLastSyncAt(DateTime lastSyncAt) => _readProtected(() { Future<void> updateLastSyncAt(DateTime lastSyncAt) {
_logger.info('updateLastSyncAt'); assert(_debugIsConnected, '');
return db.connectionEventDao.updateLastSyncAt(lastSyncAt); _logger.info('updateLastSyncAt');
}); return _readProtected(
() => db!.connectionEventDao.updateLastSyncAt(lastSyncAt),
);
}
@override @override
Future<DateTime> getLastSyncAt() => _readProtected(() { Future<DateTime?> getLastSyncAt() {
_logger.info('getLastSyncAt'); assert(_debugIsConnected, '');
return db.connectionEventDao.lastSyncAt; _logger.info('getLastSyncAt');
}); return _readProtected(() => db!.connectionEventDao.lastSyncAt);
}
@override @override
Future<void> deleteChannels(List<String> cids) => _readProtected(() { Future<void> deleteChannels(List<String> cids) {
_logger.info('deleteChannels'); assert(_debugIsConnected, '');
return db.channelDao.deleteChannelByCids(cids); _logger.info('deleteChannels');
}); return _readProtected(() => db!.channelDao.deleteChannelByCids(cids));
}
@override @override
Future<List<String>> getChannelCids() => _readProtected(() { Future<List<String>> getChannelCids() {
_logger.info('getChannelCids'); assert(_debugIsConnected, '');
return db.channelDao.cids; _logger.info('getChannelCids');
}); return _readProtected(() => db!.channelDao.cids);
}
@override @override
Future<void> deleteMessageByIds(List<String> messageIds) => Future<void> deleteMessageByIds(List<String> messageIds) {
_readProtected(() { assert(_debugIsConnected, '');
_logger.info('deleteMessageByIds'); _logger.info('deleteMessageByIds');
return db.messageDao.deleteMessageByIds(messageIds); return _readProtected(() => db!.messageDao.deleteMessageByIds(messageIds));
}); }
@override @override
Future<void> deletePinnedMessageByIds(List<String> messageIds) => Future<void> deletePinnedMessageByIds(List<String> messageIds) {
_readProtected(() { assert(_debugIsConnected, '');
_logger.info('deletePinnedMessageByIds'); _logger.info('deletePinnedMessageByIds');
return db.pinnedMessageDao.deleteMessageByIds(messageIds); return _readProtected(
}); () => db!.pinnedMessageDao.deleteMessageByIds(messageIds),
);
}
@override @override
Future<void> deleteMessageByCids(List<String> cids) => _readProtected(() { Future<void> deleteMessageByCids(List<String> cids) {
_logger.info('deleteMessageByCids'); assert(_debugIsConnected, '');
return db.messageDao.deleteMessageByCids(cids); _logger.info('deleteMessageByCids');
}); return _readProtected(() => db!.messageDao.deleteMessageByCids(cids));
}
@override @override
Future<void> deletePinnedMessageByCids(List<String> cids) => Future<void> deletePinnedMessageByCids(List<String> cids) {
_readProtected(() { assert(_debugIsConnected, '');
_logger.info('deletePinnedMessageByCids'); _logger.info('deletePinnedMessageByCids');
return db.pinnedMessageDao.deleteMessageByCids(cids); return _readProtected(() => db!.pinnedMessageDao.deleteMessageByCids(cids));
}); }
@override @override
Future<List<Member>> getMembersByCid(String cid) => _readProtected(() { Future<List<Member>> getMembersByCid(String cid) {
_logger.info('getMembersByCid'); assert(_debugIsConnected, '');
return db.memberDao.getMembersByCid(cid); _logger.info('getMembersByCid');
}); return _readProtected(() => db!.memberDao.getMembersByCid(cid));
}
@override @override
Future<ChannelModel> getChannelByCid(String cid) => _readProtected(() { Future<ChannelModel?> getChannelByCid(String cid) {
_logger.info('getChannelByCid'); assert(_debugIsConnected, '');
return db.channelDao.getChannelByCid(cid); _logger.info('getChannelByCid');
}); return _readProtected(() => db!.channelDao.getChannelByCid(cid));
}
@override @override
Future<List<Message>> getMessagesByCid( Future<List<Message>> getMessagesByCid(
String cid, { String cid, {
PaginationParams messagePagination, PaginationParams? messagePagination,
}) => }) {
_readProtected(() { assert(_debugIsConnected, '');
_logger.info('getMessagesByCid'); _logger.info('getMessagesByCid');
return db.messageDao.getMessagesByCid( return _readProtected(
cid, () => db!.messageDao.getMessagesByCid(
messagePagination: messagePagination, cid,
); messagePagination: messagePagination,
}); ),
);
}
@override @override
Future<List<Message>> getPinnedMessagesByCid( Future<List<Message>> getPinnedMessagesByCid(
String cid, { String cid, {
PaginationParams messagePagination, PaginationParams? messagePagination,
}) => }) {
_readProtected(() { assert(_debugIsConnected, '');
_logger.info('getPinnedMessagesByCid'); _logger.info('getPinnedMessagesByCid');
return db.pinnedMessageDao.getMessagesByCid( return _readProtected(
cid, () => db!.pinnedMessageDao.getMessagesByCid(
messagePagination: messagePagination, cid,
); messagePagination: messagePagination,
}); ),
);
}
@override @override
Future<List<Read>> getReadsByCid(String cid) => _readProtected(() { Future<List<Read>> getReadsByCid(String cid) {
_logger.info('getReadsByCid'); assert(_debugIsConnected, '');
return db.readDao.getReadsByCid(cid); _logger.info('getReadsByCid');
}); return _readProtected(() => db!.readDao.getReadsByCid(cid));
}
@override @override
Future<Map<String, List<Message>>> getChannelThreads(String cid) async => Future<Map<String, List<Message>>> getChannelThreads(String cid) {
_readProtected(() async { assert(_debugIsConnected, '');
_logger.info('getChannelThreads'); _logger.info('getChannelThreads');
final messages = await db.messageDao.getThreadMessages(cid); return _readProtected(() async {
final messageByParentIdDictionary = <String, List<Message>>{}; final messages = await db!.messageDao.getThreadMessages(cid);
for (final message in messages) { final messageByParentIdDictionary = <String, List<Message>>{};
final parentId = message.parentId; for (final message in messages) {
messageByParentIdDictionary[parentId] = [ final parentId = message.parentId!;
...messageByParentIdDictionary[parentId] ?? [], messageByParentIdDictionary[parentId] = [
message ...messageByParentIdDictionary[parentId] ?? [],
]; message
} ];
return messageByParentIdDictionary; }
}); return messageByParentIdDictionary;
});
}
@override @override
Future<List<Message>> getReplies( Future<List<Message>> getReplies(
String parentId, { String parentId, {
PaginationParams options, PaginationParams? options,
}) => }) {
_readProtected(() async { assert(_debugIsConnected, '');
_logger.info('getReplies'); _logger.info('getReplies');
return db.messageDao.getThreadMessagesByParentId( return _readProtected(
parentId, () => db!.messageDao.getThreadMessagesByParentId(
options: options, parentId,
); options: options,
}); ),
);
}
@override @override
Future<List<ChannelState>> getChannelStates({ Future<List<ChannelState>> getChannelStates({
Map<String, dynamic> filter, Map<String, dynamic>? filter,
List<SortOption<ChannelModel>> sort = const [], List<SortOption<ChannelModel>>? sort,
PaginationParams paginationParams, PaginationParams? paginationParams,
}) async => }) {
_readProtected(() async { assert(_debugIsConnected, '');
_logger.info('getChannelStates'); _logger.info('getChannelStates');
final channels = await db.channelQueryDao.getChannels( return _readProtected(
() async {
final channels = await db!.channelQueryDao.getChannels(
filter: filter, filter: filter,
sort: sort, sort: sort,
paginationParams: paginationParams, paginationParams: paginationParams,
); );
return Future.wait(channels.map((e) => getChannelStateByCid(e.cid))); return Future.wait(channels.map((e) => getChannelStateByCid(e.cid)));
}); },
);
}
@override @override
Future<void> updateChannelQueries( Future<void> updateChannelQueries(
Map<String, dynamic> filter, Map<String, dynamic> filter,
List<String> cids, { List<String> cids, {
bool clearQueryCache = false, bool clearQueryCache = false,
}) => }) {
_readProtected(() async { assert(_debugIsConnected, '');
_logger.info('updateChannelQueries'); _logger.info('updateChannelQueries');
return db.channelQueryDao.updateChannelQueries( return _readProtected(
filter, () => db!.channelQueryDao.updateChannelQueries(
cids, filter,
clearQueryCache: clearQueryCache, cids,
); clearQueryCache: clearQueryCache,
}); ),
);
}
@override @override
Future<void> updateChannels(List<ChannelModel> channels) => Future<void> updateChannels(List<ChannelModel> channels) {
_readProtected(() async { assert(_debugIsConnected, '');
_logger.info('updateChannels'); _logger.info('updateChannels');
return db.channelDao.updateChannels(channels); return _readProtected(() => db!.channelDao.updateChannels(channels));
}); }
@override @override
Future<void> updateMembers(String cid, List<Member> members) => Future<void> updateMembers(String cid, List<Member> members) {
_readProtected(() async { assert(_debugIsConnected, '');
_logger.info('updateMembers'); _logger.info('updateMembers');
return db.memberDao.updateMembers(cid, members); return _readProtected(() => db!.memberDao.updateMembers(cid, members));
}); }
@override @override
Future<void> updateMessages(String cid, List<Message> messages) => Future<void> updateMessages(String cid, List<Message> messages) {
_readProtected(() async { assert(_debugIsConnected, '');
_logger.info('updateMessages'); _logger.info('updateMessages');
return db.messageDao.updateMessages(cid, messages); return _readProtected(() => db!.messageDao.updateMessages(cid, messages));
}); }
@override @override
Future<void> updatePinnedMessages(String cid, List<Message> messages) => Future<void> updatePinnedMessages(String cid, List<Message> messages) {
_readProtected(() async { assert(_debugIsConnected, '');
_logger.info('updatePinnedMessages'); _logger.info('updatePinnedMessages');
return db.pinnedMessageDao.updateMessages(cid, messages); return _readProtected(
}); () => db!.pinnedMessageDao.updateMessages(cid, messages),
);
}
@override @override
Future<void> updateReactions(List<Reaction> reactions) => Future<void> updateReactions(List<Reaction> reactions) {
_readProtected(() async { assert(_debugIsConnected, '');
_logger.info('updateReactions'); _logger.info('updateReactions');
return db.reactionDao.updateReactions(reactions); return _readProtected(() => db!.reactionDao.updateReactions(reactions));
}); }
@override @override
Future<void> updateReads(String cid, List<Read> reads) => Future<void> updateReads(String cid, List<Read> reads) {
_readProtected(() async { assert(_debugIsConnected, '');
_logger.info('updateReads'); _logger.info('updateReads');
return db.readDao.updateReads(cid, reads); return _readProtected(() => db!.readDao.updateReads(cid, reads));
}); }
@override @override
Future<void> updateUsers(List<User> users) => _readProtected(() async { Future<void> updateUsers(List<User> users) {
_logger.info('updateUsers'); assert(_debugIsConnected, '');
return db.userDao.updateUsers(users); _logger.info('updateUsers');
}); return _readProtected(() => db!.userDao.updateUsers(users));
}
@override @override
Future<void> deleteReactionsByMessageId(List<String> messageIds) => Future<void> deleteReactionsByMessageId(List<String> messageIds) {
_readProtected(() async { assert(_debugIsConnected, '');
_logger.info('deleteReactionsByMessageId'); _logger.info('deleteReactionsByMessageId');
return db.reactionDao.deleteReactionsByMessageIds(messageIds); return _readProtected(
}); () => db!.reactionDao.deleteReactionsByMessageIds(messageIds),
);
}
@override @override
Future<void> deleteMembersByCids(List<String> cids) => Future<void> deleteMembersByCids(List<String> cids) {
_readProtected(() async { assert(_debugIsConnected, '');
_logger.info('deleteMembersByCids'); _logger.info('deleteMembersByCids');
return db.memberDao.deleteMemberByCids(cids); return _readProtected(() => db!.memberDao.deleteMemberByCids(cids));
}); }
@override @override
Future<void> updateChannelStates(List<ChannelState> channelStates) => Future<void> updateChannelStates(List<ChannelState> channelStates) {
_readProtected(() async => db.transaction(() async { assert(_debugIsConnected, '');
await super.updateChannelStates(channelStates); _logger.info('updateChannelStates');
})); return _readProtected(
() async => db!.transaction(
() async {
await super.updateChannelStates(channelStates);
},
),
);
}
@override @override
Future<void> disconnect({bool flush = false}) async => Future<void> disconnect({bool flush = false}) async =>
@@ -330,13 +376,9 @@ class StreamChatPersistenceClient extends ChatPersistenceClient {
_logger.info('Disconnecting'); _logger.info('Disconnecting');
if (flush) { if (flush) {
_logger.info('Flushing'); _logger.info('Flushing');
await db.batch((batch) { await db!.flush();
db.allTables.forEach((table) {
db.delete(table).go();
});
});
} }
await db.disconnect(); await db!.disconnect();
db = null; db = null;
} }
}); });
+9 -11
View File
@@ -5,21 +5,19 @@ version: 1.5.1
repository: https://github.com/GetStream/stream-chat-flutter repository: https://github.com/GetStream/stream-chat-flutter
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
publish_to: none
environment: environment:
sdk: ">=2.7.0 <3.0.0" sdk: ">=2.12.0 <3.0.0"
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
logging: ^1.0.0 logging: ^1.0.1
meta: ^1.3.0 meta: ^1.3.0
moor: ^4.2.0 moor: ^4.2.1
mutex: ^3.0.0 mutex: ^3.0.0
path: ^1.8.0 path: ^1.8.0
path_provider: ^2.0.0 path_provider: ^2.0.1
sqlite3_flutter_libs: ^0.4.0+1 sqlite3_flutter_libs: ^0.4.1
stream_chat: ^1.5.1 stream_chat: ^1.5.1
dependency_overrides: dependency_overrides:
@@ -27,8 +25,8 @@ dependency_overrides:
path: ../stream_chat path: ../stream_chat
dev_dependencies: dev_dependencies:
build_runner: ^1.11.0 build_runner: ^1.12.2
mocktail: ^0.1.0 mocktail: ^0.1.1
moor_generator: ^4.2.0 moor_generator: ^4.2.1
pedantic: ^1.11.0 pedantic: ^1.11.0
test: ^1.16.0 test: ^1.16.8
@@ -3,53 +3,59 @@ import 'package:stream_chat_persistence/src/dao/dao.dart';
import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; import 'package:stream_chat_persistence/src/db/moor_chat_database.dart';
class MockChatDatabase extends Mock implements MoorChatDatabase { class MockChatDatabase extends Mock implements MoorChatDatabase {
UserDao _userDao; UserDao? _userDao;
@override @override
UserDao get userDao => _userDao ??= MockUserDao(); UserDao get userDao => _userDao ??= MockUserDao();
ChannelDao _channelDao; ChannelDao? _channelDao;
@override @override
ChannelDao get channelDao => _channelDao ??= MockChannelDao(); ChannelDao get channelDao => _channelDao ??= MockChannelDao();
MessageDao _messageDao; MessageDao? _messageDao;
@override @override
MessageDao get messageDao => _messageDao ??= MockMessageDao(); MessageDao get messageDao => _messageDao ??= MockMessageDao();
PinnedMessageDao _pinnedMessageDao; PinnedMessageDao? _pinnedMessageDao;
@override @override
PinnedMessageDao get pinnedMessageDao => PinnedMessageDao get pinnedMessageDao =>
_pinnedMessageDao ??= MockPinnedMessageDao(); _pinnedMessageDao ??= MockPinnedMessageDao();
MemberDao _memberDao; MemberDao? _memberDao;
@override @override
MemberDao get memberDao => _memberDao ??= MockMemberDao(); MemberDao get memberDao => _memberDao ??= MockMemberDao();
ReactionDao _reactionDao; ReactionDao? _reactionDao;
@override @override
ReactionDao get reactionDao => _reactionDao ??= MockReactionDao(); ReactionDao get reactionDao => _reactionDao ??= MockReactionDao();
ReadDao _readDao; ReadDao? _readDao;
@override @override
ReadDao get readDao => _readDao ??= MockReadDao(); ReadDao get readDao => _readDao ??= MockReadDao();
ChannelQueryDao _channelQueryDao; ChannelQueryDao? _channelQueryDao;
@override @override
ChannelQueryDao get channelQueryDao => ChannelQueryDao get channelQueryDao =>
_channelQueryDao ??= MockChannelQueryDao(); _channelQueryDao ??= MockChannelQueryDao();
ConnectionEventDao _connectionEventDao; ConnectionEventDao? _connectionEventDao;
@override @override
ConnectionEventDao get connectionEventDao => ConnectionEventDao get connectionEventDao =>
_connectionEventDao ??= MockConnectionEventDao(); _connectionEventDao ??= MockConnectionEventDao();
@override
Future<void> flush() => Future.value();
@override
Future<void> disconnect() => Future.value();
} }
class MockUserDao extends Mock implements UserDao {} class MockUserDao extends Mock implements UserDao {}
@@ -32,7 +32,7 @@ void main() {
test('should return list of String if json data list is provided', () { test('should return list of String if json data list is provided', () {
final data = ['data1', 'data2', 'data3']; final data = ['data1', 'data2', 'data3'];
final res = listConverter.mapToDart(jsonEncode(data)); final res = listConverter.mapToDart(jsonEncode(data));
expect(res.length, data.length); expect(res!.length, data.length);
}); });
}); });
@@ -4,8 +4,8 @@ import 'package:stream_chat_persistence/src/db/moor_chat_database.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
void main() { void main() {
ChannelDao channelDao; late ChannelDao channelDao;
MoorChatDatabase database; late MoorChatDatabase database;
setUp(() { setUp(() {
database = MoorChatDatabase.testable('testUserId'); database = MoorChatDatabase.testable('testUserId');
@@ -32,7 +32,8 @@ void main() {
// Should match the dummy channel // Should match the dummy channel
final updatedChannel = await channelDao.getChannelByCid(cid); final updatedChannel = await channelDao.getChannelByCid(cid);
expect(updatedChannel.id, id); expect(updatedChannel, isNotNull);
expect(updatedChannel!.id, id);
expect(updatedChannel.cid, cid); expect(updatedChannel.cid, cid);
expect(updatedChannel.type, type); expect(updatedChannel.type, type);
}); });
@@ -53,7 +54,8 @@ void main() {
// Should match the dummy channel // Should match the dummy channel
final updatedChannel = await channelDao.getChannelByCid(cid); final updatedChannel = await channelDao.getChannelByCid(cid);
expect(updatedChannel.id, id); expect(updatedChannel, isNotNull);
expect(updatedChannel!.id, id);
expect(updatedChannel.cid, cid); expect(updatedChannel.cid, cid);
expect(updatedChannel.type, type); expect(updatedChannel.type, type);
@@ -108,7 +110,8 @@ void main() {
// Should match the dummy channel // Should match the dummy channel
final updatedChannel = await channelDao.getChannelByCid(cid); final updatedChannel = await channelDao.getChannelByCid(cid);
expect(updatedChannel.id, id); expect(updatedChannel, isNotNull);
expect(updatedChannel!.id, id);
expect(updatedChannel.cid, cid); expect(updatedChannel.cid, cid);
expect(updatedChannel.type, type); expect(updatedChannel.type, type);
@@ -119,7 +122,8 @@ void main() {
// Should match the new channel // Should match the new channel
final newUpdatedChannel = await channelDao.getChannelByCid(cid); final newUpdatedChannel = await channelDao.getChannelByCid(cid);
expect(newUpdatedChannel.id, id); expect(newUpdatedChannel, isNotNull);
expect(newUpdatedChannel!.id, id);
expect(newUpdatedChannel.cid, cid); expect(newUpdatedChannel.cid, cid);
expect(newUpdatedChannel.type, newType); expect(newUpdatedChannel.type, newType);
}); });
@@ -8,8 +8,8 @@ import 'package:test/test.dart';
import '../utils/date_matcher.dart'; import '../utils/date_matcher.dart';
void main() { void main() {
MoorChatDatabase database; late MoorChatDatabase database;
ChannelQueryDao channelQueryDao; late ChannelQueryDao channelQueryDao;
setUp(() { setUp(() {
database = MoorChatDatabase.testable('testUserId'); database = MoorChatDatabase.testable('testUserId');
@@ -147,7 +147,7 @@ void main() {
// Should match lastMessageAt date // Should match lastMessageAt date
expect( expect(
updatedChannel.lastMessageAt, updatedChannel.lastMessageAt,
isSameDateAs(insertedChannel.lastMessageAt), isSameDateAs(insertedChannel.lastMessageAt!),
); );
} }
}); });
@@ -160,10 +160,7 @@ void main() {
const pagination = PaginationParams(offset: offset, limit: limit); const pagination = PaginationParams(offset: offset, limit: limit);
// Inserting test data for get channels // Inserting test data for get channels
final insertedChannels = await _insertTestDataForGetChannel( await _insertTestDataForGetChannel(filter, count: 30);
filter,
count: 30,
);
// Should match with the inserted channels // Should match with the inserted channels
final updatedChannels = await channelQueryDao.getChannels( final updatedChannels = await channelQueryDao.getChannels(
@@ -210,7 +207,7 @@ void main() {
// Should match lastMessageAt date // Should match lastMessageAt date
expect( expect(
updatedChannel.lastMessageAt, updatedChannel.lastMessageAt,
isSameDateAs(insertedChannel.lastMessageAt), isSameDateAs(insertedChannel.lastMessageAt!),
); );
} }
}); });
@@ -226,8 +223,8 @@ void main() {
test('should return sorted channels using custom field', () async { test('should return sorted channels using custom field', () async {
int sortComparator(ChannelModel a, ChannelModel b) { int sortComparator(ChannelModel a, ChannelModel b) {
final aData = a.extraData['test_custom_field'] as int; final aData = a.extraData!['test_custom_field'] as int;
final bData = b.extraData['test_custom_field'] as int; final bData = b.extraData!['test_custom_field'] as int;
return bData.compareTo(aData); return bData.compareTo(aData);
} }
@@ -261,7 +258,7 @@ void main() {
// Should match lastMessageAt date // Should match lastMessageAt date
expect( expect(
updatedChannel.lastMessageAt, updatedChannel.lastMessageAt,
isSameDateAs(insertedChannel.lastMessageAt), isSameDateAs(insertedChannel.lastMessageAt!),
); );
} }
}); });
@@ -6,8 +6,8 @@ import 'package:test/test.dart';
import '../utils/date_matcher.dart'; import '../utils/date_matcher.dart';
void main() { void main() {
ConnectionEventDao eventDao; late ConnectionEventDao eventDao;
MoorChatDatabase database; late MoorChatDatabase database;
setUp(() { setUp(() {
database = MoorChatDatabase.testable('testUserId'); database = MoorChatDatabase.testable('testUserId');
@@ -30,7 +30,8 @@ void main() {
// Should match the added event // Should match the added event
final updatedEvent = await eventDao.connectionEvent; final updatedEvent = await eventDao.connectionEvent;
expect(updatedEvent.me.id, newEvent.me.id); expect(updatedEvent, isNotNull);
expect(updatedEvent!.me!.id, newEvent.me!.id);
expect(updatedEvent.totalUnreadCount, newEvent.totalUnreadCount); expect(updatedEvent.totalUnreadCount, newEvent.totalUnreadCount);
expect(updatedEvent.unreadChannels, newEvent.unreadChannels); expect(updatedEvent.unreadChannels, newEvent.unreadChannels);
}); });
@@ -70,7 +71,8 @@ void main() {
// Should match the previously added event // Should match the previously added event
final fetchedEvent = await eventDao.connectionEvent; final fetchedEvent = await eventDao.connectionEvent;
expect(fetchedEvent.me.id, event.me.id); expect(fetchedEvent, isNotNull);
expect(fetchedEvent!.me!.id, event.me!.id);
expect(fetchedEvent.totalUnreadCount, event.totalUnreadCount); expect(fetchedEvent.totalUnreadCount, event.totalUnreadCount);
expect(fetchedEvent.unreadChannels, event.unreadChannels); expect(fetchedEvent.unreadChannels, event.unreadChannels);
@@ -80,7 +82,8 @@ void main() {
// Should match the updated event // Should match the updated event
final fetchedNewEvent = await eventDao.connectionEvent; final fetchedNewEvent = await eventDao.connectionEvent;
expect(fetchedNewEvent.me.id, event.me.id); expect(fetchedNewEvent, isNotNull);
expect(fetchedNewEvent!.me!.id, event.me!.id);
expect(fetchedNewEvent.totalUnreadCount, event.totalUnreadCount); expect(fetchedNewEvent.totalUnreadCount, event.totalUnreadCount);
expect(fetchedNewEvent.unreadChannels, newEvent.unreadChannels); expect(fetchedNewEvent.unreadChannels, newEvent.unreadChannels);
}); });
@@ -8,8 +8,8 @@ import 'package:test/test.dart';
import '../utils/date_matcher.dart'; import '../utils/date_matcher.dart';
void main() { void main() {
MemberDao memberDao; late MemberDao memberDao;
MoorChatDatabase database; late MoorChatDatabase database;
setUp(() { setUp(() {
database = MoorChatDatabase.testable('testUserId'); database = MoorChatDatabase.testable('testUserId');
@@ -53,7 +53,7 @@ void main() {
for (var i = 0; i < fetchedMembers.length; i++) { for (var i = 0; i < fetchedMembers.length; i++) {
final member = memberList[i]; final member = memberList[i];
final fetchedMember = fetchedMembers[i]; final fetchedMember = fetchedMembers[i];
expect(fetchedMember.user.id, member.user.id); expect(fetchedMember.user!.id, member.user!.id);
expect(fetchedMember.banned, member.banned); expect(fetchedMember.banned, member.banned);
expect(fetchedMember.shadowBanned, member.shadowBanned); expect(fetchedMember.shadowBanned, member.shadowBanned);
expect(fetchedMember.createdAt, isSameDateAs(member.createdAt)); expect(fetchedMember.createdAt, isSameDateAs(member.createdAt));
@@ -63,7 +63,7 @@ void main() {
expect(fetchedMember.updatedAt, isSameDateAs(member.updatedAt)); expect(fetchedMember.updatedAt, isSameDateAs(member.updatedAt));
expect( expect(
fetchedMember.inviteAcceptedAt, fetchedMember.inviteAcceptedAt,
isSameDateAs(member.inviteAcceptedAt), isSameDateAs(member.inviteAcceptedAt!),
); );
} }
}); });
@@ -80,7 +80,7 @@ void main() {
for (var i = 0; i < fetchedMembers.length; i++) { for (var i = 0; i < fetchedMembers.length; i++) {
final member = memberList[i]; final member = memberList[i];
final fetchedMember = fetchedMembers[i]; final fetchedMember = fetchedMembers[i];
expect(fetchedMember.user.id, member.user.id); expect(fetchedMember.user!.id, member.user!.id);
expect(fetchedMember.banned, member.banned); expect(fetchedMember.banned, member.banned);
expect(fetchedMember.shadowBanned, member.shadowBanned); expect(fetchedMember.shadowBanned, member.shadowBanned);
expect(fetchedMember.createdAt, isSameDateAs(member.createdAt)); expect(fetchedMember.createdAt, isSameDateAs(member.createdAt));
@@ -90,7 +90,7 @@ void main() {
expect(fetchedMember.updatedAt, isSameDateAs(member.updatedAt)); expect(fetchedMember.updatedAt, isSameDateAs(member.updatedAt));
expect( expect(
fetchedMember.inviteAcceptedAt, fetchedMember.inviteAcceptedAt,
isSameDateAs(member.inviteAcceptedAt), isSameDateAs(member.inviteAcceptedAt!),
); );
} }
@@ -118,13 +118,13 @@ void main() {
expect(newFetchedMembers.length, fetchedMembers.length + 1); expect(newFetchedMembers.length, fetchedMembers.length + 1);
expect( expect(
newFetchedMembers newFetchedMembers
.firstWhere((it) => it.user.id == copyMember.user.id) .firstWhere((it) => it.user!.id == copyMember.user!.id)
.banned, .banned,
true, true,
); );
expect( expect(
newFetchedMembers newFetchedMembers
.where((it) => it.user.id == newMember.user.id) .where((it) => it.user!.id == newMember.user!.id)
.isNotEmpty, .isNotEmpty,
true, true,
); );
@@ -6,8 +6,8 @@ import 'package:stream_chat_persistence/src/db/moor_chat_database.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
void main() { void main() {
MessageDao messageDao; late MessageDao messageDao;
MoorChatDatabase database; late MoorChatDatabase database;
setUp(() { setUp(() {
database = MoorChatDatabase.testable('testUserId'); database = MoorChatDatabase.testable('testUserId');
@@ -32,7 +32,7 @@ void main() {
shadowed: math.Random().nextBool(), shadowed: math.Random().nextBool(),
replyCount: index, replyCount: index,
updatedAt: DateTime.now(), updatedAt: DateTime.now(),
extraData: {'extra_test_field': 'extraTestData'}, extraData: const {'extra_test_field': 'extraTestData'},
text: 'Dummy text #$index', text: 'Dummy text #$index',
pinned: math.Random().nextBool(), pinned: math.Random().nextBool(),
pinnedAt: DateTime.now(), pinnedAt: DateTime.now(),
@@ -49,7 +49,7 @@ void main() {
shadowed: math.Random().nextBool(), shadowed: math.Random().nextBool(),
replyCount: index, replyCount: index,
updatedAt: DateTime.now(), updatedAt: DateTime.now(),
extraData: {'extra_test_field': 'extraTestData'}, extraData: const {'extra_test_field': 'extraTestData'},
text: 'Dummy text #$index', text: 'Dummy text #$index',
quotedMessageId: messages[index].id, quotedMessageId: messages[index].id,
pinned: math.Random().nextBool(), pinned: math.Random().nextBool(),
@@ -69,7 +69,7 @@ void main() {
shadowed: math.Random().nextBool(), shadowed: math.Random().nextBool(),
replyCount: index, replyCount: index,
updatedAt: DateTime.now(), updatedAt: DateTime.now(),
extraData: {'extra_test_field': 'extraTestData'}, extraData: const {'extra_test_field': 'extraTestData'},
text: 'Dummy text #$index', text: 'Dummy text #$index',
pinned: math.Random().nextBool(), pinned: math.Random().nextBool(),
pinnedAt: DateTime.now(), pinnedAt: DateTime.now(),
@@ -168,7 +168,8 @@ void main() {
// Fetched message id should match the inserted message id // Fetched message id should match the inserted message id
final fetchedMessage = await messageDao.getMessageById(id); final fetchedMessage = await messageDao.getMessageById(id);
expect(fetchedMessage.id, insertedMessages.first.id); expect(fetchedMessage, isNotNull);
expect(fetchedMessage!.id, insertedMessages.first.id);
}); });
test('getThreadMessages', () async { test('getThreadMessages', () async {
@@ -332,7 +333,7 @@ void main() {
showInChannel: math.Random().nextBool(), showInChannel: math.Random().nextBool(),
replyCount: 4, replyCount: 4,
updatedAt: DateTime.now(), updatedAt: DateTime.now(),
extraData: {'extra_test_field': 'extraTestData'}, extraData: const {'extra_test_field': 'extraTestData'},
text: 'Dummy text #4', text: 'Dummy text #4',
pinned: math.Random().nextBool(), pinned: math.Random().nextBool(),
pinnedAt: DateTime.now(), pinnedAt: DateTime.now(),
@@ -6,8 +6,8 @@ import 'package:stream_chat_persistence/src/db/moor_chat_database.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
void main() { void main() {
PinnedMessageDao pinnedMessageDao; late PinnedMessageDao pinnedMessageDao;
MoorChatDatabase database; late MoorChatDatabase database;
setUp(() { setUp(() {
database = MoorChatDatabase.testable('testUserId'); database = MoorChatDatabase.testable('testUserId');
@@ -32,7 +32,7 @@ void main() {
shadowed: math.Random().nextBool(), shadowed: math.Random().nextBool(),
replyCount: index, replyCount: index,
updatedAt: DateTime.now(), updatedAt: DateTime.now(),
extraData: {'extra_test_field': 'extraTestData'}, extraData: const {'extra_test_field': 'extraTestData'},
text: 'Dummy text #$index', text: 'Dummy text #$index',
pinned: math.Random().nextBool(), pinned: math.Random().nextBool(),
pinnedAt: DateTime.now(), pinnedAt: DateTime.now(),
@@ -49,7 +49,7 @@ void main() {
shadowed: math.Random().nextBool(), shadowed: math.Random().nextBool(),
replyCount: index, replyCount: index,
updatedAt: DateTime.now(), updatedAt: DateTime.now(),
extraData: {'extra_test_field': 'extraTestData'}, extraData: const {'extra_test_field': 'extraTestData'},
text: 'Dummy text #$index', text: 'Dummy text #$index',
quotedMessageId: messages[index].id, quotedMessageId: messages[index].id,
pinned: math.Random().nextBool(), pinned: math.Random().nextBool(),
@@ -69,7 +69,7 @@ void main() {
shadowed: math.Random().nextBool(), shadowed: math.Random().nextBool(),
replyCount: index, replyCount: index,
updatedAt: DateTime.now(), updatedAt: DateTime.now(),
extraData: {'extra_test_field': 'extraTestData'}, extraData: const {'extra_test_field': 'extraTestData'},
text: 'Dummy text #$index', text: 'Dummy text #$index',
pinned: math.Random().nextBool(), pinned: math.Random().nextBool(),
pinnedAt: DateTime.now(), pinnedAt: DateTime.now(),
@@ -168,7 +168,8 @@ void main() {
// Fetched message id should match the inserted message id // Fetched message id should match the inserted message id
final fetchedMessage = await pinnedMessageDao.getMessageById(id); final fetchedMessage = await pinnedMessageDao.getMessageById(id);
expect(fetchedMessage.id, insertedMessages.first.id); expect(fetchedMessage, isNotNull);
expect(fetchedMessage!.id, insertedMessages.first.id);
}); });
test('getThreadMessages', () async { test('getThreadMessages', () async {
@@ -333,7 +334,7 @@ void main() {
showInChannel: math.Random().nextBool(), showInChannel: math.Random().nextBool(),
replyCount: 4, replyCount: 4,
updatedAt: DateTime.now(), updatedAt: DateTime.now(),
extraData: {'extra_test_field': 'extraTestData'}, extraData: const {'extra_test_field': 'extraTestData'},
text: 'Dummy text #4', text: 'Dummy text #4',
pinned: math.Random().nextBool(), pinned: math.Random().nextBool(),
pinnedAt: DateTime.now(), pinnedAt: DateTime.now(),
@@ -6,8 +6,8 @@ import 'package:stream_chat_persistence/src/db/moor_chat_database.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
void main() { void main() {
ReactionDao reactionDao; late ReactionDao reactionDao;
MoorChatDatabase database; late MoorChatDatabase database;
setUp(() { setUp(() {
database = MoorChatDatabase.testable('testUserId'); database = MoorChatDatabase.testable('testUserId');
@@ -16,7 +16,7 @@ void main() {
Future<List<Reaction>> _prepareReactionData( Future<List<Reaction>> _prepareReactionData(
String messageId, { String messageId, {
String userId, String? userId,
int count = 3, int count = 3,
}) async { }) async {
final users = List.generate(count, (index) => User(id: 'testUserId$index')); final users = List.generate(count, (index) => User(id: 'testUserId$index'));
@@ -29,7 +29,7 @@ void main() {
showInChannel: math.Random().nextBool(), showInChannel: math.Random().nextBool(),
replyCount: 3, replyCount: 3,
updatedAt: DateTime.now(), updatedAt: DateTime.now(),
extraData: {'extra_test_field': 'extraTestData'}, extraData: const {'extra_test_field': 'extraTestData'},
text: 'Dummy text', text: 'Dummy text',
pinned: math.Random().nextBool(), pinned: math.Random().nextBool(),
pinnedAt: DateTime.now(), pinnedAt: DateTime.now(),
@@ -6,8 +6,8 @@ import 'package:test/test.dart';
import '../utils/date_matcher.dart'; import '../utils/date_matcher.dart';
void main() { void main() {
ReadDao readDao; late ReadDao readDao;
MoorChatDatabase database; late MoorChatDatabase database;
setUp(() { setUp(() {
database = MoorChatDatabase.testable('testUserId'); database = MoorChatDatabase.testable('testUserId');
@@ -6,8 +6,8 @@ import 'package:test/test.dart';
import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat/stream_chat.dart';
void main() { void main() {
UserDao userDao; late UserDao userDao;
MoorChatDatabase database; late MoorChatDatabase database;
setUp(() { setUp(() {
database = MoorChatDatabase.testable('testUserId'); database = MoorChatDatabase.testable('testUserId');
@@ -34,15 +34,21 @@ void main() {
expect(channelModel.updatedAt, isSameDateAs(entity.updatedAt)); expect(channelModel.updatedAt, isSameDateAs(entity.updatedAt));
expect(channelModel.memberCount, entity.memberCount); expect(channelModel.memberCount, entity.memberCount);
expect(channelModel.cid, entity.cid); expect(channelModel.cid, entity.cid);
expect(channelModel.lastMessageAt, isSameDateAs(entity.lastMessageAt)); expect(channelModel.lastMessageAt, isSameDateAs(entity.lastMessageAt!));
expect(channelModel.deletedAt, isSameDateAs(entity.deletedAt)); expect(channelModel.deletedAt, isSameDateAs(entity.deletedAt!));
expect(channelModel.extraData, entity.extraData); expect(channelModel.extraData, entity.extraData);
expect(channelModel.createdBy.id, entity.createdById); expect(channelModel.createdBy!.id, entity.createdById);
}); });
test('toChannelState should map entity into ChannelState ', () { test('toChannelState should map entity into ChannelState ', () {
final members = List.generate(3, (index) => Member()); final members = List.generate(3, (index) => Member());
final reads = List.generate(3, (index) => Read()); final reads = List.generate(
3,
(index) => Read(
user: User(id: 'testUserId$index'),
lastRead: DateTime.now(),
),
);
final messages = List.generate(3, (index) => Message()); final messages = List.generate(3, (index) => Message());
final channelState = entity.toChannelState( final channelState = entity.toChannelState(
@@ -59,7 +65,7 @@ void main() {
expect(channelState.messages.length, messages.length); expect(channelState.messages.length, messages.length);
expect(channelState.pinnedMessages.length, messages.length); expect(channelState.pinnedMessages.length, messages.length);
final channelModel = channelState.channel; final channelModel = channelState.channel!;
expect(channelModel.id, entity.id); expect(channelModel.id, entity.id);
expect(channelModel.config.toJson()['max_message_length'], 33); expect(channelModel.config.toJson()['max_message_length'], 33);
expect(channelModel.frozen, entity.frozen); expect(channelModel.frozen, entity.frozen);
@@ -67,10 +73,10 @@ void main() {
expect(channelModel.updatedAt, isSameDateAs(entity.updatedAt)); expect(channelModel.updatedAt, isSameDateAs(entity.updatedAt));
expect(channelModel.memberCount, entity.memberCount); expect(channelModel.memberCount, entity.memberCount);
expect(channelModel.cid, entity.cid); expect(channelModel.cid, entity.cid);
expect(channelModel.lastMessageAt, isSameDateAs(entity.lastMessageAt)); expect(channelModel.lastMessageAt, isSameDateAs(entity.lastMessageAt!));
expect(channelModel.deletedAt, isSameDateAs(entity.deletedAt)); expect(channelModel.deletedAt, isSameDateAs(entity.deletedAt!));
expect(channelModel.extraData, entity.extraData); expect(channelModel.extraData, entity.extraData);
expect(channelModel.createdBy.id, entity.createdById); expect(channelModel.createdBy!.id, entity.createdById);
}); });
}); });
@@ -103,9 +109,9 @@ void main() {
expect(channelEntity.updatedAt, isSameDateAs(model.updatedAt)); expect(channelEntity.updatedAt, isSameDateAs(model.updatedAt));
expect(channelEntity.memberCount, model.memberCount); expect(channelEntity.memberCount, model.memberCount);
expect(channelEntity.cid, model.cid); expect(channelEntity.cid, model.cid);
expect(channelEntity.lastMessageAt, isSameDateAs(model.lastMessageAt)); expect(channelEntity.lastMessageAt, isSameDateAs(model.lastMessageAt!));
expect(channelEntity.deletedAt, isSameDateAs(model.deletedAt)); expect(channelEntity.deletedAt, isSameDateAs(model.deletedAt!));
expect(channelEntity.extraData, model.extraData); expect(channelEntity.extraData, model.extraData);
expect(channelEntity.createdById, model.createdBy.id); expect(channelEntity.createdById, model.createdBy!.id);
}); });
} }
@@ -16,7 +16,7 @@ void main() {
); );
final event = entity.toEvent(); final event = entity.toEvent();
expect(event, isA<Event>()); expect(event, isA<Event>());
expect(event.me.id, ownUser.id); expect(event.me!.id, ownUser.id);
expect(event.totalUnreadCount, entity.totalUnreadCount); expect(event.totalUnreadCount, entity.totalUnreadCount);
expect(event.unreadChannels, entity.unreadChannels); expect(event.unreadChannels, entity.unreadChannels);
}); });
@@ -25,12 +25,12 @@ void main() {
); );
final member = entity.toMember(user: user); final member = entity.toMember(user: user);
expect(member, isA<Member>()); expect(member, isA<Member>());
expect(member.user.id, entity.userId); expect(member.user!.id, entity.userId);
expect(member.createdAt, isSameDateAs(entity.createdAt)); expect(member.createdAt, isSameDateAs(entity.createdAt));
expect(member.updatedAt, isSameDateAs(entity.updatedAt)); expect(member.updatedAt, isSameDateAs(entity.updatedAt));
expect(member.role, entity.role); expect(member.role, entity.role);
expect(member.inviteAcceptedAt, isSameDateAs(entity.inviteAcceptedAt)); expect(member.inviteAcceptedAt, isSameDateAs(entity.inviteAcceptedAt!));
expect(member.inviteRejectedAt, isSameDateAs(entity.inviteRejectedAt)); expect(member.inviteRejectedAt, isSameDateAs(entity.inviteRejectedAt!));
expect(member.invited, entity.invited); expect(member.invited, entity.invited);
expect(member.banned, entity.banned); expect(member.banned, entity.banned);
expect(member.shadowBanned, entity.shadowBanned); expect(member.shadowBanned, entity.shadowBanned);
@@ -55,12 +55,12 @@ void main() {
final entity = member.toEntity(cid: cid); final entity = member.toEntity(cid: cid);
expect(entity, isA<MemberEntity>()); expect(entity, isA<MemberEntity>());
expect(entity.channelCid, cid); expect(entity.channelCid, cid);
expect(entity.userId, member.user.id); expect(entity.userId, member.user!.id);
expect(entity.createdAt, isSameDateAs(member.createdAt)); expect(entity.createdAt, isSameDateAs(member.createdAt));
expect(entity.updatedAt, isSameDateAs(member.updatedAt)); expect(entity.updatedAt, isSameDateAs(member.updatedAt));
expect(entity.role, member.role); expect(entity.role, member.role);
expect(entity.inviteAcceptedAt, isSameDateAs(member.inviteAcceptedAt)); expect(entity.inviteAcceptedAt, isSameDateAs(member.inviteAcceptedAt!));
expect(entity.inviteRejectedAt, isSameDateAs(member.inviteRejectedAt)); expect(entity.inviteRejectedAt, isSameDateAs(member.inviteRejectedAt!));
expect(entity.invited, member.invited); expect(entity.invited, member.invited);
expect(entity.banned, member.banned); expect(entity.banned, member.banned);
expect(entity.shadowBanned, member.shadowBanned); expect(entity.shadowBanned, member.shadowBanned);
@@ -32,7 +32,7 @@ void main() {
); );
final entity = MessageEntity( final entity = MessageEntity(
id: 'testMessageId', id: 'testMessageId',
attachments: attachments?.map((it) => jsonEncode(it.toData()))?.toList(), attachments: attachments.map((it) => jsonEncode(it.toData())).toList(),
channelCid: 'testCid', channelCid: 'testCid',
type: 'testType', type: 'testType',
parentId: 'testParentId', parentId: 'testParentId',
@@ -46,8 +46,9 @@ void main() {
reactionCounts: reactions.fold( reactionCounts: reactions.fold(
{}, {},
(prev, curr) => (prev, curr) =>
prev..update(curr.type, (value) => value + 1, ifAbsent: () => 1), prev?..update(curr.type, (value) => value + 1, ifAbsent: () => 1),
), ),
mentionedUsers: const [],
status: MessageSendingStatus.sent, status: MessageSendingStatus.sent,
updatedAt: DateTime.now(), updatedAt: DateTime.now(),
extraData: {'extra_test_data': 'extraData'}, extraData: {'extra_test_data': 'extraData'},
@@ -82,13 +83,13 @@ void main() {
expect(message.status, entity.status); expect(message.status, entity.status);
expect(message.updatedAt, isSameDateAs(entity.updatedAt)); expect(message.updatedAt, isSameDateAs(entity.updatedAt));
expect(message.extraData, entity.extraData); expect(message.extraData, entity.extraData);
expect(message.user.id, entity.userId); expect(message.user!.id, entity.userId);
expect(message.deletedAt, isSameDateAs(entity.deletedAt)); expect(message.deletedAt, isSameDateAs(entity.deletedAt!));
expect(message.text, entity.messageText); expect(message.text, entity.messageText);
expect(message.pinned, entity.pinned); expect(message.pinned, entity.pinned);
expect(message.pinExpires, isSameDateAs(entity.pinExpires)); expect(message.pinExpires, isSameDateAs(entity.pinExpires!));
expect(message.pinnedAt, isSameDateAs(entity.pinnedAt)); expect(message.pinnedAt, isSameDateAs(entity.pinnedAt!));
expect(message.pinnedBy.id, entity.pinnedByUserId); expect(message.pinnedBy!.id, entity.pinnedByUserId);
expect(message.reactionCounts, entity.reactionCounts); expect(message.reactionCounts, entity.reactionCounts);
expect(message.reactionScores, entity.reactionScores); expect(message.reactionScores, entity.reactionScores);
for (var i = 0; i < message.attachments.length; i++) { for (var i = 0; i < message.attachments.length; i++) {
@@ -138,11 +139,11 @@ void main() {
reactionCounts: reactions.fold( reactionCounts: reactions.fold(
{}, {},
(prev, curr) => (prev, curr) =>
prev..update(curr.type, (value) => value + 1, ifAbsent: () => 1), prev?..update(curr.type, (value) => value + 1, ifAbsent: () => 1),
), ),
status: MessageSendingStatus.sending, status: MessageSendingStatus.sending,
updatedAt: DateTime.now(), updatedAt: DateTime.now(),
extraData: {'extra_test_data': 'extraData'}, extraData: const {'extra_test_data': 'extraData'},
user: user, user: user,
deletedAt: DateTime.now(), deletedAt: DateTime.now(),
text: 'dummy text', text: 'dummy text',
@@ -167,18 +168,18 @@ void main() {
expect(entity.status, message.status); expect(entity.status, message.status);
expect(entity.updatedAt, isSameDateAs(message.updatedAt)); expect(entity.updatedAt, isSameDateAs(message.updatedAt));
expect(entity.extraData, message.extraData); expect(entity.extraData, message.extraData);
expect(entity.userId, message.user.id); expect(entity.userId, message.user!.id);
expect(entity.deletedAt, isSameDateAs(message.deletedAt)); expect(entity.deletedAt, isSameDateAs(message.deletedAt!));
expect(entity.messageText, message.text); expect(entity.messageText, message.text);
expect(entity.pinned, message.pinned); expect(entity.pinned, message.pinned);
expect(entity.pinExpires, isSameDateAs(message.pinExpires)); expect(entity.pinExpires, isSameDateAs(message.pinExpires!));
expect(entity.pinnedAt, isSameDateAs(message.pinnedAt)); expect(entity.pinnedAt, isSameDateAs(message.pinnedAt!));
expect(entity.pinnedByUserId, message.pinnedBy.id); expect(entity.pinnedByUserId, message.pinnedBy!.id);
expect(entity.reactionCounts, message.reactionCounts); expect(entity.reactionCounts, message.reactionCounts);
expect(entity.reactionScores, message.reactionScores); expect(entity.reactionScores, message.reactionScores);
expect( expect(
entity.attachments, entity.attachments,
message.attachments?.map((it) => jsonEncode(it.toData()))?.toList(), message.attachments.map((it) => jsonEncode(it.toData())).toList(),
); );
}); });
} }
@@ -32,7 +32,7 @@ void main() {
); );
final entity = PinnedMessageEntity( final entity = PinnedMessageEntity(
id: 'testMessageId', id: 'testMessageId',
attachments: attachments?.map((it) => jsonEncode(it.toData()))?.toList(), attachments: attachments.map((it) => jsonEncode(it.toData())).toList(),
channelCid: 'testCid', channelCid: 'testCid',
type: 'testType', type: 'testType',
parentId: 'testParentId', parentId: 'testParentId',
@@ -46,8 +46,9 @@ void main() {
reactionCounts: reactions.fold( reactionCounts: reactions.fold(
{}, {},
(prev, curr) => (prev, curr) =>
prev..update(curr.type, (value) => value + 1, ifAbsent: () => 1), prev?..update(curr.type, (value) => value + 1, ifAbsent: () => 1),
), ),
mentionedUsers: [],
status: MessageSendingStatus.sent, status: MessageSendingStatus.sent,
updatedAt: DateTime.now(), updatedAt: DateTime.now(),
extraData: {'extra_test_data': 'extraData'}, extraData: {'extra_test_data': 'extraData'},
@@ -82,13 +83,13 @@ void main() {
expect(message.status, entity.status); expect(message.status, entity.status);
expect(message.updatedAt, isSameDateAs(entity.updatedAt)); expect(message.updatedAt, isSameDateAs(entity.updatedAt));
expect(message.extraData, entity.extraData); expect(message.extraData, entity.extraData);
expect(message.user.id, entity.userId); expect(message.user!.id, entity.userId);
expect(message.deletedAt, isSameDateAs(entity.deletedAt)); expect(message.deletedAt, isSameDateAs(entity.deletedAt!));
expect(message.text, entity.messageText); expect(message.text, entity.messageText);
expect(message.pinned, entity.pinned); expect(message.pinned, entity.pinned);
expect(message.pinExpires, isSameDateAs(entity.pinExpires)); expect(message.pinExpires, isSameDateAs(entity.pinExpires!));
expect(message.pinnedAt, isSameDateAs(entity.pinnedAt)); expect(message.pinnedAt, isSameDateAs(entity.pinnedAt!));
expect(message.pinnedBy.id, entity.pinnedByUserId); expect(message.pinnedBy!.id, entity.pinnedByUserId);
expect(message.reactionCounts, entity.reactionCounts); expect(message.reactionCounts, entity.reactionCounts);
expect(message.reactionScores, entity.reactionScores); expect(message.reactionScores, entity.reactionScores);
for (var i = 0; i < message.attachments.length; i++) { for (var i = 0; i < message.attachments.length; i++) {
@@ -138,11 +139,11 @@ void main() {
reactionCounts: reactions.fold( reactionCounts: reactions.fold(
{}, {},
(prev, curr) => (prev, curr) =>
prev..update(curr.type, (value) => value + 1, ifAbsent: () => 1), prev?..update(curr.type, (value) => value + 1, ifAbsent: () => 1),
), ),
status: MessageSendingStatus.sending, status: MessageSendingStatus.sending,
updatedAt: DateTime.now(), updatedAt: DateTime.now(),
extraData: {'extra_test_data': 'extraData'}, extraData: const {'extra_test_data': 'extraData'},
user: user, user: user,
deletedAt: DateTime.now(), deletedAt: DateTime.now(),
text: 'dummy text', text: 'dummy text',
@@ -167,18 +168,18 @@ void main() {
expect(entity.status, message.status); expect(entity.status, message.status);
expect(entity.updatedAt, isSameDateAs(message.updatedAt)); expect(entity.updatedAt, isSameDateAs(message.updatedAt));
expect(entity.extraData, message.extraData); expect(entity.extraData, message.extraData);
expect(entity.userId, message.user.id); expect(entity.userId, message.user!.id);
expect(entity.deletedAt, isSameDateAs(message.deletedAt)); expect(entity.deletedAt, isSameDateAs(message.deletedAt!));
expect(entity.messageText, message.text); expect(entity.messageText, message.text);
expect(entity.pinned, message.pinned); expect(entity.pinned, message.pinned);
expect(entity.pinExpires, isSameDateAs(message.pinExpires)); expect(entity.pinExpires, isSameDateAs(message.pinExpires!));
expect(entity.pinnedAt, isSameDateAs(message.pinnedAt)); expect(entity.pinnedAt, isSameDateAs(message.pinnedAt!));
expect(entity.pinnedByUserId, message.pinnedBy.id); expect(entity.pinnedByUserId, message.pinnedBy!.id);
expect(entity.reactionCounts, message.reactionCounts); expect(entity.reactionCounts, message.reactionCounts);
expect(entity.reactionScores, message.reactionScores); expect(entity.reactionScores, message.reactionScores);
expect( expect(
entity.attachments, entity.attachments,
message.attachments?.map((it) => jsonEncode(it.toData()))?.toList(), message.attachments.map((it) => jsonEncode(it.toData())).toList(),
); );
}); });
} }
@@ -24,7 +24,7 @@ void main() {
expect(user.role, entity.role); expect(user.role, entity.role);
expect(user.createdAt, isSameDateAs(entity.createdAt)); expect(user.createdAt, isSameDateAs(entity.createdAt));
expect(user.updatedAt, isSameDateAs(entity.updatedAt)); expect(user.updatedAt, isSameDateAs(entity.updatedAt));
expect(user.lastActive, isSameDateAs(entity.lastActive)); expect(user.lastActive, isSameDateAs(entity.lastActive!));
expect(user.online, entity.online); expect(user.online, entity.online);
expect(user.banned, entity.banned); expect(user.banned, entity.banned);
expect(user.extraData, entity.extraData); expect(user.extraData, entity.extraData);
@@ -47,7 +47,7 @@ void main() {
expect(entity.role, user.role); expect(entity.role, user.role);
expect(entity.createdAt, isSameDateAs(user.createdAt)); expect(entity.createdAt, isSameDateAs(user.createdAt));
expect(entity.updatedAt, isSameDateAs(user.updatedAt)); expect(entity.updatedAt, isSameDateAs(user.updatedAt));
expect(entity.lastActive, isSameDateAs(user.lastActive)); expect(entity.lastActive, isSameDateAs(user.lastActive!));
expect(entity.online, user.online); expect(entity.online, user.online);
expect(entity.banned, user.banned); expect(entity.banned, user.banned);
expect(entity.extraData, user.extraData); expect(entity.extraData, user.extraData);
@@ -1,13 +1,10 @@
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'package:meta/meta.dart';
Matcher isSameDateAs(DateTime targetDate) => Matcher isSameDateAs(DateTime targetDate) =>
_IsSameDateAs(targetDate: targetDate); _IsSameDateAs(targetDate: targetDate);
class _IsSameDateAs extends Matcher { class _IsSameDateAs extends Matcher {
const _IsSameDateAs({ const _IsSameDateAs({required this.targetDate});
@required this.targetDate,
}) : assert(targetDate != null, '');
final DateTime targetDate; final DateTime targetDate;
@@ -10,22 +10,6 @@ MoorChatDatabase _testDatabaseProvider(String userId, ConnectionMode mode) =>
MoorChatDatabase.testable(userId); MoorChatDatabase.testable(userId);
void main() { void main() {
group('client constructor', () {
test('throws assertion error if null connectionMode is provided', () {
expect(
() => StreamChatPersistenceClient(connectionMode: null),
throwsA(isA<AssertionError>()),
);
});
test('throws assertion error if null logLevel is provided', () {
expect(
() => StreamChatPersistenceClient(logLevel: null),
throwsA(isA<AssertionError>()),
);
});
});
group('connect', () { group('connect', () {
const userId = 'testUserId'; const userId = 'testUserId';
test('successfully connects with the Database', () async { test('successfully connects with the Database', () async {
@@ -34,7 +18,7 @@ void main() {
await client.connect(userId, databaseProvider: _testDatabaseProvider); await client.connect(userId, databaseProvider: _testDatabaseProvider);
expect(client.db, isNotNull); expect(client.db, isNotNull);
expect(client.db, isA<MoorChatDatabase>()); expect(client.db, isA<MoorChatDatabase>());
expect(client.db.userId, userId); expect(client.db!.userId, userId);
addTearDown(() async { addTearDown(() async {
await client.disconnect(); await client.disconnect();
@@ -48,7 +32,7 @@ void main() {
expect(client.db, isNotNull); expect(client.db, isNotNull);
expect(client.db, isNotNull); expect(client.db, isNotNull);
expect(client.db, isA<MoorChatDatabase>()); expect(client.db, isA<MoorChatDatabase>());
expect(client.db.userId, userId); expect(client.db!.userId, userId);
expect( expect(
() => client.connect(userId, databaseProvider: _testDatabaseProvider), () => client.connect(userId, databaseProvider: _testDatabaseProvider),
throwsException, throwsException,
@@ -73,7 +57,7 @@ void main() {
const userId = 'testUserId'; const userId = 'testUserId';
final mockDatabase = MockChatDatabase(); final mockDatabase = MockChatDatabase();
MoorChatDatabase _mockDatabaseProvider(_, __) => mockDatabase; MoorChatDatabase _mockDatabaseProvider(_, __) => mockDatabase;
StreamChatPersistenceClient client; late StreamChatPersistenceClient client;
setUp(() async { setUp(() async {
client = StreamChatPersistenceClient(logLevel: Level.ALL); client = StreamChatPersistenceClient(logLevel: Level.ALL);
@@ -95,12 +79,13 @@ void main() {
}); });
test('getConnectionInfo', () async { test('getConnectionInfo', () async {
final event = Event(type: 'testEvent'); const event = Event(type: 'testEvent');
when(() => mockDatabase.connectionEventDao.connectionEvent) when(() => mockDatabase.connectionEventDao.connectionEvent)
.thenAnswer((_) async => event); .thenAnswer((_) async => event);
final fetchedEvent = await client.getConnectionInfo(); final fetchedEvent = await client.getConnectionInfo();
expect(fetchedEvent.type, event.type); expect(fetchedEvent, isNotNull);
expect(fetchedEvent!.type, event.type);
verify(() => mockDatabase.connectionEventDao.connectionEvent).called(1); verify(() => mockDatabase.connectionEventDao.connectionEvent).called(1);
}); });
@@ -115,11 +100,9 @@ void main() {
}); });
test('updateConnectionInfo', () async { test('updateConnectionInfo', () async {
final event = Event(type: 'testEvent'); const event = Event(type: 'testEvent');
when(() => mockDatabase.connectionEventDao.updateConnectionEvent(event)) when(() => mockDatabase.connectionEventDao.updateConnectionEvent(event))
.thenAnswer((_) async { .thenAnswer((_) async => 1);
return;
});
await client.updateConnectionInfo(event); await client.updateConnectionInfo(event);
verify(() => mockDatabase.connectionEventDao.updateConnectionEvent(event)) verify(() => mockDatabase.connectionEventDao.updateConnectionEvent(event))
@@ -129,9 +112,7 @@ void main() {
test('updateLastSyncAt', () async { test('updateLastSyncAt', () async {
final lastSync = DateTime.now(); final lastSync = DateTime.now();
when(() => mockDatabase.connectionEventDao.updateLastSyncAt(lastSync)) when(() => mockDatabase.connectionEventDao.updateLastSyncAt(lastSync))
.thenAnswer((_) { .thenAnswer((_) async => 1);
return;
});
await client.updateLastSyncAt(lastSync); await client.updateLastSyncAt(lastSync);
verify(() => mockDatabase.connectionEventDao.updateLastSyncAt(lastSync)) verify(() => mockDatabase.connectionEventDao.updateLastSyncAt(lastSync))
@@ -149,13 +130,14 @@ void main() {
}); });
test('getChannelByCid', () async { test('getChannelByCid', () async {
const cid = 'testCid'; const cid = 'testType:testId';
final channelModel = ChannelModel(cid: cid); final channelModel = ChannelModel(cid: cid);
when(() => mockDatabase.channelDao.getChannelByCid(cid)) when(() => mockDatabase.channelDao.getChannelByCid(cid))
.thenAnswer((_) async => channelModel); .thenAnswer((_) async => channelModel);
final fetchedChannelModel = await client.getChannelByCid(cid); final fetchedChannelModel = await client.getChannelByCid(cid);
expect(fetchedChannelModel.cid, channelModel.cid); expect(fetchedChannelModel, isNotNull);
expect(fetchedChannelModel!.cid, channelModel.cid);
verify(() => mockDatabase.channelDao.getChannelByCid(cid)).called(1); verify(() => mockDatabase.channelDao.getChannelByCid(cid)).called(1);
}); });
@@ -172,7 +154,13 @@ void main() {
test('getReadsByCid', () async { test('getReadsByCid', () async {
const cid = 'testCid'; const cid = 'testCid';
final reads = List.generate(3, (index) => Read()); final reads = List.generate(
3,
(index) => Read(
user: User(id: 'testUserId$index'),
lastRead: DateTime.now(),
),
);
when(() => mockDatabase.readDao.getReadsByCid(cid)) when(() => mockDatabase.readDao.getReadsByCid(cid))
.thenAnswer((_) async => reads); .thenAnswer((_) async => reads);
@@ -205,10 +193,16 @@ void main() {
}); });
test('getChannelStateByCid', () async { test('getChannelStateByCid', () async {
const cid = 'testCid'; const cid = 'testType:testId';
final messages = List.generate(3, (index) => Message()); final messages = List.generate(3, (index) => Message());
final members = List.generate(3, (index) => Member()); final members = List.generate(3, (index) => Member());
final reads = List.generate(3, (index) => Read()); final reads = List.generate(
3,
(index) => Read(
user: User(id: 'testUserId$index'),
lastRead: DateTime.now(),
),
);
final channel = ChannelModel(cid: cid); final channel = ChannelModel(cid: cid);
when(() => mockDatabase.memberDao.getMembersByCid(cid)) when(() => mockDatabase.memberDao.getMembersByCid(cid))
@@ -227,7 +221,7 @@ void main() {
expect(fetchedChannelState.pinnedMessages.length, messages.length); expect(fetchedChannelState.pinnedMessages.length, messages.length);
expect(fetchedChannelState.members.length, members.length); expect(fetchedChannelState.members.length, members.length);
expect(fetchedChannelState.read.length, reads.length); expect(fetchedChannelState.read.length, reads.length);
expect(fetchedChannelState.channel.cid, channel.cid); expect(fetchedChannelState.channel!.cid, channel.cid);
verify(() => mockDatabase.memberDao.getMembersByCid(cid)).called(1); verify(() => mockDatabase.memberDao.getMembersByCid(cid)).called(1);
verify(() => mockDatabase.readDao.getReadsByCid(cid)).called(1); verify(() => mockDatabase.readDao.getReadsByCid(cid)).called(1);
@@ -238,11 +232,17 @@ void main() {
}); });
test('getChannelStates', () async { test('getChannelStates', () async {
const cid = 'testCid'; const cid = 'testType:testId';
final channels = List.generate(3, (index) => ChannelModel(cid: cid)); final channels = List.generate(3, (index) => ChannelModel(cid: cid));
final messages = List.generate(3, (index) => Message()); final messages = List.generate(3, (index) => Message());
final members = List.generate(3, (index) => Member()); final members = List.generate(3, (index) => Member());
final reads = List.generate(3, (index) => Read()); final reads = List.generate(
3,
(index) => Read(
user: User(id: 'testUserId$index'),
lastRead: DateTime.now(),
),
);
final channel = ChannelModel(cid: cid); final channel = ChannelModel(cid: cid);
final channelStates = channels final channelStates = channels
.map( .map(
@@ -279,7 +279,7 @@ void main() {
expect(fetched.messages.length, original.messages.length); expect(fetched.messages.length, original.messages.length);
expect(fetched.pinnedMessages.length, original.pinnedMessages.length); expect(fetched.pinnedMessages.length, original.pinnedMessages.length);
expect(fetched.read.length, original.read.length); expect(fetched.read.length, original.read.length);
expect(fetched.channel.cid, original.channel.cid); expect(fetched.channel!.cid, original.channel!.cid);
} }
verify(() => mockDatabase.channelQueryDao.getChannels()).called(1); verify(() => mockDatabase.channelQueryDao.getChannels()).called(1);
@@ -296,9 +296,7 @@ void main() {
const cids = <String>[]; const cids = <String>[];
when(() => when(() =>
mockDatabase.channelQueryDao.updateChannelQueries(filter, cids)) mockDatabase.channelQueryDao.updateChannelQueries(filter, cids))
.thenAnswer((realInvocation) async { .thenAnswer((_) => Future.value());
return;
});
await client.updateChannelQueries(filter, cids); await client.updateChannelQueries(filter, cids);
verify(() => verify(() =>
@@ -309,9 +307,7 @@ void main() {
test('deleteMessageById', () async { test('deleteMessageById', () async {
const messageId = 'testMessageId'; const messageId = 'testMessageId';
when(() => mockDatabase.messageDao.deleteMessageByIds([messageId])) when(() => mockDatabase.messageDao.deleteMessageByIds([messageId]))
.thenAnswer((_) async { .thenAnswer((_) async => 1);
return;
});
await client.deleteMessageById(messageId); await client.deleteMessageById(messageId);
verify(() => mockDatabase.messageDao.deleteMessageByIds([messageId])) verify(() => mockDatabase.messageDao.deleteMessageByIds([messageId]))
@@ -321,9 +317,7 @@ void main() {
test('deletePinnedMessageById', () async { test('deletePinnedMessageById', () async {
const messageId = 'testMessageId'; const messageId = 'testMessageId';
when(() => mockDatabase.pinnedMessageDao.deleteMessageByIds([messageId])) when(() => mockDatabase.pinnedMessageDao.deleteMessageByIds([messageId]))
.thenAnswer((_) async { .thenAnswer((_) async => 1);
return;
});
await client.deletePinnedMessageById(messageId); await client.deletePinnedMessageById(messageId);
verify(() => verify(() =>
@@ -334,9 +328,7 @@ void main() {
test('deleteMessageByIds', () async { test('deleteMessageByIds', () async {
const messageIds = <String>[]; const messageIds = <String>[];
when(() => mockDatabase.messageDao.deleteMessageByIds(messageIds)) when(() => mockDatabase.messageDao.deleteMessageByIds(messageIds))
.thenAnswer((_) async { .thenAnswer((_) async => 1);
return;
});
await client.deleteMessageByIds(messageIds); await client.deleteMessageByIds(messageIds);
verify(() => mockDatabase.messageDao.deleteMessageByIds(messageIds)) verify(() => mockDatabase.messageDao.deleteMessageByIds(messageIds))
@@ -346,9 +338,7 @@ void main() {
test('deletePinnedMessageByIds', () async { test('deletePinnedMessageByIds', () async {
const messageIds = <String>[]; const messageIds = <String>[];
when(() => mockDatabase.pinnedMessageDao.deleteMessageByIds(messageIds)) when(() => mockDatabase.pinnedMessageDao.deleteMessageByIds(messageIds))
.thenAnswer((_) async { .thenAnswer((_) async => 1);
return;
});
await client.deletePinnedMessageByIds(messageIds); await client.deletePinnedMessageByIds(messageIds);
verify(() => mockDatabase.pinnedMessageDao.deleteMessageByIds(messageIds)) verify(() => mockDatabase.pinnedMessageDao.deleteMessageByIds(messageIds))
@@ -358,9 +348,7 @@ void main() {
test('deleteMessageByCid', () async { test('deleteMessageByCid', () async {
const cid = 'testCid'; const cid = 'testCid';
when(() => mockDatabase.messageDao.deleteMessageByCids([cid])) when(() => mockDatabase.messageDao.deleteMessageByCids([cid]))
.thenAnswer((_) async { .thenAnswer((_) async => 1);
return;
});
await client.deleteMessageByCid(cid); await client.deleteMessageByCid(cid);
verify(() => mockDatabase.messageDao.deleteMessageByCids([cid])) verify(() => mockDatabase.messageDao.deleteMessageByCids([cid]))
@@ -370,9 +358,7 @@ void main() {
test('deletePinnedMessageByCid', () async { test('deletePinnedMessageByCid', () async {
const cid = 'testCid'; const cid = 'testCid';
when(() => mockDatabase.pinnedMessageDao.deleteMessageByCids([cid])) when(() => mockDatabase.pinnedMessageDao.deleteMessageByCids([cid]))
.thenAnswer((_) async { .thenAnswer((_) async => 1);
return;
});
await client.deletePinnedMessageByCid(cid); await client.deletePinnedMessageByCid(cid);
verify(() => mockDatabase.pinnedMessageDao.deleteMessageByCids([cid])) verify(() => mockDatabase.pinnedMessageDao.deleteMessageByCids([cid]))
@@ -382,9 +368,7 @@ void main() {
test('deleteMessageByCids', () async { test('deleteMessageByCids', () async {
const cids = <String>[]; const cids = <String>[];
when(() => mockDatabase.messageDao.deleteMessageByCids(cids)) when(() => mockDatabase.messageDao.deleteMessageByCids(cids))
.thenAnswer((_) async { .thenAnswer((_) async => 1);
return;
});
await client.deleteMessageByCids(cids); await client.deleteMessageByCids(cids);
verify(() => mockDatabase.messageDao.deleteMessageByCids(cids)).called(1); verify(() => mockDatabase.messageDao.deleteMessageByCids(cids)).called(1);
@@ -393,9 +377,7 @@ void main() {
test('deletePinnedMessageByCids', () async { test('deletePinnedMessageByCids', () async {
const cids = <String>[]; const cids = <String>[];
when(() => mockDatabase.pinnedMessageDao.deleteMessageByCids(cids)) when(() => mockDatabase.pinnedMessageDao.deleteMessageByCids(cids))
.thenAnswer((_) async { .thenAnswer((_) async => 1);
return;
});
await client.deletePinnedMessageByCids(cids); await client.deletePinnedMessageByCids(cids);
verify(() => mockDatabase.pinnedMessageDao.deleteMessageByCids(cids)) verify(() => mockDatabase.pinnedMessageDao.deleteMessageByCids(cids))
@@ -405,9 +387,7 @@ void main() {
test('deleteChannels', () async { test('deleteChannels', () async {
const cids = <String>[]; const cids = <String>[];
when(() => mockDatabase.channelDao.deleteChannelByCids(cids)) when(() => mockDatabase.channelDao.deleteChannelByCids(cids))
.thenAnswer((_) async { .thenAnswer((_) async => 1);
return;
});
await client.deleteChannels(cids); await client.deleteChannels(cids);
verify(() => mockDatabase.channelDao.deleteChannelByCids(cids)).called(1); verify(() => mockDatabase.channelDao.deleteChannelByCids(cids)).called(1);
@@ -417,9 +397,7 @@ void main() {
const cid = 'testCid'; const cid = 'testCid';
final messages = List.generate(3, (index) => Message()); final messages = List.generate(3, (index) => Message());
when(() => mockDatabase.messageDao.updateMessages(cid, messages)) when(() => mockDatabase.messageDao.updateMessages(cid, messages))
.thenAnswer((_) async { .thenAnswer((_) => Future.value());
return;
});
await client.updateMessages(cid, messages); await client.updateMessages(cid, messages);
verify(() => mockDatabase.messageDao.updateMessages(cid, messages)) verify(() => mockDatabase.messageDao.updateMessages(cid, messages))
@@ -430,9 +408,7 @@ void main() {
const cid = 'testCid'; const cid = 'testCid';
final messages = List.generate(3, (index) => Message()); final messages = List.generate(3, (index) => Message());
when(() => mockDatabase.pinnedMessageDao.updateMessages(cid, messages)) when(() => mockDatabase.pinnedMessageDao.updateMessages(cid, messages))
.thenAnswer((_) async { .thenAnswer((_) => Future.value());
return;
});
await client.updatePinnedMessages(cid, messages); await client.updatePinnedMessages(cid, messages);
verify(() => mockDatabase.pinnedMessageDao.updateMessages(cid, messages)) verify(() => mockDatabase.pinnedMessageDao.updateMessages(cid, messages))
@@ -445,14 +421,12 @@ void main() {
List.generate(3, (index) => Message(parentId: 'testParentId$index')); List.generate(3, (index) => Message(parentId: 'testParentId$index'));
final threads = messages.fold<Map<String, List<Message>>>( final threads = messages.fold<Map<String, List<Message>>>(
{}, {},
(prev, curr) { (prev, curr) => prev
return prev ..update(
..update( curr.parentId!,
curr.parentId, (value) => [...value, curr],
(value) => [...value, curr], ifAbsent: () => [],
ifAbsent: () => [], ),
);
},
); );
when(() => mockDatabase.messageDao.getThreadMessages(cid)) when(() => mockDatabase.messageDao.getThreadMessages(cid))
.thenAnswer((realInvocation) async => messages); .thenAnswer((realInvocation) async => messages);
@@ -469,11 +443,10 @@ void main() {
}); });
test('updateChannels', () async { test('updateChannels', () async {
final channels = List.generate(3, (index) => ChannelModel()); const cid = 'testType:testId';
final channels = List.generate(3, (index) => ChannelModel(cid: cid));
when(() => mockDatabase.channelDao.updateChannels(channels)) when(() => mockDatabase.channelDao.updateChannels(channels))
.thenAnswer((_) async { .thenAnswer((_) => Future.value());
return;
});
await client.updateChannels(channels); await client.updateChannels(channels);
verify(() => mockDatabase.channelDao.updateChannels(channels)).called(1); verify(() => mockDatabase.channelDao.updateChannels(channels)).called(1);
@@ -483,9 +456,7 @@ void main() {
const cid = 'testCid'; const cid = 'testCid';
final members = List.generate(3, (index) => Member()); final members = List.generate(3, (index) => Member());
when(() => mockDatabase.memberDao.updateMembers(cid, members)) when(() => mockDatabase.memberDao.updateMembers(cid, members))
.thenAnswer((_) async { .thenAnswer((_) => Future.value());
return;
});
await client.updateMembers(cid, members); await client.updateMembers(cid, members);
verify(() => mockDatabase.memberDao.updateMembers(cid, members)) verify(() => mockDatabase.memberDao.updateMembers(cid, members))
@@ -494,32 +465,36 @@ void main() {
test('updateReads', () async { test('updateReads', () async {
const cid = 'testCid'; const cid = 'testCid';
final reads = List.generate(3, (index) => Read()); final reads = List.generate(
3,
(index) => Read(
user: User(id: 'testUserId$index'),
lastRead: DateTime.now(),
),
);
when(() => mockDatabase.readDao.updateReads(cid, reads)) when(() => mockDatabase.readDao.updateReads(cid, reads))
.thenAnswer((_) async { .thenAnswer((_) => Future.value());
return;
});
await client.updateReads(cid, reads); await client.updateReads(cid, reads);
verify(() => mockDatabase.readDao.updateReads(cid, reads)).called(1); verify(() => mockDatabase.readDao.updateReads(cid, reads)).called(1);
}); });
test('updateUsers', () async { test('updateUsers', () async {
final users = List.generate(3, (index) => User()); final users = List.generate(3, (index) => User(id: 'testUserId$index'));
when(() => mockDatabase.userDao.updateUsers(users)).thenAnswer((_) async { when(() => mockDatabase.userDao.updateUsers(users))
return; .thenAnswer((_) => Future.value());
});
await client.updateUsers(users); await client.updateUsers(users);
verify(() => mockDatabase.userDao.updateUsers(users)).called(1); verify(() => mockDatabase.userDao.updateUsers(users)).called(1);
}); });
test('updateReactions', () async { test('updateReactions', () async {
final reactions = List.generate(3, (index) => Reaction()); final reactions = List.generate(
3,
(index) => Reaction(type: 'testType$index'),
);
when(() => mockDatabase.reactionDao.updateReactions(reactions)) when(() => mockDatabase.reactionDao.updateReactions(reactions))
.thenAnswer((_) async { .thenAnswer((_) => Future.value());
return;
});
await client.updateReactions(reactions); await client.updateReactions(reactions);
verify(() => mockDatabase.reactionDao.updateReactions(reactions)) verify(() => mockDatabase.reactionDao.updateReactions(reactions))
@@ -530,9 +505,7 @@ void main() {
final messageIds = <String>[]; final messageIds = <String>[];
when(() => when(() =>
mockDatabase.reactionDao.deleteReactionsByMessageIds(messageIds)) mockDatabase.reactionDao.deleteReactionsByMessageIds(messageIds))
.thenAnswer((_) async { .thenAnswer((_) => Future.value());
return;
});
await client.deleteReactionsByMessageId(messageIds); await client.deleteReactionsByMessageId(messageIds);
verify(() => verify(() =>
@@ -543,9 +516,7 @@ void main() {
test('deleteMembersByCids', () async { test('deleteMembersByCids', () async {
final cids = <String>[]; final cids = <String>[];
when(() => mockDatabase.memberDao.deleteMemberByCids(cids)) when(() => mockDatabase.memberDao.deleteMemberByCids(cids))
.thenAnswer((_) async { .thenAnswer((_) => Future.value());
return;
});
await client.deleteMembersByCids(cids); await client.deleteMembersByCids(cids);
verify(() => mockDatabase.memberDao.deleteMemberByCids(cids)).called(1); verify(() => mockDatabase.memberDao.deleteMemberByCids(cids)).called(1);