diff --git a/src/EventStore.Client.Common/protos/persistentsubscriptions.proto b/src/EventStore.Client.Common/protos/persistentsubscriptions.proto index 59a5b1c26..966cd7e58 100644 --- a/src/EventStore.Client.Common/protos/persistentsubscriptions.proto +++ b/src/EventStore.Client.Common/protos/persistentsubscriptions.proto @@ -19,7 +19,7 @@ message ReadReq { } message Options { - string stream_name = 1; + event_store.client.StreamIdentifier stream_identifier = 1; string group_name = 2; int32 buffer_size = 3; UUIDOption uuid_option = 4; @@ -71,7 +71,7 @@ message ReadResp { } message RecordedEvent { event_store.client.UUID id = 1; - string stream_name = 2; + event_store.client.StreamIdentifier stream_identifier = 2; uint64 stream_revision = 3; uint64 prepare_position = 4; uint64 commit_position = 5; @@ -89,7 +89,7 @@ message CreateReq { Options options = 1; message Options { - string stream_name = 1; + event_store.client.StreamIdentifier stream_identifier = 1; string group_name = 2; Settings settings = 3; } @@ -124,7 +124,7 @@ message UpdateReq { Options options = 1; message Options { - string stream_name = 1; + event_store.client.StreamIdentifier stream_identifier = 1; string group_name = 2; Settings settings = 3; } @@ -159,7 +159,7 @@ message DeleteReq { Options options = 1; message Options { - string stream_name = 1; + event_store.client.StreamIdentifier stream_identifier = 1; string group_name = 2; } } diff --git a/src/EventStore.Client.Common/protos/shared.proto b/src/EventStore.Client.Common/protos/shared.proto index 5954b9033..6b18dd5ba 100644 --- a/src/EventStore.Client.Common/protos/shared.proto +++ b/src/EventStore.Client.Common/protos/shared.proto @@ -15,3 +15,8 @@ message UUID { } message Empty { } + +message StreamIdentifier { + reserved 1 to 2; + bytes streamName = 3; +} diff --git a/src/EventStore.Client.Common/protos/streams.proto b/src/EventStore.Client.Common/protos/streams.proto index aee5428d3..8594af31b 100644 --- a/src/EventStore.Client.Common/protos/streams.proto +++ b/src/EventStore.Client.Common/protos/streams.proto @@ -36,7 +36,7 @@ message ReadReq { Backwards = 1; } message StreamOptions { - string stream_name = 1; + event_store.client.StreamIdentifier stream_identifier = 1; oneof revision_option { uint64 revision = 2; event_store.client.Empty start = 3; @@ -99,7 +99,7 @@ message ReadResp { message RecordedEvent { event_store.client.UUID id = 1; - string stream_name = 2; + event_store.client.StreamIdentifier stream_identifier = 2; uint64 stream_revision = 3; uint64 prepare_position = 4; uint64 commit_position = 5; @@ -127,7 +127,7 @@ message AppendReq { } message Options { - string stream_name = 1; + event_store.client.StreamIdentifier stream_identifier = 1; oneof expected_stream_revision { uint64 revision = 2; event_store.client.Empty no_stream = 3; @@ -182,7 +182,7 @@ message DeleteReq { Options options = 1; message Options { - string stream_name = 1; + event_store.client.StreamIdentifier stream_identifier = 1; oneof expected_stream_revision { uint64 revision = 2; event_store.client.Empty no_stream = 3; @@ -208,7 +208,7 @@ message TombstoneReq { Options options = 1; message Options { - string stream_name = 1; + event_store.client.StreamIdentifier stream_identifier = 1; oneof expected_stream_revision { uint64 revision = 2; event_store.client.Empty no_stream = 3; diff --git a/src/EventStore.Client.PersistentSubscriptions/EventStorePersistentSubscriptionsClient.Create.cs b/src/EventStore.Client.PersistentSubscriptions/EventStorePersistentSubscriptionsClient.Create.cs index cba67298d..aae39800e 100644 --- a/src/EventStore.Client.PersistentSubscriptions/EventStorePersistentSubscriptionsClient.Create.cs +++ b/src/EventStore.Client.PersistentSubscriptions/EventStorePersistentSubscriptionsClient.Create.cs @@ -31,7 +31,7 @@ public async Task CreateAsync(string streamName, string groupName, await _client.CreateAsync(new CreateReq { Options = new CreateReq.Types.Options { - StreamName = streamName, + StreamIdentifier = streamName, GroupName = groupName, Settings = new CreateReq.Types.Settings { Revision = settings.StartFrom, diff --git a/src/EventStore.Client.PersistentSubscriptions/EventStorePersistentSubscriptionsClient.Delete.cs b/src/EventStore.Client.PersistentSubscriptions/EventStorePersistentSubscriptionsClient.Delete.cs index b7e28a512..bb121fa53 100644 --- a/src/EventStore.Client.PersistentSubscriptions/EventStorePersistentSubscriptionsClient.Delete.cs +++ b/src/EventStore.Client.PersistentSubscriptions/EventStorePersistentSubscriptionsClient.Delete.cs @@ -9,7 +9,7 @@ public async Task DeleteAsync(string streamName, string groupName, UserCredentia CancellationToken cancellationToken = default) { await _client.DeleteAsync(new DeleteReq { Options = new DeleteReq.Types.Options { - StreamName = streamName, + StreamIdentifier = streamName, GroupName = groupName } }, RequestMetadata.Create(userCredentials ?? Settings.DefaultCredentials), cancellationToken: cancellationToken); diff --git a/src/EventStore.Client.PersistentSubscriptions/EventStorePersistentSubscriptionsClient.Read.cs b/src/EventStore.Client.PersistentSubscriptions/EventStorePersistentSubscriptionsClient.Read.cs index c548fe09e..5b29f8842 100644 --- a/src/EventStore.Client.PersistentSubscriptions/EventStorePersistentSubscriptionsClient.Read.cs +++ b/src/EventStore.Client.PersistentSubscriptions/EventStorePersistentSubscriptionsClient.Read.cs @@ -40,7 +40,7 @@ public Task SubscribeAsync(string streamName, string gro return PersistentSubscription.Confirm(call, new ReadReq.Types.Options { BufferSize = bufferSize, GroupName = groupName, - StreamName = streamName, + StreamIdentifier = streamName, UuidOption = new ReadReq.Types.Options.Types.UUIDOption {Structured = new Empty()} }, autoAck, eventAppeared, subscriptionDropped ?? delegate { }, cancellationToken); diff --git a/src/EventStore.Client.PersistentSubscriptions/EventStorePersistentSubscriptionsClient.Update.cs b/src/EventStore.Client.PersistentSubscriptions/EventStorePersistentSubscriptionsClient.Update.cs index 02c5b568c..75b565b54 100644 --- a/src/EventStore.Client.PersistentSubscriptions/EventStorePersistentSubscriptionsClient.Update.cs +++ b/src/EventStore.Client.PersistentSubscriptions/EventStorePersistentSubscriptionsClient.Update.cs @@ -31,7 +31,7 @@ public async Task UpdateAsync(string streamName, string groupName, PersistentSub await _client.UpdateAsync(new UpdateReq { Options = new UpdateReq.Types.Options { - StreamName = streamName, + StreamIdentifier = streamName, GroupName = groupName, Settings = new UpdateReq.Types.Settings { Revision = settings.StartFrom, diff --git a/src/EventStore.Client.PersistentSubscriptions/PersistentSubscription.cs b/src/EventStore.Client.PersistentSubscriptions/PersistentSubscription.cs index 7e0196335..46f902401 100644 --- a/src/EventStore.Client.PersistentSubscriptions/PersistentSubscription.cs +++ b/src/EventStore.Client.PersistentSubscriptions/PersistentSubscription.cs @@ -144,7 +144,7 @@ ResolvedEvent ConvertToResolvedEvent(ReadResp response) => e == null ? null : new EventRecord( - e.StreamName, + e.StreamIdentifier, Uuid.FromDto(e.Id), new StreamPosition(e.StreamRevision), new Position(e.CommitPosition, e.PreparePosition), diff --git a/src/EventStore.Client.Streams/EventStoreClient.Append.cs b/src/EventStore.Client.Streams/EventStoreClient.Append.cs index 8cca6d45c..3441a3295 100644 --- a/src/EventStore.Client.Streams/EventStoreClient.Append.cs +++ b/src/EventStore.Client.Streams/EventStoreClient.Append.cs @@ -21,7 +21,7 @@ private Task AppendToStreamAsync( return AppendToStreamInternal(new AppendReq { Options = new AppendReq.Types.Options { - StreamName = streamName, + StreamIdentifier = streamName, Revision = expectedRevision } }, eventData, operationOptions, userCredentials, cancellationToken); @@ -62,7 +62,7 @@ private Task AppendToStreamAsync( return AppendToStreamInternal(new AppendReq { Options = new AppendReq.Types.Options { - StreamName = streamName + StreamIdentifier = streamName } }.WithAnyStreamRevision(expectedState), eventData, operationOptions, userCredentials, cancellationToken); } @@ -106,7 +106,7 @@ private async Task AppendToStreamInternal( foreach (var e in eventData) { _log.LogTrace("Appending event to stream - {streamName}@{eventId} {eventType}.", - header.Options.StreamName, e.EventId, e.Type); + header.Options.StreamIdentifier, e.EventId, e.Type); await call.RequestStream.WriteAsync(new AppendReq { ProposedMessage = new AppendReq.Types.ProposedMessage { Id = e.EventId.ToDto(), @@ -135,7 +135,7 @@ await call.RequestStream.WriteAsync(new AppendReq { response.Success.Position.PreparePosition) : default); _log.LogDebug("Append to stream succeeded - {streamName}@{logPosition}/{nextExpectedVersion}.", - header.Options.StreamName, writeResult.LogPosition, writeResult.NextExpectedVersion); + header.Options.StreamIdentifier, writeResult.LogPosition, writeResult.NextExpectedVersion); } else { if (response.WrongExpectedVersion != null) { var expectedRevision = response.WrongExpectedVersion.ExpectedRevisionOptionCase switch { @@ -154,15 +154,15 @@ await call.RequestStream.WriteAsync(new AppendReq { _log.LogDebug( "Append to stream failed with Wrong Expected Version - {streamName}/{expectedRevision}/{currentRevision}", - header.Options.StreamName, expectedRevision, currentRevision); + header.Options.StreamIdentifier, expectedRevision, currentRevision); if (operationOptions.ThrowOnAppendFailure) { - throw new WrongExpectedVersionException(header.Options.StreamName, expectedRevision, + throw new WrongExpectedVersionException(header.Options.StreamIdentifier, expectedRevision, currentRevision); } writeResult = new WrongExpectedVersionResult( - header.Options.StreamName, expectedRevision, currentRevision); + header.Options.StreamIdentifier, expectedRevision, currentRevision); } else { throw new InvalidOperationException("The operation completed with an unexpected result."); } diff --git a/src/EventStore.Client.Streams/EventStoreClient.Delete.cs b/src/EventStore.Client.Streams/EventStoreClient.Delete.cs index c2a3aec81..e1ba610b3 100644 --- a/src/EventStore.Client.Streams/EventStoreClient.Delete.cs +++ b/src/EventStore.Client.Streams/EventStoreClient.Delete.cs @@ -59,7 +59,7 @@ private Task SoftDeleteAsync( CancellationToken cancellationToken = default) => DeleteInternal(new DeleteReq { Options = new DeleteReq.Types.Options { - StreamName = streamName + StreamIdentifier = streamName } }.WithAnyStreamRevision(expectedState), operationOptions, userCredentials, cancellationToken); @@ -71,7 +71,7 @@ private Task SoftDeleteAsync( CancellationToken cancellationToken = default) => DeleteInternal(new DeleteReq { Options = new DeleteReq.Types.Options { - StreamName = streamName, + StreamIdentifier = streamName, Revision = expectedRevision } }, operationOptions, userCredentials, cancellationToken); @@ -79,7 +79,7 @@ private Task SoftDeleteAsync( private async Task DeleteInternal(DeleteReq request, EventStoreClientOperationOptions operationOptions, UserCredentials? userCredentials, CancellationToken cancellationToken) { - _log.LogDebug("Deleting stream {streamName}.", request.Options.StreamName); + _log.LogDebug("Deleting stream {streamName}.", request.Options.StreamIdentifier); var result = await _client.DeleteAsync(request, RequestMetadata.Create(userCredentials ?? Settings.DefaultCredentials), deadline: DeadLine.After(operationOptions.TimeoutAfter), cancellationToken); diff --git a/src/EventStore.Client.Streams/EventStoreClient.Metadata.cs b/src/EventStore.Client.Streams/EventStoreClient.Metadata.cs index 2e9913d78..f70abfca8 100644 --- a/src/EventStore.Client.Streams/EventStoreClient.Metadata.cs +++ b/src/EventStore.Client.Streams/EventStoreClient.Metadata.cs @@ -53,7 +53,7 @@ private Task SetStreamMetadataAsync(string streamName, StreamState UserCredentials? userCredentials = null, CancellationToken cancellationToken = default) => SetStreamMetadataInternal(metadata, new AppendReq { Options = new AppendReq.Types.Options { - StreamName = SystemStreams.MetastreamOf(streamName) + StreamIdentifier = SystemStreams.MetastreamOf(streamName) } }.WithAnyStreamRevision(expectedState), operationOptions, userCredentials, cancellationToken); @@ -82,7 +82,7 @@ private Task SetStreamMetadataAsync(string streamName, StreamRevis UserCredentials? userCredentials = null, CancellationToken cancellationToken = default) => SetStreamMetadataInternal(metadata, new AppendReq { Options = new AppendReq.Types.Options { - StreamName = SystemStreams.MetastreamOf(streamName), + StreamIdentifier = SystemStreams.MetastreamOf(streamName), Revision = expectedRevision } }, operationOptions, userCredentials, cancellationToken); diff --git a/src/EventStore.Client.Streams/EventStoreClient.Read.cs b/src/EventStore.Client.Streams/EventStoreClient.Read.cs index 1f87ef062..380d66b18 100644 --- a/src/EventStore.Client.Streams/EventStoreClient.Read.cs +++ b/src/EventStore.Client.Streams/EventStoreClient.Read.cs @@ -137,7 +137,7 @@ public ReadStreamResult( throw new ArgumentOutOfRangeException("count"); } - _streamName = request.Options.Stream.StreamName; + _streamName = request.Options.Stream.StreamIdentifier; if (request.Options.Filter == null) { request.Options.NoFilter = new Empty(); @@ -271,7 +271,7 @@ private static ResolvedEvent ConvertToResolvedEvent(ReadResp.Types.ReadEvent rea e == null ? null : new EventRecord( - e.StreamName, + e.StreamIdentifier, Uuid.FromDto(e.Id), new StreamPosition(e.StreamRevision), new Position(e.CommitPosition, e.PreparePosition), diff --git a/src/EventStore.Client.Streams/EventStoreClient.Subscriptions.cs b/src/EventStore.Client.Streams/EventStoreClient.Subscriptions.cs index 0eb5c3617..18546ec9e 100644 --- a/src/EventStore.Client.Streams/EventStoreClient.Subscriptions.cs +++ b/src/EventStore.Client.Streams/EventStoreClient.Subscriptions.cs @@ -120,7 +120,7 @@ private Task SubscribeToStreamAsync(string streamName, ResolveLinks = resolveLinkTos, Stream = new ReadReq.Types.Options.Types.StreamOptions { Start = new Empty(), - StreamName = streamName + StreamIdentifier = streamName }, Subscription = new ReadReq.Types.Options.Types.SubscriptionOptions() } @@ -171,11 +171,11 @@ private Task SubscribeToStreamAsync(string streamName, Stream = start == StreamPosition.End ? new ReadReq.Types.Options.Types.StreamOptions { End = new Empty(), - StreamName = streamName + StreamIdentifier = streamName } : new ReadReq.Types.Options.Types.StreamOptions { Revision = start, - StreamName = streamName + StreamIdentifier = streamName }, Subscription = new ReadReq.Types.Options.Types.SubscriptionOptions() } diff --git a/src/EventStore.Client.Streams/EventStoreClient.Tombstone.cs b/src/EventStore.Client.Streams/EventStoreClient.Tombstone.cs index af5595e07..33386eb3b 100644 --- a/src/EventStore.Client.Streams/EventStoreClient.Tombstone.cs +++ b/src/EventStore.Client.Streams/EventStoreClient.Tombstone.cs @@ -15,7 +15,7 @@ private Task TombstoneAsync( CancellationToken cancellationToken = default) => TombstoneInternal(new TombstoneReq { Options = new TombstoneReq.Types.Options { - StreamName = streamName, + StreamIdentifier = streamName, Revision = expectedRevision } }, operationOptions, userCredentials, cancellationToken); @@ -50,7 +50,7 @@ private Task TombstoneAsync( CancellationToken cancellationToken = default) => TombstoneInternal(new TombstoneReq { Options = new TombstoneReq.Types.Options { - StreamName = streamName + StreamIdentifier = streamName } }.WithAnyStreamRevision(expectedState), operationOptions, userCredentials, cancellationToken); @@ -79,7 +79,7 @@ public Task TombstoneAsync( private async Task TombstoneInternal(TombstoneReq request, EventStoreClientOperationOptions operationOptions, UserCredentials? userCredentials, CancellationToken cancellationToken) { - _log.LogDebug("Tombstoning stream {streamName}.", request.Options.StreamName); + _log.LogDebug("Tombstoning stream {streamName}.", request.Options.StreamIdentifier); var result = await _client.TombstoneAsync(request, RequestMetadata.Create(userCredentials ?? Settings.DefaultCredentials), deadline: DeadLine.After(operationOptions.TimeoutAfter), cancellationToken); diff --git a/src/EventStore.Client.Streams/Streams/ReadReq.cs b/src/EventStore.Client.Streams/Streams/ReadReq.cs index 2515dd2c1..c60020c8c 100644 --- a/src/EventStore.Client.Streams/Streams/ReadReq.cs +++ b/src/EventStore.Client.Streams/Streams/ReadReq.cs @@ -15,20 +15,20 @@ public static StreamOptions FromStreamNameAndRevision( if (streamRevision == StreamPosition.End) { return new StreamOptions { - StreamName = streamName, + StreamIdentifier = streamName, End = new Empty() }; } if (streamRevision == StreamPosition.Start) { return new StreamOptions { - StreamName = streamName, + StreamIdentifier = streamName, Start = new Empty() }; } return new StreamOptions { - StreamName = streamName, + StreamIdentifier = streamName, Revision = streamRevision }; } diff --git a/src/EventStore.Client/StreamIdentifier.cs b/src/EventStore.Client/StreamIdentifier.cs new file mode 100644 index 000000000..83d488bde --- /dev/null +++ b/src/EventStore.Client/StreamIdentifier.cs @@ -0,0 +1,20 @@ +using System.Text; +using Google.Protobuf; + +namespace EventStore.Client { + public partial class StreamIdentifier{private string _cached; + public static implicit operator string(StreamIdentifier source) { + if (source._cached != null || source.StreamName.IsEmpty) return source._cached; + var tmp = Encoding.UTF8.GetString(source.StreamName.Span); + //this doesn't have to be thread safe, its just a cache in case the identifier is turned into a string several times + source._cached = tmp; + return source._cached; + } + + public static implicit operator StreamIdentifier(string source) { + var result = new StreamIdentifier(); + result.StreamName = ByteString.CopyFromUtf8(source); + return result; + } + } +}