Return retrieved document metadata from the Nexus document client.
ci/woodpecker/push/woodpecker Pipeline failed
Details
ci/woodpecker/push/woodpecker Pipeline failed
Details
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
c2360c2e9e
commit
574cadc0a1
|
|
@ -53,6 +53,29 @@ public sealed class NexusDocumentClient
|
||||||
return NexusWireStatus.ToResult(response.Status, body);
|
return NexusWireStatus.ToResult(response.Status, body);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads many documents in one RPC. Missing ids are omitted from the list.
|
||||||
|
/// </summary>
|
||||||
|
public Robotico.Result.Result<IReadOnlyList<NexusRetrievedDocument>> GetDocuments(
|
||||||
|
string collectionName,
|
||||||
|
IReadOnlyList<string> documentIds) => InvokeGeneric(() =>
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(documentIds);
|
||||||
|
DocumentCollectionGetManyRequest request = new() { CollectionName = collectionName };
|
||||||
|
request.DocumentIds.AddRange(documentIds);
|
||||||
|
DocumentCollectionGetManyResponse response = _client.CollectionGetMany(request, Metadata());
|
||||||
|
List<NexusRetrievedDocument> found = new(response.Documents.Count);
|
||||||
|
foreach (DocumentCollectionDocumentWire doc in response.Documents)
|
||||||
|
{
|
||||||
|
string body = doc.JsonUtf8.Length > 0
|
||||||
|
? System.Text.Encoding.UTF8.GetString(doc.JsonUtf8.Span)
|
||||||
|
: doc.JsonBody;
|
||||||
|
found.Add(new NexusRetrievedDocument(doc.DocumentId, body));
|
||||||
|
}
|
||||||
|
|
||||||
|
return NexusWireStatus.ToResult(response.Status, (IReadOnlyList<NexusRetrievedDocument>)found);
|
||||||
|
});
|
||||||
|
|
||||||
/// <summary>Deletes a document by id when present (idempotent).</summary>
|
/// <summary>Deletes a document by id when present (idempotent).</summary>
|
||||||
public Robotico.Result.Result DeleteDocument(string collectionName, string documentId) => Invoke(() =>
|
public Robotico.Result.Result DeleteDocument(string collectionName, string documentId) => Invoke(() =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
namespace Robotico.Nexus.Client.Document;
|
||||||
|
|
||||||
|
/// <summary>One document returned by <see cref="NexusDocumentClient.GetDocuments"/>.</summary>
|
||||||
|
public readonly record struct NexusRetrievedDocument(string DocumentId, string JsonBody);
|
||||||
|
|
@ -48,6 +48,22 @@ public class NexusDocumentClientTests : IAsyncLifetime
|
||||||
Assert.Equal("""{"name":"Ada"}""", body);
|
Assert.Equal("""{"name":"Ada"}""", body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetDocuments_ReturnsFound_AndOmitsMissing()
|
||||||
|
{
|
||||||
|
_documentClient.UpsertDocument("users", "u1", """{"name":"Ada"}""");
|
||||||
|
_documentClient.UpsertDocument("users", "u3", """{"name":"Grace"}""");
|
||||||
|
|
||||||
|
Robotico.Result.Result<IReadOnlyList<NexusRetrievedDocument>> fetched =
|
||||||
|
_documentClient.GetDocuments("users", ["u3", "missing", "u1"]);
|
||||||
|
|
||||||
|
Assert.True(fetched.IsSuccess(out IReadOnlyList<NexusRetrievedDocument>? docs, out _));
|
||||||
|
Assert.Equal(2, docs!.Count);
|
||||||
|
Assert.Equal("u3", docs[0].DocumentId);
|
||||||
|
Assert.Equal("""{"name":"Grace"}""", docs[0].JsonBody);
|
||||||
|
Assert.Equal("u1", docs[1].DocumentId);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetDocument_ReturnsNull_WhenNotFound()
|
public void GetDocument_ReturnsNull_WhenNotFound()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ using Mishima.Nexus.Wire.V1;
|
||||||
namespace Robotico.Nexus.Client.Tests.TestSupport;
|
namespace Robotico.Nexus.Client.Tests.TestSupport;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// In-memory fake standing in for a real Nexus document engine host — only the RPCs used by
|
/// In-memory fake standing in for a real Nexus document engine host — the RPCs used by
|
||||||
/// <see cref="Robotico.Nexus.Client.Document.NexusDocumentClient"/> (Ping + single-document CRUD).
|
/// <see cref="Robotico.Nexus.Client.Document.NexusDocumentClient"/> (Ping, CRUD, GetMany).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class FakeDocumentEngineService : NexusDocumentEngineService.NexusDocumentEngineServiceBase
|
public sealed class FakeDocumentEngineService : NexusDocumentEngineService.NexusDocumentEngineServiceBase
|
||||||
{
|
{
|
||||||
|
|
@ -36,6 +36,29 @@ public sealed class FakeDocumentEngineService : NexusDocumentEngineService.Nexus
|
||||||
return Task.FromResult(new DocumentGetResponse { Status = NexusStatuses.Ok, Found = false });
|
return Task.FromResult(new DocumentGetResponse { Status = NexusStatuses.Ok, Found = false });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override Task<DocumentCollectionGetManyResponse> CollectionGetMany(
|
||||||
|
DocumentCollectionGetManyRequest request,
|
||||||
|
ServerCallContext context)
|
||||||
|
{
|
||||||
|
DocumentCollectionGetManyResponse response = new() { Status = NexusStatuses.Ok };
|
||||||
|
foreach (string id in request.DocumentIds)
|
||||||
|
{
|
||||||
|
if (!_documents.TryGetValue((request.CollectionName, id), out string? body))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
response.Documents.Add(new DocumentCollectionDocumentWire
|
||||||
|
{
|
||||||
|
DocumentId = id,
|
||||||
|
JsonBody = body,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.FromResult(response);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override Task<DocumentDeleteResponse> DeleteDocument(DocumentDeleteRequest request, ServerCallContext context)
|
public override Task<DocumentDeleteResponse> DeleteDocument(DocumentDeleteRequest request, ServerCallContext context)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue