diff --git a/packages/stream_chat/lib/src/client/client.dart b/packages/stream_chat/lib/src/client/client.dart index 9c593694..c3605ac5 100644 --- a/packages/stream_chat/lib/src/client/client.dart +++ b/packages/stream_chat/lib/src/client/client.dart @@ -1073,6 +1073,28 @@ class StreamChatClient { Future updateUsers(List users) => _chatApi.user.updateUsers(users); + /// Partially update the given user with [id]. + /// Use [set] to define values to be set. + /// Use [unset] to define values to be unset. + Future partialUpdateUser( + String id, { + Map? set, + List? unset, + }) { + final user = PartialUpdateUserRequest( + id: id, + set: set, + unset: unset, + ); + return partialUpdateUsers([user]); + } + + /// Batch partial updates the [users]. + Future partialUpdateUsers( + List users, + ) => + _chatApi.user.partialUpdateUsers(users); + /// Bans a user from all channels Future banUser( String targetUserId, [ diff --git a/packages/stream_chat/lib/src/core/api/requests.dart b/packages/stream_chat/lib/src/core/api/requests.dart index 6f00b374..3f4e79de 100644 --- a/packages/stream_chat/lib/src/core/api/requests.dart +++ b/packages/stream_chat/lib/src/core/api/requests.dart @@ -156,3 +156,29 @@ class PaginationParams extends Equatable { lessThanOrEqual, ]; } + +/// Request model for the [client.partialUpdateUser] api call. +@JsonSerializable(createFactory: false) +class PartialUpdateUserRequest extends Equatable { + /// Creates a new PartialUpdateUserRequest instance. + const PartialUpdateUserRequest({ + required this.id, + this.set, + this.unset, + }); + + /// User ID. + final String id; + + /// Fields to set. + final Map? set; + + /// Fields to unset. + final List? unset; + + /// Serialize model to json + Map toJson() => _$PartialUpdateUserRequestToJson(this); + + @override + List get props => [id, set, unset]; +} diff --git a/packages/stream_chat/lib/src/core/api/requests.g.dart b/packages/stream_chat/lib/src/core/api/requests.g.dart index 7d45ee86..62ec12b3 100644 --- a/packages/stream_chat/lib/src/core/api/requests.g.dart +++ b/packages/stream_chat/lib/src/core/api/requests.g.dart @@ -54,3 +54,14 @@ Map _$PaginationParamsToJson(PaginationParams instance) { writeNotNull('id_lte', instance.lessThanOrEqual); return val; } + +Map _$PartialUpdateUserRequestToJson( + PartialUpdateUserRequest instance) => + { + 'stringify': instance.stringify, + 'hash_code': instance.hashCode, + 'id': instance.id, + 'set': instance.set, + 'unset': instance.unset, + 'props': instance.props, + }; diff --git a/packages/stream_chat/lib/src/core/api/user_api.dart b/packages/stream_chat/lib/src/core/api/user_api.dart index 61159731..916976c8 100644 --- a/packages/stream_chat/lib/src/core/api/user_api.dart +++ b/packages/stream_chat/lib/src/core/api/user_api.dart @@ -46,4 +46,17 @@ class UserApi { ); return UpdateUsersResponse.fromJson(response.data); } + + /// Batch partial update of [users]. + Future partialUpdateUsers( + List users, + ) async { + final response = await _client.patch( + '/users', + data: { + 'users': users, + }, + ); + return UpdateUsersResponse.fromJson(response.data); + } } diff --git a/packages/stream_chat/lib/src/core/models/channel_state.g.dart b/packages/stream_chat/lib/src/core/models/channel_state.g.dart index 0da51768..5100932c 100644 --- a/packages/stream_chat/lib/src/core/models/channel_state.g.dart +++ b/packages/stream_chat/lib/src/core/models/channel_state.g.dart @@ -21,7 +21,7 @@ ChannelState _$ChannelStateFromJson(Map json) => ChannelState( pinnedMessages: (json['pinned_messages'] as List?) ?.map((e) => Message.fromJson(e as Map)) .toList() ?? - const [], + _emptyPinnedMessages, watcherCount: json['watcher_count'] as int?, watchers: (json['watchers'] as List?) ?.map((e) => User.fromJson(e as Map)) diff --git a/packages/stream_chat/test/src/client/client_test.dart b/packages/stream_chat/test/src/client/client_test.dart index c9aa8968..b59937bb 100644 --- a/packages/stream_chat/test/src/client/client_test.dart +++ b/packages/stream_chat/test/src/client/client_test.dart @@ -1772,6 +1772,46 @@ void main() { verifyNoMoreInteractions(api.user); }); + test('`.partialUpdateUser`', () async { + const userId = 'test-user-id'; + + final set = {'color': 'yellow'}; + final unset = []; + + final partialUpdateRequest = PartialUpdateUserRequest( + id: userId, + set: set, + unset: unset, + ); + + final updatedUser = User( + id: userId, + extraData: {'color': set['color']}, + ); + + when(() => api.user.partialUpdateUsers([partialUpdateRequest])) + .thenAnswer( + (_) async => UpdateUsersResponse() + ..users = { + updatedUser.id: updatedUser, + }, + ); + + final res = await client.partialUpdateUser( + userId, + set: set, + unset: unset, + ); + + expect(res, isNotNull); + expect(res.users, {updatedUser.id: updatedUser}); + + verify( + () => api.user.partialUpdateUsers([partialUpdateRequest]), + ).called(1); + verifyNoMoreInteractions(api.user); + }); + test('`.banUser`', () async { const userId = 'test-user-id';