From 68ccd3ee3e28dbe8058411a8a4c205e584a301df Mon Sep 17 00:00:00 2001 From: Morten Fischer-Madsen Date: Thu, 23 Apr 2026 22:31:09 +0200 Subject: [PATCH] Ensure ExistingStreamIdCollisionException is thrown when UseArchivedStreamPartitioning is enabled. --- ...seArchivedStreamPartitioning_is_enabled.cs | 35 +++++++++++++++++++ .../Events/Operations/InsertStreamBase.cs | 7 +++- src/Marten/Events/Schema/StreamsTable.cs | 1 + 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 src/EventSourcingTests/Bugs/start_stream_should_enforce_that_it_is_a_new_stream_when_UseArchivedStreamPartitioning_is_enabled.cs diff --git a/src/EventSourcingTests/Bugs/start_stream_should_enforce_that_it_is_a_new_stream_when_UseArchivedStreamPartitioning_is_enabled.cs b/src/EventSourcingTests/Bugs/start_stream_should_enforce_that_it_is_a_new_stream_when_UseArchivedStreamPartitioning_is_enabled.cs new file mode 100644 index 0000000000..5aa0e585e2 --- /dev/null +++ b/src/EventSourcingTests/Bugs/start_stream_should_enforce_that_it_is_a_new_stream_when_UseArchivedStreamPartitioning_is_enabled.cs @@ -0,0 +1,35 @@ +using System; +using System.Threading.Tasks; +using Marten.Exceptions; +using Marten.Testing.Harness; +using Shouldly; +using Xunit; + +namespace EventSourcingTests.Bugs; + +public class start_stream_should_enforce_that_it_is_a_new_stream_when_UseArchivedStreamPartitioning_is_enabled: OneOffConfigurationsContext +{ + [Fact] + public async Task throw_exception_if_start_stream_is_called_on_existing_stream_when_UseArchivedStreamPartitioning() + { + StoreOptions(_ => _.Events.UseArchivedStreamPartitioning = true); + + var stream = Guid.NewGuid(); + + using (var session = theStore.LightweightSession()) + { + session.Events.StartStream(stream, new MembersJoined()); + await session.SaveChangesAsync(); + } + + using (var session = theStore.LightweightSession()) + { + session.Events.StartStream(stream, new MembersJoined()); + + await Should.ThrowAsync(async () => + { + await session.SaveChangesAsync(); + }); + } + } +} diff --git a/src/Marten/Events/Operations/InsertStreamBase.cs b/src/Marten/Events/Operations/InsertStreamBase.cs index 1d3c7ef5b8..5c24ed11a4 100644 --- a/src/Marten/Events/Operations/InsertStreamBase.cs +++ b/src/Marten/Events/Operations/InsertStreamBase.cs @@ -49,11 +49,16 @@ public override string ToString() } private static bool matches(Exception e) - { + { return e is PostgresException { SqlState: PostgresErrorCodes.UniqueViolation, TableName: StreamsTable.TableName + } + || e is PostgresException + { + SqlState: PostgresErrorCodes.UniqueViolation, + TableName: StreamsTable.DefaultPartionedTableName }; } diff --git a/src/Marten/Events/Schema/StreamsTable.cs b/src/Marten/Events/Schema/StreamsTable.cs index a1f9561263..3f6612c33d 100644 --- a/src/Marten/Events/Schema/StreamsTable.cs +++ b/src/Marten/Events/Schema/StreamsTable.cs @@ -20,6 +20,7 @@ namespace Marten.Events.Schema; internal class StreamsTable: Table { public const string TableName = "mt_streams"; + public const string DefaultPartionedTableName = $"{TableName}_default"; public StreamsTable(EventGraph events): base(new PostgresqlObjectName(events.DatabaseSchemaName, TableName)) {