From 6bdd065888848a329a0fbf5f825f44104c049a3c Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 15 Mar 2021 12:00:32 +0530 Subject: [PATCH 01/50] lint(persistence): Apply team linter Signed-off-by: Sahil Kumar --- .../analysis_options.yaml | 147 ++++++ .../lib/src/converter/list_converter.dart | 4 +- .../lib/src/converter/map_converter.dart | 4 +- .../lib/src/dao/channel_dao.dart | 52 +- .../lib/src/dao/channel_query_dao.dart | 49 +- .../lib/src/dao/connection_event_dao.dart | 63 ++- .../lib/src/dao/dao.dart | 8 +- .../lib/src/dao/member_dao.dart | 56 +-- .../lib/src/dao/message_dao.dart | 54 +-- .../lib/src/dao/pinned_message_dao.dart | 56 +-- .../lib/src/dao/reaction_dao.dart | 59 ++- .../lib/src/dao/read_dao.dart | 44 +- .../lib/src/dao/user_dao.dart | 18 +- .../lib/src/db/moor_chat_database.dart | 15 +- .../lib/src/db/shared/native_db.dart | 24 +- .../lib/src/db/shared/unsupported_db.dart | 6 +- .../lib/src/db/shared/web_db.dart | 2 +- .../lib/src/entity/entity.dart | 8 +- .../lib/src/entity/pinned_messages.dart | 2 +- .../lib/src/mapper/channel_mapper.dart | 47 +- .../lib/src/mapper/event_mapper.dart | 12 +- .../lib/src/mapper/mapper.dart | 6 +- .../lib/src/mapper/member_mapper.dart | 56 +-- .../lib/src/mapper/message_mapper.dart | 118 +++-- .../lib/src/mapper/pinned_message_mapper.dart | 118 +++-- .../lib/src/mapper/reaction_mapper.dart | 8 +- .../lib/src/mapper/read_mapper.dart | 8 +- .../lib/src/mapper/user_mapper.dart | 44 +- .../src/stream_chat_persistence_client.dart | 447 ++++++++---------- packages/stream_chat_persistence/pubspec.yaml | 2 +- 30 files changed, 789 insertions(+), 748 deletions(-) create mode 100644 packages/stream_chat_persistence/analysis_options.yaml diff --git a/packages/stream_chat_persistence/analysis_options.yaml b/packages/stream_chat_persistence/analysis_options.yaml new file mode 100644 index 00000000..7e4b00fa --- /dev/null +++ b/packages/stream_chat_persistence/analysis_options.yaml @@ -0,0 +1,147 @@ +analyzer: + exclude: + - lib/**/*.g.dart + - lib/**/*.freezed.dart + - example/* + - test/* +linter: + rules: + - always_use_package_imports + - avoid_empty_else + - avoid_relative_lib_imports + - avoid_slow_async_io + - avoid_types_as_parameter_names + - cancel_subscriptions + - close_sinks + - control_flow_in_finally + - diagnostic_describe_all_properties + - empty_statements + - hash_and_equals + - invariant_booleans + - iterable_contains_unrelated_type + - list_remove_unrelated_type + - literal_only_boolean_expressions + - no_adjacent_strings_in_list + - no_duplicate_case_values + - no_logic_in_create_state + - prefer_void_to_null + - test_types_in_equals + - throw_in_finally + - unnecessary_statements + - unrelated_type_equality_checks + - omit_local_variable_types + - use_key_in_widget_constructors + - valid_regexps + - always_declare_return_types + - always_put_required_named_parameters_first + - always_require_non_null_named_parameters + - annotate_overrides + - avoid_bool_literals_in_conditional_expressions + - avoid_catching_errors + - avoid_init_to_null + - avoid_null_checks_in_equality_operators + - avoid_positional_boolean_parameters + - avoid_private_typedef_functions + - avoid_redundant_argument_values + - avoid_return_types_on_setters + - avoid_returning_null + - avoid_returning_null_for_void + - avoid_shadowing_type_parameters + - avoid_single_cascade_in_expression_statements + - avoid_unnecessary_containers + - avoid_unused_constructor_parameters + - await_only_futures + - camel_case_extensions + - camel_case_types + - cascade_invocations + + - constant_identifier_names + - curly_braces_in_flow_control_structures + - directives_ordering + - empty_catches + - empty_constructor_bodies + - exhaustive_cases + - file_names + - implementation_imports + - join_return_with_assignment + - leading_newlines_in_multiline_strings + - library_names + - library_prefixes + - lines_longer_than_80_chars + - missing_whitespace_between_adjacent_strings + - non_constant_identifier_names + - null_closures + - one_member_abstracts + - only_throw_errors + - package_api_docs + - package_prefixed_library_names + - parameter_assignments + - prefer_adjacent_string_concatenation + - prefer_asserts_in_initializer_lists + - prefer_asserts_with_message + - prefer_collection_literals + - prefer_conditional_assignment + - prefer_const_constructors + - prefer_const_constructors_in_immutables + - prefer_const_declarations + - prefer_const_literals_to_create_immutables + - prefer_constructors_over_static_methods + - prefer_contains + - prefer_equal_for_default_values + - prefer_expression_function_bodies + - prefer_final_fields + - prefer_final_in_for_each + - prefer_final_locals + - prefer_function_declarations_over_variables + - prefer_generic_function_type_aliases + - prefer_if_elements_to_conditional_expressions + - prefer_if_null_operators + - prefer_initializing_formals + - prefer_inlined_adds + - prefer_int_literals + - prefer_interpolation_to_compose_strings + - prefer_is_empty + - prefer_is_not_empty + - prefer_is_not_operator + - prefer_null_aware_operators + - prefer_single_quotes + - prefer_spread_collections + - prefer_typing_uninitialized_variables + - provide_deprecation_message + - public_member_api_docs + - recursive_getters + - sized_box_for_whitespace + - slash_for_doc_comments + - sort_child_properties_last + - sort_constructors_first + - sort_unnamed_constructors_first + + - type_annotate_public_apis + - type_init_formals + - unnecessary_await_in_return + - unnecessary_brace_in_string_interps + - unnecessary_const + - unnecessary_getters_setters + - unnecessary_lambdas + - unnecessary_new + - unnecessary_null_aware_assignments + - unnecessary_null_in_if_null_operators + - unnecessary_nullable_for_final_variable_declarations + - unnecessary_parenthesis + - unnecessary_raw_strings + - unnecessary_string_escapes + - unnecessary_string_interpolations + - unnecessary_this + - use_is_even_rather_than_modulo + - use_late_for_private_fields_and_variables + - use_rethrow_when_possible + - use_setters_to_change_properties + - use_to_and_as_if_applicable + - package_names + - sort_pub_dependencies + + # To be added when null-safe: + # - cast_nullable_to_non_nullable + #- unnecessary_null_checks + # - tighten_type_of_initializing_formals + # - null_check_on_nullable_type_parameter \ No newline at end of file diff --git a/packages/stream_chat_persistence/lib/src/converter/list_converter.dart b/packages/stream_chat_persistence/lib/src/converter/list_converter.dart index d14642ce..cbb8ec05 100644 --- a/packages/stream_chat_persistence/lib/src/converter/list_converter.dart +++ b/packages/stream_chat_persistence/lib/src/converter/list_converter.dart @@ -6,7 +6,7 @@ import 'package:moor/moor.dart'; /// by the sqlite backend. class ListConverter extends TypeConverter, String> { @override - List mapToDart(fromDb) { + List mapToDart(String fromDb) { if (fromDb == null) { return null; } @@ -14,7 +14,7 @@ class ListConverter extends TypeConverter, String> { } @override - String mapToSql(value) { + String mapToSql(List value) { if (value == null) { return null; } diff --git a/packages/stream_chat_persistence/lib/src/converter/map_converter.dart b/packages/stream_chat_persistence/lib/src/converter/map_converter.dart index 6e7a648d..b11eb5b8 100644 --- a/packages/stream_chat_persistence/lib/src/converter/map_converter.dart +++ b/packages/stream_chat_persistence/lib/src/converter/map_converter.dart @@ -6,7 +6,7 @@ import 'package:moor/moor.dart'; /// by the sqlite backend. class MapConverter extends TypeConverter, String> { @override - Map mapToDart(fromDb) { + Map mapToDart(String fromDb) { if (fromDb == null) { return null; } @@ -14,7 +14,7 @@ class MapConverter extends TypeConverter, String> { } @override - String mapToSql(value) { + String mapToSql(Map value) { if (value == null) { return null; } diff --git a/packages/stream_chat_persistence/lib/src/dao/channel_dao.dart b/packages/stream_chat_persistence/lib/src/dao/channel_dao.dart index 57ec95d3..e75cead6 100644 --- a/packages/stream_chat_persistence/lib/src/dao/channel_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/channel_dao.dart @@ -3,7 +3,7 @@ import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; import 'package:stream_chat_persistence/src/entity/channels.dart'; import 'package:stream_chat_persistence/src/entity/users.dart'; -import '../mapper/mapper.dart'; +import 'package:stream_chat_persistence/src/mapper/mapper.dart'; part 'channel_dao.g.dart'; @@ -15,15 +15,14 @@ class ChannelDao extends DatabaseAccessor ChannelDao(MoorChatDatabase db) : super(db); /// Get channel by cid - Future getChannelByCid(String cid) async { - return (select(channels)..where((c) => c.cid.equals(cid))).join([ - leftOuterJoin(users, channels.createdById.equalsExp(users.id)), - ]).map((rows) { - final channel = rows.readTable(channels); - final createdBy = rows.readTable(users); - return channel.toChannelModel(createdBy: createdBy?.toUser()); - }).getSingle(); - } + Future getChannelByCid(String cid) async => + (select(channels)..where((c) => c.cid.equals(cid))).join([ + leftOuterJoin(users, channels.createdById.equalsExp(users.id)), + ]).map((rows) { + final channel = rows.readTable(channels); + final createdBy = rows.readTable(users); + return channel.toChannelModel(createdBy: createdBy?.toUser()); + }).getSingle(); /// Delete all channels by matching cid in [cids] /// @@ -31,27 +30,22 @@ class ChannelDao extends DatabaseAccessor /// 1. Channel Reads /// 2. Channel Members /// 3. Channel Messages -> Messages Reactions - Future deleteChannelByCids(List cids) async { - return (delete(channels)..where((tbl) => tbl.cid.isIn(cids))).go(); - } + Future deleteChannelByCids(List cids) async => + (delete(channels)..where((tbl) => tbl.cid.isIn(cids))).go(); /// Get the channel cids saved in the storage - Future> get cids { - return (select(channels) - ..orderBy([(c) => OrderingTerm.desc(c.lastMessageAt)]) - ..limit(250)) - .map((c) => c.cid) - .get(); - } + Future> get cids => (select(channels) + ..orderBy([(c) => OrderingTerm.desc(c.lastMessageAt)]) + ..limit(250)) + .map((c) => c.cid) + .get(); /// Updates all the channels using the new [channelList] data - Future updateChannels(List channelList) { - return batch( - (it) => it.insertAll( - channels, - channelList.map((c) => c.toEntity()).toList(), - mode: InsertMode.insertOrReplace, - ), - ); - } + Future updateChannels(List channelList) => batch( + (it) => it.insertAll( + channels, + channelList.map((c) => c.toEntity()).toList(), + mode: InsertMode.insertOrReplace, + ), + ); } diff --git a/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.dart b/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.dart index b5f6fe59..785b5946 100644 --- a/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.dart @@ -7,7 +7,7 @@ import 'package:stream_chat_persistence/src/entity/channel_queries.dart'; import 'package:stream_chat_persistence/src/entity/channels.dart'; import 'package:stream_chat_persistence/src/entity/users.dart'; -import '../mapper/mapper.dart'; +import 'package:stream_chat_persistence/src/mapper/mapper.dart'; part 'channel_query_dao.g.dart'; @@ -31,31 +31,31 @@ class ChannelQueryDao extends DatabaseAccessor /// the list of matching rows will be deleted Future updateChannelQueries( Map filter, - List cids, + List cids, { bool clearQueryCache, - ) async { - return transaction(() async { - final hash = _computeHash(filter); - if (clearQueryCache) { + }) async => + transaction(() async { + final hash = _computeHash(filter); + if (clearQueryCache) { + await batch((it) { + it.deleteWhere( + channelQueries, + (c) => c.queryHash.equals(hash), + ); + }); + } + await batch((it) { - it.deleteWhere( + it.insertAll( channelQueries, - (c) => c.queryHash.equals(hash), + cids + .map((cid) => + ChannelQueryEntity(queryHash: hash, channelCid: cid)) + .toList(), + mode: InsertMode.insertOrReplace, ); }); - } - - await batch((it) { - it.insertAll( - channelQueries, - cids.map((cid) { - return ChannelQueryEntity(queryHash: hash, channelCid: cid); - }).toList(), - mode: InsertMode.insertOrReplace, - ); }); - }); - } /// Get list of channels by filter, sort and paginationParams Future> getChannels({ @@ -70,7 +70,7 @@ class ChannelQueryDao extends DatabaseAccessor ); } return true; - }()); + }(), ''); final hash = _computeHash(filter); final cachedChannelCids = await (select(channelQueries) @@ -89,10 +89,11 @@ class ChannelQueryDao extends DatabaseAccessor })).get(); final possibleSortingFields = cachedChannels.fold>( - ChannelModel.topLevelFields, (previousValue, element) { - return {...previousValue, ...element.extraData.keys}.toList(); - }); + ChannelModel.topLevelFields, + (previousValue, element) => + {...previousValue, ...element.extraData.keys}.toList()); + // ignore: parameter_assignments sort = sort ?.where((s) => possibleSortingFields.contains(s.field)) ?.toList(growable: false); diff --git a/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.dart b/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.dart index 92764b10..94b0d333 100644 --- a/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.dart @@ -4,7 +4,7 @@ import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; import 'package:stream_chat_persistence/src/entity/connection_events.dart'; import 'package:stream_chat_persistence/src/entity/users.dart'; -import '../mapper/mapper.dart'; +import 'package:stream_chat_persistence/src/mapper/mapper.dart'; part 'connection_event_dao.g.dart'; @@ -16,43 +16,38 @@ class ConnectionEventDao extends DatabaseAccessor ConnectionEventDao(MoorChatDatabase db) : super(db); /// Get the latest stored connection event - Future get connectionEvent { - return select(connectionEvents).map((eventEntity) { - return eventEntity.toEvent(); - }).getSingle(); - } + Future get connectionEvent => select(connectionEvents) + .map((eventEntity) => eventEntity.toEvent()) + .getSingle(); /// Get the latest stored lastSyncAt - Future get lastSyncAt { - return select(connectionEvents).getSingle().then((r) => r?.lastSyncAt); - } + Future get lastSyncAt => + select(connectionEvents).getSingle().then((r) => r?.lastSyncAt); /// Update stored connection event with latest data - Future updateConnectionEvent(Event event) async { - return transaction(() async { - final connectionInfo = await select(connectionEvents).getSingle(); - await into(connectionEvents).insert( - ConnectionEventEntity( - id: 1, - lastSyncAt: connectionInfo?.lastSyncAt, - lastEventAt: event.createdAt ?? connectionInfo?.lastEventAt, - totalUnreadCount: - event.totalUnreadCount ?? connectionInfo?.totalUnreadCount, - ownUser: event.me?.toJson() ?? connectionInfo?.ownUser, - unreadChannels: - event.unreadChannels ?? connectionInfo?.unreadChannels, - ), - mode: InsertMode.insertOrReplace, - ); - }); - } + Future updateConnectionEvent(Event event) async => + transaction(() async { + final connectionInfo = await select(connectionEvents).getSingle(); + await into(connectionEvents).insert( + ConnectionEventEntity( + id: 1, + lastSyncAt: connectionInfo?.lastSyncAt, + lastEventAt: event.createdAt ?? connectionInfo?.lastEventAt, + totalUnreadCount: + event.totalUnreadCount ?? connectionInfo?.totalUnreadCount, + ownUser: event.me?.toJson() ?? connectionInfo?.ownUser, + unreadChannels: + event.unreadChannels ?? connectionInfo?.unreadChannels, + ), + mode: InsertMode.insertOrReplace, + ); + }); /// Update stored lastSyncAt with latest data - Future updateLastSyncAt(DateTime lastSyncAt) async { - return (update(connectionEvents)..where((tbl) => tbl.id.equals(1))).write( - ConnectionEventsCompanion( - lastSyncAt: Value(lastSyncAt), - ), - ); - } + Future updateLastSyncAt(DateTime lastSyncAt) async => + (update(connectionEvents)..where((tbl) => tbl.id.equals(1))).write( + ConnectionEventsCompanion( + lastSyncAt: Value(lastSyncAt), + ), + ); } diff --git a/packages/stream_chat_persistence/lib/src/dao/dao.dart b/packages/stream_chat_persistence/lib/src/dao/dao.dart index 31953630..53c2f372 100644 --- a/packages/stream_chat_persistence/lib/src/dao/dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/dao.dart @@ -1,9 +1,9 @@ -export 'user_dao.dart'; export 'channel_dao.dart'; +export 'channel_query_dao.dart'; +export 'connection_event_dao.dart'; +export 'member_dao.dart'; export 'message_dao.dart'; export 'pinned_message_dao.dart'; -export 'member_dao.dart'; -export 'connection_event_dao.dart'; export 'reaction_dao.dart'; export 'read_dao.dart'; -export 'channel_query_dao.dart'; +export 'user_dao.dart'; diff --git a/packages/stream_chat_persistence/lib/src/dao/member_dao.dart b/packages/stream_chat_persistence/lib/src/dao/member_dao.dart index ed30a931..e6c03996 100644 --- a/packages/stream_chat_persistence/lib/src/dao/member_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/member_dao.dart @@ -5,7 +5,7 @@ import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; import 'package:stream_chat_persistence/src/entity/members.dart'; import 'package:stream_chat_persistence/src/entity/users.dart'; -import '../mapper/mapper.dart'; +import 'package:stream_chat_persistence/src/mapper/mapper.dart'; part 'member_dao.g.dart'; @@ -17,37 +17,33 @@ class MemberDao extends DatabaseAccessor MemberDao(MoorChatDatabase db) : super(db); /// Get all members where [Members.channelCid] matches [cid] - Future> getMembersByCid(String cid) async { - return (select(members).join([ - leftOuterJoin(users, members.userId.equalsExp(users.id)), - ]) - ..where(members.channelCid.equals(cid)) - ..orderBy([OrderingTerm.asc(members.createdAt)])) - .map((row) { - final userEntity = row.readTable(users); - final memberEntity = row.readTable(members); - return memberEntity.toMember(user: userEntity?.toUser()); - }).get(); - } + Future> getMembersByCid(String cid) async => + (select(members).join([ + leftOuterJoin(users, members.userId.equalsExp(users.id)), + ]) + ..where(members.channelCid.equals(cid)) + ..orderBy([OrderingTerm.asc(members.createdAt)])) + .map((row) { + final userEntity = row.readTable(users); + final memberEntity = row.readTable(members); + return memberEntity.toMember(user: userEntity?.toUser()); + }).get(); /// Updates all the members using the new [memberList] data - Future updateMembers(String cid, List memberList) async { - return batch( - (it) => it.insertAll( - members, - memberList.map((m) => m.toEntity(cid: cid)).toList(), - mode: InsertMode.insertOrReplace, - ), - ); - } + Future updateMembers(String cid, List memberList) async => + batch( + (it) => it.insertAll( + members, + memberList.map((m) => m.toEntity(cid: cid)).toList(), + mode: InsertMode.insertOrReplace, + ), + ); /// Deletes all the members whose [Members.channelCid] is present in [cids] - Future deleteMemberByCids(List cids) async { - return batch((it) { - it.deleteWhere( - members, - (m) => m.channelCid.isIn(cids), - ); - }); - } + Future deleteMemberByCids(List cids) async => batch((it) { + it.deleteWhere( + members, + (m) => m.channelCid.isIn(cids), + ); + }); } diff --git a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart index 204daaed..0be4446b 100644 --- a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart @@ -4,7 +4,7 @@ import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; import 'package:stream_chat_persistence/src/entity/messages.dart'; import 'package:stream_chat_persistence/src/entity/users.dart'; -import '../mapper/mapper.dart'; +import 'package:stream_chat_persistence/src/mapper/mapper.dart'; part 'message_dao.g.dart'; @@ -25,17 +25,15 @@ class MessageDao extends DatabaseAccessor /// /// This will automatically delete the following linked records /// 1. Message Reactions - Future deleteMessageByIds(List messageIds) { - return (delete(messages)..where((tbl) => tbl.id.isIn(messageIds))).go(); - } + Future deleteMessageByIds(List messageIds) => + (delete(messages)..where((tbl) => tbl.id.isIn(messageIds))).go(); /// Removes all the messages by matching [Messages.channelCid] in [cids] /// /// This will automatically delete the following linked records /// 1. Message Reactions - Future deleteMessageByCids(List cids) async { - return (delete(messages)..where((tbl) => tbl.channelCid.isIn(cids))).go(); - } + Future deleteMessageByCids(List cids) async => + (delete(messages)..where((tbl) => tbl.channelCid.isIn(cids))).go(); Future _messageFromJoinRow(TypedResult rows) async { final userEntity = rows.readTable(_users); @@ -60,31 +58,29 @@ class MessageDao extends DatabaseAccessor } /// Returns a single message by matching the [Messages.id] with [id] - Future getMessageById(String id) async { - return await (select(messages).join([ - leftOuterJoin(_users, messages.userId.equalsExp(_users.id)), - leftOuterJoin( - _pinnedByUsers, messages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), - ]) - ..where(messages.id.equals(id))) - .map(_messageFromJoinRow) - .getSingle(); - } + Future getMessageById(String id) async => + await (select(messages).join([ + leftOuterJoin(_users, messages.userId.equalsExp(_users.id)), + leftOuterJoin(_pinnedByUsers, + messages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), + ]) + ..where(messages.id.equals(id))) + .map(_messageFromJoinRow) + .getSingle(); /// Returns all the messages of a particular thread by matching /// [Messages.channelCid] with [cid] - Future> getThreadMessages(String cid) async { - return Future.wait(await (select(messages).join([ - leftOuterJoin(users, messages.userId.equalsExp(_users.id)), - leftOuterJoin( - _pinnedByUsers, messages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), - ]) - ..where(messages.channelCid.equals(cid)) - ..where(isNotNull(messages.parentId)) - ..orderBy([OrderingTerm.asc(messages.createdAt)])) - .map(_messageFromJoinRow) - .get()); - } + Future> getThreadMessages(String cid) async => + Future.wait(await (select(messages).join([ + leftOuterJoin(users, messages.userId.equalsExp(_users.id)), + leftOuterJoin(_pinnedByUsers, + messages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), + ]) + ..where(messages.channelCid.equals(cid)) + ..where(isNotNull(messages.parentId)) + ..orderBy([OrderingTerm.asc(messages.createdAt)])) + .map(_messageFromJoinRow) + .get()); /// Returns all the messages of a particular thread by matching /// [Messages.parentId] with [parentId] diff --git a/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart b/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart index edf8e438..5e0ae721 100644 --- a/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart @@ -4,7 +4,7 @@ import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; import 'package:stream_chat_persistence/src/entity/pinned_messages.dart'; import 'package:stream_chat_persistence/src/entity/users.dart'; -import '../mapper/mapper.dart'; +import 'package:stream_chat_persistence/src/mapper/mapper.dart'; part 'pinned_message_dao.g.dart'; @@ -25,19 +25,15 @@ class PinnedMessageDao extends DatabaseAccessor /// /// This will automatically delete the following linked records /// 1. Message Reactions - Future deleteMessageByIds(List messageIds) { - return (delete(pinnedMessages)..where((tbl) => tbl.id.isIn(messageIds))) - .go(); - } + Future deleteMessageByIds(List messageIds) => + (delete(pinnedMessages)..where((tbl) => tbl.id.isIn(messageIds))).go(); /// Removes all the messages by matching [PinnedMessages.channelCid] in [cids] /// /// This will automatically delete the following linked records /// 1. Message Reactions - Future deleteMessageByCids(List cids) async { - return (delete(pinnedMessages)..where((tbl) => tbl.channelCid.isIn(cids))) - .go(); - } + Future deleteMessageByCids(List cids) async => + (delete(pinnedMessages)..where((tbl) => tbl.channelCid.isIn(cids))).go(); Future _messageFromJoinRow(TypedResult rows) async { final userEntity = rows.readTable(users); @@ -62,31 +58,29 @@ class PinnedMessageDao extends DatabaseAccessor } /// Returns a single message by matching the [PinnedMessages.id] with [id] - Future getMessageById(String id) async { - return await (select(pinnedMessages).join([ - leftOuterJoin(_users, pinnedMessages.userId.equalsExp(_users.id)), - leftOuterJoin(_pinnedByUsers, - pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), - ]) - ..where(pinnedMessages.id.equals(id))) - .map(_messageFromJoinRow) - .getSingle(); - } + Future getMessageById(String id) async => + await (select(pinnedMessages).join([ + leftOuterJoin(_users, pinnedMessages.userId.equalsExp(_users.id)), + leftOuterJoin(_pinnedByUsers, + pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), + ]) + ..where(pinnedMessages.id.equals(id))) + .map(_messageFromJoinRow) + .getSingle(); /// Returns all the messages of a particular thread by matching /// [PinnedMessages.channelCid] with [cid] - Future> getThreadMessages(String cid) async { - return Future.wait(await (select(pinnedMessages).join([ - leftOuterJoin(_users, pinnedMessages.userId.equalsExp(_users.id)), - leftOuterJoin(_pinnedByUsers, - pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), - ]) - ..where(pinnedMessages.channelCid.equals(cid)) - ..where(isNotNull(pinnedMessages.parentId)) - ..orderBy([OrderingTerm.asc(pinnedMessages.createdAt)])) - .map(_messageFromJoinRow) - .get()); - } + Future> getThreadMessages(String cid) async => + Future.wait(await (select(pinnedMessages).join([ + leftOuterJoin(_users, pinnedMessages.userId.equalsExp(_users.id)), + leftOuterJoin(_pinnedByUsers, + pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), + ]) + ..where(pinnedMessages.channelCid.equals(cid)) + ..where(isNotNull(pinnedMessages.parentId)) + ..orderBy([OrderingTerm.asc(pinnedMessages.createdAt)])) + .map(_messageFromJoinRow) + .get()); /// Returns all the messages of a particular thread by matching /// [PinnedMessages.parentId] with [parentId] diff --git a/packages/stream_chat_persistence/lib/src/dao/reaction_dao.dart b/packages/stream_chat_persistence/lib/src/dao/reaction_dao.dart index 99053fca..ef06326a 100644 --- a/packages/stream_chat_persistence/lib/src/dao/reaction_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/reaction_dao.dart @@ -3,7 +3,7 @@ import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; import 'package:stream_chat_persistence/src/entity/reactions.dart'; import 'package:stream_chat_persistence/src/entity/users.dart'; -import '../mapper/mapper.dart'; +import 'package:stream_chat_persistence/src/mapper/mapper.dart'; part 'reaction_dao.g.dart'; @@ -16,18 +16,17 @@ class ReactionDao extends DatabaseAccessor /// Returns all the reactions of a particular message by matching /// [Reactions.messageId] with [messageId] - Future> getReactions(String messageId) { - return (select(reactions).join([ - leftOuterJoin(users, reactions.userId.equalsExp(users.id)), - ]) - ..where(reactions.messageId.equals(messageId)) - ..orderBy([OrderingTerm.asc(reactions.createdAt)])) - .map((rows) { - final userEntity = rows.readTable(users); - final reactionEntity = rows.readTable(reactions); - return reactionEntity.toReaction(user: userEntity?.toUser()); - }).get(); - } + Future> getReactions(String messageId) => + (select(reactions).join([ + leftOuterJoin(users, reactions.userId.equalsExp(users.id)), + ]) + ..where(reactions.messageId.equals(messageId)) + ..orderBy([OrderingTerm.asc(reactions.createdAt)])) + .map((rows) { + final userEntity = rows.readTable(users); + final reactionEntity = rows.readTable(reactions); + return reactionEntity.toReaction(user: userEntity?.toUser()); + }).get(); /// Returns all the reactions of a particular message /// added by a particular user by matching @@ -42,23 +41,21 @@ class ReactionDao extends DatabaseAccessor } /// Updates the reactions data with the new [reactionList] data - Future updateReactions(List reactionList) { - return batch((it) { - it.insertAll( - reactions, - reactionList.map((r) => r.toEntity()).toList(), - mode: InsertMode.insertOrReplace, - ); - }); - } + Future updateReactions(List reactionList) => batch((it) { + it.insertAll( + reactions, + reactionList.map((r) => r.toEntity()).toList(), + mode: InsertMode.insertOrReplace, + ); + }); - /// Deletes all the reactions whose [Reactions.messageId] is present in [messageIds] - Future deleteReactionsByMessageIds(List messageIds) { - return batch((it) { - it.deleteWhere( - reactions, - (r) => r.messageId.isIn(messageIds), - ); - }); - } + /// Deletes all the reactions whose [Reactions.messageId] is + /// present in [messageIds] + Future deleteReactionsByMessageIds(List messageIds) => + batch((it) { + it.deleteWhere( + reactions, + (r) => r.messageId.isIn(messageIds), + ); + }); } diff --git a/packages/stream_chat_persistence/lib/src/dao/read_dao.dart b/packages/stream_chat_persistence/lib/src/dao/read_dao.dart index c78cab07..95e23d8b 100644 --- a/packages/stream_chat_persistence/lib/src/dao/read_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/read_dao.dart @@ -3,7 +3,7 @@ import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; import 'package:stream_chat_persistence/src/entity/reads.dart'; import 'package:stream_chat_persistence/src/entity/users.dart'; -import '../mapper/mapper.dart'; +import 'package:stream_chat_persistence/src/mapper/mapper.dart'; part 'read_dao.g.dart'; @@ -14,30 +14,26 @@ class ReadDao extends DatabaseAccessor with _$ReadDaoMixin { ReadDao(MoorChatDatabase db) : super(db); /// Get all reads where [Reads.channelCid] matches [cid] - Future> getReadsByCid(String cid) async { - return (select(reads).join([ - leftOuterJoin(users, reads.userId.equalsExp(users.id)), - ]) - ..where(reads.channelCid.equals(cid)) - ..orderBy([ - OrderingTerm.asc(reads.lastRead), - ])) - .map((row) { - final userEntity = row.readTable(users); - final readEntity = row.readTable(reads); - return readEntity.toRead(user: userEntity?.toUser()); - }).get(); - } + Future> getReadsByCid(String cid) async => (select(reads).join([ + leftOuterJoin(users, reads.userId.equalsExp(users.id)), + ]) + ..where(reads.channelCid.equals(cid)) + ..orderBy([ + OrderingTerm.asc(reads.lastRead), + ])) + .map((row) { + final userEntity = row.readTable(users); + final readEntity = row.readTable(reads); + return readEntity.toRead(user: userEntity?.toUser()); + }).get(); /// Updates the read data of a particular channel with /// the new [readList] data - Future updateReads(String cid, List readList) { - return batch( - (it) => it.insertAll( - reads, - readList.map((r) => r.toEntity(cid: cid)).toList(), - mode: InsertMode.insertOrReplace, - ), - ); - } + Future updateReads(String cid, List readList) => batch( + (it) => it.insertAll( + reads, + readList.map((r) => r.toEntity(cid: cid)).toList(), + mode: InsertMode.insertOrReplace, + ), + ); } diff --git a/packages/stream_chat_persistence/lib/src/dao/user_dao.dart b/packages/stream_chat_persistence/lib/src/dao/user_dao.dart index 795c7968..65ce1521 100644 --- a/packages/stream_chat_persistence/lib/src/dao/user_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/user_dao.dart @@ -2,7 +2,7 @@ import 'package:moor/moor.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; import 'package:stream_chat_persistence/src/entity/users.dart'; -import '../mapper/user_mapper.dart'; +import 'package:stream_chat_persistence/src/mapper/user_mapper.dart'; part 'user_dao.g.dart'; @@ -13,13 +13,11 @@ class UserDao extends DatabaseAccessor with _$UserDaoMixin { UserDao(MoorChatDatabase db) : super(db); /// Updates the users data with the new [userList] data - Future updateUsers(List userList) { - return batch( - (it) => it.insertAll( - users, - userList.map((u) => u.toEntity()).toList(), - mode: InsertMode.insertOrReplace, - ), - ); - } + Future updateUsers(List userList) => batch( + (it) => it.insertAll( + users, + userList.map((u) => u.toEntity()).toList(), + mode: InsertMode.insertOrReplace, + ), + ); } diff --git a/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart b/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart index 57348330..cc3e86b3 100644 --- a/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart +++ b/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart @@ -13,15 +13,12 @@ LazyDatabase _openConnection( String userId, { bool logStatements = false, bool persistOnDisk = true, -}) { - return LazyDatabase(() async { - return await SharedDB.constructDatabase( - userId, - logStatements: logStatements, - persistOnDisk: persistOnDisk, - ); - }); -} +}) => + LazyDatabase(() async => SharedDB.constructDatabase( + userId, + logStatements: logStatements, + persistOnDisk: persistOnDisk, + )); /// A chat database implemented using moor @UseMoor(tables: [ diff --git a/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart b/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart index 9580ae50..7592247e 100644 --- a/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart +++ b/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart @@ -9,7 +9,7 @@ import 'package:path_provider/path_provider.dart'; import 'package:stream_chat_persistence/src/stream_chat_persistence_client.dart'; import 'package:stream_chat_persistence/stream_chat_persistence.dart'; -import '../moor_chat_database.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; /// A Helper class to construct new instances of [MoorChatDatabase] specifically /// for native platform applications @@ -40,12 +40,10 @@ class SharedDB { } static void _startBackground(_IsolateStartRequest request) { - final executor = LazyDatabase(() async { - return VmDatabase( - File(request.targetPath), - logStatements: request.logStatements, - ); - }); + final executor = LazyDatabase(() async => VmDatabase( + File(request.targetPath), + logStatements: request.logStatements, + )); final moorIsolate = MoorIsolate.inCurrent( () => DatabaseConnection.fromExecutor(executor), ); @@ -69,7 +67,7 @@ class SharedDB { ), ); - return (await receivePort.first as MoorIsolate); + return await receivePort.first as MoorIsolate; } /// Returns a new instance of [MoorChatDatabase] using the factory constructor @@ -84,7 +82,7 @@ class SharedDB { return MoorChatDatabase.connect( userId, DatabaseConnection.delayed(Future(() async { - MoorIsolate isolate = await _createMoorIsolate( + final isolate = await _createMoorIsolate( dbName, logStatements: logStatements, ); @@ -95,13 +93,13 @@ class SharedDB { } class _IsolateStartRequest { - final SendPort sendMoorIsolate; - final String targetPath; - final bool logStatements; - const _IsolateStartRequest( this.sendMoorIsolate, this.targetPath, { this.logStatements = false, }); + + final SendPort sendMoorIsolate; + final String targetPath; + final bool logStatements; } diff --git a/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart b/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart index 811e5cc7..3a764d24 100644 --- a/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart +++ b/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart @@ -12,7 +12,8 @@ class SharedDB { bool logStatements = false, bool persistOnDisk = true, }) { - throw 'Unsupported Platform'; + throw UnsupportedError( + 'No implementation of the constructDatabase api provided'); } /// Return a new instance of moor chat database. @@ -22,6 +23,7 @@ class SharedDB { String userId, { bool logStatements = false, }) { - throw 'Unsupported Platform'; + throw UnsupportedError( + 'No implementation of the constructMoorChatDatabase api provided'); } } diff --git a/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart b/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart index f44a41ec..32b108ba 100644 --- a/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart +++ b/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart @@ -1,7 +1,7 @@ import 'package:moor/moor_web.dart'; import 'package:stream_chat_persistence/src/stream_chat_persistence_client.dart'; -import '../moor_chat_database.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; /// A Helper class to construct new instances of [MoorChatDatabase] specifically /// for Web applications diff --git a/packages/stream_chat_persistence/lib/src/entity/entity.dart b/packages/stream_chat_persistence/lib/src/entity/entity.dart index ca9d04cb..d5218768 100644 --- a/packages/stream_chat_persistence/lib/src/entity/entity.dart +++ b/packages/stream_chat_persistence/lib/src/entity/entity.dart @@ -1,9 +1,9 @@ +export 'channel_queries.dart'; export 'channels.dart'; +export 'connection_events.dart'; +export 'members.dart'; export 'messages.dart'; export 'pinned_messages.dart'; export 'reactions.dart'; -export 'users.dart'; -export 'members.dart'; export 'reads.dart'; -export 'channel_queries.dart'; -export 'connection_events.dart'; +export 'users.dart'; diff --git a/packages/stream_chat_persistence/lib/src/entity/pinned_messages.dart b/packages/stream_chat_persistence/lib/src/entity/pinned_messages.dart index f6956f54..de081552 100644 --- a/packages/stream_chat_persistence/lib/src/entity/pinned_messages.dart +++ b/packages/stream_chat_persistence/lib/src/entity/pinned_messages.dart @@ -1,6 +1,6 @@ import 'package:moor/moor.dart'; -import 'messages.dart'; +import 'package:stream_chat_persistence/src/entity/messages.dart'; /// Represents a [PinnedMessages] table in [MoorChatDatabase]. @DataClassName('PinnedMessageEntity') diff --git a/packages/stream_chat_persistence/lib/src/mapper/channel_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/channel_mapper.dart index 3e2520fb..5c8e3e2a 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/channel_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/channel_mapper.dart @@ -29,34 +29,31 @@ extension ChannelEntityX on ChannelEntity { List reads, List messages, List pinnedMessages, - }) { - return ChannelState( - members: members, - read: reads, - messages: messages, - pinnedMessages: pinnedMessages, - channel: toChannelModel(createdBy: createdBy), - ); - } + }) => + ChannelState( + members: members, + read: reads, + messages: messages, + pinnedMessages: pinnedMessages, + channel: toChannelModel(createdBy: createdBy), + ); } /// Useful mapping functions for [ChannelModel] extension ChannelModelX on ChannelModel { /// Maps a [ChannelModel] into [ChannelEntity] - ChannelEntity toEntity() { - return ChannelEntity( - id: id, - type: type, - cid: cid, - config: config.toJson(), - frozen: frozen, - lastMessageAt: lastMessageAt, - createdAt: createdAt, - updatedAt: updatedAt, - deletedAt: deletedAt, - memberCount: memberCount, - createdById: createdBy.id, - extraData: extraData, - ); - } + ChannelEntity toEntity() => ChannelEntity( + id: id, + type: type, + cid: cid, + config: config.toJson(), + frozen: frozen, + lastMessageAt: lastMessageAt, + createdAt: createdAt, + updatedAt: updatedAt, + deletedAt: deletedAt, + memberCount: memberCount, + createdById: createdBy.id, + extraData: extraData, + ); } diff --git a/packages/stream_chat_persistence/lib/src/mapper/event_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/event_mapper.dart index 7bc1739c..fc2a57ba 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/event_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/event_mapper.dart @@ -4,11 +4,9 @@ import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; /// Useful mapping functions for [ConnectionEventEntity] extension ConnectionEventX on ConnectionEventEntity { /// Maps a [ConnectionEventEntity] into [Event] - Event toEvent() { - return Event( - me: ownUser != null ? OwnUser.fromJson(ownUser) : null, - totalUnreadCount: totalUnreadCount, - unreadChannels: unreadChannels, - ); - } + Event toEvent() => Event( + me: ownUser != null ? OwnUser.fromJson(ownUser) : null, + totalUnreadCount: totalUnreadCount, + unreadChannels: unreadChannels, + ); } diff --git a/packages/stream_chat_persistence/lib/src/mapper/mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/mapper.dart index cdc31e05..66bf3cda 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/mapper.dart @@ -1,8 +1,8 @@ -export 'user_mapper.dart'; -export 'reaction_mapper.dart'; export 'channel_mapper.dart'; export 'event_mapper.dart'; export 'member_mapper.dart'; -export 'read_mapper.dart'; export 'message_mapper.dart'; export 'pinned_message_mapper.dart'; +export 'reaction_mapper.dart'; +export 'read_mapper.dart'; +export 'user_mapper.dart'; diff --git a/packages/stream_chat_persistence/lib/src/mapper/member_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/member_mapper.dart index 2d32c9f1..cbdcc297 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/member_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/member_mapper.dart @@ -4,39 +4,35 @@ import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; /// Useful mapping functions for [MemberEntity] extension MemberEntityX on MemberEntity { /// Maps a [MemberEntity] into [Member] - Member toMember({User user}) { - return Member( - user: user, - userId: userId, - banned: banned, - shadowBanned: shadowBanned, - updatedAt: updatedAt, - createdAt: createdAt, - role: role, - inviteAcceptedAt: inviteAcceptedAt, - invited: invited, - inviteRejectedAt: inviteRejectedAt, - isModerator: isModerator, - ); - } + Member toMember({User user}) => Member( + user: user, + userId: userId, + banned: banned, + shadowBanned: shadowBanned, + updatedAt: updatedAt, + createdAt: createdAt, + role: role, + inviteAcceptedAt: inviteAcceptedAt, + invited: invited, + inviteRejectedAt: inviteRejectedAt, + isModerator: isModerator, + ); } /// Useful mapping functions for [Member] extension MemberX on Member { /// Maps a [Member] into [MemberEntity] - MemberEntity toEntity({String cid}) { - return MemberEntity( - userId: user?.id, - banned: banned, - shadowBanned: shadowBanned, - channelCid: cid, - createdAt: createdAt, - isModerator: isModerator, - inviteRejectedAt: inviteRejectedAt, - invited: invited, - inviteAcceptedAt: inviteAcceptedAt, - role: role, - updatedAt: updatedAt, - ); - } + MemberEntity toEntity({String cid}) => MemberEntity( + userId: user?.id, + banned: banned, + shadowBanned: shadowBanned, + channelCid: cid, + createdAt: createdAt, + isModerator: isModerator, + inviteRejectedAt: inviteRejectedAt, + invited: invited, + inviteAcceptedAt: inviteAcceptedAt, + role: role, + updatedAt: updatedAt, + ); } diff --git a/packages/stream_chat_persistence/lib/src/mapper/message_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/message_mapper.dart index 5acf1a84..fdf93cc5 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/message_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/message_mapper.dart @@ -12,70 +12,66 @@ extension MessageEntityX on MessageEntity { List latestReactions, List ownReactions, Message quotedMessage, - }) { - return Message( - shadowed: shadowed, - latestReactions: latestReactions, - ownReactions: ownReactions, - attachments: attachments?.map((it) { - final json = jsonDecode(it); - return Attachment.fromData(json); - })?.toList(), - createdAt: createdAt, - extraData: extraData, - updatedAt: updatedAt, - id: id, - type: type, - status: status, - command: command, - parentId: parentId, - quotedMessageId: quotedMessageId, - quotedMessage: quotedMessage, - reactionCounts: reactionCounts, - reactionScores: reactionScores, - replyCount: replyCount, - showInChannel: showInChannel, - text: messageText, - user: user, - deletedAt: deletedAt, - pinned: pinned, - pinnedAt: pinnedAt, - pinExpires: pinExpires, - pinnedBy: pinnedBy, - ); - } + }) => + Message( + shadowed: shadowed, + latestReactions: latestReactions, + ownReactions: ownReactions, + attachments: attachments?.map((it) { + final json = jsonDecode(it); + return Attachment.fromData(json); + })?.toList(), + createdAt: createdAt, + extraData: extraData, + updatedAt: updatedAt, + id: id, + type: type, + status: status, + command: command, + parentId: parentId, + quotedMessageId: quotedMessageId, + quotedMessage: quotedMessage, + reactionCounts: reactionCounts, + reactionScores: reactionScores, + replyCount: replyCount, + showInChannel: showInChannel, + text: messageText, + user: user, + deletedAt: deletedAt, + pinned: pinned, + pinnedAt: pinnedAt, + pinExpires: pinExpires, + pinnedBy: pinnedBy, + ); } /// Useful mapping functions for [Message] extension MessageX on Message { /// Maps a [Message] into [MessageEntity] - MessageEntity toEntity({String cid}) { - return MessageEntity( - id: id, - attachments: attachments?.map((it) { - return jsonEncode(it.toData()); - })?.toList(), - channelCid: cid, - type: type, - parentId: parentId, - quotedMessageId: quotedMessageId, - command: command, - createdAt: createdAt, - shadowed: shadowed, - showInChannel: showInChannel, - replyCount: replyCount, - reactionScores: reactionScores, - reactionCounts: reactionCounts, - status: status, - updatedAt: updatedAt, - extraData: extraData, - userId: user?.id, - deletedAt: deletedAt, - messageText: text, - pinned: pinned, - pinnedAt: pinnedAt, - pinExpires: pinExpires, - pinnedByUserId: pinnedBy?.id, - ); - } + MessageEntity toEntity({String cid}) => MessageEntity( + id: id, + attachments: + attachments?.map((it) => jsonEncode(it.toData()))?.toList(), + channelCid: cid, + type: type, + parentId: parentId, + quotedMessageId: quotedMessageId, + command: command, + createdAt: createdAt, + shadowed: shadowed, + showInChannel: showInChannel, + replyCount: replyCount, + reactionScores: reactionScores, + reactionCounts: reactionCounts, + status: status, + updatedAt: updatedAt, + extraData: extraData, + userId: user?.id, + deletedAt: deletedAt, + messageText: text, + pinned: pinned, + pinnedAt: pinnedAt, + pinExpires: pinExpires, + pinnedByUserId: pinnedBy?.id, + ); } diff --git a/packages/stream_chat_persistence/lib/src/mapper/pinned_message_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/pinned_message_mapper.dart index 1abe896f..ec2a0e91 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/pinned_message_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/pinned_message_mapper.dart @@ -12,70 +12,66 @@ extension PinnedMessageEntityX on PinnedMessageEntity { List latestReactions, List ownReactions, Message quotedMessage, - }) { - return Message( - shadowed: shadowed, - latestReactions: latestReactions, - ownReactions: ownReactions, - attachments: attachments?.map((it) { - final json = jsonDecode(it); - return Attachment.fromData(json); - })?.toList(), - createdAt: createdAt, - extraData: extraData, - updatedAt: updatedAt, - id: id, - type: type, - status: status, - command: command, - parentId: parentId, - quotedMessageId: quotedMessageId, - quotedMessage: quotedMessage, - reactionCounts: reactionCounts, - reactionScores: reactionScores, - replyCount: replyCount, - showInChannel: showInChannel, - text: messageText, - user: user, - deletedAt: deletedAt, - pinned: pinned, - pinnedAt: pinnedAt, - pinExpires: pinExpires, - pinnedBy: pinnedBy, - ); - } + }) => + Message( + shadowed: shadowed, + latestReactions: latestReactions, + ownReactions: ownReactions, + attachments: attachments?.map((it) { + final json = jsonDecode(it); + return Attachment.fromData(json); + })?.toList(), + createdAt: createdAt, + extraData: extraData, + updatedAt: updatedAt, + id: id, + type: type, + status: status, + command: command, + parentId: parentId, + quotedMessageId: quotedMessageId, + quotedMessage: quotedMessage, + reactionCounts: reactionCounts, + reactionScores: reactionScores, + replyCount: replyCount, + showInChannel: showInChannel, + text: messageText, + user: user, + deletedAt: deletedAt, + pinned: pinned, + pinnedAt: pinnedAt, + pinExpires: pinExpires, + pinnedBy: pinnedBy, + ); } /// Useful mapping functions for [Message] extension PMessageX on Message { /// Maps a [Message] into [PinnedMessageEntity] - PinnedMessageEntity toPinnedEntity({String cid}) { - return PinnedMessageEntity( - id: id, - attachments: attachments?.map((it) { - return jsonEncode(it.toData()); - })?.toList(), - channelCid: cid, - type: type, - parentId: parentId, - quotedMessageId: quotedMessageId, - command: command, - createdAt: createdAt, - shadowed: shadowed, - showInChannel: showInChannel, - replyCount: replyCount, - reactionScores: reactionScores, - reactionCounts: reactionCounts, - status: status, - updatedAt: updatedAt, - extraData: extraData, - userId: user?.id, - deletedAt: deletedAt, - messageText: text, - pinned: pinned, - pinnedAt: pinnedAt, - pinExpires: pinExpires, - pinnedByUserId: pinnedBy?.id, - ); - } + PinnedMessageEntity toPinnedEntity({String cid}) => PinnedMessageEntity( + id: id, + attachments: + attachments?.map((it) => jsonEncode(it.toData()))?.toList(), + channelCid: cid, + type: type, + parentId: parentId, + quotedMessageId: quotedMessageId, + command: command, + createdAt: createdAt, + shadowed: shadowed, + showInChannel: showInChannel, + replyCount: replyCount, + reactionScores: reactionScores, + reactionCounts: reactionCounts, + status: status, + updatedAt: updatedAt, + extraData: extraData, + userId: user?.id, + deletedAt: deletedAt, + messageText: text, + pinned: pinned, + pinnedAt: pinnedAt, + pinExpires: pinExpires, + pinnedByUserId: pinnedBy?.id, + ); } diff --git a/packages/stream_chat_persistence/lib/src/mapper/reaction_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/reaction_mapper.dart index d265fcb7..3f8533db 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/reaction_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/reaction_mapper.dart @@ -4,8 +4,7 @@ import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; /// Useful mapping functions for [ReactionEntity] extension ReactionEntityX on ReactionEntity { /// Maps a [ReactionEntity] into [Reaction] - Reaction toReaction({User user}) { - return Reaction( + Reaction toReaction({User user}) => Reaction( extraData: extraData, type: type, createdAt: createdAt, @@ -14,14 +13,12 @@ extension ReactionEntityX on ReactionEntity { messageId: messageId, score: score, ); - } } /// Useful mapping functions for [Reaction] extension ReactionX on Reaction { /// Maps a [Reaction] into [ReactionEntity] - ReactionEntity toEntity() { - return ReactionEntity( + ReactionEntity toEntity() => ReactionEntity( extraData: extraData, type: type, createdAt: createdAt, @@ -29,5 +26,4 @@ extension ReactionX on Reaction { messageId: messageId, score: score, ); - } } diff --git a/packages/stream_chat_persistence/lib/src/mapper/read_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/read_mapper.dart index c79cf8d5..5493c5da 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/read_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/read_mapper.dart @@ -4,24 +4,20 @@ import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; /// Useful mapping functions for [ReadEntity] extension ReadEntityX on ReadEntity { /// Maps a [ReadEntity] into [Read] - Read toRead({User user}) { - return Read( + Read toRead({User user}) => Read( user: user, lastRead: lastRead, unreadMessages: unreadMessages, ); - } } /// Useful mapping functions for [Read] extension ReadX on Read { /// Maps a [Read] into [ReadEntity] - ReadEntity toEntity({String cid}) { - return ReadEntity( + ReadEntity toEntity({String cid}) => ReadEntity( lastRead: lastRead, userId: user?.id, channelCid: cid, unreadMessages: unreadMessages, ); - } } diff --git a/packages/stream_chat_persistence/lib/src/mapper/user_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/user_mapper.dart index b1e53786..533a45b1 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/user_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/user_mapper.dart @@ -4,33 +4,29 @@ import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; /// Useful mapping functions for [UserEntity] extension UserEntityX on UserEntity { /// Maps a [UserEntity] into [User] - User toUser() { - return User( - id: id, - updatedAt: updatedAt, - role: role, - online: online, - lastActive: lastActive, - extraData: extraData, - banned: banned, - createdAt: createdAt, - ); - } + User toUser() => User( + id: id, + updatedAt: updatedAt, + role: role, + online: online, + lastActive: lastActive, + extraData: extraData, + banned: banned, + createdAt: createdAt, + ); } /// Useful mapping functions for [User] extension UserX on User { /// Maps a [User] into [UserEntity] - UserEntity toEntity() { - return UserEntity( - id: id, - role: role, - createdAt: createdAt, - updatedAt: updatedAt, - lastActive: lastActive, - online: online, - banned: banned, - extraData: extraData, - ); - } + UserEntity toEntity() => UserEntity( + id: id, + role: role, + createdAt: createdAt, + updatedAt: updatedAt, + lastActive: lastActive, + online: online, + banned: banned, + extraData: extraData, + ); } diff --git a/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart index 832eabbd..e7ee060b 100644 --- a/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart +++ b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart @@ -3,8 +3,8 @@ import 'package:meta/meta.dart'; import 'package:mutex/mutex.dart'; import 'package:stream_chat/stream_chat.dart'; -import 'db/moor_chat_database.dart'; -import 'db/shared/shared_db.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:stream_chat_persistence/src/db/shared/shared_db.dart'; /// Various connection modes on which [StreamChatPersistenceClient] can work enum ConnectionMode { @@ -15,7 +15,7 @@ enum ConnectionMode { background, } -final levelEmojiMapper = { +final _levelEmojiMapper = { Level.INFO: 'ℹ️', Level.WARNING: '⚠️', Level.SEVERE: '🚨', @@ -29,8 +29,8 @@ class StreamChatPersistenceClient extends ChatPersistenceClient { ConnectionMode connectionMode = ConnectionMode.regular, Level logLevel = Level.WARNING, LogHandlerFunction logHandlerFunction, - }) : assert(connectionMode != null), - assert(logLevel != null), + }) : assert(connectionMode != null, 'ConnectionMode cannot be null'), + assert(logLevel != null, 'LogLevel cannot be null'), _connectionMode = connectionMode, _logger = Logger.detached('💽')..level = logLevel { _logger.onRecord.listen(logHandlerFunction ?? _defaultLogHandler); @@ -56,8 +56,10 @@ class StreamChatPersistenceClient extends ChatPersistenceClient { ///``` LogHandlerFunction logHandlerFunction; + /// [MoorChatDatabase] instance used by this client. @visibleForTesting MoorChatDatabase db; + final Logger _logger; final ConnectionMode _connectionMode; final _mutex = ReadWriteMutex(); @@ -65,13 +67,13 @@ class StreamChatPersistenceClient extends ChatPersistenceClient { void _defaultLogHandler(LogRecord record) { print( '(${record.time}) ' - '${levelEmojiMapper[record.level] ?? record.level.name} ' + '${_levelEmojiMapper[record.level] ?? record.level.name} ' '${record.loggerName} ${record.message}', ); if (record.stackTrace != null) print(record.stackTrace); } - Future readProtected(Future Function() f) async { + Future _readProtected(Future Function() f) async { T ret; await _mutex.protectRead(() async { if (db == null) { @@ -103,299 +105,256 @@ class StreamChatPersistenceClient extends ChatPersistenceClient { } @override - Future getConnectionInfo() { - return readProtected(() { - _logger.info('getConnectionInfo'); - return db.connectionEventDao.connectionEvent; - }); - } + Future getConnectionInfo() => _readProtected(() { + _logger.info('getConnectionInfo'); + return db.connectionEventDao.connectionEvent; + }); @override - Future updateConnectionInfo(Event event) { - return readProtected(() { - _logger.info('updateConnectionInfo'); - return db.connectionEventDao.updateConnectionEvent(event); - }); - } + Future updateConnectionInfo(Event event) => _readProtected(() { + _logger.info('updateConnectionInfo'); + return db.connectionEventDao.updateConnectionEvent(event); + }); @override - Future updateLastSyncAt(DateTime lastSyncAt) { - return readProtected(() { - _logger.info('updateLastSyncAt'); - return db.connectionEventDao.updateLastSyncAt(lastSyncAt); - }); - } + Future updateLastSyncAt(DateTime lastSyncAt) => _readProtected(() { + _logger.info('updateLastSyncAt'); + return db.connectionEventDao.updateLastSyncAt(lastSyncAt); + }); @override - Future getLastSyncAt() { - return readProtected(() { - _logger.info('getLastSyncAt'); - return db.connectionEventDao.lastSyncAt; - }); - } + Future getLastSyncAt() => _readProtected(() { + _logger.info('getLastSyncAt'); + return db.connectionEventDao.lastSyncAt; + }); @override - Future deleteChannels(List cids) { - return readProtected(() { - _logger.info('deleteChannels'); - return db.channelDao.deleteChannelByCids(cids); - }); - } + Future deleteChannels(List cids) => _readProtected(() { + _logger.info('deleteChannels'); + return db.channelDao.deleteChannelByCids(cids); + }); @override - Future> getChannelCids() { - return readProtected(() { - _logger.info('getChannelCids'); - return db.channelDao.cids; - }); - } + Future> getChannelCids() => _readProtected(() { + _logger.info('getChannelCids'); + return db.channelDao.cids; + }); @override - Future deleteMessageByIds(List messageIds) { - return readProtected(() { - _logger.info('deleteMessageByIds'); - return db.messageDao.deleteMessageByIds(messageIds); - }); - } + Future deleteMessageByIds(List messageIds) => + _readProtected(() { + _logger.info('deleteMessageByIds'); + return db.messageDao.deleteMessageByIds(messageIds); + }); @override - Future deletePinnedMessageByIds(List messageIds) { - return readProtected(() { - _logger.info('deletePinnedMessageByIds'); - return db.pinnedMessageDao.deleteMessageByIds(messageIds); - }); - } + Future deletePinnedMessageByIds(List messageIds) => + _readProtected(() { + _logger.info('deletePinnedMessageByIds'); + return db.pinnedMessageDao.deleteMessageByIds(messageIds); + }); @override - Future deleteMessageByCids(List cids) { - return readProtected(() { - _logger.info('deleteMessageByCids'); - return db.messageDao.deleteMessageByCids(cids); - }); - } + Future deleteMessageByCids(List cids) => _readProtected(() { + _logger.info('deleteMessageByCids'); + return db.messageDao.deleteMessageByCids(cids); + }); @override - Future deletePinnedMessageByCids(List cids) { - return readProtected(() { - _logger.info('deletePinnedMessageByCids'); - return db.pinnedMessageDao.deleteMessageByCids(cids); - }); - } + Future deletePinnedMessageByCids(List cids) => + _readProtected(() { + _logger.info('deletePinnedMessageByCids'); + return db.pinnedMessageDao.deleteMessageByCids(cids); + }); @override - Future> getMembersByCid(String cid) { - return readProtected(() { - _logger.info('getMembersByCid'); - return db.memberDao.getMembersByCid(cid); - }); - } + Future> getMembersByCid(String cid) => _readProtected(() { + _logger.info('getMembersByCid'); + return db.memberDao.getMembersByCid(cid); + }); @override - Future getChannelByCid(String cid) { - return readProtected(() { - _logger.info('getChannelByCid'); - return db.channelDao.getChannelByCid(cid); - }); - } + Future getChannelByCid(String cid) => _readProtected(() { + _logger.info('getChannelByCid'); + return db.channelDao.getChannelByCid(cid); + }); @override Future> getMessagesByCid( String cid, { PaginationParams messagePagination, - }) { - return readProtected(() { - _logger.info('getMessagesByCid'); - return db.messageDao.getMessagesByCid( - cid, - messagePagination: messagePagination, - ); - }); - } + }) => + _readProtected(() { + _logger.info('getMessagesByCid'); + return db.messageDao.getMessagesByCid( + cid, + messagePagination: messagePagination, + ); + }); @override Future> getPinnedMessagesByCid( String cid, { PaginationParams messagePagination, - }) { - return readProtected(() { - _logger.info('getPinnedMessagesByCid'); - return db.pinnedMessageDao.getMessagesByCid( - cid, - messagePagination: messagePagination, - ); - }); - } + }) => + _readProtected(() { + _logger.info('getPinnedMessagesByCid'); + return db.pinnedMessageDao.getMessagesByCid( + cid, + messagePagination: messagePagination, + ); + }); @override - Future> getReadsByCid(String cid) { - return readProtected(() { - _logger.info('getReadsByCid'); - return db.readDao.getReadsByCid(cid); - }); - } + Future> getReadsByCid(String cid) => _readProtected(() { + _logger.info('getReadsByCid'); + return db.readDao.getReadsByCid(cid); + }); @override - Future>> getChannelThreads(String cid) async { - return readProtected(() async { - _logger.info('getChannelThreads'); - final messages = await db.messageDao.getThreadMessages(cid); - final messageByParentIdDictionary = >{}; - for (final message in messages) { - final parentId = message.parentId; - messageByParentIdDictionary[parentId] = [ - ...messageByParentIdDictionary[parentId] ?? [], - message - ]; - } - return messageByParentIdDictionary; - }); - } + Future>> getChannelThreads(String cid) async => + _readProtected(() async { + _logger.info('getChannelThreads'); + final messages = await db.messageDao.getThreadMessages(cid); + final messageByParentIdDictionary = >{}; + for (final message in messages) { + final parentId = message.parentId; + messageByParentIdDictionary[parentId] = [ + ...messageByParentIdDictionary[parentId] ?? [], + message + ]; + } + return messageByParentIdDictionary; + }); @override Future> getReplies( String parentId, { PaginationParams options, - }) { - return readProtected(() async { - _logger.info('getReplies'); - return db.messageDao.getThreadMessagesByParentId( - parentId, - options: options, - ); - }); - } + }) => + _readProtected(() async { + _logger.info('getReplies'); + return db.messageDao.getThreadMessagesByParentId( + parentId, + options: options, + ); + }); @override Future> getChannelStates({ Map filter, List> sort = const [], PaginationParams paginationParams, - }) async { - return readProtected(() async { - _logger.info('getChannelStates'); - final channels = await db.channelQueryDao.getChannels( - filter: filter, - sort: sort, - paginationParams: paginationParams, - ); - return Future.wait(channels.map((e) => getChannelStateByCid(e.cid))); - }); - } + }) async => + _readProtected(() async { + _logger.info('getChannelStates'); + final channels = await db.channelQueryDao.getChannels( + filter: filter, + sort: sort, + paginationParams: paginationParams, + ); + return Future.wait(channels.map((e) => getChannelStateByCid(e.cid))); + }); @override Future updateChannelQueries( Map filter, List cids, bool clearQueryCache, - ) { - return readProtected(() async { - _logger.info('updateChannelQueries'); - return db.channelQueryDao.updateChannelQueries( - filter, - cids, - clearQueryCache, - ); - }); - } - - @override - Future updateChannels(List channels) { - return readProtected(() async { - _logger.info('updateChannels'); - return db.channelDao.updateChannels(channels); - }); - } - - @override - Future updateMembers(String cid, List members) { - return readProtected(() async { - _logger.info('updateMembers'); - return db.memberDao.updateMembers(cid, members); - }); - } - - @override - Future updateMessages(String cid, List messages) { - return readProtected(() async { - _logger.info('updateMessages'); - return db.messageDao.updateMessages(cid, messages); - }); - } - - @override - Future updatePinnedMessages(String cid, List messages) { - return readProtected(() async { - _logger.info('updatePinnedMessages'); - return db.pinnedMessageDao.updateMessages(cid, messages); - }); - } - - @override - Future updateReactions(List reactions) { - return readProtected(() async { - _logger.info('updateReactions'); - return db.reactionDao.updateReactions(reactions); - }); - } - - @override - Future updateReads(String cid, List reads) { - return readProtected(() async { - _logger.info('updateReads'); - return db.readDao.updateReads(cid, reads); - }); - } - - @override - Future updateUsers(List users) { - return readProtected(() async { - _logger.info('updateUsers'); - return db.userDao.updateUsers(users); - }); - } - - @override - Future deleteReactionsByMessageId(List messageIds) { - return readProtected(() async { - _logger.info('deleteReactionsByMessageId'); - return db.reactionDao.deleteReactionsByMessageIds(messageIds); - }); - } - - @override - Future deleteMembersByCids(List cids) { - return readProtected(() async { - _logger.info('deleteMembersByCids'); - return db.memberDao.deleteMemberByCids(cids); - }); - } - - @override - Future updateChannelStates(List channelStates) { - return readProtected(() async { - return db.transaction(() async { - await super.updateChannelStates(channelStates); + ) => + _readProtected(() async { + _logger.info('updateChannelQueries'); + return db.channelQueryDao.updateChannelQueries( + filter, + cids, + clearQueryCache: clearQueryCache, + ); }); - }); - } @override - Future disconnect({bool flush = false}) async { - return _mutex.protectWrite(() async { - _logger.info('disconnect'); - if (db != null) { - _logger.info('Disconnecting'); - if (flush) { - _logger.info('Flushing'); - await db.batch((batch) { - db.allTables.forEach((table) { - db.delete(table).go(); + Future updateChannels(List channels) => + _readProtected(() async { + _logger.info('updateChannels'); + return db.channelDao.updateChannels(channels); + }); + + @override + Future updateMembers(String cid, List members) => + _readProtected(() async { + _logger.info('updateMembers'); + return db.memberDao.updateMembers(cid, members); + }); + + @override + Future updateMessages(String cid, List messages) => + _readProtected(() async { + _logger.info('updateMessages'); + return db.messageDao.updateMessages(cid, messages); + }); + + @override + Future updatePinnedMessages(String cid, List messages) => + _readProtected(() async { + _logger.info('updatePinnedMessages'); + return db.pinnedMessageDao.updateMessages(cid, messages); + }); + + @override + Future updateReactions(List reactions) => + _readProtected(() async { + _logger.info('updateReactions'); + return db.reactionDao.updateReactions(reactions); + }); + + @override + Future updateReads(String cid, List reads) => + _readProtected(() async { + _logger.info('updateReads'); + return db.readDao.updateReads(cid, reads); + }); + + @override + Future updateUsers(List users) => _readProtected(() async { + _logger.info('updateUsers'); + return db.userDao.updateUsers(users); + }); + + @override + Future deleteReactionsByMessageId(List messageIds) => + _readProtected(() async { + _logger.info('deleteReactionsByMessageId'); + return db.reactionDao.deleteReactionsByMessageIds(messageIds); + }); + + @override + Future deleteMembersByCids(List cids) => + _readProtected(() async { + _logger.info('deleteMembersByCids'); + return db.memberDao.deleteMemberByCids(cids); + }); + + @override + Future updateChannelStates(List channelStates) => + _readProtected(() async => db.transaction(() async { + await super.updateChannelStates(channelStates); + })); + + @override + Future disconnect({bool flush = false}) async => + _mutex.protectWrite(() async { + _logger.info('disconnect'); + if (db != null) { + _logger.info('Disconnecting'); + if (flush) { + _logger.info('Flushing'); + await db.batch((batch) { + db.allTables.forEach((table) { + db.delete(table).go(); + }); }); - }); + } + await db.disconnect(); + db = null; } - await db.disconnect(); - db = null; - } - }); - } + }); } diff --git a/packages/stream_chat_persistence/pubspec.yaml b/packages/stream_chat_persistence/pubspec.yaml index 06f991e1..a91ac666 100644 --- a/packages/stream_chat_persistence/pubspec.yaml +++ b/packages/stream_chat_persistence/pubspec.yaml @@ -17,7 +17,7 @@ dependencies: path_provider: ^1.6.27 sqlite3_flutter_libs: ^0.4.0+1 stream_chat: - git: + git: url: https://github.com/GetStream/stream-chat-flutter.git ref: develop path: packages/stream_chat From 8c0da62f792e68d0b08e1bff4f9bfd355130aef7 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 15 Mar 2021 12:05:36 +0530 Subject: [PATCH 02/50] style: flutter format Signed-off-by: Sahil Kumar --- .../lib/src/mapper/reaction_mapper.dart | 30 +++++++++---------- .../lib/src/mapper/read_mapper.dart | 18 +++++------ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/packages/stream_chat_persistence/lib/src/mapper/reaction_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/reaction_mapper.dart index 3f8533db..20842307 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/reaction_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/reaction_mapper.dart @@ -5,25 +5,25 @@ import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; extension ReactionEntityX on ReactionEntity { /// Maps a [ReactionEntity] into [Reaction] Reaction toReaction({User user}) => Reaction( - extraData: extraData, - type: type, - createdAt: createdAt, - userId: userId, - user: user, - messageId: messageId, - score: score, - ); + extraData: extraData, + type: type, + createdAt: createdAt, + userId: userId, + user: user, + messageId: messageId, + score: score, + ); } /// Useful mapping functions for [Reaction] extension ReactionX on Reaction { /// Maps a [Reaction] into [ReactionEntity] ReactionEntity toEntity() => ReactionEntity( - extraData: extraData, - type: type, - createdAt: createdAt, - userId: userId, - messageId: messageId, - score: score, - ); + extraData: extraData, + type: type, + createdAt: createdAt, + userId: userId, + messageId: messageId, + score: score, + ); } diff --git a/packages/stream_chat_persistence/lib/src/mapper/read_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/read_mapper.dart index 5493c5da..9664030e 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/read_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/read_mapper.dart @@ -5,19 +5,19 @@ import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; extension ReadEntityX on ReadEntity { /// Maps a [ReadEntity] into [Read] Read toRead({User user}) => Read( - user: user, - lastRead: lastRead, - unreadMessages: unreadMessages, - ); + user: user, + lastRead: lastRead, + unreadMessages: unreadMessages, + ); } /// Useful mapping functions for [Read] extension ReadX on Read { /// Maps a [Read] into [ReadEntity] ReadEntity toEntity({String cid}) => ReadEntity( - lastRead: lastRead, - userId: user?.id, - channelCid: cid, - unreadMessages: unreadMessages, - ); + lastRead: lastRead, + userId: user?.id, + channelCid: cid, + unreadMessages: unreadMessages, + ); } From 4cbbc059d3a8e76e78c2e770144380cf468ba498 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 15 Mar 2021 14:17:01 +0530 Subject: [PATCH 03/50] test(persistence): Add tests for channel dao Signed-off-by: Sahil Kumar --- .../lib/src/db/moor_chat_database.dart | 19 +-- .../lib/src/db/shared/native_db.dart | 21 ++- .../lib/src/db/shared/unsupported_db.dart | 1 - .../lib/src/db/shared/web_db.dart | 1 - .../lib/src/mapper/channel_mapper.dart | 4 +- .../test/src/dao/channel_dao_test.dart | 139 ++++++++++++++++++ 6 files changed, 160 insertions(+), 25 deletions(-) create mode 100644 packages/stream_chat_persistence/test/src/dao/channel_dao_test.dart diff --git a/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart b/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart index cc3e86b3..2edaed4f 100644 --- a/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart +++ b/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart @@ -1,23 +1,22 @@ -import 'package:moor/isolate.dart'; +import 'package:meta/meta.dart'; +import 'package:moor/ffi.dart'; import 'package:moor/moor.dart'; import 'package:stream_chat/stream_chat.dart'; -import '../converter/converter.dart'; -import '../dao/dao.dart'; -import '../entity/entity.dart'; -import 'shared/shared_db.dart'; +import 'package:stream_chat_persistence/src/converter/converter.dart'; +import 'package:stream_chat_persistence/src/dao/dao.dart'; +import 'package:stream_chat_persistence/src/entity/entity.dart'; +import 'package:stream_chat_persistence/src/db/shared/shared_db.dart'; part 'moor_chat_database.g.dart'; LazyDatabase _openConnection( String userId, { bool logStatements = false, - bool persistOnDisk = true, }) => LazyDatabase(() async => SharedDB.constructDatabase( userId, logStatements: logStatements, - persistOnDisk: persistOnDisk, )); /// A chat database implemented using moor @@ -47,11 +46,9 @@ class MoorChatDatabase extends _$MoorChatDatabase { MoorChatDatabase( this._userId, { logStatements = false, - bool persistOnDisk = true, }) : super(_openConnection( _userId, logStatements: logStatements, - persistOnDisk: persistOnDisk, )); /// Instantiate a new database instance @@ -60,6 +57,10 @@ class MoorChatDatabase extends _$MoorChatDatabase { DatabaseConnection connection, ) : super.connect(connection); + /// Custom constructor used only for testing + @visibleForTesting + MoorChatDatabase.testable(this._userId) : super(VmDatabase.memory()); + final String _userId; /// User id to which the database is connected diff --git a/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart b/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart index 7592247e..a3b1ce8e 100644 --- a/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart +++ b/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart @@ -21,20 +21,17 @@ class SharedDB { static Future constructDatabase( String userId, { bool logStatements = false, - bool persistOnDisk = true, }) async { final dbName = 'db_$userId'; - if (persistOnDisk) { - if (Platform.isIOS || Platform.isAndroid) { - final dir = await getApplicationDocumentsDirectory(); - final path = join(dir.path, '$dbName.sqlite'); - final file = File(path); - return VmDatabase(file, logStatements: logStatements); - } - if (Platform.isMacOS || Platform.isLinux) { - final file = File('$dbName.sqlite'); - return VmDatabase(file, logStatements: logStatements); - } + if (Platform.isIOS || Platform.isAndroid) { + final dir = await getApplicationDocumentsDirectory(); + final path = join(dir.path, '$dbName.sqlite'); + final file = File(path); + return VmDatabase(file, logStatements: logStatements); + } + if (Platform.isMacOS || Platform.isLinux) { + final file = File('$dbName.sqlite'); + return VmDatabase(file, logStatements: logStatements); } return VmDatabase.memory(logStatements: logStatements); } diff --git a/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart b/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart index 3a764d24..15734a7c 100644 --- a/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart +++ b/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart @@ -10,7 +10,6 @@ class SharedDB { static Future constructDatabase( String userId, { bool logStatements = false, - bool persistOnDisk = true, }) { throw UnsupportedError( 'No implementation of the constructDatabase api provided'); diff --git a/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart b/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart index 32b108ba..7388543e 100644 --- a/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart +++ b/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart @@ -12,7 +12,6 @@ class SharedDB { static Future constructDatabase( String userId, { bool logStatements = false, - bool persistOnDisk = true, // ignored on web }) async { final dbName = 'db_$userId'; return WebDatabase(dbName, logStatements: logStatements); diff --git a/packages/stream_chat_persistence/lib/src/mapper/channel_mapper.dart b/packages/stream_chat_persistence/lib/src/mapper/channel_mapper.dart index 5c8e3e2a..65315519 100644 --- a/packages/stream_chat_persistence/lib/src/mapper/channel_mapper.dart +++ b/packages/stream_chat_persistence/lib/src/mapper/channel_mapper.dart @@ -46,14 +46,14 @@ extension ChannelModelX on ChannelModel { id: id, type: type, cid: cid, - config: config.toJson(), + config: config?.toJson(), frozen: frozen, lastMessageAt: lastMessageAt, createdAt: createdAt, updatedAt: updatedAt, deletedAt: deletedAt, memberCount: memberCount, - createdById: createdBy.id, + createdById: createdBy?.id, extraData: extraData, ); } diff --git a/packages/stream_chat_persistence/test/src/dao/channel_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/channel_dao_test.dart new file mode 100644 index 00000000..9d6a3070 --- /dev/null +++ b/packages/stream_chat_persistence/test/src/dao/channel_dao_test.dart @@ -0,0 +1,139 @@ +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/dao/channel_dao.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:test/test.dart'; + +void main() { + ChannelDao channelDao; + MoorChatDatabase database; + + setUp(() { + database = MoorChatDatabase.testable('testUserId'); + channelDao = database.channelDao; + }); + + test('getChannelByCid', () async { + const id = 'testId'; + const cid = 'testCid'; + const type = 'testType'; + + // Should be null initially + final channel = await channelDao.getChannelByCid(cid); + expect(channel, isNull); + + // Saving a dummy channel + final dummyChannel = ChannelModel( + id: id, + type: type, + cid: cid, + config: ChannelConfig(), + ); + await channelDao.updateChannels([dummyChannel]); + + // Should match the dummy channel + final updatedChannel = await channelDao.getChannelByCid(cid); + expect(updatedChannel.id, id); + expect(updatedChannel.cid, cid); + expect(updatedChannel.type, type); + }); + + test('deleteChannelByCids', () async { + const id = 'testId'; + const cid = 'testCid'; + const type = 'testType'; + + // Saving a dummy channel + final dummyChannel = ChannelModel( + id: id, + type: type, + cid: cid, + config: ChannelConfig(), + ); + await channelDao.updateChannels([dummyChannel]); + + // Should match the dummy channel + final updatedChannel = await channelDao.getChannelByCid(cid); + expect(updatedChannel.id, id); + expect(updatedChannel.cid, cid); + expect(updatedChannel.type, type); + + // Deleting the dummyChannel using cid + await channelDao.deleteChannelByCids([cid]); + + // Fetched channel Should be null + final channel = await channelDao.getChannelByCid(cid); + expect(channel, isNull); + }); + + test('cids', () async { + // Should be empty initially + final cids = await channelDao.cids; + expect(cids, []); + + const id = 'testId'; + const cid = 'testCid'; + const type = 'testType'; + + // Saving a dummy channel + final dummyChannel = ChannelModel( + id: id, + type: type, + cid: cid, + config: ChannelConfig(), + ); + await channelDao.updateChannels([dummyChannel]); + + // Should return the cid of the dummy channel + final updatedCids = await channelDao.cids; + expect(updatedCids, [cid]); + }); + +// /// Updates all the channels using the new [channelList] data +// Future updateChannels(List channelList) => batch( +// (it) => it.insertAll( +// channels, +// channelList.map((c) => c.toEntity()).toList(), +// mode: InsertMode.insertOrReplace, +// ), +// ); + + test('updateChannels', () async { + const id = 'testId'; + const cid = 'testCid'; + const type = 'testType'; + + // Should be null initially + final channel = await channelDao.getChannelByCid(cid); + expect(channel, isNull); + + // Saving a dummy channel + final dummyChannel = ChannelModel( + id: id, + type: type, + cid: cid, + config: ChannelConfig(), + ); + await channelDao.updateChannels([dummyChannel]); + + // Should match the dummy channel + final updatedChannel = await channelDao.getChannelByCid(cid); + expect(updatedChannel.id, id); + expect(updatedChannel.cid, cid); + expect(updatedChannel.type, type); + + // Updating the previously saved channel + const newType = 'newTestType'; + final newChannel = dummyChannel.copyWith(type: newType); + await channelDao.updateChannels([newChannel]); + + // Should match the new channel + final newUpdatedChannel = await channelDao.getChannelByCid(cid); + expect(newUpdatedChannel.id, id); + expect(newUpdatedChannel.cid, cid); + expect(newUpdatedChannel.type, newType); + }); + + tearDown(() async { + await database.disconnect(); + }); +} From ae65b2b8b2d9c14125784107ce8e4359257a4b52 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 15 Mar 2021 14:20:00 +0530 Subject: [PATCH 04/50] refactor(persistence): remove dummy comments Signed-off-by: Sahil Kumar --- .../test/src/dao/channel_dao_test.dart | 9 --------- 1 file changed, 9 deletions(-) diff --git a/packages/stream_chat_persistence/test/src/dao/channel_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/channel_dao_test.dart index 9d6a3070..47c655a8 100644 --- a/packages/stream_chat_persistence/test/src/dao/channel_dao_test.dart +++ b/packages/stream_chat_persistence/test/src/dao/channel_dao_test.dart @@ -88,15 +88,6 @@ void main() { expect(updatedCids, [cid]); }); -// /// Updates all the channels using the new [channelList] data -// Future updateChannels(List channelList) => batch( -// (it) => it.insertAll( -// channels, -// channelList.map((c) => c.toEntity()).toList(), -// mode: InsertMode.insertOrReplace, -// ), -// ); - test('updateChannels', () async { const id = 'testId'; const cid = 'testCid'; From 083ca282837e495054790bf058f356562e373337 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 15 Mar 2021 16:48:56 +0530 Subject: [PATCH 05/50] test(persistence): Add test for channel query dao Signed-off-by: Sahil Kumar --- packages/stream_chat/lib/src/client.dart | 3 +- .../lib/src/db/chat_persistence_client.dart | 7 +- .../lib/src/dao/channel_query_dao.dart | 17 +- .../test/src/dao/channel_query_dao_test.dart | 270 ++++++++++++++++++ 4 files changed, 285 insertions(+), 12 deletions(-) create mode 100644 packages/stream_chat_persistence/test/src/dao/channel_query_dao_test.dart diff --git a/packages/stream_chat/lib/src/client.dart b/packages/stream_chat/lib/src/client.dart index 11619b35..8b9d3a75 100644 --- a/packages/stream_chat/lib/src/client.dart +++ b/packages/stream_chat/lib/src/client.dart @@ -738,7 +738,8 @@ class StreamChatClient { await _chatPersistenceClient?.updateChannelQueries( filter, channels.map((c) => c.channel.cid).toList(), - paginationParams?.offset == null || paginationParams.offset == 0, + clearQueryCache: + paginationParams?.offset == null || paginationParams.offset == 0, ); state.channels = updateData.key; diff --git a/packages/stream_chat/lib/src/db/chat_persistence_client.dart b/packages/stream_chat/lib/src/db/chat_persistence_client.dart index d90872a2..d15772df 100644 --- a/packages/stream_chat/lib/src/db/chat_persistence_client.dart +++ b/packages/stream_chat/lib/src/db/chat_persistence_client.dart @@ -100,10 +100,9 @@ abstract class ChatPersistenceClient { /// the list of matching rows will be deleted Future updateChannelQueries( Map filter, - List cids, - // ignore: avoid_positional_boolean_parameters - bool clearQueryCache, - ); + List cids, { + bool clearQueryCache = false, + }); /// Remove a message by [messageId] Future deleteMessageById(String messageId) => diff --git a/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.dart b/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.dart index 785b5946..233fd4ef 100644 --- a/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.dart @@ -32,7 +32,7 @@ class ChannelQueryDao extends DatabaseAccessor Future updateChannelQueries( Map filter, List cids, { - bool clearQueryCache, + bool clearQueryCache = false, }) async => transaction(() async { final hash = _computeHash(filter); @@ -57,6 +57,14 @@ class ChannelQueryDao extends DatabaseAccessor }); }); + /// + Future> getCachedChannelCids(Map filter) { + final hash = _computeHash(filter); + return (select(channelQueries)..where((c) => c.queryHash.equals(hash))) + .map((c) => c.channelCid) + .get(); + } + /// Get list of channels by filter, sort and paginationParams Future> getChannels({ Map filter, @@ -72,12 +80,7 @@ class ChannelQueryDao extends DatabaseAccessor return true; }(), ''); - final hash = _computeHash(filter); - final cachedChannelCids = await (select(channelQueries) - ..where((c) => c.queryHash.equals(hash))) - .map((c) => c.channelCid) - .get(); - + final cachedChannelCids = await getCachedChannelCids(filter); final query = select(channels)..where((c) => c.cid.isIn(cachedChannelCids)); final cachedChannels = await (query.join([ diff --git a/packages/stream_chat_persistence/test/src/dao/channel_query_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/channel_query_dao_test.dart new file mode 100644 index 00000000..1a437dfc --- /dev/null +++ b/packages/stream_chat_persistence/test/src/dao/channel_query_dao_test.dart @@ -0,0 +1,270 @@ +import 'dart:math' as math; + +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/dao/channel_query_dao.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:test/test.dart'; + +void main() { + MoorChatDatabase database; + ChannelQueryDao channelQueryDao; + + setUp(() { + database = MoorChatDatabase.testable('testUserId'); + channelQueryDao = database.channelQueryDao; + }); + + test('updateChannelQueries', () async { + const filter = { + 'members': { + r'$in': ['testUserId'], + }, + }; + + const cids = ['testCid1', 'testCid2', 'testCid3']; + + final cachedCids = await channelQueryDao.getCachedChannelCids(filter); + expect(cachedCids, []); + + // Updating channel queries + await channelQueryDao.updateChannelQueries(filter, cids); + + final updatedCids = await channelQueryDao.getCachedChannelCids(filter); + expect(updatedCids, cids); + }); + + test('getCachedChannelCids', () async { + const filter = { + 'members': { + r'$in': ['testUserId'], + }, + }; + + const cids = ['testCid1', 'testCid2', 'testCid3']; + + final cachedCids = await channelQueryDao.getCachedChannelCids(filter); + expect(cachedCids, []); + + // Updating channel queries + await channelQueryDao.updateChannelQueries(filter, cids); + + final updatedCids = await channelQueryDao.getCachedChannelCids(filter); + expect(updatedCids, cids); + }); + + Future> _insertTestDataForGetChannel( + Map filter) async { + final now = DateTime.now(); + final userDao = database.userDao; + final channelDao = database.channelDao; + + const cids = ['testCid0', 'testCid1', 'testCid2']; + final users = List.generate(3, (index) => User(id: 'testId$index')); + final channels = List.generate( + 3, + (index) => ChannelModel( + id: 'testId$index', + type: 'testType$index', + cid: cids[index], + createdBy: users[index], + config: ChannelConfig(), + extraData: {'test_custom_field': math.Random().nextInt(100)}, + createdAt: now, + memberCount: math.Random().nextInt(100), + lastMessageAt: now.add(Duration(hours: index)), + ), + ).reversed.toList(growable: false); + + await userDao.updateUsers(users); + await channelDao.updateChannels(channels); + await channelQueryDao.updateChannelQueries(filter, cids); + + return channels; + } + + group('getChannels', () { + const filter = { + 'members': { + r'$in': ['testUserId'], + }, + }; + + test('should return empty list of channels', () async { + final channels = await channelQueryDao.getChannels(filter: filter); + expect(channels, []); + }); + + test('should return all the inserted channels', () async { + // Inserting test data for get channels + final insertedChannels = await _insertTestDataForGetChannel(filter); + + // Should match with the inserted channels + final updatedChannels = await channelQueryDao.getChannels(filter: filter); + expect(updatedChannels.length, insertedChannels.length); + for (var i = 0; i < updatedChannels.length; i++) { + final updatedChannel = updatedChannels[i]; + final insertedChannel = insertedChannels[i]; + + // Should match all the basic details + expect(updatedChannel.id, insertedChannel.id); + expect(updatedChannel.type, insertedChannel.type); + expect(updatedChannel.cid, insertedChannel.cid); + expect(updatedChannel.memberCount, insertedChannel.memberCount); + + // Should match createdAt date + expect( + updatedChannel.createdAt.hour, + insertedChannel.createdAt.hour, + ); + expect( + updatedChannel.createdAt.minute, + insertedChannel.createdAt.minute, + ); + expect( + updatedChannel.createdAt.second, + insertedChannel.createdAt.second, + ); + + // Should match lastMessageAt date + expect( + updatedChannel.lastMessageAt.hour, + insertedChannel.lastMessageAt.hour, + ); + expect( + updatedChannel.lastMessageAt.minute, + insertedChannel.lastMessageAt.minute, + ); + expect( + updatedChannel.lastMessageAt.second, + insertedChannel.lastMessageAt.second, + ); + } + }); + + test('should return sorted channels using member count', () async { + int sortComparator(ChannelModel a, ChannelModel b) => + b.memberCount.compareTo(a.memberCount); + + // Inserting test data for get channels + final insertedChannels = await _insertTestDataForGetChannel(filter); + insertedChannels.sort(sortComparator); + + // Should match with the inserted channels + final updatedChannels = await channelQueryDao.getChannels( + filter: filter, + sort: [SortOption('member_count', comparator: sortComparator)], + ); + + expect(updatedChannels.length, insertedChannels.length); + for (var i = 0; i < updatedChannels.length; i++) { + final updatedChannel = updatedChannels[i]; + final insertedChannel = insertedChannels[i]; + + // Should match all the basic details + expect(updatedChannel.id, insertedChannel.id); + expect(updatedChannel.type, insertedChannel.type); + expect(updatedChannel.cid, insertedChannel.cid); + expect(updatedChannel.memberCount, insertedChannel.memberCount); + + // Should match createdAt date + expect( + updatedChannel.createdAt.hour, + insertedChannel.createdAt.hour, + ); + expect( + updatedChannel.createdAt.minute, + insertedChannel.createdAt.minute, + ); + expect( + updatedChannel.createdAt.second, + insertedChannel.createdAt.second, + ); + + // Should match lastMessageAt date + expect( + updatedChannel.lastMessageAt.hour, + insertedChannel.lastMessageAt.hour, + ); + expect( + updatedChannel.lastMessageAt.minute, + insertedChannel.lastMessageAt.minute, + ); + expect( + updatedChannel.lastMessageAt.second, + insertedChannel.lastMessageAt.second, + ); + } + }); + + test('should throw if comparator is not provided in sort list', () { + expect( + () => channelQueryDao.getChannels( + sort: [const SortOption('test_custom_field')], + ), + throwsArgumentError, + ); + }); + + test('should return sorted channels using custom field', () async { + int sortComparator(ChannelModel a, ChannelModel b) { + final aData = a.extraData['test_custom_field'] as int; + final bData = b.extraData['test_custom_field'] as int; + return bData.compareTo(aData); + } + + // Inserting test data for get channels + final insertedChannels = await _insertTestDataForGetChannel(filter); + insertedChannels.sort(sortComparator); + + // Should match with the inserted channels + final updatedChannels = await channelQueryDao.getChannels( + filter: filter, + sort: [SortOption('test_custom_field', comparator: sortComparator)], + ); + + expect(updatedChannels.length, insertedChannels.length); + for (var i = 0; i < updatedChannels.length; i++) { + final updatedChannel = updatedChannels[i]; + final insertedChannel = insertedChannels[i]; + + // Should match all the basic details + expect(updatedChannel.id, insertedChannel.id); + expect(updatedChannel.type, insertedChannel.type); + expect(updatedChannel.cid, insertedChannel.cid); + expect(updatedChannel.memberCount, insertedChannel.memberCount); + + // Should match createdAt date + expect( + updatedChannel.createdAt.hour, + insertedChannel.createdAt.hour, + ); + expect( + updatedChannel.createdAt.minute, + insertedChannel.createdAt.minute, + ); + expect( + updatedChannel.createdAt.second, + insertedChannel.createdAt.second, + ); + + // Should match lastMessageAt date + expect( + updatedChannel.lastMessageAt.hour, + insertedChannel.lastMessageAt.hour, + ); + expect( + updatedChannel.lastMessageAt.minute, + insertedChannel.lastMessageAt.minute, + ); + expect( + updatedChannel.lastMessageAt.second, + insertedChannel.lastMessageAt.second, + ); + } + }); + }); + + tearDown(() async { + await database.disconnect(); + }); +} From edc8c4d1814526a15e5a086666ed39b78dbe2984 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 16 Mar 2021 15:51:41 +0530 Subject: [PATCH 06/50] test(persistence): add tests for connection event dao Signed-off-by: Sahil Kumar --- .../stream_chat/lib/src/models/event.dart | 40 ++++++ packages/stream_chat_persistence/pubspec.yaml | 7 +- .../test/src/dao/channel_query_dao_test.dart | 80 +++--------- .../src/dao/connection_event_dao_test.dart | 114 ++++++++++++++++++ .../test/src/utils/date_matcher.dart | 26 ++++ 5 files changed, 202 insertions(+), 65 deletions(-) create mode 100644 packages/stream_chat_persistence/test/src/dao/connection_event_dao_test.dart create mode 100644 packages/stream_chat_persistence/test/src/utils/date_matcher.dart diff --git a/packages/stream_chat/lib/src/models/event.dart b/packages/stream_chat/lib/src/models/event.dart index b1140ebc..28cf1b38 100644 --- a/packages/stream_chat/lib/src/models/event.dart +++ b/packages/stream_chat/lib/src/models/event.dart @@ -121,6 +121,46 @@ class Event { _$EventToJson(this), topLevelFields, ); + + /// Creates a copy of [Event] with specified attributes overridden. + Event copyWith({ + String type, + String cid, + String channelId, + String channelType, + String connectionId, + DateTime createdAt, + OwnUser me, + User user, + Message message, + EventChannel channel, + Member member, + Reaction reaction, + int totalUnreadCount, + int unreadChannels, + bool online, + String parentId, + Map extraData, + }) => + Event( + type: type ?? this.type, + cid: cid ?? this.cid, + connectionId: connectionId ?? this.connectionId, + createdAt: createdAt ?? this.createdAt, + me: me ?? this.me, + user: user ?? this.user, + message: message ?? this.message, + totalUnreadCount: totalUnreadCount ?? this.totalUnreadCount, + unreadChannels: unreadChannels ?? this.unreadChannels, + reaction: reaction ?? this.reaction, + online: online ?? this.online, + channel: channel ?? this.channel, + member: member ?? this.member, + channelId: channelId ?? this.channelId, + channelType: channelType ?? this.channelType, + parentId: parentId ?? this.parentId, + extraData: extraData ?? this.extraData, + ); } /// The channel embedded in the event object diff --git a/packages/stream_chat_persistence/pubspec.yaml b/packages/stream_chat_persistence/pubspec.yaml index a91ac666..8b235710 100644 --- a/packages/stream_chat_persistence/pubspec.yaml +++ b/packages/stream_chat_persistence/pubspec.yaml @@ -22,8 +22,11 @@ dependencies: ref: develop path: packages/stream_chat +dependency_overrides: + stream_chat: + path: ../stream_chat + dev_dependencies: test: ^1.15.7 build_runner: ^1.11.0 - moor_generator: ^3.4.1 - pedantic: ^1.9.2 + moor_generator: ^3.4.1 \ No newline at end of file diff --git a/packages/stream_chat_persistence/test/src/dao/channel_query_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/channel_query_dao_test.dart index 1a437dfc..dd9ecf0b 100644 --- a/packages/stream_chat_persistence/test/src/dao/channel_query_dao_test.dart +++ b/packages/stream_chat_persistence/test/src/dao/channel_query_dao_test.dart @@ -5,6 +5,8 @@ import 'package:stream_chat_persistence/src/dao/channel_query_dao.dart'; import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; import 'package:test/test.dart'; +import '../utils/date_matcher.dart'; + void main() { MoorChatDatabase database; ChannelQueryDao channelQueryDao; @@ -24,7 +26,7 @@ void main() { const cids = ['testCid1', 'testCid2', 'testCid3']; final cachedCids = await channelQueryDao.getCachedChannelCids(filter); - expect(cachedCids, []); + expect(cachedCids, isEmpty); // Updating channel queries await channelQueryDao.updateChannelQueries(filter, cids); @@ -43,7 +45,7 @@ void main() { const cids = ['testCid1', 'testCid2', 'testCid3']; final cachedCids = await channelQueryDao.getCachedChannelCids(filter); - expect(cachedCids, []); + expect(cachedCids, isEmpty); // Updating channel queries await channelQueryDao.updateChannelQueries(filter, cids); @@ -91,7 +93,7 @@ void main() { test('should return empty list of channels', () async { final channels = await channelQueryDao.getChannels(filter: filter); - expect(channels, []); + expect(channels, isEmpty); }); test('should return all the inserted channels', () async { @@ -113,30 +115,14 @@ void main() { // Should match createdAt date expect( - updatedChannel.createdAt.hour, - insertedChannel.createdAt.hour, - ); - expect( - updatedChannel.createdAt.minute, - insertedChannel.createdAt.minute, - ); - expect( - updatedChannel.createdAt.second, - insertedChannel.createdAt.second, + updatedChannel.createdAt, + isSameDateAs(insertedChannel.createdAt), ); // Should match lastMessageAt date expect( - updatedChannel.lastMessageAt.hour, - insertedChannel.lastMessageAt.hour, - ); - expect( - updatedChannel.lastMessageAt.minute, - insertedChannel.lastMessageAt.minute, - ); - expect( - updatedChannel.lastMessageAt.second, - insertedChannel.lastMessageAt.second, + updatedChannel.lastMessageAt, + isSameDateAs(insertedChannel.lastMessageAt), ); } }); @@ -168,30 +154,14 @@ void main() { // Should match createdAt date expect( - updatedChannel.createdAt.hour, - insertedChannel.createdAt.hour, - ); - expect( - updatedChannel.createdAt.minute, - insertedChannel.createdAt.minute, - ); - expect( - updatedChannel.createdAt.second, - insertedChannel.createdAt.second, + updatedChannel.createdAt, + isSameDateAs(insertedChannel.createdAt), ); // Should match lastMessageAt date expect( - updatedChannel.lastMessageAt.hour, - insertedChannel.lastMessageAt.hour, - ); - expect( - updatedChannel.lastMessageAt.minute, - insertedChannel.lastMessageAt.minute, - ); - expect( - updatedChannel.lastMessageAt.second, - insertedChannel.lastMessageAt.second, + updatedChannel.lastMessageAt, + isSameDateAs(insertedChannel.lastMessageAt), ); } }); @@ -235,30 +205,14 @@ void main() { // Should match createdAt date expect( - updatedChannel.createdAt.hour, - insertedChannel.createdAt.hour, - ); - expect( - updatedChannel.createdAt.minute, - insertedChannel.createdAt.minute, - ); - expect( - updatedChannel.createdAt.second, - insertedChannel.createdAt.second, + updatedChannel.createdAt, + isSameDateAs(insertedChannel.createdAt), ); // Should match lastMessageAt date expect( - updatedChannel.lastMessageAt.hour, - insertedChannel.lastMessageAt.hour, - ); - expect( - updatedChannel.lastMessageAt.minute, - insertedChannel.lastMessageAt.minute, - ); - expect( - updatedChannel.lastMessageAt.second, - insertedChannel.lastMessageAt.second, + updatedChannel.lastMessageAt, + isSameDateAs(insertedChannel.lastMessageAt), ); } }); diff --git a/packages/stream_chat_persistence/test/src/dao/connection_event_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/connection_event_dao_test.dart new file mode 100644 index 00000000..2969751b --- /dev/null +++ b/packages/stream_chat_persistence/test/src/dao/connection_event_dao_test.dart @@ -0,0 +1,114 @@ +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/dao/connection_event_dao.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:test/test.dart'; + +import '../utils/date_matcher.dart'; + +void main() { + ConnectionEventDao eventDao; + MoorChatDatabase database; + + setUp(() { + database = MoorChatDatabase.testable('testUserId'); + eventDao = database.connectionEventDao; + }); + + test('connectionEvent', () async { + // Should be null initially + final event = await eventDao.connectionEvent; + expect(event, isNull); + + // Adding a new event + final newEvent = Event( + createdAt: DateTime.now(), + totalUnreadCount: 33, + unreadChannels: 3, + me: OwnUser(id: 'testUserId'), + ); + await eventDao.updateConnectionEvent(newEvent); + + // Should match the added event + final updatedEvent = await eventDao.connectionEvent; + expect(updatedEvent.me.id, newEvent.me.id); + expect(updatedEvent.totalUnreadCount, newEvent.totalUnreadCount); + expect(updatedEvent.unreadChannels, newEvent.unreadChannels); + }); + + test('lastSyncAt', () async { + // Should be null initially + final lastSyncAt = await eventDao.lastSyncAt; + expect(lastSyncAt, isNull); + + // Adding an event for testing + final event = Event( + createdAt: DateTime.now(), + totalUnreadCount: 33, + unreadChannels: 3, + me: OwnUser(id: 'testUserId'), + ); + await eventDao.updateConnectionEvent(event); + + // Updating it's last sync + final now = DateTime.now(); + await eventDao.updateLastSyncAt(now); + + // Should match the updated last sync + final updatedLastSyncAt = await eventDao.lastSyncAt; + expect(updatedLastSyncAt, isSameDateAs(now)); + }); + + test('updateConnectionEvent', () async { + // Adding and event for testing + final event = Event( + createdAt: DateTime.now(), + totalUnreadCount: 33, + unreadChannels: 3, + me: OwnUser(id: 'testUserId'), + ); + await eventDao.updateConnectionEvent(event); + + // Should match the previously added event + final fetchedEvent = await eventDao.connectionEvent; + expect(fetchedEvent.me.id, event.me.id); + expect(fetchedEvent.totalUnreadCount, event.totalUnreadCount); + expect(fetchedEvent.unreadChannels, event.unreadChannels); + + // Updating the added event + final newEvent = event.copyWith(unreadChannels: 4); + await eventDao.updateConnectionEvent(newEvent); + + // Should match the updated event + final fetchedNewEvent = await eventDao.connectionEvent; + expect(fetchedNewEvent.me.id, event.me.id); + expect(fetchedNewEvent.totalUnreadCount, event.totalUnreadCount); + expect(fetchedNewEvent.unreadChannels, newEvent.unreadChannels); + }); + + test('updateLastSyncAt', () async { + // Should be null initially + final lastSyncAt = await eventDao.lastSyncAt; + expect(lastSyncAt, isNull); + + // Adding an event just for testing + final event = Event( + createdAt: DateTime.now(), + totalUnreadCount: 33, + unreadChannels: 3, + me: OwnUser(id: 'testUserId'), + ); + await eventDao.updateConnectionEvent(event); + + // Updating it's last sync + final now = DateTime.now(); + await eventDao.updateLastSyncAt(now); + + // Should match the last sync + final updatedLastSyncAt = await eventDao.lastSyncAt; + expect(updatedLastSyncAt, isSameDateAs(now)); + }); + + tearDown(() async { + await database.disconnect(); + }); +} diff --git a/packages/stream_chat_persistence/test/src/utils/date_matcher.dart b/packages/stream_chat_persistence/test/src/utils/date_matcher.dart new file mode 100644 index 00000000..909e58b0 --- /dev/null +++ b/packages/stream_chat_persistence/test/src/utils/date_matcher.dart @@ -0,0 +1,26 @@ +import 'package:test/test.dart'; +import 'package:meta/meta.dart'; + +Matcher isSameDateAs(DateTime targetDate) => + _IsSameDateAs(targetDate: targetDate); + +class _IsSameDateAs extends Matcher { + const _IsSameDateAs({ + @required this.targetDate, + }) : assert(targetDate != null, ''); + + final DateTime targetDate; + + @override + bool matches(covariant DateTime date, Map matchState) => + date.year == targetDate.year && + date.month == targetDate.month && + date.day == targetDate.day && + date.hour == targetDate.hour && + date.minute == targetDate.minute && + date.second == targetDate.second; + + @override + Description describe(Description description) => + description.add('is same date as $targetDate'); +} From 2e2061614554a27bcd479d6505081dc448395097 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 16 Mar 2021 16:42:47 +0530 Subject: [PATCH 07/50] test(persistence): add test for member dao Signed-off-by: Sahil Kumar --- .../test/src/dao/member_dao_test.dart | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 packages/stream_chat_persistence/test/src/dao/member_dao_test.dart diff --git a/packages/stream_chat_persistence/test/src/dao/member_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/member_dao_test.dart new file mode 100644 index 00000000..6671c902 --- /dev/null +++ b/packages/stream_chat_persistence/test/src/dao/member_dao_test.dart @@ -0,0 +1,127 @@ +import 'dart:math' as math; + +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/dao/dao.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:test/test.dart'; + +import '../utils/date_matcher.dart'; + +void main() { + MemberDao memberDao; + MoorChatDatabase database; + + setUp(() { + database = MoorChatDatabase.testable('testUserId'); + memberDao = database.memberDao; + }); + + Future> _prepareTestData(String cid) async { + final users = List.generate(3, (index) => User(id: 'testUserId$index')); + final memberList = List.generate( + 3, + (index) => Member( + user: users[index], + banned: math.Random().nextBool(), + shadowBanned: math.Random().nextBool(), + createdAt: DateTime.now(), + isModerator: math.Random().nextBool(), + invited: math.Random().nextBool(), + inviteAcceptedAt: DateTime.now(), + role: 'testRole', + updatedAt: DateTime.now(), + ), + ); + await database.userDao.updateUsers(users); + await memberDao.updateMembers(cid, memberList); + return memberList; + } + + test('getMembersByCid', () async { + const cid = 'testCid'; + + // Should be empty initially + final members = await memberDao.getMembersByCid(cid); + expect(members, isEmpty); + + // Preparing test data + final memberList = await _prepareTestData(cid); + + // Should match the previous test data + final fetchedMembers = await memberDao.getMembersByCid(cid); + expect(fetchedMembers.length, memberList.length); + for (var i = 0; i < fetchedMembers.length; i++) { + final member = memberList[i]; + final fetchedMember = fetchedMembers[i]; + expect(fetchedMember.user.id, member.user.id); + expect(fetchedMember.banned, member.banned); + expect(fetchedMember.shadowBanned, member.shadowBanned); + expect(fetchedMember.createdAt, isSameDateAs(member.createdAt)); + expect(fetchedMember.isModerator, member.isModerator); + expect(fetchedMember.invited, member.invited); + expect(fetchedMember.role, member.role); + expect(fetchedMember.updatedAt, isSameDateAs(member.updatedAt)); + expect( + fetchedMember.inviteAcceptedAt, + isSameDateAs(member.inviteAcceptedAt), + ); + } + }); + + test('updateMembers', () async { + const cid = 'testCid'; + + // Preparing test data + final memberList = await _prepareTestData(cid); + + // Should match the previous test data + final fetchedMembers = await memberDao.getMembersByCid(cid); + expect(fetchedMembers.length, memberList.length); + for (var i = 0; i < fetchedMembers.length; i++) { + final member = memberList[i]; + final fetchedMember = fetchedMembers[i]; + expect(fetchedMember.user.id, member.user.id); + expect(fetchedMember.banned, member.banned); + expect(fetchedMember.shadowBanned, member.shadowBanned); + expect(fetchedMember.createdAt, isSameDateAs(member.createdAt)); + expect(fetchedMember.isModerator, member.isModerator); + expect(fetchedMember.invited, member.invited); + expect(fetchedMember.role, member.role); + expect(fetchedMember.updatedAt, isSameDateAs(member.updatedAt)); + expect( + fetchedMember.inviteAcceptedAt, + isSameDateAs(member.inviteAcceptedAt), + ); + } + + // Updating the last added member + final updatedMember = fetchedMembers.last.copyWith(banned: true); + await memberDao.updateMembers(cid, [updatedMember]); + + // Last member banned field should match the previous updated user + final newFetchedMembers = await memberDao.getMembersByCid(cid); + expect(newFetchedMembers.length, fetchedMembers.length); + final lastMember = newFetchedMembers.last; + expect(lastMember.banned, true); + }); + + test('deleteMemberByCids', () async { + const cid = 'testCid'; + + // Preparing test data + final members = await _prepareTestData(cid); + final fetchedMembers = await memberDao.getMembersByCid(cid); + expect(members.length, fetchedMembers.length); + + // Deleting all the members + await memberDao.deleteMemberByCids([cid]); + + // Fetched member list should be empty + final newFetchedMembers = await memberDao.getMembersByCid(cid); + expect(newFetchedMembers, isEmpty); + }); + + tearDown(() async { + await database.disconnect(); + }); +} From a24ec99a44ff21a0c5643e4852106d6f0bfdedb0 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 16 Mar 2021 18:42:06 +0530 Subject: [PATCH 08/50] test(persistence): add tests for message dao Signed-off-by: Sahil Kumar --- .../lib/src/dao/message_dao.dart | 7 +- .../test/src/dao/message_dao_test.dart | 253 ++++++++++++++++++ 2 files changed, 257 insertions(+), 3 deletions(-) create mode 100644 packages/stream_chat_persistence/test/src/dao/message_dao_test.dart diff --git a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart index 0be4446b..ae238069 100644 --- a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart @@ -72,7 +72,7 @@ class MessageDao extends DatabaseAccessor /// [Messages.channelCid] with [cid] Future> getThreadMessages(String cid) async => Future.wait(await (select(messages).join([ - leftOuterJoin(users, messages.userId.equalsExp(_users.id)), + leftOuterJoin(_users, messages.userId.equalsExp(_users.id)), leftOuterJoin(_pinnedByUsers, messages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), ]) @@ -89,10 +89,11 @@ class MessageDao extends DatabaseAccessor PaginationParams options, }) async { final msgList = await Future.wait(await (select(messages).join([ - innerJoin(_users, messages.userId.equalsExp(_users.id)), - innerJoin( + leftOuterJoin(_users, messages.userId.equalsExp(_users.id)), + leftOuterJoin( _pinnedByUsers, messages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), ]) + ..where(isNotNull(messages.parentId)) ..where(messages.parentId.equals(parentId)) ..orderBy([OrderingTerm.asc(messages.createdAt)])) .map(_messageFromJoinRow) diff --git a/packages/stream_chat_persistence/test/src/dao/message_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/message_dao_test.dart new file mode 100644 index 00000000..6ee8ca2f --- /dev/null +++ b/packages/stream_chat_persistence/test/src/dao/message_dao_test.dart @@ -0,0 +1,253 @@ +import 'dart:math' as math; + +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/dao/dao.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:test/test.dart'; + +void main() { + MessageDao messageDao; + MoorChatDatabase database; + + setUp(() { + database = MoorChatDatabase.testable('testUserId'); + messageDao = database.messageDao; + }); + + Future> _prepareTestData( + String cid, { + bool threads = false, + int count = 3, + }) async { + final messages = List.generate( + count, + (index) => Message( + id: 'testMessageId$cid$index', + type: 'testType', + user: User(id: 'testUserId$index'), + createdAt: DateTime.now(), + shadowed: math.Random().nextBool(), + showInChannel: math.Random().nextBool(), + replyCount: index, + updatedAt: DateTime.now(), + extraData: {'extra_test_field': 'extraTestData'}, + text: 'Dummy text #$index', + pinned: math.Random().nextBool(), + pinnedAt: DateTime.now(), + pinnedBy: User(id: 'testUserId$index'), + ), + ); + final threadMessages = List.generate( + count, + (index) => Message( + id: 'testThreadMessageId$cid$index', + type: 'testType', + user: User(id: 'testUserId$index'), + parentId: messages[index].id, + createdAt: DateTime.now(), + shadowed: math.Random().nextBool(), + showInChannel: math.Random().nextBool(), + replyCount: index, + updatedAt: DateTime.now(), + extraData: {'extra_test_field': 'extraTestData'}, + text: 'Dummy text #$index', + pinned: math.Random().nextBool(), + pinnedAt: DateTime.now(), + pinnedBy: User(id: 'testUserId$index'), + ), + ); + final allMessages = [...messages, if (threads) ...threadMessages]; + await messageDao.updateMessages(cid, allMessages); + return allMessages; + } + + test('deleteMessageByIds', () async { + const cid = 'testCid'; + + // Preparing test data + final insertedMessages = await _prepareTestData(cid); + + // Fetched message list should match the test message list length + final messages = await messageDao.getMessagesByCid(cid); + expect(messages.length, insertedMessages.length); + + // Deleting 2 messages from DB + await messageDao.deleteMessageByIds( + ['testMessageId${cid}0', 'testMessageId${cid}1'], + ); + + // New fetched messages length should 2 less than the + // previous fetched messages + final newMessages = await messageDao.getMessagesByCid(cid); + expect(newMessages.length, messages.length - 2); + }); + + group('deleteMessageByCids', () { + const cid1 = 'testCid1'; + const cid2 = 'testCid2'; + + test('should delete all the messages of first channel', () async { + // Preparing test data + final cid1InsertedMessages = await _prepareTestData(cid1); + final cid2InsertedMessages = await _prepareTestData(cid2); + + // Fetched message list should match the test message list length + final cid1Messages = await messageDao.getMessagesByCid(cid1); + final cid2Messages = await messageDao.getMessagesByCid(cid2); + expect(cid1Messages.length, cid1InsertedMessages.length); + expect(cid2Messages.length, cid2InsertedMessages.length); + + // Deleting all the messages of cid1 + await messageDao.deleteMessageByCids([cid1]); + + // Fetched messages length of only cid1 should be empty + final cid1FetchedMessages = await messageDao.getMessagesByCid(cid1); + final cid2FetchedMessages = await messageDao.getMessagesByCid(cid2); + expect(cid1FetchedMessages, isEmpty); + expect(cid2FetchedMessages, isNotEmpty); + }); + + test('should delete all the messages of both channel', () async { + // Preparing test data + final cid1InsertedMessages = await _prepareTestData(cid1); + final cid2InsertedMessages = await _prepareTestData(cid2); + + // Fetched message list should match the test message list length + final cid1Messages = await messageDao.getMessagesByCid(cid1); + final cid2Messages = await messageDao.getMessagesByCid(cid2); + expect(cid1Messages.length, cid1InsertedMessages.length); + expect(cid2Messages.length, cid2InsertedMessages.length); + + // Deleting all the messages of cid1 + await messageDao.deleteMessageByCids([cid1, cid2]); + + // Fetched messages length of both cid1 and cid2 should be empty + final cid1FetchedMessages = await messageDao.getMessagesByCid(cid1); + final cid2FetchedMessages = await messageDao.getMessagesByCid(cid2); + expect(cid1FetchedMessages, isEmpty); + expect(cid2FetchedMessages, isEmpty); + }); + }); + + test('getMessageById', () async { + const cid = 'testCid'; + const id = 'testMessageId${cid}0'; + + // Should be null initially + final message = await messageDao.getMessageById(id); + expect(message, isNull); + + // Adding test message with the cid and id + final insertedMessages = await _prepareTestData(cid, count: 1); + expect(insertedMessages.first.id, id); + + // Fetched message id should match the inserted message id + final fetchedMessage = await messageDao.getMessageById(id); + expect(fetchedMessage.id, insertedMessages.first.id); + }); + + test('getThreadMessages', () async { + const cid = 'testCid'; + + // Messages should be empty initially + final messages = await messageDao.getThreadMessages(cid); + expect(messages, isEmpty); + + // Preparing test data + final insertedMessages = await _prepareTestData(cid, threads: true); + expect(insertedMessages, isNotEmpty); + + // Should fetch all the thread messages of cid + final threadMessages = await messageDao.getThreadMessages(cid); + expect(threadMessages, isNotEmpty); + for (final message in threadMessages) { + expect(message.parentId, isNotNull); + } + }); + + test('getThreadMessagesByParentId', () async { + const cid = 'testCid'; + const parentId = 'testMessageId${cid}0'; + + // Messages should be empty initially + final messages = await messageDao.getThreadMessagesByParentId(parentId); + expect(messages, isEmpty); + + // Preparing test data + final insertedMessages = await _prepareTestData(cid, threads: true); + expect(insertedMessages, isNotEmpty); + + // Should fetch all the thread messages of parentId + final threadMessages = + await messageDao.getThreadMessagesByParentId(parentId); + expect(threadMessages.length, 1); + expect(threadMessages.first.parentId, parentId); + }); + + test('getMessagesByCid', () async { + const cid = 'testCid'; + + // Should be empty initially + final messages = await messageDao.getMessagesByCid(cid); + expect(messages, isEmpty); + + // Preparing test data + final insertedMessages = await _prepareTestData(cid); + expect(insertedMessages, isNotEmpty); + + // Fetched message should match the inserted messages + final fetchedMessages = await messageDao.getMessagesByCid(cid); + expect(fetchedMessages.length, insertedMessages.length); + for (var i = 0; i < fetchedMessages.length; i++) { + final fetchedMessage = fetchedMessages[i]; + final insertedMessage = insertedMessages[i]; + expect(fetchedMessage.id, insertedMessage.id); + } + }); + + test('updateMessages', () async { + const cid = 'testCid'; + + // Preparing test data + final insertedMessages = await _prepareTestData(cid); + expect(insertedMessages, isNotEmpty); + + // Modifying one of the message and also adding one new + final copyMessage = insertedMessages.first.copyWith(showInChannel: false); + final newMessage = Message( + id: 'testMessageId${cid}4', + type: 'testType', + user: User(id: 'testUserId4'), + createdAt: DateTime.now(), + shadowed: math.Random().nextBool(), + showInChannel: math.Random().nextBool(), + replyCount: 4, + updatedAt: DateTime.now(), + extraData: {'extra_test_field': 'extraTestData'}, + text: 'Dummy text #4', + pinned: math.Random().nextBool(), + pinnedAt: DateTime.now(), + pinnedBy: User(id: 'testUserId4'), + ); + + await messageDao.updateMessages(cid, [copyMessage, newMessage]); + + // Fetched messages length should be one more than inserted message. + // copyMessage `showInChannel` modified field should be false. + // Fetched messages should contain the newMessage. + final fetchedMessages = await messageDao.getMessagesByCid(cid); + expect(fetchedMessages.length, insertedMessages.length + 1); + expect( + fetchedMessages.firstWhere((it) => it.id == copyMessage.id).showInChannel, + false, + ); + expect( + fetchedMessages.map((it) => it.id).contains('testMessageId${cid}4'), + true, + ); + }); + + tearDown(() async { + await database.disconnect(); + }); +} From 8fefa3c1293b629293890c3f19fe801959a8865c Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 16 Mar 2021 18:53:07 +0530 Subject: [PATCH 09/50] test(persistence): add test for pinned message dao Signed-off-by: Sahil Kumar --- .../lib/src/dao/pinned_message_dao.dart | 5 +- .../test/src/dao/pinned_message_dao_test.dart | 254 ++++++++++++++++++ 2 files changed, 257 insertions(+), 2 deletions(-) create mode 100644 packages/stream_chat_persistence/test/src/dao/pinned_message_dao_test.dart diff --git a/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart b/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart index 5e0ae721..cb634703 100644 --- a/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart @@ -89,10 +89,11 @@ class PinnedMessageDao extends DatabaseAccessor PaginationParams options, }) async { final msgList = await Future.wait(await (select(pinnedMessages).join([ - innerJoin(_users, pinnedMessages.userId.equalsExp(_users.id)), - innerJoin(_pinnedByUsers, + leftOuterJoin(_users, pinnedMessages.userId.equalsExp(_users.id)), + leftOuterJoin(_pinnedByUsers, pinnedMessages.pinnedByUserId.equalsExp(_pinnedByUsers.id)), ]) + ..where(isNotNull(pinnedMessages.parentId)) ..where(pinnedMessages.parentId.equals(parentId)) ..orderBy([OrderingTerm.asc(pinnedMessages.createdAt)])) .map(_messageFromJoinRow) diff --git a/packages/stream_chat_persistence/test/src/dao/pinned_message_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/pinned_message_dao_test.dart new file mode 100644 index 00000000..1af3276e --- /dev/null +++ b/packages/stream_chat_persistence/test/src/dao/pinned_message_dao_test.dart @@ -0,0 +1,254 @@ +import 'dart:math' as math; + +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/dao/dao.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:test/test.dart'; + +void main() { + PinnedMessageDao pinnedMessageDao; + MoorChatDatabase database; + + setUp(() { + database = MoorChatDatabase.testable('testUserId'); + pinnedMessageDao = database.pinnedMessageDao; + }); + + Future> _prepareTestData( + String cid, { + bool threads = false, + int count = 3, + }) async { + final messages = List.generate( + count, + (index) => Message( + id: 'testMessageId$cid$index', + type: 'testType', + user: User(id: 'testUserId$index'), + createdAt: DateTime.now(), + shadowed: math.Random().nextBool(), + showInChannel: math.Random().nextBool(), + replyCount: index, + updatedAt: DateTime.now(), + extraData: {'extra_test_field': 'extraTestData'}, + text: 'Dummy text #$index', + pinned: math.Random().nextBool(), + pinnedAt: DateTime.now(), + pinnedBy: User(id: 'testUserId$index'), + ), + ); + final threadMessages = List.generate( + count, + (index) => Message( + id: 'testThreadMessageId$cid$index', + type: 'testType', + user: User(id: 'testUserId$index'), + parentId: messages[index].id, + createdAt: DateTime.now(), + shadowed: math.Random().nextBool(), + showInChannel: math.Random().nextBool(), + replyCount: index, + updatedAt: DateTime.now(), + extraData: {'extra_test_field': 'extraTestData'}, + text: 'Dummy text #$index', + pinned: math.Random().nextBool(), + pinnedAt: DateTime.now(), + pinnedBy: User(id: 'testUserId$index'), + ), + ); + final allMessages = [...messages, if (threads) ...threadMessages]; + await pinnedMessageDao.updateMessages(cid, allMessages); + return allMessages; + } + + test('deleteMessageByIds', () async { + const cid = 'testCid'; + + // Preparing test data + final insertedMessages = await _prepareTestData(cid); + + // Fetched message list should match the test message list length + final messages = await pinnedMessageDao.getMessagesByCid(cid); + expect(messages.length, insertedMessages.length); + + // Deleting 2 messages from DB + await pinnedMessageDao.deleteMessageByIds( + ['testMessageId${cid}0', 'testMessageId${cid}1'], + ); + + // New fetched messages length should 2 less than the + // previous fetched messages + final newMessages = await pinnedMessageDao.getMessagesByCid(cid); + expect(newMessages.length, messages.length - 2); + }); + + group('deleteMessageByCids', () { + const cid1 = 'testCid1'; + const cid2 = 'testCid2'; + + test('should delete all the messages of first channel', () async { + // Preparing test data + final cid1InsertedMessages = await _prepareTestData(cid1); + final cid2InsertedMessages = await _prepareTestData(cid2); + + // Fetched message list should match the test message list length + final cid1Messages = await pinnedMessageDao.getMessagesByCid(cid1); + final cid2Messages = await pinnedMessageDao.getMessagesByCid(cid2); + expect(cid1Messages.length, cid1InsertedMessages.length); + expect(cid2Messages.length, cid2InsertedMessages.length); + + // Deleting all the messages of cid1 + await pinnedMessageDao.deleteMessageByCids([cid1]); + + // Fetched messages length of only cid1 should be empty + final cid1FetchedMessages = await pinnedMessageDao.getMessagesByCid(cid1); + final cid2FetchedMessages = await pinnedMessageDao.getMessagesByCid(cid2); + expect(cid1FetchedMessages, isEmpty); + expect(cid2FetchedMessages, isNotEmpty); + }); + + test('should delete all the messages of both channel', () async { + // Preparing test data + final cid1InsertedMessages = await _prepareTestData(cid1); + final cid2InsertedMessages = await _prepareTestData(cid2); + + // Fetched message list should match the test message list length + final cid1Messages = await pinnedMessageDao.getMessagesByCid(cid1); + final cid2Messages = await pinnedMessageDao.getMessagesByCid(cid2); + expect(cid1Messages.length, cid1InsertedMessages.length); + expect(cid2Messages.length, cid2InsertedMessages.length); + + // Deleting all the messages of cid1 + await pinnedMessageDao.deleteMessageByCids([cid1, cid2]); + + // Fetched messages length of both cid1 and cid2 should be empty + final cid1FetchedMessages = await pinnedMessageDao.getMessagesByCid(cid1); + final cid2FetchedMessages = await pinnedMessageDao.getMessagesByCid(cid2); + expect(cid1FetchedMessages, isEmpty); + expect(cid2FetchedMessages, isEmpty); + }); + }); + + test('getMessageById', () async { + const cid = 'testCid'; + const id = 'testMessageId${cid}0'; + + // Should be null initially + final message = await pinnedMessageDao.getMessageById(id); + expect(message, isNull); + + // Adding test message with the cid and id + final insertedMessages = await _prepareTestData(cid, count: 1); + expect(insertedMessages.first.id, id); + + // Fetched message id should match the inserted message id + final fetchedMessage = await pinnedMessageDao.getMessageById(id); + expect(fetchedMessage.id, insertedMessages.first.id); + }); + + test('getThreadMessages', () async { + const cid = 'testCid'; + + // Messages should be empty initially + final messages = await pinnedMessageDao.getThreadMessages(cid); + expect(messages, isEmpty); + + // Preparing test data + final insertedMessages = await _prepareTestData(cid, threads: true); + expect(insertedMessages, isNotEmpty); + + // Should fetch all the thread messages of cid + final threadMessages = await pinnedMessageDao.getThreadMessages(cid); + expect(threadMessages, isNotEmpty); + for (final message in threadMessages) { + expect(message.parentId, isNotNull); + } + }); + + test('getThreadMessagesByParentId', () async { + const cid = 'testCid'; + const parentId = 'testMessageId${cid}0'; + + // Messages should be empty initially + final messages = + await pinnedMessageDao.getThreadMessagesByParentId(parentId); + expect(messages, isEmpty); + + // Preparing test data + final insertedMessages = await _prepareTestData(cid, threads: true); + expect(insertedMessages, isNotEmpty); + + // Should fetch all the thread messages of parentId + final threadMessages = + await pinnedMessageDao.getThreadMessagesByParentId(parentId); + expect(threadMessages.length, 1); + expect(threadMessages.first.parentId, parentId); + }); + + test('getMessagesByCid', () async { + const cid = 'testCid'; + + // Should be empty initially + final messages = await pinnedMessageDao.getMessagesByCid(cid); + expect(messages, isEmpty); + + // Preparing test data + final insertedMessages = await _prepareTestData(cid); + expect(insertedMessages, isNotEmpty); + + // Fetched message should match the inserted messages + final fetchedMessages = await pinnedMessageDao.getMessagesByCid(cid); + expect(fetchedMessages.length, insertedMessages.length); + for (var i = 0; i < fetchedMessages.length; i++) { + final fetchedMessage = fetchedMessages[i]; + final insertedMessage = insertedMessages[i]; + expect(fetchedMessage.id, insertedMessage.id); + } + }); + + test('updateMessages', () async { + const cid = 'testCid'; + + // Preparing test data + final insertedMessages = await _prepareTestData(cid); + expect(insertedMessages, isNotEmpty); + + // Modifying one of the message and also adding one new + final copyMessage = insertedMessages.first.copyWith(showInChannel: false); + final newMessage = Message( + id: 'testMessageId${cid}4', + type: 'testType', + user: User(id: 'testUserId4'), + createdAt: DateTime.now(), + shadowed: math.Random().nextBool(), + showInChannel: math.Random().nextBool(), + replyCount: 4, + updatedAt: DateTime.now(), + extraData: {'extra_test_field': 'extraTestData'}, + text: 'Dummy text #4', + pinned: math.Random().nextBool(), + pinnedAt: DateTime.now(), + pinnedBy: User(id: 'testUserId4'), + ); + + await pinnedMessageDao.updateMessages(cid, [copyMessage, newMessage]); + + // Fetched messages length should be one more than inserted message. + // copyMessage `showInChannel` modified field should be false. + // Fetched messages should contain the newMessage. + final fetchedMessages = await pinnedMessageDao.getMessagesByCid(cid); + expect(fetchedMessages.length, insertedMessages.length + 1); + expect( + fetchedMessages.firstWhere((it) => it.id == copyMessage.id).showInChannel, + false, + ); + expect( + fetchedMessages.map((it) => it.id).contains('testMessageId${cid}4'), + true, + ); + }); + + tearDown(() async { + await database.disconnect(); + }); +} From 125931d89e4a1e404f5bf2315731330221fccb49 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 16 Mar 2021 20:02:24 +0530 Subject: [PATCH 10/50] test(persistence): add test for reaction dao Signed-off-by: Sahil Kumar --- .../test/src/dao/reaction_dao_test.dart | 187 ++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 packages/stream_chat_persistence/test/src/dao/reaction_dao_test.dart diff --git a/packages/stream_chat_persistence/test/src/dao/reaction_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/reaction_dao_test.dart new file mode 100644 index 00000000..42273efa --- /dev/null +++ b/packages/stream_chat_persistence/test/src/dao/reaction_dao_test.dart @@ -0,0 +1,187 @@ +import 'dart:math' as math; + +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/dao/reaction_dao.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:test/test.dart'; + +void main() { + ReactionDao reactionDao; + MoorChatDatabase database; + + setUp(() { + database = MoorChatDatabase.testable('testUserId'); + reactionDao = database.reactionDao; + }); + + Future> _prepareReactionData( + String messageId, { + String userId, + int count = 3, + }) async { + final users = List.generate(count, (index) => User(id: 'testUserId$index')); + final message = Message( + id: messageId, + type: 'testType', + user: users.first, + createdAt: DateTime.now(), + shadowed: math.Random().nextBool(), + showInChannel: math.Random().nextBool(), + replyCount: 3, + updatedAt: DateTime.now(), + extraData: {'extra_test_field': 'extraTestData'}, + text: 'Dummy text', + pinned: math.Random().nextBool(), + pinnedAt: DateTime.now(), + pinnedBy: users.first, + ); + final reactions = List.generate( + count, + (index) => Reaction( + type: 'testType$index', + createdAt: DateTime.now(), + userId: userId ?? users[index].id, + messageId: message.id, + score: count + 3, + extraData: {'extra_test_field': 'extraTestData'}, + ), + ); + + await database.userDao.updateUsers(users); + await database.messageDao.updateMessages('testCid', [message]); + await reactionDao.updateReactions(reactions); + + return reactions; + } + + test('getReactions', () async { + const messageId = 'testMessageId'; + + // Should be empty initially + final reactions = await reactionDao.getReactions(messageId); + expect(reactions, isEmpty); + + // Adding sample reactions + final insertedReactions = await _prepareReactionData(messageId); + expect(insertedReactions, isNotEmpty); + + // Fetched reaction length should match inserted reactions length. + // Every reaction messageId should match the provided messageId. + final fetchedReactions = await reactionDao.getReactions(messageId); + expect(fetchedReactions.length, insertedReactions.length); + expect(fetchedReactions.every((it) => it.messageId == messageId), true); + }); + + test('getReactionsByUserId', () async { + const messageId = 'testMessageId'; + const userId = 'testUserId'; + + // Should be empty initially + final reactions = await reactionDao.getReactionsByUserId(messageId, userId); + expect(reactions, isEmpty); + + // Adding sample reactions + final insertedReactions = + await _prepareReactionData(messageId, userId: userId); + expect(insertedReactions, isNotEmpty); + + // Fetched reaction length should match inserted reactions length. + // Every reaction messageId should match the provided messageId. + // Every reaction userId should match the provided userId. + final fetchedReactions = + await reactionDao.getReactionsByUserId(messageId, userId); + expect(fetchedReactions.length, insertedReactions.length); + expect(fetchedReactions.every((it) => it.messageId == messageId), true); + expect(fetchedReactions.every((it) => it.userId == userId), true); + }); + + test('updateReactions', () async { + const messageId = 'testMessageId'; + + // Preparing test data + final reactions = await _prepareReactionData(messageId); + + // Modifying one of the reaction and also adding one new + final copyReaction = reactions.first.copyWith(score: 33); + final newReaction = Reaction( + type: 'testType3', + createdAt: DateTime.now(), + userId: 'testUserId3', + messageId: messageId, + score: 30, + extraData: {'extra_test_field': 'extraTestData'}, + ); + + await reactionDao.updateReactions([copyReaction, newReaction]); + + // Fetched reaction length should be one more than inserted reactions. + // copyReaction `score` modified field should be 33. + // Fetched reactions should contain the newReaction. + final fetchedReactions = await reactionDao.getReactions(messageId); + expect(fetchedReactions.length, reactions.length + 1); + expect( + fetchedReactions + .firstWhere((it) => + it.userId == copyReaction.userId && it.type == copyReaction.type) + .score, + 33, + ); + expect( + fetchedReactions + .where((it) => it.userId == 'testUserId3' && it.type == 'testType3') + .isNotEmpty, + true, + ); + }); + + group('deleteReactionsByMessageIds', () { + const messageId1 = 'testMessageId1'; + const messageId2 = 'testMessageId2'; + test('should delete all the reactions of first message', () async { + // Preparing test data + final insertedReactions1 = await _prepareReactionData(messageId1); + final insertedReactions2 = await _prepareReactionData(messageId2); + + // Fetched reaction list length should match + // the inserted reactions list length + final reactions1 = await reactionDao.getReactions(messageId1); + final reactions2 = await reactionDao.getReactions(messageId2); + expect(reactions1.length, insertedReactions1.length); + expect(reactions2.length, insertedReactions2.length); + + // Deleting all the reactions of messageId1 + await reactionDao.deleteReactionsByMessageIds([messageId1]); + + // Fetched reactions length of only messageId1 should be empty + final fetchedReactions1 = await reactionDao.getReactions(messageId1); + final fetchedReactions2 = await reactionDao.getReactions(messageId2); + expect(fetchedReactions1, isEmpty); + expect(fetchedReactions2, isNotEmpty); + }); + test('should delete all the messages of both message', () async { + // Preparing test data + final insertedReactions1 = await _prepareReactionData(messageId1); + final insertedReactions2 = await _prepareReactionData(messageId2); + + // Fetched reaction list length should match + // the inserted reactions list length + final reactions1 = await reactionDao.getReactions(messageId1); + final reactions2 = await reactionDao.getReactions(messageId2); + expect(reactions1.length, insertedReactions1.length); + expect(reactions2.length, insertedReactions2.length); + + // Deleting all the reactions of messageId1 and messageId2 + await reactionDao.deleteReactionsByMessageIds([messageId1, messageId2]); + + // Fetched reactions length of both messages should be empty + final fetchedReactions1 = await reactionDao.getReactions(messageId1); + final fetchedReactions2 = await reactionDao.getReactions(messageId2); + expect(fetchedReactions1, isEmpty); + expect(fetchedReactions2, isEmpty); + }); + }); + + tearDown(() async { + await database.disconnect(); + }); +} From 45870d7fab7ce5daeeffe2c21de227cbd072c171 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 16 Mar 2021 20:45:11 +0530 Subject: [PATCH 11/50] test(persistence): add test for read dao Signed-off-by: Sahil Kumar --- packages/stream_chat/lib/src/models/read.dart | 12 +++ .../test/src/dao/read_dao_test.dart | 97 +++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 packages/stream_chat_persistence/test/src/dao/read_dao_test.dart diff --git a/packages/stream_chat/lib/src/models/read.dart b/packages/stream_chat/lib/src/models/read.dart index 2be639d5..fc8ef1bc 100644 --- a/packages/stream_chat/lib/src/models/read.dart +++ b/packages/stream_chat/lib/src/models/read.dart @@ -27,4 +27,16 @@ class Read { /// Serialize to json Map toJson() => _$ReadToJson(this); + + /// Creates a copy of [Read] with specified attributes overridden. + Read copyWith({ + DateTime lastRead, + User user, + int unreadMessages, + }) => + Read( + lastRead: lastRead ?? this.lastRead, + user: user ?? this.user, + unreadMessages: unreadMessages ?? this.unreadMessages, + ); } diff --git a/packages/stream_chat_persistence/test/src/dao/read_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/read_dao_test.dart new file mode 100644 index 00000000..52207f68 --- /dev/null +++ b/packages/stream_chat_persistence/test/src/dao/read_dao_test.dart @@ -0,0 +1,97 @@ +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/dao/dao.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:test/test.dart'; + +import '../utils/date_matcher.dart'; + +void main() { + ReadDao readDao; + MoorChatDatabase database; + + setUp(() { + database = MoorChatDatabase.testable('testUserId'); + readDao = database.readDao; + }); + + Future> _prepareReadData(String cid, {int count = 3}) async { + final users = List.generate(count, (index) => User(id: 'testUserId$index')); + final reads = List.generate( + count, + (index) => Read( + lastRead: DateTime.now(), + user: users[index], + unreadMessages: index + 10, + ), + ); + + await database.userDao.updateUsers(users); + await readDao.updateReads(cid, reads); + return reads; + } + + test('getReadsByCid', () async { + const cid = 'testCid'; + + // Should be empty initially + final reads = await readDao.getReadsByCid(cid); + expect(reads, isEmpty); + + // Preparing test data + final insertedReads = await _prepareReadData(cid); + expect(insertedReads, isNotEmpty); + + // Fetched reads should be equal to inserted reads + final fetchedReads = await readDao.getReadsByCid(cid); + expect(fetchedReads.length, insertedReads.length); + for (var i = 0; i < fetchedReads.length; i++) { + final fetchedRead = fetchedReads[i]; + final insertedRead = insertedReads[i]; + expect(fetchedRead.user.id, insertedRead.user.id); + expect(fetchedRead.lastRead, isSameDateAs(insertedRead.lastRead)); + expect(fetchedRead.unreadMessages, insertedRead.unreadMessages); + } + }); + + test('updateReads', () async { + const cid = 'testCid'; + + // Preparing test data + final insertedReads = await _prepareReadData(cid); + + // Modifying one of the read and also adding one new + final copyRead = insertedReads.first.copyWith(unreadMessages: 33); + final newUser = User(id: 'testUserId3'); + final newRead = Read( + lastRead: DateTime.now(), + user: newUser, + unreadMessages: 30, + ); + await database.userDao.updateUsers([newUser]); + await readDao.updateReads(cid, [copyRead, newRead]); + + // Fetched reads length should be one more than inserted reads. + // copyRead `unreadMessages` modified field should be 33. + // Fetched reads should contain the newRead. + final fetchedReads = await readDao.getReadsByCid(cid); + expect(fetchedReads.length, insertedReads.length + 1); + expect( + fetchedReads + .firstWhere((it) => it.user.id == copyRead.user.id) + .unreadMessages, + 33, + ); + expect( + fetchedReads + .where((it) => + it.user.id == newRead.user.id && + it.unreadMessages == newRead.unreadMessages) + .isNotEmpty, + true, + ); + }); + + tearDown(() async { + await database.disconnect(); + }); +} From 66a577901c70a56c453a1fd105d042cbf9cfafc9 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 16 Mar 2021 20:45:41 +0530 Subject: [PATCH 12/50] test(persistence): minor improvement in update function tests Signed-off-by: Sahil Kumar --- .../test/src/dao/member_dao_test.dart | 39 +++++++++++++++---- .../test/src/dao/message_dao_test.dart | 2 +- .../test/src/dao/pinned_message_dao_test.dart | 2 +- .../test/src/dao/reaction_dao_test.dart | 3 +- 4 files changed, 36 insertions(+), 10 deletions(-) diff --git a/packages/stream_chat_persistence/test/src/dao/member_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/member_dao_test.dart index 6671c902..dbb8c73c 100644 --- a/packages/stream_chat_persistence/test/src/dao/member_dao_test.dart +++ b/packages/stream_chat_persistence/test/src/dao/member_dao_test.dart @@ -94,15 +94,40 @@ void main() { ); } - // Updating the last added member - final updatedMember = fetchedMembers.last.copyWith(banned: true); - await memberDao.updateMembers(cid, [updatedMember]); + // Modifying one of the member and also adding one new + final copyMember = fetchedMembers.first.copyWith(banned: true); + final newUser = User(id: 'testUserId3'); + final newMember = Member( + user: newUser, + banned: math.Random().nextBool(), + shadowBanned: math.Random().nextBool(), + createdAt: DateTime.now(), + isModerator: math.Random().nextBool(), + invited: math.Random().nextBool(), + inviteAcceptedAt: DateTime.now(), + role: 'testRole', + updatedAt: DateTime.now(), + ); + await database.userDao.updateUsers([newUser]); + await memberDao.updateMembers(cid, [copyMember, newMember]); - // Last member banned field should match the previous updated user + // Fetched member length should be one more than inserted members. + // copyMember `banned` modified field should be true. + // Fetched members should contain the newMember. final newFetchedMembers = await memberDao.getMembersByCid(cid); - expect(newFetchedMembers.length, fetchedMembers.length); - final lastMember = newFetchedMembers.last; - expect(lastMember.banned, true); + expect(newFetchedMembers.length, fetchedMembers.length + 1); + expect( + newFetchedMembers + .firstWhere((it) => it.user.id == copyMember.user.id) + .banned, + true, + ); + expect( + newFetchedMembers + .where((it) => it.user.id == newMember.user.id) + .isNotEmpty, + true, + ); }); test('deleteMemberByCids', () async { diff --git a/packages/stream_chat_persistence/test/src/dao/message_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/message_dao_test.dart index 6ee8ca2f..dccb414c 100644 --- a/packages/stream_chat_persistence/test/src/dao/message_dao_test.dart +++ b/packages/stream_chat_persistence/test/src/dao/message_dao_test.dart @@ -242,7 +242,7 @@ void main() { false, ); expect( - fetchedMessages.map((it) => it.id).contains('testMessageId${cid}4'), + fetchedMessages.map((it) => it.id).contains(newMessage.id), true, ); }); diff --git a/packages/stream_chat_persistence/test/src/dao/pinned_message_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/pinned_message_dao_test.dart index 1af3276e..5c1bce46 100644 --- a/packages/stream_chat_persistence/test/src/dao/pinned_message_dao_test.dart +++ b/packages/stream_chat_persistence/test/src/dao/pinned_message_dao_test.dart @@ -243,7 +243,7 @@ void main() { false, ); expect( - fetchedMessages.map((it) => it.id).contains('testMessageId${cid}4'), + fetchedMessages.map((it) => it.id).contains(newMessage.id), true, ); }); diff --git a/packages/stream_chat_persistence/test/src/dao/reaction_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/reaction_dao_test.dart index 42273efa..94f8ebdd 100644 --- a/packages/stream_chat_persistence/test/src/dao/reaction_dao_test.dart +++ b/packages/stream_chat_persistence/test/src/dao/reaction_dao_test.dart @@ -128,7 +128,8 @@ void main() { ); expect( fetchedReactions - .where((it) => it.userId == 'testUserId3' && it.type == 'testType3') + .where((it) => + it.userId == newReaction.userId && it.type == newReaction.type) .isNotEmpty, true, ); From e87a8a07a15cab50b0e0853bbb8b9c33607a4b44 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 16 Mar 2021 21:11:07 +0530 Subject: [PATCH 13/50] test(persistence): add tests for user dao Signed-off-by: Sahil Kumar --- packages/stream_chat/lib/src/models/user.dart | 24 ++++++ .../lib/src/dao/user_dao.dart | 6 ++ .../test/src/dao/user_dao_test.dart | 77 +++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 packages/stream_chat_persistence/test/src/dao/user_dao_test.dart diff --git a/packages/stream_chat/lib/src/models/user.dart b/packages/stream_chat/lib/src/models/user.dart index 618c1986..3b9f9add 100644 --- a/packages/stream_chat/lib/src/models/user.dart +++ b/packages/stream_chat/lib/src/models/user.dart @@ -100,4 +100,28 @@ class User { /// Serialize to json Map toJson() => Serialization.moveFromExtraDataToRoot(_$UserToJson(this), topLevelFields); + + /// Creates a copy of [User] with specified attributes overridden. + User copyWith({ + String id, + String role, + DateTime createdAt, + DateTime updatedAt, + DateTime lastActive, + bool online, + Map extraData, + bool banned, + List teams, + }) => + User( + id: id ?? this.id, + role: role ?? this.role, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + lastActive: lastActive ?? this.lastActive, + online: online ?? this.online, + extraData: extraData ?? this.extraData, + banned: banned ?? this.banned, + teams: teams ?? this.teams, + ); } diff --git a/packages/stream_chat_persistence/lib/src/dao/user_dao.dart b/packages/stream_chat_persistence/lib/src/dao/user_dao.dart index 65ce1521..9cdff8e7 100644 --- a/packages/stream_chat_persistence/lib/src/dao/user_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/user_dao.dart @@ -20,4 +20,10 @@ class UserDao extends DatabaseAccessor with _$UserDaoMixin { mode: InsertMode.insertOrReplace, ), ); + + /// Returns the list of all the users stored in db + Future> getUsers() => + (select(users)..orderBy([(u) => OrderingTerm.desc(u.createdAt)])) + .map((it) => it.toUser()) + .get(); } diff --git a/packages/stream_chat_persistence/test/src/dao/user_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/user_dao_test.dart new file mode 100644 index 00000000..8c5898a0 --- /dev/null +++ b/packages/stream_chat_persistence/test/src/dao/user_dao_test.dart @@ -0,0 +1,77 @@ +import 'dart:math' as math; + +import 'package:stream_chat_persistence/src/dao/dao.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:test/test.dart'; +import 'package:stream_chat/stream_chat.dart'; + +void main() { + UserDao userDao; + MoorChatDatabase database; + + setUp(() { + database = MoorChatDatabase.testable('testUserId'); + userDao = database.userDao; + }); + + Future> _prepareUserData({int count = 3}) async { + final users = List.generate( + count, + (index) => User( + id: 'testUserId$index', + role: 'testRole', + createdAt: DateTime.now(), + updatedAt: DateTime.now(), + lastActive: DateTime.now(), + online: math.Random().nextBool(), + banned: math.Random().nextBool(), + ), + ); + await userDao.updateUsers(users); + return users; + } + + test('updateUsers', () async { + // Preparing test data + final insertedUsers = await _prepareUserData(); + + // Modifying one of the user and also adding one new + final copyUser = insertedUsers.first.copyWith(online: false); + final newUser = User( + id: 'testUserId3', + role: 'testRole', + createdAt: DateTime.now(), + updatedAt: DateTime.now(), + lastActive: DateTime.now(), + online: math.Random().nextBool(), + banned: math.Random().nextBool(), + ); + await userDao.updateUsers([copyUser, newUser]); + + // Fetched users length should be one more than inserted users. + // copyUser `online` modified field should be `false`. + // Fetched users should contain the newUser. + final fetchedUsers = await userDao.getUsers(); + expect(fetchedUsers.length, insertedUsers.length + 1); + expect(fetchedUsers.firstWhere((it) => it.id == copyUser.id).online, false); + expect(fetchedUsers.contains(newUser), true); + }); + + test('getUsers', () async { + // Should be empty initially + final users = await userDao.getUsers(); + expect(users, isEmpty); + + // Preparing test data + final insertedUsers = await _prepareUserData(); + expect(insertedUsers, isNotEmpty); + + // Fetched user list should match inserted user list length + final fetchedUsers = await userDao.getUsers(); + expect(fetchedUsers.length, insertedUsers.length); + }); + + tearDown(() async { + await database.disconnect(); + }); +} From 3854bfcdc93b0d7b22150d48ae8a7337ddc42a3f Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 17 Mar 2021 14:01:39 +0530 Subject: [PATCH 14/50] test(persistence): add test for list converter Signed-off-by: Sahil Kumar --- .../src/converter/list_coverter_test.dart | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 packages/stream_chat_persistence/test/src/converter/list_coverter_test.dart diff --git a/packages/stream_chat_persistence/test/src/converter/list_coverter_test.dart b/packages/stream_chat_persistence/test/src/converter/list_coverter_test.dart new file mode 100644 index 00000000..a5bedd40 --- /dev/null +++ b/packages/stream_chat_persistence/test/src/converter/list_coverter_test.dart @@ -0,0 +1,53 @@ +import 'dart:convert'; + +import 'package:test/test.dart'; +import 'package:stream_chat_persistence/src/converter/list_converter.dart'; + +void main() { + group('mapToDart', () { + final listConverter = ListConverter(); + + test('should return null if nothing is provided', () { + final res = listConverter.mapToDart(null); + expect(res, isNull); + }); + + test('should throw type error if the provided json is not a list', () { + final json = {'test_key': 'testData'}; + expect( + () => listConverter.mapToDart(jsonEncode(json)), + throwsA(isA()), + ); + }); + + test('should throw type error if the provided json is not a list of String', + () { + final json = [22, 33, 44]; + expect( + () => listConverter.mapToDart(jsonEncode(json)), + throwsA(isA()), + ); + }); + + test('should return list of String if json data list is provided', () { + final data = ['data1', 'data2', 'data3']; + final res = listConverter.mapToDart(jsonEncode(data)); + expect(res.length, data.length); + }); + }); + + group('mapToSql', () { + final listConverter = ListConverter(); + + test('should return null if nothing is provided', () { + final res = listConverter.mapToSql(null); + expect(res, isNull); + }); + + test('should return json string if data list is provided', () { + final data = ['data1', 'data2', 'data3']; + final res = listConverter.mapToSql(data); + expect(res, jsonEncode(data)); + }); + }); +} From 28e3e5edc4265cd5a0fc20f9f6c91fedf0a5b5e5 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 17 Mar 2021 14:11:45 +0530 Subject: [PATCH 15/50] test(persistence): add test for map converter Signed-off-by: Sahil Kumar --- .../src/converter/map_converter_test.dart | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 packages/stream_chat_persistence/test/src/converter/map_converter_test.dart diff --git a/packages/stream_chat_persistence/test/src/converter/map_converter_test.dart b/packages/stream_chat_persistence/test/src/converter/map_converter_test.dart new file mode 100644 index 00000000..4727cb0d --- /dev/null +++ b/packages/stream_chat_persistence/test/src/converter/map_converter_test.dart @@ -0,0 +1,64 @@ +import 'dart:convert'; + +import 'package:test/test.dart'; +import 'package:stream_chat_persistence/src/converter/map_converter.dart'; + +void main() { + group('mapToDart', () { + final mapConverter = MapConverter(); + + test('should return null if nothing is provided', () { + final res = mapConverter.mapToDart(null); + expect(res, isNull); + }); + + test('should throw type error if the provided json is not a map', () { + const json = ['testData1', 'testData2', 'testData3']; + expect( + () => mapConverter.mapToDart(jsonEncode(json)), + throwsA(isA()), + ); + }); + + test( + 'should throw type error if the provided json is not a ' + 'map of String, String', + () { + const json = {'test_key': 22, 'test_key2': 33, 'test_key3': 44}; + expect( + () => mapConverter.mapToDart(jsonEncode(json)), + throwsA(isA()), + ); + }, + ); + + test('should return map of String, String if json data is provided', () { + const data = { + 'test_key': 'testValue', + 'test_key2': 'testValue2', + 'test_key3': 'testValue3', + }; + final res = mapConverter.mapToDart(jsonEncode(data)); + expect(res, data); + }); + }); + + group('mapToSql', () { + final mapConverter = MapConverter(); + + test('should return null if nothing is provided', () { + final res = mapConverter.mapToSql(null); + expect(res, isNull); + }); + + test('should return json string if data map is provided', () { + const data = { + 'test_key': 'testValue', + 'test_key2': 'testValue2', + 'test_key3': 'testValue3', + }; + final res = mapConverter.mapToSql(data); + expect(res, jsonEncode(data)); + }); + }); +} From b738a47c2aa9949644105e9390ba3197b80424f7 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 17 Mar 2021 14:19:06 +0530 Subject: [PATCH 16/50] test(persistence): add tests for message sending status converter Signed-off-by: Sahil Kumar --- ...message_sending_status_converter_test.dart | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 packages/stream_chat_persistence/test/src/converter/message_sending_status_converter_test.dart diff --git a/packages/stream_chat_persistence/test/src/converter/message_sending_status_converter_test.dart b/packages/stream_chat_persistence/test/src/converter/message_sending_status_converter_test.dart new file mode 100644 index 00000000..1035a759 --- /dev/null +++ b/packages/stream_chat_persistence/test/src/converter/message_sending_status_converter_test.dart @@ -0,0 +1,33 @@ +import 'package:test/test.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/converter/message_sending_status_converter.dart'; + +void main() { + group('mapToDart', () { + final statusConverter = MessageSendingStatusConverter(); + + test('should return null if nothing is provided', () { + final res = statusConverter.mapToDart(null); + expect(res, isNull); + }); + + test('should return expected status if status code is provided', () { + final res = statusConverter.mapToDart(3); + expect(res, MessageSendingStatus.updating); + }); + }); + + group('mapToSql', () { + final statusConverter = MessageSendingStatusConverter(); + + test('should return null if nothing is provided', () { + final res = statusConverter.mapToSql(null); + expect(res, isNull); + }); + + test('should return expected code if the status is provided', () { + final res = statusConverter.mapToSql(MessageSendingStatus.updating); + expect(res, 3); + }); + }); +} From 830cb0c281155ff9faeee1118b16ba878ba844d2 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 17 Mar 2021 14:57:26 +0530 Subject: [PATCH 17/50] test(persistence): add tests for channel mapper Signed-off-by: Sahil Kumar --- .../test/src/mapper/channel_mapper_test.dart | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 packages/stream_chat_persistence/test/src/mapper/channel_mapper_test.dart diff --git a/packages/stream_chat_persistence/test/src/mapper/channel_mapper_test.dart b/packages/stream_chat_persistence/test/src/mapper/channel_mapper_test.dart new file mode 100644 index 00000000..dc02ee4b --- /dev/null +++ b/packages/stream_chat_persistence/test/src/mapper/channel_mapper_test.dart @@ -0,0 +1,111 @@ +import 'dart:math' as math; + +import 'package:test/test.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:stream_chat_persistence/src/mapper/channel_mapper.dart'; +import '../utils/date_matcher.dart'; + +void main() { + group('ChannelEntity', () { + final user = User(id: 'testUserId'); + final entity = ChannelEntity( + id: 'testId', + type: 'testType', + cid: 'testCid', + config: {'max_message_length': 33}, + frozen: math.Random().nextBool(), + lastMessageAt: DateTime.now(), + createdAt: DateTime.now(), + updatedAt: DateTime.now(), + deletedAt: DateTime.now(), + memberCount: 33, + createdById: user.id, + extraData: {'test_extra_data': 'testData'}, + ); + + test('toChannelModel should map entity into ChannelModel', () { + final channelModel = entity.toChannelModel(createdBy: user); + expect(channelModel, isA()); + expect(channelModel.id, entity.id); + expect(channelModel.config.toJson()['max_message_length'], 33); + expect(channelModel.frozen, entity.frozen); + expect(channelModel.createdAt, isSameDateAs(entity.createdAt)); + expect(channelModel.updatedAt, isSameDateAs(entity.updatedAt)); + expect(channelModel.memberCount, entity.memberCount); + expect(channelModel.cid, entity.cid); + expect(channelModel.lastMessageAt, isSameDateAs(entity.lastMessageAt)); + expect(channelModel.deletedAt, isSameDateAs(entity.deletedAt)); + expect(channelModel.extraData, entity.extraData); + expect(channelModel.createdBy.id, entity.createdById); + }); + + test('toChannelState should map entity into ChannelState ', () { + final members = List.generate(3, (index) => Member()); + final reads = List.generate(3, (index) => Read()); + final messages = List.generate(3, (index) => Message()); + + final channelState = entity.toChannelState( + createdBy: user, + members: members, + reads: reads, + messages: messages, + pinnedMessages: messages, + ); + + expect(channelState, isA()); + expect(channelState.members.length, members.length); + expect(channelState.read.length, reads.length); + expect(channelState.messages.length, messages.length); + expect(channelState.pinnedMessages.length, messages.length); + + final channelModel = channelState.channel; + expect(channelModel.id, entity.id); + expect(channelModel.config.toJson()['max_message_length'], 33); + expect(channelModel.frozen, entity.frozen); + expect(channelModel.createdAt, isSameDateAs(entity.createdAt)); + expect(channelModel.updatedAt, isSameDateAs(entity.updatedAt)); + expect(channelModel.memberCount, entity.memberCount); + expect(channelModel.cid, entity.cid); + expect(channelModel.lastMessageAt, isSameDateAs(entity.lastMessageAt)); + expect(channelModel.deletedAt, isSameDateAs(entity.deletedAt)); + expect(channelModel.extraData, entity.extraData); + expect(channelModel.createdBy.id, entity.createdById); + }); + }); + + test('toEntity should map model into ChannelEntity', () { + final createdBy = User(id: 'testUserId'); + final model = ChannelModel( + id: 'testId', + type: 'testType', + cid: 'testCid', + config: ChannelConfig(maxMessageLength: 33), + frozen: math.Random().nextBool(), + lastMessageAt: DateTime.now(), + createdAt: DateTime.now(), + updatedAt: DateTime.now(), + deletedAt: DateTime.now(), + memberCount: 33, + createdBy: createdBy, + extraData: {'test_extra_data': 'testData'}, + ); + + final channelEntity = model.toEntity(); + expect(channelEntity, isA()); + expect(channelEntity.id, model.id); + expect( + channelEntity.config['max_message_length'], + model.config.maxMessageLength, + ); + expect(channelEntity.frozen, model.frozen); + expect(channelEntity.createdAt, isSameDateAs(model.createdAt)); + expect(channelEntity.updatedAt, isSameDateAs(model.updatedAt)); + expect(channelEntity.memberCount, model.memberCount); + expect(channelEntity.cid, model.cid); + expect(channelEntity.lastMessageAt, isSameDateAs(model.lastMessageAt)); + expect(channelEntity.deletedAt, isSameDateAs(model.deletedAt)); + expect(channelEntity.extraData, model.extraData); + expect(channelEntity.createdById, model.createdBy.id); + }); +} From 60613d44bf0d9b019bb7d8b8082b6d50f3205d3c Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 17 Mar 2021 15:03:40 +0530 Subject: [PATCH 18/50] test(persistence): add test for event mapper Signed-off-by: Sahil Kumar --- .../test/src/mapper/event_mapper_test.dart | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 packages/stream_chat_persistence/test/src/mapper/event_mapper_test.dart diff --git a/packages/stream_chat_persistence/test/src/mapper/event_mapper_test.dart b/packages/stream_chat_persistence/test/src/mapper/event_mapper_test.dart new file mode 100644 index 00000000..240ce1a7 --- /dev/null +++ b/packages/stream_chat_persistence/test/src/mapper/event_mapper_test.dart @@ -0,0 +1,23 @@ +import 'package:test/test.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:stream_chat_persistence/src/mapper/event_mapper.dart'; + +void main() { + test('toEvent should map entity into Event', () { + final ownUser = OwnUser(id: 'testUserId'); + final entity = ConnectionEventEntity( + id: 3, + ownUser: ownUser.toJson(), + totalUnreadCount: 33, + unreadChannels: 33, + lastSyncAt: DateTime.now(), + lastEventAt: DateTime.now(), + ); + final event = entity.toEvent(); + expect(event, isA()); + expect(event.me.id, ownUser.id); + expect(event.totalUnreadCount, entity.totalUnreadCount); + expect(event.unreadChannels, entity.unreadChannels); + }); +} From 323c5b6cba9f874e736cb6221467da19a32d6fa8 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 17 Mar 2021 15:43:50 +0530 Subject: [PATCH 19/50] test(persistence): add tests for member mapper Signed-off-by: Sahil Kumar --- .../test/src/mapper/member_mapper_test.dart | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 packages/stream_chat_persistence/test/src/mapper/member_mapper_test.dart diff --git a/packages/stream_chat_persistence/test/src/mapper/member_mapper_test.dart b/packages/stream_chat_persistence/test/src/mapper/member_mapper_test.dart new file mode 100644 index 00000000..0f7d4f11 --- /dev/null +++ b/packages/stream_chat_persistence/test/src/mapper/member_mapper_test.dart @@ -0,0 +1,69 @@ +import 'dart:math' as math; + +import 'package:test/test.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:stream_chat_persistence/src/mapper/member_mapper.dart'; + +import '../utils/date_matcher.dart'; + +void main() { + test('toMember should map entity into Member', () { + final user = User(id: 'testUserId'); + final entity = MemberEntity( + userId: user.id, + channelCid: 'testCid', + createdAt: DateTime.now(), + updatedAt: DateTime.now(), + role: 'testRole', + inviteAcceptedAt: DateTime.now(), + inviteRejectedAt: DateTime.now(), + invited: math.Random().nextBool(), + banned: math.Random().nextBool(), + shadowBanned: math.Random().nextBool(), + isModerator: math.Random().nextBool(), + ); + final member = entity.toMember(user: user); + expect(member, isA()); + expect(member.user.id, entity.userId); + expect(member.createdAt, isSameDateAs(entity.createdAt)); + expect(member.updatedAt, isSameDateAs(entity.updatedAt)); + expect(member.role, entity.role); + expect(member.inviteAcceptedAt, isSameDateAs(entity.inviteAcceptedAt)); + expect(member.inviteRejectedAt, isSameDateAs(entity.inviteRejectedAt)); + expect(member.invited, entity.invited); + expect(member.banned, entity.banned); + expect(member.shadowBanned, entity.shadowBanned); + expect(member.isModerator, entity.isModerator); + }); + + test('toEntity show map member into MemberEntity', () { + const cid = 'testCid'; + final user = User(id: 'testUserId'); + final member = Member( + user: user, + createdAt: DateTime.now(), + updatedAt: DateTime.now(), + role: 'testRole', + inviteAcceptedAt: DateTime.now(), + inviteRejectedAt: DateTime.now(), + invited: math.Random().nextBool(), + banned: math.Random().nextBool(), + shadowBanned: math.Random().nextBool(), + isModerator: math.Random().nextBool(), + ); + final entity = member.toEntity(cid: cid); + expect(entity, isA()); + expect(entity.channelCid, cid); + expect(entity.userId, member.user.id); + expect(entity.createdAt, isSameDateAs(member.createdAt)); + expect(entity.updatedAt, isSameDateAs(member.updatedAt)); + expect(entity.role, member.role); + expect(entity.inviteAcceptedAt, isSameDateAs(member.inviteAcceptedAt)); + expect(entity.inviteRejectedAt, isSameDateAs(member.inviteRejectedAt)); + expect(entity.invited, member.invited); + expect(entity.banned, member.banned); + expect(entity.shadowBanned, member.shadowBanned); + expect(entity.isModerator, member.isModerator); + }); +} From b77c4dfc5d87c4b51e28b452a12bef0a7ec571eb Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 17 Mar 2021 11:50:01 +0100 Subject: [PATCH 20/50] remove useless dependencies --- packages/stream_chat_flutter/pubspec.yaml | 3 --- packages/stream_chat_flutter_core/pubspec.yaml | 1 - packages/stream_chat_persistence/pubspec.yaml | 1 - 3 files changed, 5 deletions(-) diff --git a/packages/stream_chat_flutter/pubspec.yaml b/packages/stream_chat_flutter/pubspec.yaml index 24f83efe..867178d6 100644 --- a/packages/stream_chat_flutter/pubspec.yaml +++ b/packages/stream_chat_flutter/pubspec.yaml @@ -30,16 +30,13 @@ dependencies: flutter_keyboard_visibility: ^4.0.2 video_compress: ^2.1.1 visibility_detector: ^0.1.5 - http_parser: ^3.1.4 meta: ^1.2.4 lottie: ^0.7.0+1 substring_highlight: ^0.1.2 flutter_slidable: ^0.5.7 - clipboard: ^0.1.2+8 image_gallery_saver: ^1.6.7 share_plus: ^1.2.0 photo_manager: ^1.0.0 - transparent_image: ^1.0.0 ezanimation: ^0.4.1 synchronized: ^2.1.0 characters: ^1.0.0 diff --git a/packages/stream_chat_flutter_core/pubspec.yaml b/packages/stream_chat_flutter_core/pubspec.yaml index 5a5fc7da..cc36f149 100644 --- a/packages/stream_chat_flutter_core/pubspec.yaml +++ b/packages/stream_chat_flutter_core/pubspec.yaml @@ -20,5 +20,4 @@ dev_dependencies: flutter_test: sdk: flutter fake_async: ^1.1.0 - pedantic: ^1.9.2 \ No newline at end of file diff --git a/packages/stream_chat_persistence/pubspec.yaml b/packages/stream_chat_persistence/pubspec.yaml index 12d117b1..399d1278 100644 --- a/packages/stream_chat_persistence/pubspec.yaml +++ b/packages/stream_chat_persistence/pubspec.yaml @@ -23,5 +23,4 @@ dependencies: dev_dependencies: build_runner: ^1.11.0 moor_generator: ^3.4.1 - pedantic: ^1.9.2 test: ^1.15.7 From 6804660c61ebef39eb2ff6176dd5e4532330e322 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 17 Mar 2021 17:21:57 +0530 Subject: [PATCH 21/50] test(persistence): add tests for message mapper Signed-off-by: Sahil Kumar --- .../test/src/mapper/message_mapper_test.dart | 157 ++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 packages/stream_chat_persistence/test/src/mapper/message_mapper_test.dart diff --git a/packages/stream_chat_persistence/test/src/mapper/message_mapper_test.dart b/packages/stream_chat_persistence/test/src/mapper/message_mapper_test.dart new file mode 100644 index 00000000..0554a0ce --- /dev/null +++ b/packages/stream_chat_persistence/test/src/mapper/message_mapper_test.dart @@ -0,0 +1,157 @@ +import 'dart:math' as math; + +import 'package:test/test.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:stream_chat_persistence/src/mapper/message_mapper.dart'; + +import '../utils/date_matcher.dart'; + +void main() { + test('toMessage should map the entity into Message', () { + final user = User(id: 'testUserId'); + final quotedMessage = Message(id: 'testQuotedMessageId'); + final reactions = List.generate( + 3, + (index) => Reaction( + messageId: 'testMessageId', + createdAt: DateTime.now(), + type: 'testType$index', + user: user, + score: math.Random().nextInt(50), + ), + ); + final entity = MessageEntity( + id: 'testMessageId', + attachments: [], + channelCid: 'testCid', + type: 'testType', + parentId: 'testParentId', + quotedMessageId: quotedMessage.id, + command: 'testCommand', + createdAt: DateTime.now(), + shadowed: math.Random().nextBool(), + showInChannel: math.Random().nextBool(), + replyCount: 33, + reactionScores: {for (final r in reactions) r.type: r.score}, + reactionCounts: reactions.fold( + {}, + (prev, curr) => + prev..update(curr.type, (value) => value + 1, ifAbsent: () => 1), + ), + status: MessageSendingStatus.sent, + updatedAt: DateTime.now(), + extraData: {'extra_test_data': 'extraData'}, + userId: user.id, + deletedAt: DateTime.now(), + messageText: 'dummy text', + pinned: true, + pinExpires: DateTime.now().toUtc(), + pinnedAt: DateTime.now(), + pinnedByUserId: user.id, + ); + final message = entity.toMessage( + user: user, + pinnedBy: user, + latestReactions: reactions, + ownReactions: reactions, + quotedMessage: quotedMessage, + ); + + expect(message, isA()); + expect(message.id, entity.id); + expect(message.attachments, entity.attachments); + expect(message.type, entity.type); + expect(message.parentId, entity.parentId); + expect(message.quotedMessageId, entity.quotedMessageId); + expect(message.command, entity.command); + expect(message.createdAt, isSameDateAs(entity.createdAt)); + expect(message.shadowed, entity.shadowed); + expect(message.showInChannel, entity.showInChannel); + expect(message.replyCount, entity.replyCount); + expect(message.reactionScores, entity.reactionScores); + expect(message.reactionCounts, entity.reactionCounts); + expect(message.status, entity.status); + expect(message.updatedAt, isSameDateAs(entity.updatedAt)); + expect(message.extraData, entity.extraData); + expect(message.user.id, entity.userId); + expect(message.deletedAt, isSameDateAs(entity.deletedAt)); + expect(message.text, entity.messageText); + expect(message.pinned, entity.pinned); + expect(message.pinExpires, isSameDateAs(entity.pinExpires)); + expect(message.pinnedAt, isSameDateAs(entity.pinnedAt)); + expect(message.pinnedBy.id, entity.pinnedByUserId); + expect(message.reactionCounts, entity.reactionCounts); + expect(message.reactionScores, entity.reactionScores); + }); + + test('toEntity should map message into MessageEntity', () { + const cid = 'testCid'; + final user = User(id: 'testUserId'); + final quotedMessage = Message(id: 'testQuotedMessageId'); + final reactions = List.generate( + 3, + (index) => Reaction( + messageId: 'testMessageId', + createdAt: DateTime.now(), + type: 'testType$index', + user: user, + score: math.Random().nextInt(50), + ), + ); + final message = Message( + id: 'testMessageId', + attachments: [], + type: 'testType', + parentId: 'testParentId', + quotedMessageId: quotedMessage.id, + command: 'testCommand', + createdAt: DateTime.now(), + shadowed: math.Random().nextBool(), + showInChannel: math.Random().nextBool(), + replyCount: 33, + reactionScores: {for (final r in reactions) r.type: r.score}, + reactionCounts: reactions.fold( + {}, + (prev, curr) => + prev..update(curr.type, (value) => value + 1, ifAbsent: () => 1), + ), + status: MessageSendingStatus.sending, + updatedAt: DateTime.now(), + extraData: {'extra_test_data': 'extraData'}, + user: user, + deletedAt: DateTime.now(), + text: 'dummy text', + pinned: true, + pinExpires: DateTime.now(), + pinnedAt: DateTime.now(), + pinnedBy: user, + ); + final entity = message.toEntity(cid: cid); + expect(entity, isA()); + expect(entity.id, message.id); + expect(entity.attachments, message.attachments); + expect(entity.type, message.type); + expect(entity.parentId, message.parentId); + expect(entity.quotedMessageId, message.quotedMessageId); + expect(entity.command, message.command); + expect(entity.createdAt, isSameDateAs(message.createdAt)); + expect(entity.shadowed, message.shadowed); + expect(entity.showInChannel, message.showInChannel); + expect(entity.replyCount, message.replyCount); + expect(entity.reactionScores, message.reactionScores); + expect(entity.reactionCounts, message.reactionCounts); + expect(entity.status, message.status); + expect(entity.updatedAt, isSameDateAs(message.updatedAt)); + expect(entity.extraData, message.extraData); + expect(entity.userId, message.user.id); + expect(entity.deletedAt, isSameDateAs(message.deletedAt)); + expect(entity.messageText, message.text); + expect(entity.pinned, message.pinned); + expect(entity.pinExpires, isSameDateAs(message.pinExpires)); + expect(entity.pinnedAt, isSameDateAs(message.pinnedAt)); + expect(entity.pinnedByUserId, message.pinnedBy.id); + expect(entity.reactionCounts, message.reactionCounts); + expect(entity.reactionScores, message.reactionScores); + }); +} From a78c230ef0e900e6b3d44e2ebed9b8d3720b572f Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 17 Mar 2021 17:25:25 +0530 Subject: [PATCH 22/50] test(persistence): add tests for pinned message mapper Signed-off-by: Sahil Kumar --- .../mapper/pinned_message_mapper_test.dart | 157 ++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 packages/stream_chat_persistence/test/src/mapper/pinned_message_mapper_test.dart diff --git a/packages/stream_chat_persistence/test/src/mapper/pinned_message_mapper_test.dart b/packages/stream_chat_persistence/test/src/mapper/pinned_message_mapper_test.dart new file mode 100644 index 00000000..e79dd051 --- /dev/null +++ b/packages/stream_chat_persistence/test/src/mapper/pinned_message_mapper_test.dart @@ -0,0 +1,157 @@ +import 'dart:math' as math; + +import 'package:test/test.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:stream_chat_persistence/src/mapper/pinned_message_mapper.dart'; + +import '../utils/date_matcher.dart'; + +void main() { + test('toMessage should map the entity into Message', () { + final user = User(id: 'testUserId'); + final quotedMessage = Message(id: 'testQuotedMessageId'); + final reactions = List.generate( + 3, + (index) => Reaction( + messageId: 'testMessageId', + createdAt: DateTime.now(), + type: 'testType$index', + user: user, + score: math.Random().nextInt(50), + ), + ); + final entity = PinnedMessageEntity( + id: 'testMessageId', + attachments: [], + channelCid: 'testCid', + type: 'testType', + parentId: 'testParentId', + quotedMessageId: quotedMessage.id, + command: 'testCommand', + createdAt: DateTime.now(), + shadowed: math.Random().nextBool(), + showInChannel: math.Random().nextBool(), + replyCount: 33, + reactionScores: {for (final r in reactions) r.type: r.score}, + reactionCounts: reactions.fold( + {}, + (prev, curr) => + prev..update(curr.type, (value) => value + 1, ifAbsent: () => 1), + ), + status: MessageSendingStatus.sent, + updatedAt: DateTime.now(), + extraData: {'extra_test_data': 'extraData'}, + userId: user.id, + deletedAt: DateTime.now(), + messageText: 'dummy text', + pinned: true, + pinExpires: DateTime.now().toUtc(), + pinnedAt: DateTime.now(), + pinnedByUserId: user.id, + ); + final message = entity.toMessage( + user: user, + pinnedBy: user, + latestReactions: reactions, + ownReactions: reactions, + quotedMessage: quotedMessage, + ); + + expect(message, isA()); + expect(message.id, entity.id); + expect(message.attachments, entity.attachments); + expect(message.type, entity.type); + expect(message.parentId, entity.parentId); + expect(message.quotedMessageId, entity.quotedMessageId); + expect(message.command, entity.command); + expect(message.createdAt, isSameDateAs(entity.createdAt)); + expect(message.shadowed, entity.shadowed); + expect(message.showInChannel, entity.showInChannel); + expect(message.replyCount, entity.replyCount); + expect(message.reactionScores, entity.reactionScores); + expect(message.reactionCounts, entity.reactionCounts); + expect(message.status, entity.status); + expect(message.updatedAt, isSameDateAs(entity.updatedAt)); + expect(message.extraData, entity.extraData); + expect(message.user.id, entity.userId); + expect(message.deletedAt, isSameDateAs(entity.deletedAt)); + expect(message.text, entity.messageText); + expect(message.pinned, entity.pinned); + expect(message.pinExpires, isSameDateAs(entity.pinExpires)); + expect(message.pinnedAt, isSameDateAs(entity.pinnedAt)); + expect(message.pinnedBy.id, entity.pinnedByUserId); + expect(message.reactionCounts, entity.reactionCounts); + expect(message.reactionScores, entity.reactionScores); + }); + + test('toPinnedEntity should map message into PinnedMessageEntity', () { + const cid = 'testCid'; + final user = User(id: 'testUserId'); + final quotedMessage = Message(id: 'testQuotedMessageId'); + final reactions = List.generate( + 3, + (index) => Reaction( + messageId: 'testMessageId', + createdAt: DateTime.now(), + type: 'testType$index', + user: user, + score: math.Random().nextInt(50), + ), + ); + final message = Message( + id: 'testMessageId', + attachments: [], + type: 'testType', + parentId: 'testParentId', + quotedMessageId: quotedMessage.id, + command: 'testCommand', + createdAt: DateTime.now(), + shadowed: math.Random().nextBool(), + showInChannel: math.Random().nextBool(), + replyCount: 33, + reactionScores: {for (final r in reactions) r.type: r.score}, + reactionCounts: reactions.fold( + {}, + (prev, curr) => + prev..update(curr.type, (value) => value + 1, ifAbsent: () => 1), + ), + status: MessageSendingStatus.sending, + updatedAt: DateTime.now(), + extraData: {'extra_test_data': 'extraData'}, + user: user, + deletedAt: DateTime.now(), + text: 'dummy text', + pinned: true, + pinExpires: DateTime.now(), + pinnedAt: DateTime.now(), + pinnedBy: user, + ); + final entity = message.toPinnedEntity(cid: cid); + expect(entity, isA()); + expect(entity.id, message.id); + expect(entity.attachments, message.attachments); + expect(entity.type, message.type); + expect(entity.parentId, message.parentId); + expect(entity.quotedMessageId, message.quotedMessageId); + expect(entity.command, message.command); + expect(entity.createdAt, isSameDateAs(message.createdAt)); + expect(entity.shadowed, message.shadowed); + expect(entity.showInChannel, message.showInChannel); + expect(entity.replyCount, message.replyCount); + expect(entity.reactionScores, message.reactionScores); + expect(entity.reactionCounts, message.reactionCounts); + expect(entity.status, message.status); + expect(entity.updatedAt, isSameDateAs(message.updatedAt)); + expect(entity.extraData, message.extraData); + expect(entity.userId, message.user.id); + expect(entity.deletedAt, isSameDateAs(message.deletedAt)); + expect(entity.messageText, message.text); + expect(entity.pinned, message.pinned); + expect(entity.pinExpires, isSameDateAs(message.pinExpires)); + expect(entity.pinnedAt, isSameDateAs(message.pinnedAt)); + expect(entity.pinnedByUserId, message.pinnedBy.id); + expect(entity.reactionCounts, message.reactionCounts); + expect(entity.reactionScores, message.reactionScores); + }); +} From d688d554ce07af0c1de6450363d995f26456a7f6 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 17 Mar 2021 17:32:12 +0530 Subject: [PATCH 23/50] test(persistence): add tests for reaction mapper Signed-off-by: Sahil Kumar --- .../test/src/mapper/reaction_mapper_test.dart | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 packages/stream_chat_persistence/test/src/mapper/reaction_mapper_test.dart diff --git a/packages/stream_chat_persistence/test/src/mapper/reaction_mapper_test.dart b/packages/stream_chat_persistence/test/src/mapper/reaction_mapper_test.dart new file mode 100644 index 00000000..8754ba10 --- /dev/null +++ b/packages/stream_chat_persistence/test/src/mapper/reaction_mapper_test.dart @@ -0,0 +1,54 @@ +import 'dart:math' as math; + +import 'package:test/test.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:stream_chat_persistence/src/mapper/reaction_mapper.dart'; + +import '../utils/date_matcher.dart'; + +void main() { + test('toReaction should map the entity into Reaction', () { + final user = User(id: 'testUserId'); + final message = Message(id: 'testMessageId'); + final entity = ReactionEntity( + userId: user.id, + messageId: message.id, + type: 'haha', + score: 33, + createdAt: DateTime.now(), + extraData: {'extra_test_data': 'extraData'}, + ); + + final reaction = entity.toReaction(user: user); + expect(reaction, isA()); + expect(reaction.userId, entity.userId); + expect(reaction.messageId, entity.messageId); + expect(reaction.type, entity.type); + expect(reaction.score, entity.score); + expect(reaction.createdAt, isSameDateAs(entity.createdAt)); + expect(reaction.extraData, entity.extraData); + }); + + test('toEntity should map reaction into ReactionEntity', () { + final user = User(id: 'testUserId'); + final message = Message(id: 'testMessageId'); + final reaction = Reaction( + userId: user.id, + messageId: message.id, + type: 'haha', + score: 33, + createdAt: DateTime.now(), + extraData: {'extra_test_data': 'extraData'}, + ); + + final entity = reaction.toEntity(); + expect(entity, isA()); + expect(entity.userId, reaction.userId); + expect(entity.messageId, reaction.messageId); + expect(entity.type, reaction.type); + expect(entity.score, reaction.score); + expect(entity.createdAt, isSameDateAs(reaction.createdAt)); + expect(entity.extraData, reaction.extraData); + }); +} From 818e91a106ea91376582a989fac70d70ee3e4c7c Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 17 Mar 2021 17:38:14 +0530 Subject: [PATCH 24/50] test(persistence): add tests for read mapper Signed-off-by: Sahil Kumar --- .../test/src/mapper/reaction_mapper_test.dart | 2 - .../test/src/mapper/read_mapper_test.dart | 41 +++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 packages/stream_chat_persistence/test/src/mapper/read_mapper_test.dart diff --git a/packages/stream_chat_persistence/test/src/mapper/reaction_mapper_test.dart b/packages/stream_chat_persistence/test/src/mapper/reaction_mapper_test.dart index 8754ba10..cb5d231e 100644 --- a/packages/stream_chat_persistence/test/src/mapper/reaction_mapper_test.dart +++ b/packages/stream_chat_persistence/test/src/mapper/reaction_mapper_test.dart @@ -1,5 +1,3 @@ -import 'dart:math' as math; - import 'package:test/test.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; diff --git a/packages/stream_chat_persistence/test/src/mapper/read_mapper_test.dart b/packages/stream_chat_persistence/test/src/mapper/read_mapper_test.dart new file mode 100644 index 00000000..73c87da3 --- /dev/null +++ b/packages/stream_chat_persistence/test/src/mapper/read_mapper_test.dart @@ -0,0 +1,41 @@ +import 'package:test/test.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:stream_chat_persistence/src/mapper/read_mapper.dart'; + +import '../utils/date_matcher.dart'; + +void main() { + test('toRead should map entity into Read', () { + const cid = 'testCid'; + final user = User(id: 'testUserId'); + final entity = ReadEntity( + lastRead: DateTime.now(), + userId: user.id, + channelCid: cid, + unreadMessages: 33, + ); + + final read = entity.toRead(user: user); + expect(read, isA()); + expect(read.lastRead, isSameDateAs(entity.lastRead)); + expect(read.user.id, entity.userId); + expect(read.unreadMessages, entity.unreadMessages); + }); + + test('toEntity should map read into ReadEntity', () { + const cid = 'testCid'; + final user = User(id: 'testUserId'); + final read = Read( + lastRead: DateTime.now(), + user: user, + unreadMessages: 33, + ); + + final entity = read.toEntity(cid: cid); + expect(entity, isA()); + expect(entity.lastRead, isSameDateAs(read.lastRead)); + expect(entity.userId, read.user.id); + expect(entity.unreadMessages, read.unreadMessages); + }); +} From 2233528609e7a6a031522a5945d0d0c5815fb56c Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 17 Mar 2021 17:48:39 +0530 Subject: [PATCH 25/50] test(persistence): add tests for user mapper Signed-off-by: Sahil Kumar --- .../test/src/mapper/user_mapper_test.dart | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 packages/stream_chat_persistence/test/src/mapper/user_mapper_test.dart diff --git a/packages/stream_chat_persistence/test/src/mapper/user_mapper_test.dart b/packages/stream_chat_persistence/test/src/mapper/user_mapper_test.dart new file mode 100644 index 00000000..5e40f237 --- /dev/null +++ b/packages/stream_chat_persistence/test/src/mapper/user_mapper_test.dart @@ -0,0 +1,55 @@ +import 'dart:math' as math; +import 'package:test/test.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:stream_chat_persistence/src/mapper/user_mapper.dart'; + +import '../utils/date_matcher.dart'; + +void main() { + test('toUser should map entity into User', () { + final entity = UserEntity( + id: 'testUserId', + role: 'testType', + createdAt: DateTime.now(), + updatedAt: DateTime.now(), + lastActive: DateTime.now(), + online: math.Random().nextBool(), + banned: math.Random().nextBool(), + extraData: {'test_extra_data': 'extraData'}, + ); + final user = entity.toUser(); + expect(user, isA()); + expect(user.id, entity.id); + expect(user.role, entity.role); + expect(user.createdAt, isSameDateAs(entity.createdAt)); + expect(user.updatedAt, isSameDateAs(entity.updatedAt)); + expect(user.lastActive, isSameDateAs(entity.lastActive)); + expect(user.online, entity.online); + expect(user.banned, entity.banned); + expect(user.extraData, entity.extraData); + }); + + test('toEntity should map user into UserEntity', () { + final user = User( + id: 'testUserId', + role: 'testType', + createdAt: DateTime.now(), + updatedAt: DateTime.now(), + lastActive: DateTime.now(), + online: math.Random().nextBool(), + banned: math.Random().nextBool(), + extraData: {'test_extra_data': 'extraData'}, + ); + final entity = user.toEntity(); + expect(entity, isA()); + expect(entity.id, user.id); + expect(entity.role, user.role); + expect(entity.createdAt, isSameDateAs(user.createdAt)); + expect(entity.updatedAt, isSameDateAs(user.updatedAt)); + expect(entity.lastActive, isSameDateAs(user.lastActive)); + expect(entity.online, user.online); + expect(entity.banned, user.banned); + expect(entity.extraData, user.extraData); + }); +} From 827e6a5dbd45823ed821a087838679f91a726b20 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 17 Mar 2021 19:52:40 +0530 Subject: [PATCH 26/50] refactor(persistence): remove redundant UsersTable getter from ConnectionEventDao Signed-off-by: Sahil Kumar --- .../lib/src/dao/connection_event_dao.dart | 3 +-- .../lib/src/dao/connection_event_dao.g.dart | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.dart b/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.dart index 94b0d333..50528bd2 100644 --- a/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.dart @@ -2,14 +2,13 @@ import 'package:moor/moor.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; import 'package:stream_chat_persistence/src/entity/connection_events.dart'; -import 'package:stream_chat_persistence/src/entity/users.dart'; import 'package:stream_chat_persistence/src/mapper/mapper.dart'; part 'connection_event_dao.g.dart'; /// The Data Access Object for operations in [ConnectionEvents] table. -@UseDao(tables: [ConnectionEvents, Users]) +@UseDao(tables: [ConnectionEvents]) class ConnectionEventDao extends DatabaseAccessor with _$ConnectionEventDaoMixin { /// Creates a new connection event dao instance diff --git a/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.g.dart b/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.g.dart index a8245982..28eb0913 100644 --- a/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.g.dart +++ b/packages/stream_chat_persistence/lib/src/dao/connection_event_dao.g.dart @@ -9,5 +9,4 @@ part of 'connection_event_dao.dart'; mixin _$ConnectionEventDaoMixin on DatabaseAccessor { $ConnectionEventsTable get connectionEvents => attachedDatabase.connectionEvents; - $UsersTable get users => attachedDatabase.users; } From f992bfe6989d5437fe603f2b807795e7e1433ff8 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 18 Mar 2021 14:33:42 +0100 Subject: [PATCH 27/50] fix ci --- .github/workflows/dispatch_workflows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dispatch_workflows.yml b/.github/workflows/dispatch_workflows.yml index 5743a0aa..6d626fdb 100644 --- a/.github/workflows/dispatch_workflows.yml +++ b/.github/workflows/dispatch_workflows.yml @@ -20,7 +20,7 @@ jobs: repo: GetStream/flutter-samples token: ${{ secrets.GH_TOKEN }} dispatch_stable: - if: github.ref == 'refs/heads/master' + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest steps: - uses: benc-uk/workflow-dispatch@v1 From bea545b154f752497f7227f7f3f105fd446f68d5 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 18 Mar 2021 20:38:26 +0530 Subject: [PATCH 28/50] test(persistence): add tests for stream chat persistence client Signed-off-by: Sahil Kumar --- .../lib/src/db/moor_chat_database.dart | 21 +- .../lib/src/db/shared/native_db.dart | 58 +- .../lib/src/db/shared/unsupported_db.dart | 22 +- .../lib/src/db/shared/web_db.dart | 22 +- .../src/stream_chat_persistence_client.dart | 53 +- packages/stream_chat_persistence/pubspec.yaml | 5 +- .../test/mock_chat_database.dart | 71 +++ .../stream_chat_persistence_client_test.dart | 27 - .../stream_chat_persistence_client_test.dart | 524 ++++++++++++++++++ 9 files changed, 662 insertions(+), 141 deletions(-) create mode 100644 packages/stream_chat_persistence/test/mock_chat_database.dart delete mode 100644 packages/stream_chat_persistence/test/src/stream_chat_persistence_client_test.dart create mode 100644 packages/stream_chat_persistence/test/stream_chat_persistence_client_test.dart diff --git a/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart b/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart index 2edaed4f..73c7b0fa 100644 --- a/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart +++ b/packages/stream_chat_persistence/lib/src/db/moor_chat_database.dart @@ -6,19 +6,11 @@ import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_persistence/src/converter/converter.dart'; import 'package:stream_chat_persistence/src/dao/dao.dart'; import 'package:stream_chat_persistence/src/entity/entity.dart'; -import 'package:stream_chat_persistence/src/db/shared/shared_db.dart'; + +export 'shared/shared_db.dart'; part 'moor_chat_database.g.dart'; -LazyDatabase _openConnection( - String userId, { - bool logStatements = false, -}) => - LazyDatabase(() async => SharedDB.constructDatabase( - userId, - logStatements: logStatements, - )); - /// A chat database implemented using moor @UseMoor(tables: [ Channels, @@ -44,12 +36,9 @@ LazyDatabase _openConnection( class MoorChatDatabase extends _$MoorChatDatabase { /// Creates a new moor chat database instance MoorChatDatabase( - this._userId, { - logStatements = false, - }) : super(_openConnection( - _userId, - logStatements: logStatements, - )); + this._userId, + QueryExecutor executor, + ) : super(executor); /// Instantiate a new database instance MoorChatDatabase.connect( diff --git a/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart b/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart index a3b1ce8e..0868ad69 100644 --- a/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart +++ b/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart @@ -14,15 +14,40 @@ import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; /// A Helper class to construct new instances of [MoorChatDatabase] specifically /// for native platform applications class SharedDB { - /// Returns a new instance of [VmDatabase] created using [userId] - /// on a regular isolate. - /// - /// Generally used with [ConnectionMode.regular]. - static Future constructDatabase( + /// Returns a new instance of [MoorChatDatabase]. + static MoorChatDatabase constructDatabase( String userId, { bool logStatements = false, - }) async { + ConnectionMode connectionMode = ConnectionMode.regular, + }) { final dbName = 'db_$userId'; + if (connectionMode == ConnectionMode.background) { + return MoorChatDatabase.connect( + userId, + DatabaseConnection.delayed(Future(() async { + final isolate = await _createMoorIsolate( + dbName, + logStatements: logStatements, + ); + return isolate.connect(); + })), + ); + } + return MoorChatDatabase( + userId, + LazyDatabase( + () async => _constructDatabase( + dbName, + logStatements: logStatements, + ), + ), + ); + } + + static Future _constructDatabase( + String dbName, { + bool logStatements = false, + }) async { if (Platform.isIOS || Platform.isAndroid) { final dir = await getApplicationDocumentsDirectory(); final path = join(dir.path, '$dbName.sqlite'); @@ -66,27 +91,6 @@ class SharedDB { return await receivePort.first as MoorIsolate; } - - /// Returns a new instance of [MoorChatDatabase] using the factory constructor - /// [MoorChatDatabase.connect] created on a background isolate. - /// - /// Generally used with [ConnectionMode.background]. - static MoorChatDatabase constructMoorChatDatabase( - String userId, { - bool logStatements = false, - }) { - final dbName = 'db_$userId'; - return MoorChatDatabase.connect( - userId, - DatabaseConnection.delayed(Future(() async { - final isolate = await _createMoorIsolate( - dbName, - logStatements: logStatements, - ); - return isolate.connect(); - })), - ); - } } class _IsolateStartRequest { diff --git a/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart b/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart index 15734a7c..e2877030 100644 --- a/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart +++ b/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart @@ -1,28 +1,16 @@ -import 'package:moor/backends.dart'; import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; import 'package:stream_chat_persistence/stream_chat_persistence.dart'; /// A Helper class to construct new instances of [MoorChatDatabase] class SharedDB { - /// Returns a new instance of database. - /// - /// Generally used with [ConnectionMode.regular]. - static Future constructDatabase( + /// Returns a new instance of [MoorChatDatabase]. + static MoorChatDatabase constructDatabase( String userId, { bool logStatements = false, + ConnectionMode connectionMode = ConnectionMode.regular, }) { throw UnsupportedError( - 'No implementation of the constructDatabase api provided'); - } - - /// Return a new instance of moor chat database. - /// - /// Generally used with [ConnectionMode.background]. - static MoorChatDatabase constructMoorChatDatabase( - String userId, { - bool logStatements = false, - }) { - throw UnsupportedError( - 'No implementation of the constructMoorChatDatabase api provided'); + 'No implementation of the constructDatabase api provided', + ); } } diff --git a/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart b/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart index 7388543e..9c504a11 100644 --- a/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart +++ b/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart @@ -6,26 +6,14 @@ import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; /// A Helper class to construct new instances of [MoorChatDatabase] specifically /// for Web applications class SharedDB { - /// Returns a new instance of [WebDatabase] created using [userId]. - /// - /// Generally used with [ConnectionMode.regular]. - static Future constructDatabase( - String userId, { - bool logStatements = false, - }) async { - final dbName = 'db_$userId'; - return WebDatabase(dbName, logStatements: logStatements); - } - - /// Returns a new instance of [MoorChatDatabase] creating using the - /// default constructor. - /// - /// Generally used with [ConnectionMode.background]. - static MoorChatDatabase constructMoorChatDatabase( + /// Returns a new instance of [MoorChatDatabase]. + static MoorChatDatabase constructDatabase( String userId, { bool logStatements = false, + ConnectionMode connectionMode = ConnectionMode.regular, // Ignored on web }) { final dbName = 'db_$userId'; - return MoorChatDatabase(dbName, logStatements: logStatements); + final queryExecutor = WebDatabase(dbName, logStatements: logStatements); + return MoorChatDatabase(userId, queryExecutor); } } diff --git a/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart index e7ee060b..2c9d28fb 100644 --- a/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart +++ b/packages/stream_chat_persistence/lib/src/stream_chat_persistence_client.dart @@ -4,7 +4,6 @@ import 'package:mutex/mutex.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; -import 'package:stream_chat_persistence/src/db/shared/shared_db.dart'; /// Various connection modes on which [StreamChatPersistenceClient] can work enum ConnectionMode { @@ -15,6 +14,9 @@ enum ConnectionMode { background, } +/// Signature for a function which provides instance of [MoorChatDatabase] +typedef DatabaseProvider = MoorChatDatabase Function(String, ConnectionMode); + final _levelEmojiMapper = { Level.INFO: 'ℹ️', Level.WARNING: '⚠️', @@ -36,26 +38,6 @@ class StreamChatPersistenceClient extends ChatPersistenceClient { _logger.onRecord.listen(logHandlerFunction ?? _defaultLogHandler); } - /// A function that has a parameter of type [LogRecord]. - /// This is called on every new log record. - /// By default the client will use the handler returned by - /// [_getDefaultLogHandler]. - /// Setting it you can handle the log messages directly instead of have them - /// written to stdout, - /// this is very convenient if you use an error tracking tool or if you want - /// to centralize your logs into one facility. - /// - /// ```dart - /// myLogHandlerFunction = (LogRecord record) { - /// // do something with the record (ie. send it to Sentry or Fabric) - /// } - /// - /// final client = StreamChatPersistenceClient( - /// logHandlerFunction: myLogHandlerFunction, - /// ); - ///``` - LogHandlerFunction logHandlerFunction; - /// [MoorChatDatabase] instance used by this client. @visibleForTesting MoorChatDatabase db; @@ -84,24 +66,25 @@ class StreamChatPersistenceClient extends ChatPersistenceClient { return ret; } + MoorChatDatabase _defaultDatabaseProvider( + String userId, + ConnectionMode mode, + ) => + SharedDB.constructDatabase(userId, connectionMode: mode); + @override - Future connect(String userId) async { + Future connect( + String userId, { + DatabaseProvider databaseProvider, // Used only for testing + }) async { if (db != null) { throw Exception( 'An instance of StreamChatDatabase is already connected.\n' 'disconnect the previous instance before connecting again.', ); } - switch (_connectionMode) { - case ConnectionMode.regular: - _logger.info('Connecting on a regular isolate'); - db = MoorChatDatabase(userId); - return; - case ConnectionMode.background: - _logger.info('Connecting on background isolate'); - db = SharedDB.constructMoorChatDatabase(userId); - return; - } + db = databaseProvider?.call(userId, _connectionMode) ?? + _defaultDatabaseProvider(userId, _connectionMode); } @override @@ -259,9 +242,9 @@ class StreamChatPersistenceClient extends ChatPersistenceClient { @override Future updateChannelQueries( Map filter, - List cids, - bool clearQueryCache, - ) => + List cids, { + bool clearQueryCache = false, + }) => _readProtected(() async { _logger.info('updateChannelQueries'); return db.channelQueryDao.updateChannelQueries( diff --git a/packages/stream_chat_persistence/pubspec.yaml b/packages/stream_chat_persistence/pubspec.yaml index 8b235710..5328e1a2 100644 --- a/packages/stream_chat_persistence/pubspec.yaml +++ b/packages/stream_chat_persistence/pubspec.yaml @@ -27,6 +27,7 @@ dependency_overrides: path: ../stream_chat dev_dependencies: - test: ^1.15.7 build_runner: ^1.11.0 - moor_generator: ^3.4.1 \ No newline at end of file + mockito: ^4.1.3 + moor_generator: ^3.4.1 + test: ^1.15.7 diff --git a/packages/stream_chat_persistence/test/mock_chat_database.dart b/packages/stream_chat_persistence/test/mock_chat_database.dart new file mode 100644 index 00000000..a60bd39b --- /dev/null +++ b/packages/stream_chat_persistence/test/mock_chat_database.dart @@ -0,0 +1,71 @@ +import 'package:mockito/mockito.dart'; +import 'package:stream_chat_persistence/src/dao/dao.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; + +class MockChatDatabase extends Mock implements MoorChatDatabase { + UserDao _userDao; + + @override + UserDao get userDao => _userDao ??= MockUserDao(); + + ChannelDao _channelDao; + + @override + ChannelDao get channelDao => _channelDao ??= MockChannelDao(); + + MessageDao _messageDao; + + @override + MessageDao get messageDao => _messageDao ??= MockMessageDao(); + + PinnedMessageDao _pinnedMessageDao; + + @override + PinnedMessageDao get pinnedMessageDao => + _pinnedMessageDao ??= MockPinnedMessageDao(); + + MemberDao _memberDao; + + @override + MemberDao get memberDao => _memberDao ??= MockMemberDao(); + + ReactionDao _reactionDao; + + @override + ReactionDao get reactionDao => _reactionDao ??= MockReactionDao(); + + ReadDao _readDao; + + @override + ReadDao get readDao => _readDao ??= MockReadDao(); + + ChannelQueryDao _channelQueryDao; + + @override + ChannelQueryDao get channelQueryDao => + _channelQueryDao ??= MockChannelQueryDao(); + + ConnectionEventDao _connectionEventDao; + + @override + ConnectionEventDao get connectionEventDao => + _connectionEventDao ??= MockConnectionEventDao(); +} + +class MockUserDao extends Mock implements UserDao {} + +class MockChannelDao extends Mock implements ChannelDao {} + +class MockMessageDao extends Mock implements MessageDao {} + +class MockPinnedMessageDao extends Mock implements PinnedMessageDao {} + +class MockMemberDao extends Mock implements MemberDao {} + +class MockReactionDao extends Mock implements ReactionDao {} + +class MockReadDao extends Mock implements ReadDao {} + +class MockChannelQueryDao extends Mock implements ChannelQueryDao {} + +class MockConnectionEventDao extends Mock implements ConnectionEventDao {} diff --git a/packages/stream_chat_persistence/test/src/stream_chat_persistence_client_test.dart b/packages/stream_chat_persistence/test/src/stream_chat_persistence_client_test.dart deleted file mode 100644 index 561ca04d..00000000 --- a/packages/stream_chat_persistence/test/src/stream_chat_persistence_client_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:stream_chat/stream_chat.dart'; -import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; -import 'package:stream_chat_persistence/src/stream_chat_persistence_client.dart'; -import 'package:test/test.dart'; - -void main() { - group('connect', () { - test('throws exception because already connected', () { - final streamChatPersistenceClient = StreamChatPersistenceClient( - connectionMode: ConnectionMode.background, - logLevel: Level.INFO, - )..db = MoorChatDatabase( - 'test', - persistOnDisk: false, - ); - - expect( - () => streamChatPersistenceClient.connect('test'), - throwsA(allOf(isException, predicate((e) { - return e.message == - 'An instance of StreamChatDatabase is already connected.\n' - 'disconnect the previous instance before connecting again.'; - }))), - ); - }); - }); -} diff --git a/packages/stream_chat_persistence/test/stream_chat_persistence_client_test.dart b/packages/stream_chat_persistence/test/stream_chat_persistence_client_test.dart new file mode 100644 index 00000000..ef7fd020 --- /dev/null +++ b/packages/stream_chat_persistence/test/stream_chat_persistence_client_test.dart @@ -0,0 +1,524 @@ +import 'package:mockito/mockito.dart'; +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:stream_chat_persistence/src/stream_chat_persistence_client.dart'; +import 'package:test/test.dart'; +import 'mock_chat_database.dart'; +import 'src/utils/date_matcher.dart'; + +MoorChatDatabase _testDatabaseProvider(String userId, ConnectionMode mode) => + MoorChatDatabase.testable(userId); + +void main() { + group('connect', () { + const userId = 'testUserId'; + test('successfully connects with the Database', () async { + final client = StreamChatPersistenceClient(logLevel: Level.ALL); + expect(client.db, isNull); + await client.connect(userId, databaseProvider: _testDatabaseProvider); + expect(client.db, isNotNull); + expect(client.db, isA()); + expect(client.db.userId, userId); + + addTearDown(() async { + await client.disconnect(); + }); + }); + + test('throws if already connected', () async { + final client = StreamChatPersistenceClient(logLevel: Level.ALL); + expect(client.db, isNull); + await client.connect(userId, databaseProvider: _testDatabaseProvider); + expect(client.db, isNotNull); + expect(client.db, isNotNull); + expect(client.db, isA()); + expect(client.db.userId, userId); + expect( + () => client.connect(userId, databaseProvider: _testDatabaseProvider), + throwsException, + ); + + addTearDown(() async { + await client.disconnect(); + }); + }); + }); + + test('disconnect', () async { + const userId = 'testUserId'; + final client = StreamChatPersistenceClient(logLevel: Level.ALL); + await client.connect(userId, databaseProvider: _testDatabaseProvider); + expect(client.db, isNotNull); + await client.disconnect(flush: true); + expect(client.db, isNull); + }); + + group('client functions', () { + const userId = 'testUserId'; + final mockDatabase = MockChatDatabase(); + MoorChatDatabase _mockDatabaseProvider(_, __) => mockDatabase; + StreamChatPersistenceClient client; + + setUp(() async { + client = StreamChatPersistenceClient(logLevel: Level.ALL); + await client.connect(userId, databaseProvider: _mockDatabaseProvider); + }); + + test('getReplies', () async { + const parentId = 'testParentId'; + final replies = List.generate(3, (index) => Message(id: 'testId$index')); + + when(mockDatabase.messageDao.getThreadMessagesByParentId(parentId)) + .thenAnswer((_) async => replies); + + final fetchedReplies = await client.getReplies(parentId); + expect(fetchedReplies.length, replies.length); + verify(mockDatabase.messageDao.getThreadMessagesByParentId(parentId)) + .called(1); + }); + + test('getConnectionInfo', () async { + final event = Event(type: 'testEvent'); + when(mockDatabase.connectionEventDao.connectionEvent) + .thenAnswer((_) async => event); + + final fetchedEvent = await client.getConnectionInfo(); + expect(fetchedEvent.type, event.type); + verify(mockDatabase.connectionEventDao.connectionEvent).called(1); + }); + + test('getLastSyncAt', () async { + final lastSync = DateTime.now(); + when(mockDatabase.connectionEventDao.lastSyncAt) + .thenAnswer((_) async => lastSync); + + final fetchedLastSync = await client.getLastSyncAt(); + expect(fetchedLastSync, isSameDateAs(lastSync)); + verify(mockDatabase.connectionEventDao.lastSyncAt).called(1); + }); + + test('updateConnectionInfo', () async { + final event = Event(type: 'testEvent'); + when(mockDatabase.connectionEventDao.updateConnectionEvent(event)) + .thenAnswer((_) async { + return; + }); + + await client.updateConnectionInfo(event); + verify(mockDatabase.connectionEventDao.updateConnectionEvent(event)) + .called(1); + }); + + test('updateLastSyncAt', () async { + final lastSync = DateTime.now(); + when(mockDatabase.connectionEventDao.updateLastSyncAt(lastSync)) + .thenAnswer((_) { + return; + }); + + await client.updateLastSyncAt(lastSync); + verify(mockDatabase.connectionEventDao.updateLastSyncAt(lastSync)) + .called(1); + }); + + test('getChannelCids', () async { + final channelCids = List.generate(3, (index) => 'testCid$index'); + when(mockDatabase.channelDao.cids).thenAnswer((_) async => channelCids); + + final fetchedChannelCids = await client.getChannelCids(); + expect(fetchedChannelCids.length, channelCids.length); + verify(mockDatabase.channelDao.cids).called(1); + }); + + test('getChannelByCid', () async { + const cid = 'testCid'; + final channelModel = ChannelModel(cid: cid); + when(mockDatabase.channelDao.getChannelByCid(cid)) + .thenAnswer((_) async => channelModel); + + final fetchedChannelModel = await client.getChannelByCid(cid); + expect(fetchedChannelModel.cid, channelModel.cid); + verify(mockDatabase.channelDao.getChannelByCid(cid)).called(1); + }); + + test('getMembersByCid', () async { + const cid = 'testCid'; + final members = List.generate(3, (index) => Member()); + when(mockDatabase.memberDao.getMembersByCid(cid)) + .thenAnswer((_) async => members); + + final fetchedMembers = await client.getMembersByCid(cid); + expect(fetchedMembers.length, members.length); + verify(mockDatabase.memberDao.getMembersByCid(cid)).called(1); + }); + + test('getReadsByCid', () async { + const cid = 'testCid'; + final reads = List.generate(3, (index) => Read()); + when(mockDatabase.readDao.getReadsByCid(cid)) + .thenAnswer((_) async => reads); + + final fetchedReads = await client.getReadsByCid(cid); + expect(fetchedReads.length, reads.length); + verify(mockDatabase.readDao.getReadsByCid(cid)).called(1); + }); + + test('getMessagesByCid', () async { + const cid = 'testCid'; + final messages = List.generate(3, (index) => Message()); + when(mockDatabase.messageDao.getMessagesByCid(cid)) + .thenAnswer((_) async => messages); + + final fetchedMessages = await client.getMessagesByCid(cid); + expect(fetchedMessages.length, messages.length); + verify(mockDatabase.messageDao.getMessagesByCid(cid)).called(1); + }); + + test('getPinnedMessagesByCid', () async { + const cid = 'testCid'; + final messages = List.generate(3, (index) => Message()); + when(mockDatabase.pinnedMessageDao.getMessagesByCid(cid)) + .thenAnswer((_) async => messages); + + final fetchedMessages = await client.getPinnedMessagesByCid(cid); + expect(fetchedMessages.length, messages.length); + verify(mockDatabase.pinnedMessageDao.getMessagesByCid(cid)).called(1); + }); + + test('getChannelStateByCid', () async { + const cid = 'testCid'; + final messages = List.generate(3, (index) => Message()); + final members = List.generate(3, (index) => Member()); + final reads = List.generate(3, (index) => Read()); + final channel = ChannelModel(cid: cid); + + when(mockDatabase.memberDao.getMembersByCid(cid)) + .thenAnswer((_) async => members); + when(mockDatabase.readDao.getReadsByCid(cid)) + .thenAnswer((_) async => reads); + when(mockDatabase.channelDao.getChannelByCid(cid)) + .thenAnswer((_) async => channel); + when(mockDatabase.messageDao.getMessagesByCid(cid)) + .thenAnswer((_) async => messages); + when(mockDatabase.pinnedMessageDao.getMessagesByCid(cid)) + .thenAnswer((_) async => messages); + + final fetchedChannelState = await client.getChannelStateByCid(cid); + expect(fetchedChannelState.messages.length, messages.length); + expect(fetchedChannelState.pinnedMessages.length, messages.length); + expect(fetchedChannelState.members.length, members.length); + expect(fetchedChannelState.read.length, reads.length); + expect(fetchedChannelState.channel.cid, channel.cid); + + verify(mockDatabase.memberDao.getMembersByCid(cid)).called(1); + verify(mockDatabase.readDao.getReadsByCid(cid)).called(1); + verify(mockDatabase.channelDao.getChannelByCid(cid)).called(1); + verify(mockDatabase.messageDao.getMessagesByCid(cid)).called(1); + verify(mockDatabase.pinnedMessageDao.getMessagesByCid(cid)).called(1); + }); + + test('getChannelStates', () async { + const cid = 'testCid'; + final channels = List.generate(3, (index) => ChannelModel(cid: cid)); + final messages = List.generate(3, (index) => Message()); + final members = List.generate(3, (index) => Member()); + final reads = List.generate(3, (index) => Read()); + final channel = ChannelModel(cid: cid); + final channelStates = channels + .map( + (channel) => ChannelState( + channel: channel, + messages: messages, + pinnedMessages: messages, + members: members, + read: reads, + ), + ) + .toList(growable: false); + + when(mockDatabase.channelQueryDao.getChannels()) + .thenAnswer((_) async => channels); + when(mockDatabase.memberDao.getMembersByCid(cid)) + .thenAnswer((_) async => members); + when(mockDatabase.readDao.getReadsByCid(cid)) + .thenAnswer((_) async => reads); + when(mockDatabase.channelDao.getChannelByCid(cid)) + .thenAnswer((_) async => channel); + when(mockDatabase.messageDao.getMessagesByCid(cid)) + .thenAnswer((_) async => messages); + when(mockDatabase.pinnedMessageDao.getMessagesByCid(cid)) + .thenAnswer((_) async => messages); + + final fetchedChannelStates = await client.getChannelStates(); + expect(fetchedChannelStates.length, channelStates.length); + + for (var i = 0; i < fetchedChannelStates.length; i++) { + final original = channelStates[i]; + final fetched = fetchedChannelStates[i]; + expect(fetched.members.length, original.members.length); + expect(fetched.messages.length, original.messages.length); + expect(fetched.pinnedMessages.length, original.pinnedMessages.length); + expect(fetched.read.length, original.read.length); + expect(fetched.channel.cid, original.channel.cid); + } + + verify(mockDatabase.channelQueryDao.getChannels()).called(1); + verify(mockDatabase.memberDao.getMembersByCid(cid)).called(3); + verify(mockDatabase.readDao.getReadsByCid(cid)).called(3); + verify(mockDatabase.channelDao.getChannelByCid(cid)).called(3); + verify(mockDatabase.messageDao.getMessagesByCid(cid)).called(3); + verify(mockDatabase.pinnedMessageDao.getMessagesByCid(cid)).called(3); + }); + + test('updateChannelQueries', () async { + const filter = {}; + const cids = []; + when(mockDatabase.channelQueryDao.updateChannelQueries(filter, cids)) + .thenAnswer((realInvocation) async { + return; + }); + + await client.updateChannelQueries(filter, cids); + verify(mockDatabase.channelQueryDao.updateChannelQueries(filter, cids)) + .called(1); + }); + + test('deleteMessageById', () async { + const messageId = 'testMessageId'; + when(mockDatabase.messageDao.deleteMessageByIds([messageId])) + .thenAnswer((_) async { + return; + }); + + await client.deleteMessageById(messageId); + verify(mockDatabase.messageDao.deleteMessageByIds([messageId])).called(1); + }); + + test('deletePinnedMessageById', () async { + const messageId = 'testMessageId'; + when(mockDatabase.pinnedMessageDao.deleteMessageByIds([messageId])) + .thenAnswer((_) async { + return; + }); + + await client.deletePinnedMessageById(messageId); + verify(mockDatabase.pinnedMessageDao.deleteMessageByIds([messageId])) + .called(1); + }); + + test('deleteMessageByIds', () async { + const messageIds = []; + when(mockDatabase.messageDao.deleteMessageByIds(messageIds)) + .thenAnswer((_) async { + return; + }); + + await client.deleteMessageByIds(messageIds); + verify(mockDatabase.messageDao.deleteMessageByIds(messageIds)).called(1); + }); + + test('deletePinnedMessageByIds', () async { + const messageIds = []; + when(mockDatabase.pinnedMessageDao.deleteMessageByIds(messageIds)) + .thenAnswer((_) async { + return; + }); + + await client.deletePinnedMessageByIds(messageIds); + verify(mockDatabase.pinnedMessageDao.deleteMessageByIds(messageIds)) + .called(1); + }); + + test('deleteMessageByCid', () async { + const cid = 'testCid'; + when(mockDatabase.messageDao.deleteMessageByCids([cid])) + .thenAnswer((_) async { + return; + }); + + await client.deleteMessageByCid(cid); + verify(mockDatabase.messageDao.deleteMessageByCids([cid])).called(1); + }); + + test('deletePinnedMessageByCid', () async { + const cid = 'testCid'; + when(mockDatabase.pinnedMessageDao.deleteMessageByCids([cid])) + .thenAnswer((_) async { + return; + }); + + await client.deletePinnedMessageByCid(cid); + verify(mockDatabase.pinnedMessageDao.deleteMessageByCids([cid])) + .called(1); + }); + + test('deleteMessageByCids', () async { + const cids = []; + when(mockDatabase.messageDao.deleteMessageByCids(cids)) + .thenAnswer((_) async { + return; + }); + + await client.deleteMessageByCids(cids); + verify(mockDatabase.messageDao.deleteMessageByCids(cids)).called(1); + }); + + test('deletePinnedMessageByCids', () async { + const cids = []; + when(mockDatabase.pinnedMessageDao.deleteMessageByCids(cids)) + .thenAnswer((_) async { + return; + }); + + await client.deletePinnedMessageByCids(cids); + verify(mockDatabase.pinnedMessageDao.deleteMessageByCids(cids)).called(1); + }); + + test('deleteChannels', () async { + const cids = []; + when(mockDatabase.channelDao.deleteChannelByCids(cids)) + .thenAnswer((_) async { + return; + }); + + await client.deleteChannels(cids); + verify(mockDatabase.channelDao.deleteChannelByCids(cids)).called(1); + }); + + test('updateMessages', () async { + const cid = 'testCid'; + final messages = List.generate(3, (index) => Message()); + when(mockDatabase.messageDao.updateMessages(cid, messages)) + .thenAnswer((_) async { + return; + }); + + await client.updateMessages(cid, messages); + verify(mockDatabase.messageDao.updateMessages(cid, messages)).called(1); + }); + + test('updatePinnedMessages', () async { + const cid = 'testCid'; + final messages = List.generate(3, (index) => Message()); + when(mockDatabase.pinnedMessageDao.updateMessages(cid, messages)) + .thenAnswer((_) async { + return; + }); + + await client.updatePinnedMessages(cid, messages); + verify(mockDatabase.pinnedMessageDao.updateMessages(cid, messages)) + .called(1); + }); + + test('getChannelThreads', () async { + const cid = 'testCid'; + final messages = + List.generate(3, (index) => Message(parentId: 'testParentId$index')); + final threads = messages.fold>>( + {}, + (prev, curr) { + return prev + ..update( + curr.parentId, + (value) => [...value, curr], + ifAbsent: () => [], + ); + }, + ); + when(mockDatabase.messageDao.getThreadMessages(cid)) + .thenAnswer((realInvocation) async => messages); + + final fetchedThreads = await client.getChannelThreads(cid); + expect(fetchedThreads.length, threads.length); + for (var i = 0; i < fetchedThreads.length; i++) { + final original = threads.entries.elementAt(i); + final fetched = fetchedThreads.entries.elementAt(i); + expect(fetched.key, original.key); + } + + verify(mockDatabase.messageDao.getThreadMessages(cid)).called(1); + }); + + test('updateChannels', () async { + final channels = List.generate(3, (index) => ChannelModel()); + when(mockDatabase.channelDao.updateChannels(channels)) + .thenAnswer((_) async { + return; + }); + + await client.updateChannels(channels); + verify(mockDatabase.channelDao.updateChannels(channels)).called(1); + }); + + test('updateMembers', () async { + const cid = 'testCid'; + final members = List.generate(3, (index) => Member()); + when(mockDatabase.memberDao.updateMembers(cid, members)) + .thenAnswer((_) async { + return; + }); + + await client.updateMembers(cid, members); + verify(mockDatabase.memberDao.updateMembers(cid, members)).called(1); + }); + + test('updateReads', () async { + const cid = 'testCid'; + final reads = List.generate(3, (index) => Read()); + when(mockDatabase.readDao.updateReads(cid, reads)).thenAnswer((_) async { + return; + }); + + await client.updateReads(cid, reads); + verify(mockDatabase.readDao.updateReads(cid, reads)).called(1); + }); + + test('updateUsers', () async { + final users = List.generate(3, (index) => User()); + when(mockDatabase.userDao.updateUsers(users)).thenAnswer((_) async { + return; + }); + + await client.updateUsers(users); + verify(mockDatabase.userDao.updateUsers(users)).called(1); + }); + + test('updateReactions', () async { + final reactions = List.generate(3, (index) => Reaction()); + when(mockDatabase.reactionDao.updateReactions(reactions)) + .thenAnswer((_) async { + return; + }); + + await client.updateReactions(reactions); + verify(mockDatabase.reactionDao.updateReactions(reactions)).called(1); + }); + + test('deleteReactionsByMessageId', () async { + final messageIds = []; + when(mockDatabase.reactionDao.deleteReactionsByMessageIds(messageIds)) + .thenAnswer((_) async { + return; + }); + + await client.deleteReactionsByMessageId(messageIds); + verify(mockDatabase.reactionDao.deleteReactionsByMessageIds(messageIds)) + .called(1); + }); + + test('deleteMembersByCids', () async { + final cids = []; + when(mockDatabase.memberDao.deleteMemberByCids(cids)) + .thenAnswer((_) async { + return; + }); + + await client.deleteMembersByCids(cids); + verify(mockDatabase.memberDao.deleteMemberByCids(cids)).called(1); + }); + + tearDown(() async { + await client.disconnect(flush: true); + }); + }); +} From 66edb127368a775afc14ed961f300e1bae9e4290 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 19 Mar 2021 14:35:46 +0530 Subject: [PATCH 29/50] test(persistence): add tests moor chat database Signed-off-by: Sahil Kumar --- .../test/src/db/moor_chat_database_test.dart | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 packages/stream_chat_persistence/test/src/db/moor_chat_database_test.dart diff --git a/packages/stream_chat_persistence/test/src/db/moor_chat_database_test.dart b/packages/stream_chat_persistence/test/src/db/moor_chat_database_test.dart new file mode 100644 index 00000000..2ec4c76b --- /dev/null +++ b/packages/stream_chat_persistence/test/src/db/moor_chat_database_test.dart @@ -0,0 +1,43 @@ +import 'package:test/test.dart'; +import 'package:moor/ffi.dart'; +import 'package:moor/isolate.dart'; +import 'package:moor/moor.dart' hide isNotNull; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; + +DatabaseConnection _backgroundConnection() => + DatabaseConnection.fromExecutor(VmDatabase.memory()); + +void main() { + test( + 'default constructor should create a new instance of MoorChatDatabase', + () async { + const userId = 'testUserId'; + final executor = VmDatabase.memory(); + final database = MoorChatDatabase(userId, executor); + expect(database, isNotNull); + expect(database.userId, userId); + + addTearDown(() async { + await database.disconnect(); + }); + }, + ); + + test( + 'connect constructor should create a new instance of MoorChatDatabase', + () async { + const userId = 'testUserId'; + final isolate = await MoorIsolate.spawn(_backgroundConnection); + final connection = DatabaseConnection.delayed(isolate.connect()); + + final database = MoorChatDatabase.connect(userId, connection); + expect(database, isNotNull); + expect(database.userId, userId); + + addTearDown(() async { + await database.disconnect(); + await isolate.shutdownAll(); + }); + }, + ); +} From d1e3cda2ec9b4db45b8c0b586902fcb41997b504 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 19 Mar 2021 16:11:47 +0530 Subject: [PATCH 30/50] test(persistence): add moor schemas for future migration tests Signed-off-by: Sahil Kumar --- .../moor_schemas/moor_schema_v1.json | 798 ++++++++++++ .../moor_schemas/moor_schema_v2.json | 1089 +++++++++++++++++ 2 files changed, 1887 insertions(+) create mode 100644 packages/stream_chat_persistence/moor_schemas/moor_schema_v1.json create mode 100644 packages/stream_chat_persistence/moor_schemas/moor_schema_v2.json diff --git a/packages/stream_chat_persistence/moor_schemas/moor_schema_v1.json b/packages/stream_chat_persistence/moor_schemas/moor_schema_v1.json new file mode 100644 index 00000000..1a1b39a9 --- /dev/null +++ b/packages/stream_chat_persistence/moor_schemas/moor_schema_v1.json @@ -0,0 +1,798 @@ +{ + "_meta": { + "description": "This file contains a serialized version of schema entities for moor.", + "version": "0.1.0-dev-preview" + }, + "entities": [ + { + "id": 0, + "references": [], + "type": "table", + "data": { + "name": "channels", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "type", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "cid", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "config", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "MapConverter()", + "dart_type_name": "Map" + } + }, + { + "name": "frozen", + "moor_type": "ColumnType.boolean", + "nullable": false, + "customConstraints": null, + "default_dart": "Constant(false)", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_message_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "deleted_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "member_count", + "moor_type": "ColumnType.integer", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_by_id", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "extra_data", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "MapConverter()", + "dart_type_name": "Map" + } + } + ], + "is_virtual": false, + "explicit_pk": [ + "cid" + ] + } + }, + { + "id": 1, + "references": [], + "type": "table", + "data": { + "name": "messages", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "message_text", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "attachments", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "ListConverter()", + "dart_type_name": "List" + } + }, + { + "name": "status", + "moor_type": "ColumnType.integer", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "MessageSendingStatusConverter()", + "dart_type_name": "MessageSendingStatus" + } + }, + { + "name": "type", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "mentioned_users", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "ListConverter()", + "dart_type_name": "List" + } + }, + { + "name": "reaction_counts", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "MapConverter()", + "dart_type_name": "Map" + } + }, + { + "name": "reaction_scores", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "MapConverter()", + "dart_type_name": "Map" + } + }, + { + "name": "parent_id", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "quoted_message_id", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "reply_count", + "moor_type": "ColumnType.integer", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "show_in_channel", + "moor_type": "ColumnType.boolean", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "shadowed", + "moor_type": "ColumnType.boolean", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "command", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "moor_type": "ColumnType.datetime", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "deleted_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "user_id", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "channel_cid", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": "NULLABLE REFERENCES channels(cid) ON DELETE CASCADE", + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "extra_data", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "MapConverter()", + "dart_type_name": "Map" + } + } + ], + "is_virtual": false, + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 2, + "references": [], + "type": "table", + "data": { + "name": "reactions", + "was_declared_in_moor": false, + "columns": [ + { + "name": "user_id", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "message_id", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": "REFERENCES messages(id) ON DELETE CASCADE", + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "type", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "moor_type": "ColumnType.datetime", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "score", + "moor_type": "ColumnType.integer", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "extra_data", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "MapConverter()", + "dart_type_name": "Map" + } + } + ], + "is_virtual": false, + "explicit_pk": [ + "message_id", + "type", + "user_id" + ] + } + }, + { + "id": 3, + "references": [], + "type": "table", + "data": { + "name": "users", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "role", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_active", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "online", + "moor_type": "ColumnType.boolean", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "banned", + "moor_type": "ColumnType.boolean", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "extra_data", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "MapConverter()", + "dart_type_name": "Map" + } + } + ], + "is_virtual": false, + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 4, + "references": [], + "type": "table", + "data": { + "name": "members", + "was_declared_in_moor": false, + "columns": [ + { + "name": "user_id", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "channel_cid", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": "REFERENCES channels(cid) ON DELETE CASCADE", + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "role", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "invite_accepted_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "invite_rejected_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "invited", + "moor_type": "ColumnType.boolean", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "banned", + "moor_type": "ColumnType.boolean", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "shadow_banned", + "moor_type": "ColumnType.boolean", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_moderator", + "moor_type": "ColumnType.boolean", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "moor_type": "ColumnType.datetime", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "explicit_pk": [ + "user_id", + "channel_cid" + ] + } + }, + { + "id": 5, + "references": [], + "type": "table", + "data": { + "name": "reads", + "was_declared_in_moor": false, + "columns": [ + { + "name": "last_read", + "moor_type": "ColumnType.datetime", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "user_id", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "channel_cid", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": "REFERENCES channels(cid) ON DELETE CASCADE", + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "unread_messages", + "moor_type": "ColumnType.integer", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "explicit_pk": [ + "user_id", + "channel_cid" + ] + } + }, + { + "id": 6, + "references": [], + "type": "table", + "data": { + "name": "channel_queries", + "was_declared_in_moor": false, + "columns": [ + { + "name": "query_hash", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "channel_cid", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "explicit_pk": [ + "query_hash", + "channel_cid" + ] + } + }, + { + "id": 7, + "references": [], + "type": "table", + "data": { + "name": "connection_events", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "moor_type": "ColumnType.integer", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "own_user", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "MapConverter()", + "dart_type_name": "Map" + } + }, + { + "name": "total_unread_count", + "moor_type": "ColumnType.integer", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "unread_channels", + "moor_type": "ColumnType.integer", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_event_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_sync_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "explicit_pk": [ + "id" + ] + } + } + ] +} \ No newline at end of file diff --git a/packages/stream_chat_persistence/moor_schemas/moor_schema_v2.json b/packages/stream_chat_persistence/moor_schemas/moor_schema_v2.json new file mode 100644 index 00000000..0f1caee5 --- /dev/null +++ b/packages/stream_chat_persistence/moor_schemas/moor_schema_v2.json @@ -0,0 +1,1089 @@ +{ + "_meta": { + "description": "This file contains a serialized version of schema entities for moor.", + "version": "0.1.0-dev-preview" + }, + "entities": [ + { + "id": 0, + "references": [], + "type": "table", + "data": { + "name": "channels", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "type", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "cid", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "config", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "MapConverter()", + "dart_type_name": "Map" + } + }, + { + "name": "frozen", + "moor_type": "ColumnType.boolean", + "nullable": false, + "customConstraints": null, + "default_dart": "Constant(false)", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_message_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "deleted_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "member_count", + "moor_type": "ColumnType.integer", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_by_id", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "extra_data", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "MapConverter()", + "dart_type_name": "Map" + } + } + ], + "is_virtual": false, + "explicit_pk": [ + "cid" + ] + } + }, + { + "id": 1, + "references": [], + "type": "table", + "data": { + "name": "messages", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "message_text", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "attachments", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "ListConverter()", + "dart_type_name": "List" + } + }, + { + "name": "status", + "moor_type": "ColumnType.integer", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "MessageSendingStatusConverter()", + "dart_type_name": "MessageSendingStatus" + } + }, + { + "name": "type", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "mentioned_users", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "ListConverter()", + "dart_type_name": "List" + } + }, + { + "name": "reaction_counts", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "MapConverter()", + "dart_type_name": "Map" + } + }, + { + "name": "reaction_scores", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "MapConverter()", + "dart_type_name": "Map" + } + }, + { + "name": "parent_id", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "quoted_message_id", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "reply_count", + "moor_type": "ColumnType.integer", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "show_in_channel", + "moor_type": "ColumnType.boolean", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "shadowed", + "moor_type": "ColumnType.boolean", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "command", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "moor_type": "ColumnType.datetime", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "deleted_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "user_id", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "pinned", + "moor_type": "ColumnType.boolean", + "nullable": false, + "customConstraints": null, + "default_dart": "const Constant(false)", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "pinned_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "pin_expires", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "pinned_by_user_id", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "channel_cid", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": "NULLABLE REFERENCES channels(cid) ON DELETE CASCADE", + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "extra_data", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "MapConverter()", + "dart_type_name": "Map" + } + } + ], + "is_virtual": false, + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 2, + "references": [], + "type": "table", + "data": { + "name": "pinned_messages", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "message_text", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "attachments", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "ListConverter()", + "dart_type_name": "List" + } + }, + { + "name": "status", + "moor_type": "ColumnType.integer", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "MessageSendingStatusConverter()", + "dart_type_name": "MessageSendingStatus" + } + }, + { + "name": "type", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "mentioned_users", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "ListConverter()", + "dart_type_name": "List" + } + }, + { + "name": "reaction_counts", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "MapConverter()", + "dart_type_name": "Map" + } + }, + { + "name": "reaction_scores", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "MapConverter()", + "dart_type_name": "Map" + } + }, + { + "name": "parent_id", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "quoted_message_id", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "reply_count", + "moor_type": "ColumnType.integer", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "show_in_channel", + "moor_type": "ColumnType.boolean", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "shadowed", + "moor_type": "ColumnType.boolean", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "command", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "moor_type": "ColumnType.datetime", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "deleted_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "user_id", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "pinned", + "moor_type": "ColumnType.boolean", + "nullable": false, + "customConstraints": null, + "default_dart": "const Constant(false)", + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "pinned_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "pin_expires", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "pinned_by_user_id", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "channel_cid", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": "NULLABLE REFERENCES channels(cid) ON DELETE CASCADE", + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "extra_data", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "MapConverter()", + "dart_type_name": "Map" + } + } + ], + "is_virtual": false, + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 3, + "references": [], + "type": "table", + "data": { + "name": "reactions", + "was_declared_in_moor": false, + "columns": [ + { + "name": "user_id", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "message_id", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": "REFERENCES messages(id) ON DELETE CASCADE", + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "type", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "moor_type": "ColumnType.datetime", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "score", + "moor_type": "ColumnType.integer", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "extra_data", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "MapConverter()", + "dart_type_name": "Map" + } + } + ], + "is_virtual": false, + "explicit_pk": [ + "message_id", + "type", + "user_id" + ] + } + }, + { + "id": 4, + "references": [], + "type": "table", + "data": { + "name": "users", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "role", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_active", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "online", + "moor_type": "ColumnType.boolean", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "banned", + "moor_type": "ColumnType.boolean", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "extra_data", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "MapConverter()", + "dart_type_name": "Map" + } + } + ], + "is_virtual": false, + "explicit_pk": [ + "id" + ] + } + }, + { + "id": 5, + "references": [], + "type": "table", + "data": { + "name": "members", + "was_declared_in_moor": false, + "columns": [ + { + "name": "user_id", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "channel_cid", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": "REFERENCES channels(cid) ON DELETE CASCADE", + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "role", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "invite_accepted_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "invite_rejected_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "invited", + "moor_type": "ColumnType.boolean", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "banned", + "moor_type": "ColumnType.boolean", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "shadow_banned", + "moor_type": "ColumnType.boolean", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "is_moderator", + "moor_type": "ColumnType.boolean", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "created_at", + "moor_type": "ColumnType.datetime", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "updated_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "explicit_pk": [ + "user_id", + "channel_cid" + ] + } + }, + { + "id": 6, + "references": [], + "type": "table", + "data": { + "name": "reads", + "was_declared_in_moor": false, + "columns": [ + { + "name": "last_read", + "moor_type": "ColumnType.datetime", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "user_id", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "channel_cid", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": "REFERENCES channels(cid) ON DELETE CASCADE", + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "unread_messages", + "moor_type": "ColumnType.integer", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "explicit_pk": [ + "user_id", + "channel_cid" + ] + } + }, + { + "id": 7, + "references": [], + "type": "table", + "data": { + "name": "channel_queries", + "was_declared_in_moor": false, + "columns": [ + { + "name": "query_hash", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "channel_cid", + "moor_type": "ColumnType.text", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "explicit_pk": [ + "query_hash", + "channel_cid" + ] + } + }, + { + "id": 8, + "references": [], + "type": "table", + "data": { + "name": "connection_events", + "was_declared_in_moor": false, + "columns": [ + { + "name": "id", + "moor_type": "ColumnType.integer", + "nullable": false, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "own_user", + "moor_type": "ColumnType.text", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [], + "type_converter": { + "dart_expr": "MapConverter()", + "dart_type_name": "Map" + } + }, + { + "name": "total_unread_count", + "moor_type": "ColumnType.integer", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "unread_channels", + "moor_type": "ColumnType.integer", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_event_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + }, + { + "name": "last_sync_at", + "moor_type": "ColumnType.datetime", + "nullable": true, + "customConstraints": null, + "default_dart": null, + "default_client_dart": null, + "dsl_features": [] + } + ], + "is_virtual": false, + "explicit_pk": [ + "id" + ] + } + } + ] +} \ No newline at end of file From 4c2a748291452c4707f9c3aec18942ce453e8116 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 19 Mar 2021 16:14:23 +0530 Subject: [PATCH 31/50] test(persistence): add clear queryCache test in channel query dao Signed-off-by: Sahil Kumar --- .../test/src/dao/channel_query_dao_test.dart | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/packages/stream_chat_persistence/test/src/dao/channel_query_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/channel_query_dao_test.dart index dd9ecf0b..8ee0e0c0 100644 --- a/packages/stream_chat_persistence/test/src/dao/channel_query_dao_test.dart +++ b/packages/stream_chat_persistence/test/src/dao/channel_query_dao_test.dart @@ -35,6 +35,29 @@ void main() { expect(updatedCids, cids); }); + test('clear queryCache before updateChannelQueries', () async { + const filter = { + 'members': { + r'$in': ['testUserId'], + }, + }; + + const cids = ['testCid1', 'testCid2', 'testCid3']; + + final cachedCids = await channelQueryDao.getCachedChannelCids(filter); + expect(cachedCids, isEmpty); + + // Updating channel queries + await channelQueryDao.updateChannelQueries( + filter, + cids, + clearQueryCache: true, + ); + + final updatedCids = await channelQueryDao.getCachedChannelCids(filter); + expect(updatedCids, cids); + }); + test('getCachedChannelCids', () async { const filter = { 'members': { From e00881fbdd57a2850eccb7391135603608c85974 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 19 Mar 2021 16:42:16 +0530 Subject: [PATCH 32/50] test(persistence): add getThreadMessagesByParentId along with pagination test in message, pinned message dao. Signed-off-by: Sahil Kumar --- .../lib/src/dao/message_dao.dart | 57 ++++++++++++------- .../lib/src/dao/pinned_message_dao.dart | 57 ++++++++++++------- .../test/src/dao/message_dao_test.dart | 38 ++++++++++++- .../test/src/dao/pinned_message_dao_test.dart | 38 ++++++++++++- 4 files changed, 150 insertions(+), 40 deletions(-) diff --git a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart index ae238069..8d36b758 100644 --- a/packages/stream_chat_persistence/lib/src/dao/message_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/message_dao.dart @@ -99,9 +99,26 @@ class MessageDao extends DatabaseAccessor .map(_messageFromJoinRow) .get()); - if (options?.lessThan != null && msgList.isNotEmpty) { - final lessThanIndex = msgList.indexWhere((m) => m.id == options.lessThan); - msgList.removeRange(lessThanIndex, msgList.length); + if (msgList.isNotEmpty) { + if (options?.lessThan != null) { + final lessThanIndex = msgList.indexWhere( + (m) => m.id == options.lessThan, + ); + if (lessThanIndex != -1) { + msgList.removeRange(lessThanIndex, msgList.length); + } + } + if (options?.greaterThanOrEqual != null) { + final greaterThanIndex = msgList.indexWhere( + (m) => m.id == options.greaterThanOrEqual, + ); + if (greaterThanIndex != -1) { + msgList.removeRange(0, greaterThanIndex); + } + } + if (options?.limit != null) { + return msgList.take(options.limit).toList(); + } } return msgList; } @@ -124,24 +141,26 @@ class MessageDao extends DatabaseAccessor .map(_messageFromJoinRow) .get()); - if (messagePagination?.lessThan != null) { - final lessThanIndex = msgList.indexWhere( - (m) => m.id == messagePagination.lessThan, - ); - if (lessThanIndex != -1) { - msgList.removeRange(lessThanIndex, msgList.length); + if (msgList.isNotEmpty) { + if (messagePagination?.lessThan != null) { + final lessThanIndex = msgList.indexWhere( + (m) => m.id == messagePagination.lessThan, + ); + if (lessThanIndex != -1) { + msgList.removeRange(lessThanIndex, msgList.length); + } } - } - if (messagePagination?.greaterThanOrEqual != null) { - final greaterThanIndex = msgList.indexWhere( - (m) => m.id == messagePagination.greaterThanOrEqual, - ); - if (greaterThanIndex != -1) { - msgList.removeRange(0, greaterThanIndex); + if (messagePagination?.greaterThanOrEqual != null) { + final greaterThanIndex = msgList.indexWhere( + (m) => m.id == messagePagination.greaterThanOrEqual, + ); + if (greaterThanIndex != -1) { + msgList.removeRange(0, greaterThanIndex); + } + } + if (messagePagination?.limit != null) { + return msgList.take(messagePagination.limit).toList(); } - } - if (messagePagination?.limit != null) { - return msgList.take(messagePagination.limit).toList(); } return msgList; } diff --git a/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart b/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart index cb634703..34ee4c28 100644 --- a/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/pinned_message_dao.dart @@ -99,9 +99,26 @@ class PinnedMessageDao extends DatabaseAccessor .map(_messageFromJoinRow) .get()); - if (options?.lessThan != null) { - final lessThanIndex = msgList.indexWhere((m) => m.id == options.lessThan); - msgList.removeRange(lessThanIndex, msgList.length); + if (msgList.isNotEmpty) { + if (options?.lessThan != null) { + final lessThanIndex = msgList.indexWhere( + (m) => m.id == options.lessThan, + ); + if (lessThanIndex != -1) { + msgList.removeRange(lessThanIndex, msgList.length); + } + } + if (options?.greaterThanOrEqual != null) { + final greaterThanIndex = msgList.indexWhere( + (m) => m.id == options.greaterThanOrEqual, + ); + if (greaterThanIndex != -1) { + msgList.removeRange(0, greaterThanIndex); + } + } + if (options?.limit != null) { + return msgList.take(options.limit).toList(); + } } return msgList; } @@ -124,24 +141,26 @@ class PinnedMessageDao extends DatabaseAccessor .map(_messageFromJoinRow) .get()); - if (messagePagination?.lessThan != null) { - final lessThanIndex = msgList.indexWhere( - (m) => m.id == messagePagination.lessThan, - ); - if (lessThanIndex != -1) { - msgList.removeRange(lessThanIndex, msgList.length); + if (msgList.isNotEmpty) { + if (messagePagination?.lessThan != null) { + final lessThanIndex = msgList.indexWhere( + (m) => m.id == messagePagination.lessThan, + ); + if (lessThanIndex != -1) { + msgList.removeRange(lessThanIndex, msgList.length); + } } - } - if (messagePagination?.greaterThanOrEqual != null) { - final greaterThanIndex = msgList.indexWhere( - (m) => m.id == messagePagination.greaterThanOrEqual, - ); - if (greaterThanIndex != -1) { - msgList.removeRange(0, greaterThanIndex); + if (messagePagination?.greaterThanOrEqual != null) { + final greaterThanIndex = msgList.indexWhere( + (m) => m.id == messagePagination.greaterThanOrEqual, + ); + if (greaterThanIndex != -1) { + msgList.removeRange(0, greaterThanIndex); + } + } + if (messagePagination?.limit != null) { + return msgList.take(messagePagination.limit).toList(); } - } - if (messagePagination?.limit != null) { - return msgList.take(messagePagination.limit).toList(); } return msgList; } diff --git a/packages/stream_chat_persistence/test/src/dao/message_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/message_dao_test.dart index dccb414c..7207002e 100644 --- a/packages/stream_chat_persistence/test/src/dao/message_dao_test.dart +++ b/packages/stream_chat_persistence/test/src/dao/message_dao_test.dart @@ -17,6 +17,7 @@ void main() { Future> _prepareTestData( String cid, { bool threads = false, + bool mapAllThreadToFirstMessage = false, int count = 3, }) async { final messages = List.generate( @@ -43,7 +44,8 @@ void main() { id: 'testThreadMessageId$cid$index', type: 'testType', user: User(id: 'testUserId$index'), - parentId: messages[index].id, + parentId: + mapAllThreadToFirstMessage ? messages[0].id : messages[index].id, createdAt: DateTime.now(), shadowed: math.Random().nextBool(), showInChannel: math.Random().nextBool(), @@ -184,6 +186,40 @@ void main() { expect(threadMessages.first.parentId, parentId); }); + test('getThreadMessagesByParentId along with pagination', () async { + const cid = 'testCid'; + const parentId = 'testMessageId${cid}0'; + const options = PaginationParams( + limit: 15, + lessThan: 'testThreadMessageId${cid}25', + greaterThanOrEqual: 'testThreadMessageId${cid}5', + ); + + // Messages should be empty initially + final messages = await messageDao.getThreadMessagesByParentId( + parentId, + options: options, + ); + expect(messages, isEmpty); + + // Preparing test data + final insertedMessages = await _prepareTestData( + cid, + threads: true, + mapAllThreadToFirstMessage: true, + count: 30, + ); + expect(insertedMessages, isNotEmpty); + + // Should fetch all the thread messages of parentId and apply the pagination + final threadMessages = await messageDao.getThreadMessagesByParentId( + parentId, + options: options, + ); + expect(threadMessages.length, 15); + expect(threadMessages.first.parentId, parentId); + }); + test('getMessagesByCid', () async { const cid = 'testCid'; diff --git a/packages/stream_chat_persistence/test/src/dao/pinned_message_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/pinned_message_dao_test.dart index 5c1bce46..3e197e2b 100644 --- a/packages/stream_chat_persistence/test/src/dao/pinned_message_dao_test.dart +++ b/packages/stream_chat_persistence/test/src/dao/pinned_message_dao_test.dart @@ -17,6 +17,7 @@ void main() { Future> _prepareTestData( String cid, { bool threads = false, + bool mapAllThreadToFirstMessage = false, int count = 3, }) async { final messages = List.generate( @@ -43,7 +44,8 @@ void main() { id: 'testThreadMessageId$cid$index', type: 'testType', user: User(id: 'testUserId$index'), - parentId: messages[index].id, + parentId: + mapAllThreadToFirstMessage ? messages[0].id : messages[index].id, createdAt: DateTime.now(), shadowed: math.Random().nextBool(), showInChannel: math.Random().nextBool(), @@ -185,6 +187,40 @@ void main() { expect(threadMessages.first.parentId, parentId); }); + test('getThreadMessagesByParentId along with pagination', () async { + const cid = 'testCid'; + const parentId = 'testMessageId${cid}0'; + const options = PaginationParams( + limit: 15, + lessThan: 'testThreadMessageId${cid}25', + greaterThanOrEqual: 'testThreadMessageId${cid}5', + ); + + // Messages should be empty initially + final messages = await pinnedMessageDao.getThreadMessagesByParentId( + parentId, + options: options, + ); + expect(messages, isEmpty); + + // Preparing test data + final insertedMessages = await _prepareTestData( + cid, + threads: true, + mapAllThreadToFirstMessage: true, + count: 30, + ); + expect(insertedMessages, isNotEmpty); + + // Should fetch all the thread messages of parentId and apply the pagination + final threadMessages = await pinnedMessageDao.getThreadMessagesByParentId( + parentId, + options: options, + ); + expect(threadMessages.length, 15); + expect(threadMessages.first.parentId, parentId); + }); + test('getMessagesByCid', () async { const cid = 'testCid'; From 252783adf64a37df926db4f08a5b6134056fe3fb Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 19 Mar 2021 16:52:08 +0530 Subject: [PATCH 33/50] test(persistence): add getMessagesByCid along with pagination test in message, pinned message dao. Signed-off-by: Sahil Kumar --- .../test/src/dao/message_dao_test.dart | 27 +++++++++++++++++++ .../test/src/dao/pinned_message_dao_test.dart | 27 +++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/packages/stream_chat_persistence/test/src/dao/message_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/message_dao_test.dart index 7207002e..377c949e 100644 --- a/packages/stream_chat_persistence/test/src/dao/message_dao_test.dart +++ b/packages/stream_chat_persistence/test/src/dao/message_dao_test.dart @@ -241,6 +241,33 @@ void main() { } }); + test('getMessagesByCid along with pagination', () async { + const cid = 'testCid'; + const pagination = PaginationParams( + limit: 15, + lessThan: 'testMessageId${cid}25', + greaterThanOrEqual: 'testMessageId${cid}5', + ); + + // Should be empty initially + final messages = await messageDao.getMessagesByCid( + cid, + messagePagination: pagination, + ); + expect(messages, isEmpty); + + // Preparing test data + final insertedMessages = await _prepareTestData(cid, count: 30); + expect(insertedMessages, isNotEmpty); + + // Fetched message should match the inserted messages + final fetchedMessages = await messageDao.getMessagesByCid( + cid, + messagePagination: pagination, + ); + expect(fetchedMessages.length, 15); + }); + test('updateMessages', () async { const cid = 'testCid'; diff --git a/packages/stream_chat_persistence/test/src/dao/pinned_message_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/pinned_message_dao_test.dart index 3e197e2b..66875990 100644 --- a/packages/stream_chat_persistence/test/src/dao/pinned_message_dao_test.dart +++ b/packages/stream_chat_persistence/test/src/dao/pinned_message_dao_test.dart @@ -242,6 +242,33 @@ void main() { } }); + test('getMessagesByCid along with pagination', () async { + const cid = 'testCid'; + const pagination = PaginationParams( + limit: 15, + lessThan: 'testMessageId${cid}25', + greaterThanOrEqual: 'testMessageId${cid}5', + ); + + // Should be empty initially + final messages = await pinnedMessageDao.getMessagesByCid( + cid, + messagePagination: pagination, + ); + expect(messages, isEmpty); + + // Preparing test data + final insertedMessages = await _prepareTestData(cid, count: 30); + expect(insertedMessages, isNotEmpty); + + // Fetched message should match the inserted messages + final fetchedMessages = await pinnedMessageDao.getMessagesByCid( + cid, + messagePagination: pagination, + ); + expect(fetchedMessages.length, 15); + }); + test('updateMessages', () async { const cid = 'testCid'; From 2b17fcfac89604874e0730a276bce2f7acfff70b Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 19 Mar 2021 12:25:43 +0100 Subject: [PATCH 34/50] update ci --- .github/workflows/stream_flutter_workflow.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/stream_flutter_workflow.yml b/.github/workflows/stream_flutter_workflow.yml index 52a504fe..a25bbdb3 100644 --- a/.github/workflows/stream_flutter_workflow.yml +++ b/.github/workflows/stream_flutter_workflow.yml @@ -8,6 +8,7 @@ on: push: branches: - master + - develop paths-ignore: - 'docs/**' From 8d2934f14220c18def11f79bad007e10ff7fd5ad Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 19 Mar 2021 12:26:08 +0100 Subject: [PATCH 35/50] apply locale to jiffy --- packages/stream_chat_flutter/lib/src/channel_preview.dart | 4 ++-- packages/stream_chat_flutter/lib/src/date_divider.dart | 6 +++--- .../stream_chat_flutter/lib/src/full_screen_media.dart | 2 +- .../stream_chat_flutter/lib/src/message_search_item.dart | 4 ++-- packages/stream_chat_flutter/lib/src/stream_chat.dart | 8 ++++++++ 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/channel_preview.dart b/packages/stream_chat_flutter/lib/src/channel_preview.dart index 9ba34f3a..3243988b 100644 --- a/packages/stream_chat_flutter/lib/src/channel_preview.dart +++ b/packages/stream_chat_flutter/lib/src/channel_preview.dart @@ -170,14 +170,14 @@ class ChannelPreview extends StatelessWidget { if (lastMessageAt.millisecondsSinceEpoch >= startOfDay.millisecondsSinceEpoch) { - stringDate = Jiffy(lastMessageAt.toLocal()).format('HH:mm'); + stringDate = Jiffy(lastMessageAt.toLocal()).jm; } else if (lastMessageAt.millisecondsSinceEpoch >= startOfDay.subtract(Duration(days: 1)).millisecondsSinceEpoch) { stringDate = 'Yesterday'; } else if (startOfDay.difference(lastMessageAt).inDays < 7) { stringDate = Jiffy(lastMessageAt.toLocal()).EEEE; } else { - stringDate = Jiffy(lastMessageAt.toLocal()).format('dd/MM/yyyy'); + stringDate = Jiffy(lastMessageAt.toLocal()).yMd; } return Text( diff --git a/packages/stream_chat_flutter/lib/src/date_divider.dart b/packages/stream_chat_flutter/lib/src/date_divider.dart index c7cfe296..20b8151d 100644 --- a/packages/stream_chat_flutter/lib/src/date_divider.dart +++ b/packages/stream_chat_flutter/lib/src/date_divider.dart @@ -28,14 +28,14 @@ class DateDivider extends StatelessWidget { now.subtract(Duration(days: 7)), Units.DAY, )) { - dayInfo = createdAt.format('EEEE'); + dayInfo = createdAt.EEEE; } else if (Jiffy(createdAt).isAfter( Jiffy(now).subtract(years: 1), Units.DAY, )) { - dayInfo = createdAt.format('MMMM d'); + dayInfo = createdAt.MMMd; } else { - dayInfo = createdAt.format('MMMM d'); + dayInfo = createdAt.MMMd; } if (uppercase) dayInfo = dayInfo.toUpperCase(); diff --git a/packages/stream_chat_flutter/lib/src/full_screen_media.dart b/packages/stream_chat_flutter/lib/src/full_screen_media.dart index 88c20a51..91c66ca4 100644 --- a/packages/stream_chat_flutter/lib/src/full_screen_media.dart +++ b/packages/stream_chat_flutter/lib/src/full_screen_media.dart @@ -220,7 +220,7 @@ class _FullScreenMediaState extends State 24) { return 'yesterday'; } else { - return 'on ${Jiffy(dateTime).format("MMM do")}'; + return 'on ${Jiffy(dateTime).MMMd}'; } } diff --git a/packages/stream_chat_flutter/lib/src/message_search_item.dart b/packages/stream_chat_flutter/lib/src/message_search_item.dart index 335f7ff4..4cf7b5ed 100644 --- a/packages/stream_chat_flutter/lib/src/message_search_item.dart +++ b/packages/stream_chat_flutter/lib/src/message_search_item.dart @@ -84,9 +84,9 @@ class MessageSearchItem extends StatelessWidget { if (now.year != createdAt.year || now.month != createdAt.month || now.day != createdAt.day) { - stringDate = Jiffy(createdAt.toLocal()).format('dd/MM/yyyy'); + stringDate = Jiffy(createdAt.toLocal()).yMd; } else { - stringDate = Jiffy(createdAt.toLocal()).format('HH:mm'); + stringDate = Jiffy(createdAt.toLocal()).jm; } return Text( diff --git a/packages/stream_chat_flutter/lib/src/stream_chat.dart b/packages/stream_chat_flutter/lib/src/stream_chat.dart index 66b49d88..8ad751b0 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_portal/flutter_portal.dart'; +import 'package:jiffy/jiffy.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; @@ -121,4 +122,11 @@ class StreamChatState extends State { void initState() { super.initState(); } + + @override + void didChangeDependencies() { + final locals = Localizations.localeOf(context); + Jiffy.locale(locals.languageCode); + super.didChangeDependencies(); + } } From 1f503fbc98f3d96645a2cf79f9909268d0fbbd59 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 19 Mar 2021 13:00:39 +0100 Subject: [PATCH 36/50] fix test --- packages/stream_chat_flutter/test/src/channel_preview_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat_flutter/test/src/channel_preview_test.dart b/packages/stream_chat_flutter/test/src/channel_preview_test.dart index 34b9bf92..094c74a5 100644 --- a/packages/stream_chat_flutter/test/src/channel_preview_test.dart +++ b/packages/stream_chat_flutter/test/src/channel_preview_test.dart @@ -69,7 +69,7 @@ void main() { ), )); - expect(find.text('22/06/2020'), findsOneWidget); + expect(find.text('6/22/2020'), findsOneWidget); expect(find.text('test name'), findsOneWidget); expect(find.text('1'), findsOneWidget); expect(find.text('hello'), findsOneWidget); From ab9990e5bdd5f27c964340c84ff31549eb20fe78 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 19 Mar 2021 17:34:41 +0530 Subject: [PATCH 37/50] test(persistence): add getMessagesByCid along with quotedMessage test in message, pinned message dao. Signed-off-by: Sahil Kumar --- .../test/src/dao/message_dao_test.dart | 51 +++++++++++++++++-- .../test/src/dao/pinned_message_dao_test.dart | 51 +++++++++++++++++-- 2 files changed, 92 insertions(+), 10 deletions(-) diff --git a/packages/stream_chat_persistence/test/src/dao/message_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/message_dao_test.dart index 377c949e..85e0a795 100644 --- a/packages/stream_chat_persistence/test/src/dao/message_dao_test.dart +++ b/packages/stream_chat_persistence/test/src/dao/message_dao_test.dart @@ -16,19 +16,20 @@ void main() { Future> _prepareTestData( String cid, { + bool quoted = false, bool threads = false, bool mapAllThreadToFirstMessage = false, int count = 3, }) async { + final users = List.generate(count, (index) => User(id: 'testUserId$index')); final messages = List.generate( count, (index) => Message( id: 'testMessageId$cid$index', type: 'testType', - user: User(id: 'testUserId$index'), + user: users[index], createdAt: DateTime.now(), shadowed: math.Random().nextBool(), - showInChannel: math.Random().nextBool(), replyCount: index, updatedAt: DateTime.now(), extraData: {'extra_test_field': 'extraTestData'}, @@ -38,17 +39,34 @@ void main() { pinnedBy: User(id: 'testUserId$index'), ), ); + final quotedMessages = List.generate( + count, + (index) => Message( + id: 'testQuotedMessageId$cid$index', + type: 'testType', + user: users[index], + createdAt: DateTime.now(), + shadowed: math.Random().nextBool(), + replyCount: index, + updatedAt: DateTime.now(), + extraData: {'extra_test_field': 'extraTestData'}, + text: 'Dummy text #$index', + quotedMessageId: messages[index].id, + pinned: math.Random().nextBool(), + pinnedAt: DateTime.now(), + pinnedBy: User(id: 'testUserId$index'), + ), + ); final threadMessages = List.generate( count, (index) => Message( id: 'testThreadMessageId$cid$index', type: 'testType', - user: User(id: 'testUserId$index'), + user: users[index], parentId: mapAllThreadToFirstMessage ? messages[0].id : messages[index].id, createdAt: DateTime.now(), shadowed: math.Random().nextBool(), - showInChannel: math.Random().nextBool(), replyCount: index, updatedAt: DateTime.now(), extraData: {'extra_test_field': 'extraTestData'}, @@ -58,7 +76,12 @@ void main() { pinnedBy: User(id: 'testUserId$index'), ), ); - final allMessages = [...messages, if (threads) ...threadMessages]; + final allMessages = [ + ...messages, + if (quoted) ...quotedMessages, + if (threads) ...threadMessages + ]; + await database.userDao.updateUsers(users); await messageDao.updateMessages(cid, allMessages); return allMessages; } @@ -241,6 +264,24 @@ void main() { } }); + test('getMessagesByCid along with quotedMessage', () async { + const cid = 'testCid'; + + // Should be empty initially + final messages = await messageDao.getMessagesByCid(cid); + expect(messages, isEmpty); + + // Preparing test data + final insertedMessages = await _prepareTestData(cid, quoted: true); + expect(insertedMessages, isNotEmpty); + + // Fetched message should match the inserted messages + final fetchedMessages = await messageDao.getMessagesByCid(cid); + expect(fetchedMessages.length, insertedMessages.length); + final quoted = fetchedMessages.where((it) => it.quotedMessage != null); + expect(quoted.length, insertedMessages.length / 2); + }); + test('getMessagesByCid along with pagination', () async { const cid = 'testCid'; const pagination = PaginationParams( diff --git a/packages/stream_chat_persistence/test/src/dao/pinned_message_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/pinned_message_dao_test.dart index 66875990..26c652db 100644 --- a/packages/stream_chat_persistence/test/src/dao/pinned_message_dao_test.dart +++ b/packages/stream_chat_persistence/test/src/dao/pinned_message_dao_test.dart @@ -16,19 +16,20 @@ void main() { Future> _prepareTestData( String cid, { + bool quoted = false, bool threads = false, bool mapAllThreadToFirstMessage = false, int count = 3, }) async { + final users = List.generate(count, (index) => User(id: 'testUserId$index')); final messages = List.generate( count, (index) => Message( id: 'testMessageId$cid$index', type: 'testType', - user: User(id: 'testUserId$index'), + user: users[index], createdAt: DateTime.now(), shadowed: math.Random().nextBool(), - showInChannel: math.Random().nextBool(), replyCount: index, updatedAt: DateTime.now(), extraData: {'extra_test_field': 'extraTestData'}, @@ -38,17 +39,34 @@ void main() { pinnedBy: User(id: 'testUserId$index'), ), ); + final quotedMessages = List.generate( + count, + (index) => Message( + id: 'testQuotedMessageId$cid$index', + type: 'testType', + user: users[index], + createdAt: DateTime.now(), + shadowed: math.Random().nextBool(), + replyCount: index, + updatedAt: DateTime.now(), + extraData: {'extra_test_field': 'extraTestData'}, + text: 'Dummy text #$index', + quotedMessageId: messages[index].id, + pinned: math.Random().nextBool(), + pinnedAt: DateTime.now(), + pinnedBy: User(id: 'testUserId$index'), + ), + ); final threadMessages = List.generate( count, (index) => Message( id: 'testThreadMessageId$cid$index', type: 'testType', - user: User(id: 'testUserId$index'), + user: users[index], parentId: mapAllThreadToFirstMessage ? messages[0].id : messages[index].id, createdAt: DateTime.now(), shadowed: math.Random().nextBool(), - showInChannel: math.Random().nextBool(), replyCount: index, updatedAt: DateTime.now(), extraData: {'extra_test_field': 'extraTestData'}, @@ -58,7 +76,12 @@ void main() { pinnedBy: User(id: 'testUserId$index'), ), ); - final allMessages = [...messages, if (threads) ...threadMessages]; + final allMessages = [ + ...messages, + if (quoted) ...quotedMessages, + if (threads) ...threadMessages + ]; + await database.userDao.updateUsers(users); await pinnedMessageDao.updateMessages(cid, allMessages); return allMessages; } @@ -242,6 +265,24 @@ void main() { } }); + test('getMessagesByCid along with quotedMessage', () async { + const cid = 'testCid'; + + // Should be empty initially + final messages = await pinnedMessageDao.getMessagesByCid(cid); + expect(messages, isEmpty); + + // Preparing test data + final insertedMessages = await _prepareTestData(cid, quoted: true); + expect(insertedMessages, isNotEmpty); + + // Fetched message should match the inserted messages + final fetchedMessages = await pinnedMessageDao.getMessagesByCid(cid); + expect(fetchedMessages.length, insertedMessages.length); + final quoted = fetchedMessages.where((it) => it.quotedMessage != null); + expect(quoted.length, insertedMessages.length / 2); + }); + test('getMessagesByCid along with pagination', () async { const cid = 'testCid'; const pagination = PaginationParams( From 2e3baa020d150fcef44c304ebc9d87ef6a3562f2 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 19 Mar 2021 17:38:07 +0530 Subject: [PATCH 38/50] test(persistence): add extra checks in getMessagesByCid along with pagination test in message, pinned message dao. Signed-off-by: Sahil Kumar --- .../test/src/dao/message_dao_test.dart | 13 +++++++++---- .../test/src/dao/pinned_message_dao_test.dart | 13 +++++++++---- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/stream_chat_persistence/test/src/dao/message_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/message_dao_test.dart index 85e0a795..f2440ae1 100644 --- a/packages/stream_chat_persistence/test/src/dao/message_dao_test.dart +++ b/packages/stream_chat_persistence/test/src/dao/message_dao_test.dart @@ -284,10 +284,13 @@ void main() { test('getMessagesByCid along with pagination', () async { const cid = 'testCid'; + const limit = 15; + const lessThan = 'testMessageId${cid}25'; + const greaterThanOrEqual = 'testMessageId${cid}5'; const pagination = PaginationParams( - limit: 15, - lessThan: 'testMessageId${cid}25', - greaterThanOrEqual: 'testMessageId${cid}5', + limit: limit, + lessThan: lessThan, + greaterThanOrEqual: greaterThanOrEqual, ); // Should be empty initially @@ -306,7 +309,9 @@ void main() { cid, messagePagination: pagination, ); - expect(fetchedMessages.length, 15); + expect(fetchedMessages.length, limit); + expect(fetchedMessages.first.id, greaterThanOrEqual); + expect(fetchedMessages.last.id != lessThan, true); }); test('updateMessages', () async { diff --git a/packages/stream_chat_persistence/test/src/dao/pinned_message_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/pinned_message_dao_test.dart index 26c652db..de7c8976 100644 --- a/packages/stream_chat_persistence/test/src/dao/pinned_message_dao_test.dart +++ b/packages/stream_chat_persistence/test/src/dao/pinned_message_dao_test.dart @@ -285,10 +285,13 @@ void main() { test('getMessagesByCid along with pagination', () async { const cid = 'testCid'; + const limit = 15; + const lessThan = 'testMessageId${cid}25'; + const greaterThanOrEqual = 'testMessageId${cid}5'; const pagination = PaginationParams( - limit: 15, - lessThan: 'testMessageId${cid}25', - greaterThanOrEqual: 'testMessageId${cid}5', + limit: limit, + lessThan: lessThan, + greaterThanOrEqual: greaterThanOrEqual, ); // Should be empty initially @@ -307,7 +310,9 @@ void main() { cid, messagePagination: pagination, ); - expect(fetchedMessages.length, 15); + expect(fetchedMessages.length, limit); + expect(fetchedMessages.first.id, greaterThanOrEqual); + expect(fetchedMessages.last.id != lessThan, true); }); test('updateMessages', () async { From abbe72709e905632372d3d12bedad6fee7b899e9 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 19 Mar 2021 17:49:50 +0530 Subject: [PATCH 39/50] test(persistence): add return channel with pagination applies test in channel query dao Signed-off-by: Sahil Kumar --- .../test/src/dao/channel_query_dao_test.dart | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/packages/stream_chat_persistence/test/src/dao/channel_query_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/channel_query_dao_test.dart index 8ee0e0c0..4566ca94 100644 --- a/packages/stream_chat_persistence/test/src/dao/channel_query_dao_test.dart +++ b/packages/stream_chat_persistence/test/src/dao/channel_query_dao_test.dart @@ -78,15 +78,17 @@ void main() { }); Future> _insertTestDataForGetChannel( - Map filter) async { + Map filter, { + int count = 3, + }) async { final now = DateTime.now(); final userDao = database.userDao; final channelDao = database.channelDao; - const cids = ['testCid0', 'testCid1', 'testCid2']; - final users = List.generate(3, (index) => User(id: 'testId$index')); + final cids = List.generate(count, (index) => 'testCid$index'); + final users = List.generate(count, (index) => User(id: 'testId$index')); final channels = List.generate( - 3, + count, (index) => ChannelModel( id: 'testId$index', type: 'testType$index', @@ -150,6 +152,30 @@ void main() { } }); + test( + 'should return all the inserted channels along with pagination applied', + () async { + const offset = 5; + const limit = 15; + const pagination = PaginationParams(offset: offset, limit: limit); + + // Inserting test data for get channels + final insertedChannels = await _insertTestDataForGetChannel( + filter, + count: 30, + ); + + // Should match with the inserted channels + final updatedChannels = await channelQueryDao.getChannels( + filter: filter, + paginationParams: pagination, + ); + expect(updatedChannels.length, limit); + expect(updatedChannels.first.id, 'testId24'); + expect(updatedChannels.first.cid, 'testCid24'); + }, + ); + test('should return sorted channels using member count', () async { int sortComparator(ChannelModel a, ChannelModel b) => b.memberCount.compareTo(a.memberCount); From b570d3332af615cb48fbfebf6fbcb519f1033653 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 19 Mar 2021 18:03:00 +0530 Subject: [PATCH 40/50] test(persistence): improve message mapper, pinned message mapper test Signed-off-by: Sahil Kumar --- .../test/src/mapper/message_mapper_test.dart | 35 ++++++++++++++++--- .../mapper/pinned_message_mapper_test.dart | 35 ++++++++++++++++--- 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/packages/stream_chat_persistence/test/src/mapper/message_mapper_test.dart b/packages/stream_chat_persistence/test/src/mapper/message_mapper_test.dart index 0554a0ce..21a05da8 100644 --- a/packages/stream_chat_persistence/test/src/mapper/message_mapper_test.dart +++ b/packages/stream_chat_persistence/test/src/mapper/message_mapper_test.dart @@ -1,3 +1,4 @@ +import 'dart:convert'; import 'dart:math' as math; import 'package:test/test.dart'; @@ -21,9 +22,17 @@ void main() { score: math.Random().nextInt(50), ), ); + final attachments = List.generate( + 3, + (index) => Attachment( + id: 'testAttachmentId', + type: 'testAttachmentType', + assetUrl: 'testAssetUrl', + ), + ); final entity = MessageEntity( id: 'testMessageId', - attachments: [], + attachments: attachments?.map((it) => jsonEncode(it.toData()))?.toList(), channelCid: 'testCid', type: 'testType', parentId: 'testParentId', @@ -60,7 +69,6 @@ void main() { expect(message, isA()); expect(message.id, entity.id); - expect(message.attachments, entity.attachments); expect(message.type, entity.type); expect(message.parentId, entity.parentId); expect(message.quotedMessageId, entity.quotedMessageId); @@ -83,6 +91,14 @@ void main() { expect(message.pinnedBy.id, entity.pinnedByUserId); expect(message.reactionCounts, entity.reactionCounts); expect(message.reactionScores, entity.reactionScores); + for (var i = 0; i < message.attachments.length; i++) { + final messageAttachment = message.attachments[i]; + final entityAttachmentData = jsonDecode(entity.attachments[i]); + final entityAttachment = Attachment.fromData(entityAttachmentData); + expect(messageAttachment.id, entityAttachment.id); + expect(messageAttachment.type, entityAttachment.type); + expect(messageAttachment.assetUrl, entityAttachment.assetUrl); + } }); test('toEntity should map message into MessageEntity', () { @@ -99,9 +115,17 @@ void main() { score: math.Random().nextInt(50), ), ); + final attachments = List.generate( + 3, + (index) => Attachment( + id: 'testAttachmentId', + type: 'testAttachmentType', + assetUrl: 'testAssetUrl', + ), + ); final message = Message( id: 'testMessageId', - attachments: [], + attachments: attachments, type: 'testType', parentId: 'testParentId', quotedMessageId: quotedMessage.id, @@ -130,7 +154,6 @@ void main() { final entity = message.toEntity(cid: cid); expect(entity, isA()); expect(entity.id, message.id); - expect(entity.attachments, message.attachments); expect(entity.type, message.type); expect(entity.parentId, message.parentId); expect(entity.quotedMessageId, message.quotedMessageId); @@ -153,5 +176,9 @@ void main() { expect(entity.pinnedByUserId, message.pinnedBy.id); expect(entity.reactionCounts, message.reactionCounts); expect(entity.reactionScores, message.reactionScores); + expect( + entity.attachments, + message.attachments?.map((it) => jsonEncode(it.toData()))?.toList(), + ); }); } diff --git a/packages/stream_chat_persistence/test/src/mapper/pinned_message_mapper_test.dart b/packages/stream_chat_persistence/test/src/mapper/pinned_message_mapper_test.dart index e79dd051..0aadf08a 100644 --- a/packages/stream_chat_persistence/test/src/mapper/pinned_message_mapper_test.dart +++ b/packages/stream_chat_persistence/test/src/mapper/pinned_message_mapper_test.dart @@ -1,3 +1,4 @@ +import 'dart:convert'; import 'dart:math' as math; import 'package:test/test.dart'; @@ -21,9 +22,17 @@ void main() { score: math.Random().nextInt(50), ), ); + final attachments = List.generate( + 3, + (index) => Attachment( + id: 'testAttachmentId', + type: 'testAttachmentType', + assetUrl: 'testAssetUrl', + ), + ); final entity = PinnedMessageEntity( id: 'testMessageId', - attachments: [], + attachments: attachments?.map((it) => jsonEncode(it.toData()))?.toList(), channelCid: 'testCid', type: 'testType', parentId: 'testParentId', @@ -60,7 +69,6 @@ void main() { expect(message, isA()); expect(message.id, entity.id); - expect(message.attachments, entity.attachments); expect(message.type, entity.type); expect(message.parentId, entity.parentId); expect(message.quotedMessageId, entity.quotedMessageId); @@ -83,6 +91,14 @@ void main() { expect(message.pinnedBy.id, entity.pinnedByUserId); expect(message.reactionCounts, entity.reactionCounts); expect(message.reactionScores, entity.reactionScores); + for (var i = 0; i < message.attachments.length; i++) { + final messageAttachment = message.attachments[i]; + final entityAttachmentData = jsonDecode(entity.attachments[i]); + final entityAttachment = Attachment.fromData(entityAttachmentData); + expect(messageAttachment.id, entityAttachment.id); + expect(messageAttachment.type, entityAttachment.type); + expect(messageAttachment.assetUrl, entityAttachment.assetUrl); + } }); test('toPinnedEntity should map message into PinnedMessageEntity', () { @@ -99,9 +115,17 @@ void main() { score: math.Random().nextInt(50), ), ); + final attachments = List.generate( + 3, + (index) => Attachment( + id: 'testAttachmentId', + type: 'testAttachmentType', + assetUrl: 'testAssetUrl', + ), + ); final message = Message( id: 'testMessageId', - attachments: [], + attachments: attachments, type: 'testType', parentId: 'testParentId', quotedMessageId: quotedMessage.id, @@ -130,7 +154,6 @@ void main() { final entity = message.toPinnedEntity(cid: cid); expect(entity, isA()); expect(entity.id, message.id); - expect(entity.attachments, message.attachments); expect(entity.type, message.type); expect(entity.parentId, message.parentId); expect(entity.quotedMessageId, message.quotedMessageId); @@ -153,5 +176,9 @@ void main() { expect(entity.pinnedByUserId, message.pinnedBy.id); expect(entity.reactionCounts, message.reactionCounts); expect(entity.reactionScores, message.reactionScores); + expect( + entity.attachments, + message.attachments?.map((it) => jsonEncode(it.toData()))?.toList(), + ); }); } From cc9388816ab396da00ba2c27c1a8589dc8253793 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 19 Mar 2021 18:10:25 +0530 Subject: [PATCH 41/50] test(persistence): add client constructor test in stream chat persistence client Signed-off-by: Sahil Kumar --- .../stream_chat_persistence_client_test.dart | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/packages/stream_chat_persistence/test/stream_chat_persistence_client_test.dart b/packages/stream_chat_persistence/test/stream_chat_persistence_client_test.dart index ef7fd020..55a5113a 100644 --- a/packages/stream_chat_persistence/test/stream_chat_persistence_client_test.dart +++ b/packages/stream_chat_persistence/test/stream_chat_persistence_client_test.dart @@ -10,6 +10,22 @@ MoorChatDatabase _testDatabaseProvider(String userId, ConnectionMode mode) => MoorChatDatabase.testable(userId); void main() { + group('client constructor', () { + test('throws assertion error if null connectionMode is provided', () { + expect( + () => StreamChatPersistenceClient(connectionMode: null), + throwsA(isA()), + ); + }); + + test('throws assertion error if null logLevel is provided', () { + expect( + () => StreamChatPersistenceClient(logLevel: null), + throwsA(isA()), + ); + }); + }); + group('connect', () { const userId = 'testUserId'; test('successfully connects with the Database', () async { From 74f1752ceb3009c8cc01e0fd7a364c073e370a33 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 19 Mar 2021 18:21:59 +0530 Subject: [PATCH 42/50] test(persistence): add coverage:ignore-file for entities and db/shared directory Signed-off-by: Sahil Kumar --- .../stream_chat_persistence/lib/src/db/shared/native_db.dart | 1 + .../lib/src/db/shared/unsupported_db.dart | 1 + packages/stream_chat_persistence/lib/src/db/shared/web_db.dart | 1 + .../stream_chat_persistence/lib/src/entity/channel_queries.dart | 1 + packages/stream_chat_persistence/lib/src/entity/channels.dart | 1 + .../lib/src/entity/connection_events.dart | 1 + packages/stream_chat_persistence/lib/src/entity/members.dart | 1 + packages/stream_chat_persistence/lib/src/entity/messages.dart | 1 + .../stream_chat_persistence/lib/src/entity/pinned_messages.dart | 1 + packages/stream_chat_persistence/lib/src/entity/reactions.dart | 1 + packages/stream_chat_persistence/lib/src/entity/reads.dart | 1 + packages/stream_chat_persistence/lib/src/entity/users.dart | 1 + 12 files changed, 12 insertions(+) diff --git a/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart b/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart index 0868ad69..27aa23b5 100644 --- a/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart +++ b/packages/stream_chat_persistence/lib/src/db/shared/native_db.dart @@ -1,3 +1,4 @@ +// coverage:ignore-file import 'dart:io'; import 'dart:isolate'; diff --git a/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart b/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart index e2877030..1054a1df 100644 --- a/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart +++ b/packages/stream_chat_persistence/lib/src/db/shared/unsupported_db.dart @@ -1,3 +1,4 @@ +// coverage:ignore-file import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; import 'package:stream_chat_persistence/stream_chat_persistence.dart'; diff --git a/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart b/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart index 9c504a11..bb664443 100644 --- a/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart +++ b/packages/stream_chat_persistence/lib/src/db/shared/web_db.dart @@ -1,3 +1,4 @@ +// coverage:ignore-file import 'package:moor/moor_web.dart'; import 'package:stream_chat_persistence/src/stream_chat_persistence_client.dart'; diff --git a/packages/stream_chat_persistence/lib/src/entity/channel_queries.dart b/packages/stream_chat_persistence/lib/src/entity/channel_queries.dart index 301e3592..61985d26 100644 --- a/packages/stream_chat_persistence/lib/src/entity/channel_queries.dart +++ b/packages/stream_chat_persistence/lib/src/entity/channel_queries.dart @@ -1,3 +1,4 @@ +// coverage:ignore-file import 'package:moor/moor.dart'; /// Represents a [ChannelQueries] table in [MoorChatDatabase]. diff --git a/packages/stream_chat_persistence/lib/src/entity/channels.dart b/packages/stream_chat_persistence/lib/src/entity/channels.dart index 38a40081..89842036 100644 --- a/packages/stream_chat_persistence/lib/src/entity/channels.dart +++ b/packages/stream_chat_persistence/lib/src/entity/channels.dart @@ -1,3 +1,4 @@ +// coverage:ignore-file import 'package:moor/moor.dart'; import 'package:stream_chat_persistence/src/converter/map_converter.dart'; diff --git a/packages/stream_chat_persistence/lib/src/entity/connection_events.dart b/packages/stream_chat_persistence/lib/src/entity/connection_events.dart index 7caa0407..69538edc 100644 --- a/packages/stream_chat_persistence/lib/src/entity/connection_events.dart +++ b/packages/stream_chat_persistence/lib/src/entity/connection_events.dart @@ -1,3 +1,4 @@ +// coverage:ignore-file import 'package:moor/moor.dart'; import 'package:stream_chat_persistence/src/converter/map_converter.dart'; diff --git a/packages/stream_chat_persistence/lib/src/entity/members.dart b/packages/stream_chat_persistence/lib/src/entity/members.dart index 9eafd4aa..c7316640 100644 --- a/packages/stream_chat_persistence/lib/src/entity/members.dart +++ b/packages/stream_chat_persistence/lib/src/entity/members.dart @@ -1,3 +1,4 @@ +// coverage:ignore-file import 'package:moor/moor.dart'; /// Represents a [Members] table in [MoorChatDatabase]. diff --git a/packages/stream_chat_persistence/lib/src/entity/messages.dart b/packages/stream_chat_persistence/lib/src/entity/messages.dart index 0350d9de..8840d85f 100644 --- a/packages/stream_chat_persistence/lib/src/entity/messages.dart +++ b/packages/stream_chat_persistence/lib/src/entity/messages.dart @@ -1,3 +1,4 @@ +// coverage:ignore-file import 'package:moor/moor.dart'; import 'package:stream_chat_persistence/src/converter/list_converter.dart'; import 'package:stream_chat_persistence/src/converter/map_converter.dart'; diff --git a/packages/stream_chat_persistence/lib/src/entity/pinned_messages.dart b/packages/stream_chat_persistence/lib/src/entity/pinned_messages.dart index de081552..043f69c5 100644 --- a/packages/stream_chat_persistence/lib/src/entity/pinned_messages.dart +++ b/packages/stream_chat_persistence/lib/src/entity/pinned_messages.dart @@ -1,3 +1,4 @@ +// coverage:ignore-file import 'package:moor/moor.dart'; import 'package:stream_chat_persistence/src/entity/messages.dart'; diff --git a/packages/stream_chat_persistence/lib/src/entity/reactions.dart b/packages/stream_chat_persistence/lib/src/entity/reactions.dart index b7e6342f..53cbdd11 100644 --- a/packages/stream_chat_persistence/lib/src/entity/reactions.dart +++ b/packages/stream_chat_persistence/lib/src/entity/reactions.dart @@ -1,3 +1,4 @@ +// coverage:ignore-file import 'package:moor/moor.dart'; import 'package:stream_chat_persistence/src/converter/map_converter.dart'; diff --git a/packages/stream_chat_persistence/lib/src/entity/reads.dart b/packages/stream_chat_persistence/lib/src/entity/reads.dart index 4b9ce6fb..7943ed9e 100644 --- a/packages/stream_chat_persistence/lib/src/entity/reads.dart +++ b/packages/stream_chat_persistence/lib/src/entity/reads.dart @@ -1,3 +1,4 @@ +// coverage:ignore-file import 'package:moor/moor.dart'; /// Represents a [Reads] table in [MoorChatDatabase]. diff --git a/packages/stream_chat_persistence/lib/src/entity/users.dart b/packages/stream_chat_persistence/lib/src/entity/users.dart index 4916ad28..7ece9600 100644 --- a/packages/stream_chat_persistence/lib/src/entity/users.dart +++ b/packages/stream_chat_persistence/lib/src/entity/users.dart @@ -1,3 +1,4 @@ +// coverage:ignore-file import 'package:moor/moor.dart'; import 'package:stream_chat_persistence/src/converter/map_converter.dart'; From 8f079a992435cdeaa3bdb6bc20de0abeb3d185db Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 19 Mar 2021 18:59:47 +0530 Subject: [PATCH 43/50] skip pub publish --dry-run for develop branch Signed-off-by: Sahil Kumar --- .github/workflows/stream_flutter_workflow.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/stream_flutter_workflow.yml b/.github/workflows/stream_flutter_workflow.yml index a25bbdb3..5f192320 100644 --- a/.github/workflows/stream_flutter_workflow.yml +++ b/.github/workflows/stream_flutter_workflow.yml @@ -33,6 +33,7 @@ jobs: melos exec -c 3 --ignore="*example*" -- \ tuneup check - name: 'Pub Check' + if: github.ref == 'refs/heads/master' run: | melos exec -c 1 --no-private --ignore="*example*" -- \ pub publish --dry-run @@ -89,7 +90,7 @@ jobs: - uses: VeryGoodOpenSource/very_good_coverage@v1.1.1 with: path: packages/stream_chat_persistence/coverage/lcov.info - min_coverage: 0.2 + min_coverage: 95 - uses: VeryGoodOpenSource/very_good_coverage@v1.1.1 with: path: packages/stream_chat_flutter_core/coverage/lcov.info From 6dd9f6af5eb8711deec7d1757755cfca0cccb4e9 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 19 Mar 2021 19:37:50 +0530 Subject: [PATCH 44/50] add remove from coverage script Signed-off-by: Sahil Kumar --- .github/workflows/scripts/coverage.sh | 6 ++++++ .github/workflows/stream_flutter_workflow.yml | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100755 .github/workflows/scripts/coverage.sh diff --git a/.github/workflows/scripts/coverage.sh b/.github/workflows/scripts/coverage.sh new file mode 100755 index 00000000..2710a45d --- /dev/null +++ b/.github/workflows/scripts/coverage.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +# Fast fail the script on failures. +set -e + +pub global run remove_from_coverage:remove_from_coverage -f coverage/lcov.info -r '.g.dart$' \ No newline at end of file diff --git a/.github/workflows/stream_flutter_workflow.yml b/.github/workflows/stream_flutter_workflow.yml index 5f192320..f4b17371 100644 --- a/.github/workflows/stream_flutter_workflow.yml +++ b/.github/workflows/stream_flutter_workflow.yml @@ -70,6 +70,7 @@ jobs: run: | ./.github/workflows/scripts/install-tools.sh flutter pub global activate coverage + flutter pub global activate remove_from_coverage - name: 'Bootstrap Workspace' run: melos bootstrap - name: 'Dart Test' @@ -82,7 +83,9 @@ jobs: melos exec -c 3 --flutter --dir-exists=test --ignore="*example*" --ignore="*web*" -- \ flutter test --coverage - name: CodeCov - run: bash <(curl -s https://codecov.io/bash) -t ${{ secrets.CODECOV_TOKEN }} + run: | + melos exec -c 3 --fail-fast -- "\$MELOS_ROOT_PATH/.github/workflows/scripts/coverage.sh" + bash <(curl -s https://codecov.io/bash) -t ${{ secrets.CODECOV_TOKEN }} - uses: VeryGoodOpenSource/very_good_coverage@v1.1.1 with: path: packages/stream_chat/lcov.info From 98b75d64ef1fe9ca25885790cfdc1475df3cecfe Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 19 Mar 2021 19:45:41 +0530 Subject: [PATCH 45/50] fix Signed-off-by: Sahil Kumar --- .github/workflows/stream_flutter_workflow.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/stream_flutter_workflow.yml b/.github/workflows/stream_flutter_workflow.yml index f4b17371..827d3f22 100644 --- a/.github/workflows/stream_flutter_workflow.yml +++ b/.github/workflows/stream_flutter_workflow.yml @@ -84,7 +84,8 @@ jobs: flutter test --coverage - name: CodeCov run: | - melos exec -c 3 --fail-fast -- "\$MELOS_ROOT_PATH/.github/workflows/scripts/coverage.sh" + melos exec -c 3 --fail-fast --dir-exists=test --ignore="*example*" --ignore="*web*" -- \ + "\$MELOS_ROOT_PATH/.github/workflows/scripts/coverage.sh" bash <(curl -s https://codecov.io/bash) -t ${{ secrets.CODECOV_TOKEN }} - uses: VeryGoodOpenSource/very_good_coverage@v1.1.1 with: From f31539ac872c7ab8469e9d0ea352a137cb6355ab Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 19 Mar 2021 20:00:58 +0530 Subject: [PATCH 46/50] fix Signed-off-by: Sahil Kumar --- .github/workflows/stream_flutter_workflow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stream_flutter_workflow.yml b/.github/workflows/stream_flutter_workflow.yml index 827d3f22..3b7661f9 100644 --- a/.github/workflows/stream_flutter_workflow.yml +++ b/.github/workflows/stream_flutter_workflow.yml @@ -77,7 +77,7 @@ jobs: run: | cd packages/stream_chat flutter pub run test --coverage coverage/ - format_coverage --lcov --in=coverage/ --out=lcov.info --packages=.packages --report-on=lib + format_coverage --lcov --in=coverage/ --out=coverage/lcov.info --packages=.packages --report-on=lib - name: 'Flutter Test' run: | melos exec -c 3 --flutter --dir-exists=test --ignore="*example*" --ignore="*web*" -- \ From ccb47602e8cce37b4689bce7f7c172f7222e79ab Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 19 Mar 2021 20:06:23 +0530 Subject: [PATCH 47/50] fix Signed-off-by: Sahil Kumar --- .github/workflows/stream_flutter_workflow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stream_flutter_workflow.yml b/.github/workflows/stream_flutter_workflow.yml index 3b7661f9..02ea415e 100644 --- a/.github/workflows/stream_flutter_workflow.yml +++ b/.github/workflows/stream_flutter_workflow.yml @@ -89,7 +89,7 @@ jobs: bash <(curl -s https://codecov.io/bash) -t ${{ secrets.CODECOV_TOKEN }} - uses: VeryGoodOpenSource/very_good_coverage@v1.1.1 with: - path: packages/stream_chat/lcov.info + path: packages/stream_chat/coverage/lcov.info min_coverage: 50 - uses: VeryGoodOpenSource/very_good_coverage@v1.1.1 with: From b9f955d3b203b7b428345c05a2c3acbce55dd82d Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 19 Mar 2021 20:21:04 +0530 Subject: [PATCH 48/50] fix Signed-off-by: Sahil Kumar --- .github/workflows/stream_flutter_workflow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stream_flutter_workflow.yml b/.github/workflows/stream_flutter_workflow.yml index 02ea415e..91808df2 100644 --- a/.github/workflows/stream_flutter_workflow.yml +++ b/.github/workflows/stream_flutter_workflow.yml @@ -90,7 +90,7 @@ jobs: - uses: VeryGoodOpenSource/very_good_coverage@v1.1.1 with: path: packages/stream_chat/coverage/lcov.info - min_coverage: 50 + min_coverage: 40 - uses: VeryGoodOpenSource/very_good_coverage@v1.1.1 with: path: packages/stream_chat_persistence/coverage/lcov.info From 06718b84fd689af4784478f016215048206443a8 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 19 Mar 2021 16:37:59 +0100 Subject: [PATCH 49/50] fix locale --- packages/stream_chat_flutter/lib/src/stream_chat.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/stream_chat.dart b/packages/stream_chat_flutter/lib/src/stream_chat.dart index 8ad751b0..470591e7 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat.dart @@ -7,6 +7,7 @@ import 'package:jiffy/jiffy.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; +import 'dart:ui' as ui; /// Widget used to provide information about the chat to the widget tree /// @@ -125,8 +126,8 @@ class StreamChatState extends State { @override void didChangeDependencies() { - final locals = Localizations.localeOf(context); - Jiffy.locale(locals.languageCode); + final locale = ui.window.locale; + Jiffy.locale(locale.languageCode); super.didChangeDependencies(); } } From c448a7ceef6e14e2716345611590146ac47c82d3 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 19 Mar 2021 17:49:01 +0100 Subject: [PATCH 50/50] fix message input _parseExistingMessage --- packages/stream_chat_flutter/lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index 4a18bf02..fc79b56c 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -2233,7 +2233,7 @@ class MessageInputState extends State { void _parseExistingMessage(Message message) { textEditingController.text = message.text; _messageIsPresent = true; - for (final attachment in message.attachments) { + for (final attachment in message?.attachments) { _attachments[attachment.id] = attachment.copyWith( uploadState: attachment.uploadState ?? UploadState.success(), );