diff --git a/packages/stream_chat/lib/src/api/channel.dart b/packages/stream_chat/lib/src/api/channel.dart index f2e8e0fc..2de3789a 100644 --- a/packages/stream_chat/lib/src/api/channel.dart +++ b/packages/stream_chat/lib/src/api/channel.dart @@ -19,19 +19,24 @@ class Channel { /// Create a channel client instance. Channel( this._client, - this.type, - this._id, - this._extraData, - ) : _cid = _id != null ? '$type:$_id' : null { + this._type, + this._id, { + Map extraData = const {}, + }) : _cid = _id != null ? '$_type:$_id' : null, + _extraData = extraData { _client.logger.info('New Channel instance not initialized created'); } /// Create a channel client instance from a [ChannelState] object - Channel.fromState(this._client, ChannelState channelState) : _extraData = {} { - _cid = channelState.channel!.cid; - _id = channelState.channel!.id; - type = channelState.channel!.type; - + Channel.fromState(this._client, ChannelState channelState) + : assert( + channelState.channel != null, + 'No channel found inside channel state', + ), + _id = channelState.channel!.id, + _type = channelState.channel!.type, + _cid = channelState.channel!.cid, + _extraData = channelState.channel!.extraData ?? {} { state = ChannelClientState(this, channelState); _initializedCompleter.complete(true); _client.logger.info('New Channel instance initialized created'); @@ -41,19 +46,20 @@ class Channel { ChannelClientState? state; /// The channel type - String? type; + final String _type; String? _id; String? _cid; - Map _extraData; + final Map _extraData; set extraData(Map extraData) { if (_initializedCompleter.isCompleted) { - throw Exception( - 'Once the channel is initialized you should use channel.update ' - 'to update channel data'); + throw StateError( + 'Once the channel is initialized you should use channel.update ' + 'to update channel data', + ); } - _extraData = extraData; + _extraData.addAll(extraData); } /// Returns true if the channel is muted @@ -179,6 +185,9 @@ class Channel { /// Channel id String? get id => state?._channelState.channel?.id ?? _id; + /// Channel type + String get type => state?._channelState.channel?.type ?? _type; + /// Channel cid String? get cid => state?._channelState.channel?.cid ?? _cid; @@ -193,9 +202,11 @@ class Channel { state?._channelState.channel?.extraData ?? _extraData; /// Channel extra data as a stream - Stream?>? get extraDataStream { + Stream> get extraDataStream { _checkInitialized(); - return state?.channelStateStream.map((cs) => cs.channel?.extraData); + return state!.channelStateStream.map( + (cs) => cs.channel?.extraData ?? _extraData, + ); } /// The main Stream chat client @@ -384,7 +395,7 @@ class Channel { message = await attachmentsUploadCompleter.future; } - final response = await _client.sendMessage(message, id!, type!); + final response = await _client.sendMessage(message, id!, type); state!.addMessage(response.message); return response; } catch (error) { @@ -537,7 +548,7 @@ class Channel { return _client.sendFile( file, id!, - type!, + type, onSendProgress: onSendProgress, cancelToken: cancelToken, ); @@ -553,7 +564,7 @@ class Channel { return _client.sendImage( file, id!, - type!, + type, onSendProgress: onSendProgress, cancelToken: cancelToken, ); @@ -565,18 +576,16 @@ class Channel { Map? messageFilters, List? sort, PaginationParams? paginationParams, - }) => - _client.search( - { - 'cid': { - r'$in': [cid], - }, - }, - sort: sort, - query: query, - paginationParams: paginationParams, - messageFilters: messageFilters, - ); + }) { + _checkInitialized(); + return _client.search( + Filter.in_('cid', [cid!]), + sort: sort, + query: query, + paginationParams: paginationParams, + messageFilters: messageFilters, + ); + } /// Delete a file from this channel Future deleteFile( @@ -587,7 +596,7 @@ class Channel { return _client.deleteFile( url, id!, - type!, + type, cancelToken: cancelToken, ); } @@ -601,7 +610,7 @@ class Channel { return _client.deleteImage( url, id!, - type!, + type, cancelToken: cancelToken, ); } @@ -903,7 +912,7 @@ class Channel { void _initState(ChannelState channelState) { state = ChannelClientState(this, channelState); - client.state.channels![cid] = this; + client.state.channels[cid!] = this; if (!_initializedCompleter.isCompleted) { _initializedCompleter.complete(true); } @@ -1018,9 +1027,7 @@ class Channel { bool preferOffline = false, }) async { var path = '/channels/$type'; - if (id != null) { - path = '$path/$id'; - } + if (id != null) path = '$path/$id'; path = '$path/query'; final payload = Map.from({ diff --git a/packages/stream_chat/lib/src/client.dart b/packages/stream_chat/lib/src/client.dart index 4689e9ec..28be5ac6 100644 --- a/packages/stream_chat/lib/src/client.dart +++ b/packages/stream_chat/lib/src/client.dart @@ -29,6 +29,8 @@ import 'package:stream_chat/src/platform_detector/platform_detector.dart'; import 'package:stream_chat/version.dart'; import 'package:uuid/uuid.dart'; +import 'package:stream_chat/src/models/filter.dart'; + /// Handler function used for logging records. Function requires a single /// [LogRecord] as the only parameter. typedef LogHandlerFunction = void Function(LogRecord record); @@ -552,13 +554,16 @@ class StreamChatClient { type: EventType.connectionRecovered, online: true, )); - if (state.channels?.isNotEmpty == true) { + if (state.channels.isNotEmpty == true) { // ignore: unawaited_futures - queryChannelsOnline(filter: { - 'cid': { - '\$in': state.channels!.keys.toList(), - }, - }).then( + queryChannelsOnline( + filter: Filter.in_('cid', state.channels.keys.toList()), + // { + // 'cid': { + // '\$in': state.channels!.keys.toList(), + // }, + // } + ).then( (_) async { await resync(); }, @@ -641,7 +646,7 @@ class StreamChatClient { /// Requests channels with a given query. Stream> queryChannels({ - Map? filter, + Filter? filter, List>? sort, Map? options, PaginationParams paginationParams = const PaginationParams(), @@ -684,7 +689,7 @@ class StreamChatClient { /// Requests channels with a given query from the API. Future> queryChannelsOnline({ - required Map? filter, + Filter? filter, List>? sort, Map? options, int? messageLimit, @@ -764,7 +769,7 @@ class StreamChatClient { final updateData = _mapChannelStateToChannel(channels); await _chatPersistenceClient?.updateChannelQueries( - filter ?? {}, + filter, channels.map((c) => c.channel!.cid).toList(), clearQueryCache: paginationParams.offset == 0, ); @@ -775,7 +780,7 @@ class StreamChatClient { /// Requests channels with a given query from the Persistence client. Future> queryChannelsOffline({ - required Map? filter, + required Filter? filter, required List>? sort, PaginationParams paginationParams = const PaginationParams(), }) async { @@ -790,10 +795,10 @@ class StreamChatClient { return updatedData.value; } - MapEntry, List> _mapChannelStateToChannel( + MapEntry, List> _mapChannelStateToChannel( List channelStates, ) { - final channels = {...state.channels ?? {}}; + final channels = {...state.channels}; final newChannels = []; for (final channelState in channelStates) { final channel = channels[channelState.channel!.cid]; @@ -802,7 +807,7 @@ class StreamChatClient { newChannels.add(channel); } else { final newChannel = Channel.fromState(this, channelState); - channels[newChannel.cid] = newChannel; + channels[newChannel.cid!] = newChannel; newChannels.add(newChannel); } } @@ -1061,16 +1066,13 @@ class StreamChatClient { /// A message search. Future search( - Map filters, { + Filter filter, { String? query, List? sort, PaginationParams? paginationParams, Map? messageFilters, }) async { assert(() { - if (filters.isEmpty) { - throw ArgumentError('`filters` cannot be set as null or empty'); - } if (query == null && messageFilters == null) { throw ArgumentError('Provide at least `query` or `messageFilters`'); } @@ -1083,7 +1085,7 @@ class StreamChatClient { }(), 'Check incoming params.'); final payload = { - 'filter_conditions': filters, + 'filter_conditions': filter, 'message_filter_conditions': messageFilters, 'query': query, 'sort': sort, @@ -1194,15 +1196,12 @@ class StreamChatClient { Channel channel( String type, { String? id, - Map extraData = const {}, + Map extraData = const {}, }) { - if (id != null && state.channels?.containsKey('$type:$id') == true) { - if (state.channels!['$type:$id'] != null) { - return state.channels!['$type:$id'] as Channel; - } + if (id != null && state.channels.containsKey('$type:$id')) { + return state.channels['$type:$id']!; } - - return Channel(this, type, id, extraData); + return Channel(this, type, id, extraData: extraData); } /// Update or Create the given user object. @@ -1443,9 +1442,7 @@ class ClientState { if (cid != null) { _client.chatPersistenceClient?.deleteChannels([cid]); } - if (channels != null) { - channels = channels?..removeWhere((cid, ch) => cid == event.cid); - } + channels = channels..removeWhere((cid, ch) => cid == event.cid); })); } @@ -1468,9 +1465,7 @@ class ClientState { .listen((Event event) async { final eventChannel = event.channel!; await _client.chatPersistenceClient?.deleteChannels([eventChannel.cid]); - if (channels != null) { - channels = channels?..remove(eventChannel.cid); - } + channels = channels..remove(eventChannel.cid); })); } @@ -1521,13 +1516,13 @@ class ClientState { _channelsController.stream; /// The current list of channels in memory - Map? get channels => _channelsController.value; + Map get channels => _channelsController.value!; - set channels(Map? v) { - _channelsController.add(v); + set channels(Map? v) { + if (v != null) _channelsController.add(v); } - final BehaviorSubject?> _channelsController = + final BehaviorSubject> _channelsController = BehaviorSubject.seeded({}); final BehaviorSubject _userController = BehaviorSubject(); final BehaviorSubject> _usersController = @@ -1541,7 +1536,7 @@ class ClientState { _userController.close(); _unreadChannelsController.close(); _totalUnreadCountController.close(); - channels!.values.forEach((c) => c.dispose()); + channels.values.forEach((c) => c.dispose()); _channelsController.close(); } } 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 479743b2..e9c21956 100644 --- a/packages/stream_chat/lib/src/db/chat_persistence_client.dart +++ b/packages/stream_chat/lib/src/db/chat_persistence_client.dart @@ -2,6 +2,7 @@ import 'package:stream_chat/src/api/requests.dart'; import 'package:stream_chat/src/models/channel_model.dart'; import 'package:stream_chat/src/models/channel_state.dart'; import 'package:stream_chat/src/models/event.dart'; +import 'package:stream_chat/src/models/filter.dart'; import 'package:stream_chat/src/models/member.dart'; import 'package:stream_chat/src/models/message.dart'; import 'package:stream_chat/src/models/reaction.dart'; @@ -90,7 +91,7 @@ abstract class ChatPersistenceClient { /// Optionally, pass [filter], [sort], [paginationParams] /// for filtering out states. Future> getChannelStates({ - Map? filter, + Filter? filter, List>? sort, PaginationParams? paginationParams, }); @@ -100,7 +101,7 @@ abstract class ChatPersistenceClient { /// If [clearQueryCache] is true before the insert /// the list of matching rows will be deleted Future updateChannelQueries( - Map filter, + Filter? filter, List cids, { bool clearQueryCache = false, }); diff --git a/packages/stream_chat/lib/src/models/channel_model.dart b/packages/stream_chat/lib/src/models/channel_model.dart index fa9f6eab..95145296 100644 --- a/packages/stream_chat/lib/src/models/channel_model.dart +++ b/packages/stream_chat/lib/src/models/channel_model.dart @@ -23,16 +23,16 @@ class ChannelModel { this.memberCount = 0, this.extraData, this.team, - }) : config = config ?? ChannelConfig(), - createdAt = createdAt ?? DateTime.now(), - updatedAt = updatedAt ?? DateTime.now(), - assert( + }) : assert( (cid != null && cid.contains(':')) || (id != null && type != null), 'provide either a cid or an id and type', ), id = id ?? cid!.split(':')[1], type = type ?? cid!.split(':')[0], - cid = cid ?? '$type:$id'; + cid = cid ?? '$type:$id', + config = config ?? ChannelConfig(), + createdAt = createdAt ?? DateTime.now(), + updatedAt = updatedAt ?? DateTime.now(); /// Create a new instance from a json factory ChannelModel.fromJson(Map json) => diff --git a/packages/stream_chat/lib/src/models/filter.dart b/packages/stream_chat/lib/src/models/filter.dart index 423617c7..35fcf51f 100644 --- a/packages/stream_chat/lib/src/models/filter.dart +++ b/packages/stream_chat/lib/src/models/filter.dart @@ -1,5 +1,7 @@ // ignore_for_file: non_constant_identifier_names, constant_identifier_names +import 'package:equatable/equatable.dart'; + const _groupOperators = [ FilterOperator.and, FilterOperator.or, @@ -83,7 +85,7 @@ extension FilterOperatorX on FilterOperator { /// ) /// ``` /// See Query Channels Documentation -class Filter { +class Filter extends Equatable { const Filter.__({ required this.operator, required this.value, @@ -171,6 +173,9 @@ class Filter { /// final Object /*List|List|String*/ value; + @override + List get props => [operator, key, value]; + /// Map toJson() { final json = {}; diff --git a/packages/stream_chat/test/src/api/channel_test.dart b/packages/stream_chat/test/src/api/channel_test.dart index 8f18d5e2..49a12cb4 100644 --- a/packages/stream_chat/test/src/api/channel_test.dart +++ b/packages/stream_chat/test/src/api/channel_test.dart @@ -516,7 +516,7 @@ void main() { ); await channelClient.watch(); - final event = const Event(type: EventType.any); + const event = Event(type: EventType.any); when( () => mockDio.post( @@ -564,7 +564,7 @@ void main() { ); await channelClient.watch(); - final event = const Event(type: EventType.typingStart); + const event = Event(type: EventType.typingStart); when( () => mockDio.post( @@ -610,7 +610,7 @@ void main() { ); await channelClient.watch(); - final event = const Event(type: EventType.typingStop); + const event = Event(type: EventType.typingStop); when( () => mockDio.post( diff --git a/packages/stream_chat/test/src/client_test.dart b/packages/stream_chat/test/src/client_test.dart index c93059d5..553ad88b 100644 --- a/packages/stream_chat/test/src/client_test.dart +++ b/packages/stream_chat/test/src/client_test.dart @@ -10,6 +10,7 @@ import 'package:stream_chat/src/api/requests.dart'; import 'package:stream_chat/src/client.dart'; import 'package:stream_chat/src/exceptions.dart'; import 'package:stream_chat/src/models/channel_model.dart'; +import 'package:stream_chat/src/models/filter.dart'; import 'package:stream_chat/src/models/message.dart'; import 'package:stream_chat/src/models/user.dart'; import 'package:test/test.dart'; @@ -89,7 +90,7 @@ void main() { test('Channel', () { final client = StreamChatClient('test'); - final data = {'test': 1}; + final data = {'test': 1}; final channelClient = client.channel('type', id: 'id', extraData: data); expect(channelClient.type, 'type'); expect(channelClient.id, 'id'); @@ -140,11 +141,7 @@ void main() { when(() => mockDio.interceptors).thenReturn(Interceptors()); final client = StreamChatClient('api-key', httpClient: mockDio); - final queryFilter = { - 'id': { - '\$in': ['test'], - }, - }; + final queryFilter = Filter.in_('id', ['test']); final sortOptions = >[]; final options = {'state': false, 'watch': false, 'presence': true}; const paginationParams = PaginationParams(offset: 2); @@ -192,11 +189,7 @@ void main() { when(() => mockDio.interceptors).thenReturn(Interceptors()); final client = StreamChatClient('api-key', httpClient: mockDio); - final filter = { - 'cid': { - r'$in': ['messaging:testId'] - } - }; + final filter = Filter.in_('cid', ['messaging:testId']); const query = 'hello'; final queryParams = { 'payload': json.encode({ @@ -229,11 +222,7 @@ void main() { when(() => mockDio.interceptors).thenReturn(Interceptors()); final client = StreamChatClient('api-key', httpClient: mockDio); - final filters = { - 'id': { - '\$in': ['test'], - }, - }; + final filters = Filter.in_('id', ['test']); const sortOptions = [SortOption('name')]; const query = 'query'; final queryParams = { @@ -1163,8 +1152,11 @@ void main() { httpClient: mockDio, ); - final channelClient = - client.channel('type', id: 'id', extraData: {'name': 'init'}); + final channelClient = client.channel( + 'type', + id: 'id', + extraData: {'name': 'init'}, + ); const update = { 'set': {'name': 'demo'} diff --git a/packages/stream_chat_flutter/lib/src/channel_list_view.dart b/packages/stream_chat_flutter/lib/src/channel_list_view.dart index 9751ad6d..90afbd64 100644 --- a/packages/stream_chat_flutter/lib/src/channel_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/channel_list_view.dart @@ -84,7 +84,7 @@ class ChannelListView extends StatefulWidget { /// The query filters to use. /// You can query on any of the custom fields you've defined on the [Channel]. /// You can also filter other built-in channel fields. - final Map filter; + final Filter filter; /// Query channels options. /// diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index b4b2176c..2d0e0af4 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -2096,7 +2096,7 @@ class MessageInputState extends State { } return sendingFuture.then((resp) { - if (resp.message?.type == 'error') { + if (resp.message?._type == 'error') { _parseExistingMessage(message); } if (widget.onMessageSent != null) { diff --git a/packages/stream_chat_flutter/lib/src/message_search_list_view.dart b/packages/stream_chat_flutter/lib/src/message_search_list_view.dart index 6431a311..d7ece34e 100644 --- a/packages/stream_chat_flutter/lib/src/message_search_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_search_list_view.dart @@ -71,7 +71,7 @@ class MessageSearchListView extends StatefulWidget { /// The query filters to use. /// You can query on any of the custom fields you've defined on the [Channel]. /// You can also filter other built-in channel fields. - final Map filters; + final Filter filters; /// The sorting used for the channels matching the filters. /// Sorting is based on field and direction, multiple sorting options can be provided. diff --git a/packages/stream_chat_flutter_core/analysis_options.yaml b/packages/stream_chat_flutter_core/analysis_options.yaml index 545d5492..891101e0 100644 --- a/packages/stream_chat_flutter_core/analysis_options.yaml +++ b/packages/stream_chat_flutter_core/analysis_options.yaml @@ -3,7 +3,7 @@ analyzer: - lib/**/*.g.dart - lib/**/*.freezed.dart - example/* - - test/* + linter: rules: - always_use_package_imports diff --git a/packages/stream_chat_flutter_core/example/lib/main.dart b/packages/stream_chat_flutter_core/example/lib/main.dart index f5f803c8..e7ef400a 100644 --- a/packages/stream_chat_flutter_core/example/lib/main.dart +++ b/packages/stream_chat_flutter_core/example/lib/main.dart @@ -78,14 +78,12 @@ class HomeScreen extends StatelessWidget { body: ChannelsBloc( child: ChannelListCore( channelListController: channelListController, - filter: { - 'type': 'messaging', - 'members': { - r'$in': [ - StreamChatCore.of(context).user!.id, - ] - } - }, + filter: Filter.and([ + Filter.equal('type', 'messaging'), + Filter.in_('members', [ + StreamChatCore.of(context).user!.id, + ]) + ]), emptyBuilder: (BuildContext context) { return Center( child: Text('Looks like you are not in any channels'), diff --git a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart index 322a2780..8ead2637 100644 --- a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart @@ -92,7 +92,7 @@ class ChannelListCore extends StatefulWidget { /// The query filters to use. /// You can query on any of the custom fields you've defined on the [Channel]. /// You can also filter other built-in channel fields. - final Map? filter; + final Filter? filter; /// Query channels options. /// diff --git a/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart b/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart index 7910ab7e..32e63bdc 100644 --- a/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart +++ b/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart @@ -88,7 +88,7 @@ class ChannelsBlocState extends State /// Calls [client.queryChannels] updating [queryChannelsLoading] stream Future queryChannels({ - Map? filter, + Filter? filter, List>? sortOptions, PaginationParams paginationParams = const PaginationParams(limit: 30), Map? options, @@ -160,9 +160,8 @@ class ChannelsBlocState extends State newChannels.insert(0, _hiddenChannels[hiddenIndex]); _hiddenChannels.removeAt(hiddenIndex); } else { - if (client.state.channels != null && - client.state.channels?[e.cid] != null) { - newChannels.insert(0, client.state.channels![e.cid]!); + if (client.state.channels[e.cid] != null) { + newChannels.insert(0, client.state.channels[e.cid]!); } } } diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart b/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart index 8586e1ff..d6220cf3 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_search_bloc.dart @@ -9,7 +9,7 @@ import 'package:stream_chat_flutter_core/src/stream_chat_core.dart'; /// [MessageSearchBloc] can be access at anytime by using the static [of] method /// using Flutter's [BuildContext]. /// -// API docs: https://getstream.io/chat/docs/flutter-dart/send_message/ +/// API docs: https://getstream.io/chat/docs/flutter-dart/send_message/ class MessageSearchBloc extends StatefulWidget { /// Instantiate a new MessageSearchBloc const MessageSearchBloc({ @@ -58,7 +58,7 @@ class MessageSearchBlocState extends State /// Calls [StreamChatClient.search] updating /// [messagesStream] and [queryMessagesLoading] stream Future search({ - required Map filter, + required Filter filter, Map? messageFilter, List? sort, String? query, diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart index ca661dc6..2a2d31f5 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart @@ -67,7 +67,7 @@ class MessageSearchListCore extends StatefulWidget { /// The query filters to use. /// You can query on any of the custom fields you've defined on the [Channel]. /// You can also filter other built-in channel fields. - final Map filters; + final Filter filters; /// The sorting used for the channels matching the filters. /// Sorting is based on field and direction, multiple sorting options can be diff --git a/packages/stream_chat_flutter_core/test/channel_list_core_test.dart b/packages/stream_chat_flutter_core/test/channel_list_core_test.dart index 5bbdaf39..53303231 100644 --- a/packages/stream_chat_flutter_core/test/channel_list_core_test.dart +++ b/packages/stream_chat_flutter_core/test/channel_list_core_test.dart @@ -24,7 +24,7 @@ void main() { client, 'testType$index', 'testId$index', - {'extra_data_key': 'extra_data_value_$index'}, + extraData: {'extra_data_key': 'extra_data_value_$index'}, ); }, ); diff --git a/packages/stream_chat_flutter_core/test/channels_bloc_test.dart b/packages/stream_chat_flutter_core/test/channels_bloc_test.dart index 28136add..19d327bd 100644 --- a/packages/stream_chat_flutter_core/test/channels_bloc_test.dart +++ b/packages/stream_chat_flutter_core/test/channels_bloc_test.dart @@ -26,7 +26,7 @@ void main() { client, 'testType$index', 'testId$index', - {'extra_data_key': 'extra_data_value_$index'}, + extraData: {'extra_data_key': 'extra_data_value_$index'}, ); }, ); @@ -703,7 +703,7 @@ void main() { final mockClient = MockClient(); final channels = _generateChannels(mockClient); final stateChannels = { - for (var c in _generateChannels(mockClient, offset: 5)) c.cid: c + for (var c in _generateChannels(mockClient, offset: 5)) c.cid!: c }; const channelsBlocKey = Key('channelsBloc'); final channelsBloc = ChannelsBloc( diff --git a/packages/stream_chat_flutter_core/test/message_search_bloc_test.dart b/packages/stream_chat_flutter_core/test/message_search_bloc_test.dart index 5b427c02..91c07435 100644 --- a/packages/stream_chat_flutter_core/test/message_search_bloc_test.dart +++ b/packages/stream_chat_flutter_core/test/message_search_bloc_test.dart @@ -8,6 +8,8 @@ import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'matchers/get_message_response_matcher.dart'; import 'mocks.dart'; +final testFilter = Filter.custom(operator: '\$test', value: 'testValue'); + void main() { List _generateMessages({ int count = 3, @@ -50,7 +52,7 @@ void main() { ); try { - await usersBlocState.search(filter: {}); + await usersBlocState.search(filter: testFilter); } catch (e) { expect(e, isInstanceOf()); } @@ -82,7 +84,7 @@ void main() { final messageResponseList = _generateMessages(); when(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), @@ -91,7 +93,7 @@ void main() { (_) async => SearchMessagesResponse()..results = messageResponseList, ); - messageSearchBlocState.search(filter: {}); + messageSearchBlocState.search(filter: testFilter); await expectLater( messageSearchBlocState.messagesStream, @@ -99,7 +101,7 @@ void main() { ); verify(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), @@ -133,14 +135,14 @@ void main() { const error = 'Error! Error! Error!'; when(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), paginationParams: any(named: 'paginationParams'), )).thenThrow(error); - messageSearchBlocState.search(filter: {}); + messageSearchBlocState.search(filter: testFilter); await expectLater( messageSearchBlocState.messagesStream, @@ -148,7 +150,7 @@ void main() { ); verify(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), @@ -185,7 +187,7 @@ void main() { final messageResponseList = _generateMessages(); when(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), @@ -194,7 +196,7 @@ void main() { (_) async => SearchMessagesResponse()..results = messageResponseList, ); - messageSearchBlocState.search(filter: {}); + messageSearchBlocState.search(filter: testFilter); await expectLater( messageSearchBlocState.messagesStream, @@ -202,7 +204,7 @@ void main() { ); verify(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), @@ -214,7 +216,7 @@ void main() { final pagination = PaginationParams(offset: offset); when(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), @@ -224,7 +226,7 @@ void main() { SearchMessagesResponse()..results = paginatedMessageResponseList, ); - messageSearchBlocState.search(pagination: pagination, filter: {}); + messageSearchBlocState.search(pagination: pagination, filter: testFilter); await Future.wait([ expectLater( @@ -240,7 +242,7 @@ void main() { ]); verify(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), @@ -277,7 +279,7 @@ void main() { final messageResponseList = _generateMessages(); when(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), @@ -286,7 +288,7 @@ void main() { (_) async => SearchMessagesResponse()..results = messageResponseList, ); - messageSearchBlocState.search(filter: {}); + messageSearchBlocState.search(filter: testFilter); await expectLater( messageSearchBlocState.messagesStream, @@ -294,7 +296,7 @@ void main() { ); verify(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), @@ -306,14 +308,14 @@ void main() { const error = 'Error! Error! Error!'; when(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), paginationParams: pagination, )).thenThrow(error); - messageSearchBlocState.search(pagination: pagination, filter: {}); + messageSearchBlocState.search(pagination: pagination, filter: testFilter); await expectLater( messageSearchBlocState.queryMessagesLoading, @@ -321,7 +323,7 @@ void main() { ); verify(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), diff --git a/packages/stream_chat_flutter_core/test/message_search_list_core_test.dart b/packages/stream_chat_flutter_core/test/message_search_list_core_test.dart index 00aee32a..1f7414d0 100644 --- a/packages/stream_chat_flutter_core/test/message_search_list_core_test.dart +++ b/packages/stream_chat_flutter_core/test/message_search_list_core_test.dart @@ -6,6 +6,8 @@ import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'mocks.dart'; +final testFilter = Filter.custom(operator: '\$test', value: 'testValue'); + void main() { List _generateMessages({ int count = 3, @@ -37,7 +39,7 @@ void main() { loadingBuilder: (BuildContext context) => const Offstage(), emptyBuilder: (BuildContext context) => const Offstage(), errorBuilder: (BuildContext context, Object? error) => const Offstage(), - filters: const {}, + filters: testFilter, ); await tester.pumpWidget(messageSearchListCore); @@ -58,7 +60,7 @@ void main() { loadingBuilder: (BuildContext context) => Offstage(), emptyBuilder: (BuildContext context) => Offstage(), errorBuilder: (BuildContext context, Object? error) => Offstage(), - filters: {}, + filters: testFilter, ); final mockClient = MockClient(); @@ -89,7 +91,7 @@ void main() { emptyBuilder: (BuildContext context) => Offstage(), errorBuilder: (BuildContext context, Object error) => Offstage(), messageSearchListController: controller, - filters: {}, + filters: testFilter, ); expect(controller.loadData, isNull); @@ -125,14 +127,14 @@ void main() { errorBuilder: (BuildContext context, Object error) => Offstage( key: errorWidgetKey, ), - filters: {}, + filters: testFilter, ); final mockClient = MockClient(); const error = 'Error! Error! Error!'; when(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), @@ -153,7 +155,7 @@ void main() { expect(find.byKey(errorWidgetKey), findsOneWidget); verify(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), @@ -174,14 +176,14 @@ void main() { loadingBuilder: (BuildContext context) => Offstage(), emptyBuilder: (BuildContext context) => Offstage(key: emptyWidgetKey), errorBuilder: (BuildContext context, Object error) => Offstage(), - filters: {}, + filters: testFilter, ); final mockClient = MockClient(); final messageResponseList = []; when(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), @@ -204,7 +206,7 @@ void main() { expect(find.byKey(emptyWidgetKey), findsOneWidget); verify(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), @@ -226,14 +228,14 @@ void main() { loadingBuilder: (BuildContext context) => Offstage(), emptyBuilder: (BuildContext context) => Offstage(), errorBuilder: (BuildContext context, Object error) => Offstage(), - filters: {}, + filters: testFilter, ); final mockClient = MockClient(); final messageResponseList = _generateMessages(); when(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), @@ -256,7 +258,7 @@ void main() { expect(find.byKey(childWidgetKey), findsOneWidget); verify(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), @@ -284,14 +286,14 @@ void main() { emptyBuilder: (BuildContext context) => Offstage(), errorBuilder: (BuildContext context, Object error) => Offstage(), paginationParams: pagination, - filters: {}, + filters: testFilter, ); final mockClient = MockClient(); final messageResponseList = _generateMessages(); when(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), @@ -325,7 +327,7 @@ void main() { ); verify(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), @@ -341,7 +343,7 @@ void main() { final paginatedMessageResponseList = _generateMessages(offset: offset); final updatedPagination = pagination.copyWith(offset: offset); when(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), @@ -365,7 +367,7 @@ void main() { ); verify(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), @@ -400,14 +402,14 @@ void main() { emptyBuilder: (BuildContext context) => Offstage(), errorBuilder: (BuildContext context, Object error) => Offstage(), paginationParams: pagination.copyWith(limit: limit), - filters: {}, + filters: testFilter, ); final mockClient = MockClient(); final messageResponseList = _generateMessages(); when(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), @@ -445,7 +447,7 @@ void main() { ); verify(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), @@ -458,7 +460,7 @@ void main() { final updatedMessageResponseList = _generateMessages(count: limit); final updatedPagination = pagination.copyWith(limit: limit); when(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), @@ -479,7 +481,7 @@ void main() { ); verify(() => mockClient.search( - any(), + testFilter, query: any(named: 'query'), sort: any(named: 'sort'), messageFilters: any(named: 'messageFilters'), 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 099f6798..5bff63dc 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 @@ -18,7 +18,7 @@ class ChannelQueryDao extends DatabaseAccessor /// Creates a new channel query dao instance ChannelQueryDao(MoorChatDatabase db) : super(db); - String _computeHash(Map? filter) { + String _computeHash(Filter? filter) { if (filter == null) { return 'allchannels'; } @@ -30,7 +30,7 @@ class ChannelQueryDao extends DatabaseAccessor /// If [clearQueryCache] is true before the insert /// the list of matching rows will be deleted Future updateChannelQueries( - Map filter, + Filter? filter, List cids, { bool clearQueryCache = false, }) async => @@ -58,7 +58,7 @@ class ChannelQueryDao extends DatabaseAccessor }); /// - Future> getCachedChannelCids(Map? filter) { + Future> getCachedChannelCids(Filter? filter) { final hash = _computeHash(filter); return (select(channelQueries)..where((c) => c.queryHash.equals(hash))) .map((c) => c.channelCid) @@ -67,7 +67,7 @@ class ChannelQueryDao extends DatabaseAccessor /// Get list of channels by filter, sort and paginationParams Future> getChannels({ - Map? filter, + Filter? filter, List>? sort, PaginationParams? paginationParams, }) async { 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 3f955eb2..20c4e327 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 @@ -253,7 +253,7 @@ class StreamChatPersistenceClient extends ChatPersistenceClient { @override Future> getChannelStates({ - Map? filter, + Filter? filter, List>? sort, PaginationParams? paginationParams, }) { @@ -273,7 +273,7 @@ class StreamChatPersistenceClient extends ChatPersistenceClient { @override Future updateChannelQueries( - Map filter, + Filter? filter, List cids, { bool clearQueryCache = false, }) { 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 dee6e076..3f04711d 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 @@ -17,11 +17,7 @@ void main() { }); test('updateChannelQueries', () async { - const filter = { - 'members': { - r'$in': ['testUserId'], - }, - }; + final filter = Filter.in_('members', const ['testUserId']); const cids = ['testCid1', 'testCid2', 'testCid3']; @@ -36,11 +32,7 @@ void main() { }); test('clear queryCache before updateChannelQueries', () async { - const filter = { - 'members': { - r'$in': ['testUserId'], - }, - }; + final filter = Filter.in_('members', const ['testUserId']); const cids = ['testCid1', 'testCid2', 'testCid3']; @@ -59,11 +51,7 @@ void main() { }); test('getCachedChannelCids', () async { - const filter = { - 'members': { - r'$in': ['testUserId'], - }, - }; + final filter = Filter.in_('members', const ['testUserId']); const cids = ['testCid1', 'testCid2', 'testCid3']; @@ -78,7 +66,7 @@ void main() { }); Future> _insertTestDataForGetChannel( - Map filter, { + Filter filter, { int count = 3, }) async { final now = DateTime.now(); @@ -110,11 +98,7 @@ void main() { } group('getChannels', () { - const filter = { - 'members': { - r'$in': ['testUserId'], - }, - }; + final filter = Filter.in_('members', const ['testUserId']); test('should return empty list of channels', () async { final channels = await channelQueryDao.getChannels(filter: filter); 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 26d0bfb5..8a275201 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 @@ -292,7 +292,7 @@ void main() { }); test('updateChannelQueries', () async { - const filter = {}; + final filter = Filter.in_('members', const ['testUserId']); const cids = []; when(() => mockDatabase.channelQueryDao.updateChannelQueries(filter, cids))