patchDocument method

Future<DocumentPutResponse?> patchDocument({
  1. required String path,
  2. required Map<String, dynamic> patch,
  3. String? ifMatch,
  4. PeerId? toServer,
})

Patch a document using JSON Merge Patch (RFC 7396)

Applies partial updates to an existing JSON document.

path Document path (e.g., "profile", "avatar") patch JSON Merge Patch object (keys with null values are removed, others are merged) ifMatch Optional: ETag for optimistic locking toServer Optional: specify which server to use

Implementation

Future<DocumentPutResponse?> patchDocument({
  required String path,
  required Map<String, dynamic> patch,
  String? ifMatch,
  PeerId? toServer,
}) async {
  final serverId = toServer ?? await _serverSelector.selectServer(config.preferredServers);
  if (serverId == null) {
    _logger.warning('No S&F server available for document PATCH');
    return null;
  }

  try {
    final context = Context();
    final stream = await host.newStream(
      serverId,
      ['/ricochet/store/doc/1.0.0'],
      context,
    ).timeout(config.connectionTimeout);

    final response = await DocumentHandler.patchDocument(
      stream,
      ownerPeerId: host.id,  // Can only PATCH own documents
      path: path,
      patch: patch,
      ifMatch: ifMatch,
    ).timeout(config.messageTimeout);

    await stream.close();

    if (!response.isSuccess) {
      _logger.warning('PATCH document failed with status ${response.status}: ${response.error}');
      return null;
    }

    _logger.info('Patched document: doc/$path');
    return DocumentPutResponse(
      status: response.status,
      etag: response.etag,
      lastModified: response.lastModified,
      created: false,  // PATCH never creates
    );
  } on TimeoutException {
    _logger.warning('PATCH document timed out');
    return null;
  } catch (e) {
    _logger.warning('Failed to PATCH document: $e');
    return null;
  }
}