diff --git a/src/SqlStreamStore.MySql/MySqlScripts/DeleteStream.sql b/src/SqlStreamStore.MySql/MySqlScripts/DeleteStream.sql index 7f3a6bf50..53eee14a6 100644 --- a/src/SqlStreamStore.MySql/MySqlScripts/DeleteStream.sql +++ b/src/SqlStreamStore.MySql/MySqlScripts/DeleteStream.sql @@ -3,6 +3,7 @@ DROP PROCEDURE IF EXISTS delete_stream; CREATE PROCEDURE delete_stream(_stream_id CHAR(42), _expected_version INT, _created_utc TIMESTAMP(6), + _deletion_tracking_disabled BOOLEAN, _deleted_stream_id CHAR(42), _deleted_stream_id_original NVARCHAR(1000), _deleted_metadata_stream_id CHAR(42), @@ -55,24 +56,27 @@ BEGIN DELETE FROM streams WHERE streams.id = _stream_id; - SELECT ROW_COUNT() INTO _affected; - - IF _affected > 0 + IF _deletion_tracking_disabled = FALSE THEN - CALL append_to_stream_expected_version_any - ( - _deleted_stream_id, - _deleted_stream_id_original, - _deleted_metadata_stream_id, - _created_utc, - _deleted_stream_message_message_id, - _deleted_stream_message_type, - _deleted_stream_message_json_data, - NULL, - _, - __, - ___); + SELECT ROW_COUNT() INTO _affected; + + IF _affected > 0 + THEN + CALL append_to_stream_expected_version_any + ( + _deleted_stream_id, + _deleted_stream_id_original, + _deleted_metadata_stream_id, + _created_utc, + _deleted_stream_message_message_id, + _deleted_stream_message_type, + _deleted_stream_message_json_data, + NULL, + _, + __, + ___); + END IF; END IF; END; diff --git a/src/SqlStreamStore.MySql/MySqlScripts/DeleteStreamMessage.sql b/src/SqlStreamStore.MySql/MySqlScripts/DeleteStreamMessage.sql index 1fc461e92..565597735 100644 --- a/src/SqlStreamStore.MySql/MySqlScripts/DeleteStreamMessage.sql +++ b/src/SqlStreamStore.MySql/MySqlScripts/DeleteStreamMessage.sql @@ -2,6 +2,7 @@ DROP PROCEDURE IF EXISTS delete_stream_message; CREATE PROCEDURE delete_stream_message(_stream_id CHAR(42), _message_id BINARY(16), + _deletion_tracking_disabled BOOLEAN, _deleted_stream_id CHAR(42), _deleted_stream_id_original NVARCHAR(1000), _deleted_metadata_stream_id CHAR(42), @@ -24,23 +25,27 @@ BEGIN WHERE messages.stream_id_internal = _stream_id_internal AND messages.message_id = _message_id; - IF ROW_COUNT() > 0 + IF _deletion_tracking_disabled = FALSE THEN - IF _created_utc IS NULL THEN - SET _created_utc = UTC_TIMESTAMP(6); - END IF; - CALL append_to_stream_expected_version_any( - _deleted_stream_id, - _deleted_stream_id_original, - _deleted_metadata_stream_id, - _created_utc, - _deleted_message_message_id, - _deleted_message_type, - _deleted_message_json_data, - NULL, - _, - __, - ___); + IF ROW_COUNT() > 0 + THEN + IF _created_utc IS NULL THEN + SET _created_utc = UTC_TIMESTAMP(6); + END IF; + + CALL append_to_stream_expected_version_any( + _deleted_stream_id, + _deleted_stream_id_original, + _deleted_metadata_stream_id, + _created_utc, + _deleted_message_message_id, + _deleted_message_type, + _deleted_message_json_data, + NULL, + _, + __, + ___); + END IF; END IF; END; \ No newline at end of file diff --git a/src/SqlStreamStore.MySql/MySqlScripts/Parameters.cs b/src/SqlStreamStore.MySql/MySqlScripts/Parameters.cs index 6bc6f422a..e1180463c 100644 --- a/src/SqlStreamStore.MySql/MySqlScripts/Parameters.cs +++ b/src/SqlStreamStore.MySql/MySqlScripts/Parameters.cs @@ -200,6 +200,22 @@ public static MySqlParameter MessageExists() Direction = ParameterDirection.Output }; + public static MySqlParameter DeletionTrackingDisabled(bool value) + => new MySqlParameter + { + MySqlDbType = MySqlDbType.Bool, + ParameterName = "_deletion_tracking_disabled", + Value = value + }; + + public static MySqlParameter Empty(this MySqlParameter parameter) + => new MySqlParameter + { + ParameterName = parameter.ParameterName, + MySqlDbType = MySqlDbType.Null, + Value = DBNull.Value + }; + private static MySqlParameter StreamIdInternal(MySqlStreamId streamId, string parameterName) => new MySqlParameter { diff --git a/src/SqlStreamStore.MySql/MySqlStreamStore.Delete.cs b/src/SqlStreamStore.MySql/MySqlStreamStore.Delete.cs index e1fb890d8..9d53400c5 100644 --- a/src/SqlStreamStore.MySql/MySqlStreamStore.Delete.cs +++ b/src/SqlStreamStore.MySql/MySqlStreamStore.Delete.cs @@ -44,18 +44,30 @@ private async Task DeleteStreamInternal( { var deletedStreamMessage = Deleted.CreateStreamDeletedMessage(streamId.IdOriginal); + var deletedStreamId = Parameters.DeletedStreamId(); + var deletedStreamIdOriginal = Parameters.DeletedStreamIdOriginal(); + var deletedMetadataStreamId = Parameters.DeletedMetadataStreamId(); + var deletedStreamMessageMessageId = Parameters.DeletedStreamMessageMessageId(deletedStreamMessage); + var deletedStreamMessageType = Parameters.DeletedStreamMessageType(deletedStreamMessage); + var deletedStreamMessageJsonData = Parameters.DeletedStreamMessageJsonData(deletedStreamMessage); + using(var command = BuildStoredProcedureCall( _schema.DeleteStream, transaction, Parameters.StreamId(streamId), Parameters.ExpectedVersion(expectedVersion), Parameters.CreatedUtc(_settings.GetUtcNow?.Invoke()), - Parameters.DeletedStreamId(), - Parameters.DeletedStreamIdOriginal(), - Parameters.DeletedMetadataStreamId(), - Parameters.DeletedStreamMessageMessageId(deletedStreamMessage), - Parameters.DeletedStreamMessageType(deletedStreamMessage), - Parameters.DeletedStreamMessageJsonData(deletedStreamMessage))) + Parameters.DeletionTrackingDisabled(_settings.DisableDeletionTracking), + _settings.DisableDeletionTracking ? deletedStreamId.Empty() : deletedStreamId, + _settings.DisableDeletionTracking ? deletedStreamIdOriginal.Empty() : deletedStreamIdOriginal, + _settings.DisableDeletionTracking ? deletedMetadataStreamId.Empty() : deletedMetadataStreamId, + _settings.DisableDeletionTracking + ? deletedStreamMessageMessageId.Empty() + : deletedStreamMessageMessageId, + _settings.DisableDeletionTracking ? deletedStreamMessageType.Empty() : deletedStreamMessageType, + _settings.DisableDeletionTracking + ? deletedStreamMessageJsonData.Empty() + : deletedStreamMessageJsonData)) { try { @@ -100,18 +112,26 @@ private async Task DeleteEventInternal( streamIdInfo.MySqlStreamId.IdOriginal, eventId); + var deletedStreamId = Parameters.DeletedStreamId(); + var deletedStreamIdOriginal = Parameters.DeletedStreamIdOriginal(); + var deletedMetadataStreamId = Parameters.DeletedMetadataStreamId(); + var deletedMessageMessageId = Parameters.DeletedMessageMessageId(deletedMessageMessage); + var deletedMessageType = Parameters.DeletedMessageType(deletedMessageMessage); + var deletedMessageJsonData = Parameters.DeletedMessageJsonData(deletedMessageMessage); + using(var command = BuildStoredProcedureCall( _schema.DeleteStreamMessage, transaction, Parameters.StreamId(streamIdInfo.MySqlStreamId), Parameters.MessageId(eventId), - Parameters.DeletedStreamId(), - Parameters.DeletedStreamIdOriginal(), - Parameters.DeletedMetadataStreamId(), Parameters.CreatedUtc(_settings.GetUtcNow?.Invoke()), - Parameters.DeletedMessageMessageId(deletedMessageMessage), - Parameters.DeletedMessageType(deletedMessageMessage), - Parameters.DeletedMessageJsonData(deletedMessageMessage))) + Parameters.DeletionTrackingDisabled(_settings.DisableDeletionTracking), + _settings.DisableDeletionTracking ? deletedStreamId.Empty() : deletedStreamId, + _settings.DisableDeletionTracking ? deletedStreamIdOriginal.Empty() : deletedStreamIdOriginal, + _settings.DisableDeletionTracking ? deletedMetadataStreamId.Empty() : deletedMetadataStreamId, + _settings.DisableDeletionTracking ? deletedMessageMessageId.Empty() : deletedMessageMessageId, + _settings.DisableDeletionTracking ? deletedMessageType.Empty() : deletedMessageType, + _settings.DisableDeletionTracking ? deletedMessageJsonData.Empty() : deletedMessageJsonData)) { await command.ExecuteNonQueryAsync(cancellationToken).NotOnCapturedContext(); } diff --git a/src/SqlStreamStore.MySql/MySqlStreamStoreSettings.cs b/src/SqlStreamStore.MySql/MySqlStreamStoreSettings.cs index 326c49ea0..3bd14dba9 100644 --- a/src/SqlStreamStore.MySql/MySqlStreamStoreSettings.cs +++ b/src/SqlStreamStore.MySql/MySqlStreamStoreSettings.cs @@ -75,5 +75,12 @@ public Func ConnectionFactory _connectionFactory = value; } } + + /// + /// Disables stream and message deletion tracking. Will increase + /// performance, however subscribers won't know if a stream or a + /// message has been deleted. This can be modified at runtime. + /// + public bool DisableDeletionTracking { get; set; } } } \ No newline at end of file diff --git a/src/SqlStreamStore.Postgres/PgSqlScripts/DeleteStream.sql b/src/SqlStreamStore.Postgres/PgSqlScripts/DeleteStream.sql index f01b2cdc2..ccb66b818 100644 --- a/src/SqlStreamStore.Postgres/PgSqlScripts/DeleteStream.sql +++ b/src/SqlStreamStore.Postgres/PgSqlScripts/DeleteStream.sql @@ -2,6 +2,7 @@ CREATE OR REPLACE FUNCTION __schema__.delete_stream( _stream_id CHAR(42), _expected_version INT, _created_utc TIMESTAMP, + _deletion_tracking_disabled BOOLEAN, _deleted_stream_id CHAR(42), _deleted_stream_id_original VARCHAR(1000), _deleted_stream_message __schema__.new_stream_message) @@ -48,6 +49,11 @@ BEGIN DELETE FROM __schema__.streams WHERE __schema__.streams.id = _stream_id; + IF (_deletion_tracking_disabled = TRUE) + THEN + RETURN; + END IF; + GET DIAGNOSTICS _affected = ROW_COUNT; IF _affected > 0 diff --git a/src/SqlStreamStore.Postgres/PgSqlScripts/DeleteStreamMessages.sql b/src/SqlStreamStore.Postgres/PgSqlScripts/DeleteStreamMessages.sql index 42dd8078f..609b51105 100644 --- a/src/SqlStreamStore.Postgres/PgSqlScripts/DeleteStreamMessages.sql +++ b/src/SqlStreamStore.Postgres/PgSqlScripts/DeleteStreamMessages.sql @@ -1,6 +1,7 @@ CREATE OR REPLACE FUNCTION __schema__.delete_stream_messages( _stream_id CHAR(42), _message_ids UUID [], + _deletion_tracking_disabled BOOLEAN, _deleted_stream_id CHAR(42), _deleted_stream_id_original VARCHAR(1000), _created_utc TIMESTAMP, @@ -29,7 +30,7 @@ BEGIN FROM deleted INTO _deleted_count; - IF _deleted_count > 0 + IF (_deletion_tracking_disabled = FALSE AND _deleted_count > 0) THEN PERFORM __schema__.append_to_stream( _deleted_stream_id, diff --git a/src/SqlStreamStore.Postgres/PgSqlScripts/Parameters.cs b/src/SqlStreamStore.Postgres/PgSqlScripts/Parameters.cs index 3f1edac58..5659a08e9 100644 --- a/src/SqlStreamStore.Postgres/PgSqlScripts/Parameters.cs +++ b/src/SqlStreamStore.Postgres/PgSqlScripts/Parameters.cs @@ -251,5 +251,22 @@ public static NpgsqlParameter Pattern(string value) NpgsqlDbType = NpgsqlDbType.Varchar }; } + + public static NpgsqlParameter DeletionTrackingDisabled(bool deletionTrackingDisabled) + { + return new NpgsqlParameter + { + TypedValue = deletionTrackingDisabled, + NpgsqlDbType = NpgsqlDbType.Boolean + }; + } + + public static NpgsqlParameter Empty() + { + return new NpgsqlParameter + { + TypedValue = DBNull.Value + }; + } } } \ No newline at end of file diff --git a/src/SqlStreamStore.Postgres/PostgresStreamStore.Delete.cs b/src/SqlStreamStore.Postgres/PostgresStreamStore.Delete.cs index bc28d34d4..904107a73 100644 --- a/src/SqlStreamStore.Postgres/PostgresStreamStore.Delete.cs +++ b/src/SqlStreamStore.Postgres/PostgresStreamStore.Delete.cs @@ -48,9 +48,10 @@ private async Task DeleteStreamInternal( Parameters.StreamId(streamId), Parameters.ExpectedVersion(expectedVersion), Parameters.CreatedUtc(_settings.GetUtcNow?.Invoke()), - Parameters.DeletedStreamId, - Parameters.DeletedStreamIdOriginal, - Parameters.DeletedStreamMessage(streamId))) + Parameters.DeletionTrackingDisabled(_settings.DisableDeletionTracking), + _settings.DisableDeletionTracking ? Parameters.Empty() : Parameters.DeletedStreamId, + _settings.DisableDeletionTracking ? Parameters.Empty() : Parameters.DeletedStreamIdOriginal, + _settings.DisableDeletionTracking ? Parameters.Empty() : Parameters.DeletedStreamMessage(streamId))) { try { @@ -96,10 +97,13 @@ private async Task DeleteEventsInternal( transaction, Parameters.StreamId(streamIdInfo.PostgresqlStreamId), Parameters.MessageIds(eventIds), - Parameters.DeletedStreamId, - Parameters.DeletedStreamIdOriginal, + Parameters.DeletionTrackingDisabled(_settings.DisableDeletionTracking), + _settings.DisableDeletionTracking ? Parameters.Empty() : Parameters.DeletedStreamId, + _settings.DisableDeletionTracking ? Parameters.Empty() : Parameters.DeletedStreamIdOriginal, Parameters.CreatedUtc(_settings.GetUtcNow?.Invoke()), - Parameters.DeletedMessages(streamIdInfo.PostgresqlStreamId, eventIds))) + _settings.DisableDeletionTracking + ? Parameters.Empty() + : Parameters.DeletedMessages(streamIdInfo.PostgresqlStreamId, eventIds))) { await command.ExecuteNonQueryAsync(cancellationToken).NotOnCapturedContext(); } diff --git a/src/SqlStreamStore.Postgres/PostgresStreamStoreSettings.cs b/src/SqlStreamStore.Postgres/PostgresStreamStoreSettings.cs index 6c554b2b0..796d93fdd 100644 --- a/src/SqlStreamStore.Postgres/PostgresStreamStoreSettings.cs +++ b/src/SqlStreamStore.Postgres/PostgresStreamStoreSettings.cs @@ -89,5 +89,12 @@ public Func ConnectionFactory _connectionFactory = value; } } + + /// + /// Disables stream and message deletion tracking. Will increase + /// performance, however subscribers won't know if a stream or a + /// message has been deleted. This can be modified at runtime. + /// + public bool DisableDeletionTracking { get; set; } } } \ No newline at end of file diff --git a/tests/SqlStreamStore.AcceptanceTests/AcceptanceTests.DeleteEvent.cs b/tests/SqlStreamStore.AcceptanceTests/AcceptanceTests.DeleteEvent.cs index cae115171..309967c55 100644 --- a/tests/SqlStreamStore.AcceptanceTests/AcceptanceTests.DeleteEvent.cs +++ b/tests/SqlStreamStore.AcceptanceTests/AcceptanceTests.DeleteEvent.cs @@ -125,12 +125,13 @@ public async Task When_delete_all_messages_from_stream_with_multiple_messages_th [Theory, Trait("Category", "DeleteEvent")] [InlineData("stream/id")] [InlineData("stream%id")] - public async Task When_delete_stream_message_with_url_encodable_characters_then_should_not_throw(string streamId) + public async Task When_delete_stream_message_with_url_encodable_characters_then_should_not_throw( + string streamId) { var newStreamMessages = CreateNewStreamMessages(1); await store.AppendToStream(streamId, ExpectedVersion.NoStream, newStreamMessages); await store.DeleteMessage(streamId, newStreamMessages[0].MessageId); } - } -} + } +} \ No newline at end of file diff --git a/tests/SqlStreamStore.AcceptanceTests/AcceptanceTests.DeletionTracking.cs b/tests/SqlStreamStore.AcceptanceTests/AcceptanceTests.DeletionTracking.cs new file mode 100644 index 000000000..b8f243adb --- /dev/null +++ b/tests/SqlStreamStore.AcceptanceTests/AcceptanceTests.DeletionTracking.cs @@ -0,0 +1,43 @@ +namespace SqlStreamStore +{ + using System.Threading.Tasks; + using Shouldly; + using SqlStreamStore.Streams; + using Xunit; + using static Streams.Deleted; + + partial class AcceptanceTests + { + [Fact] + public async Task When_deletion_tracking_is_disabled_deleted_message_should_not_be_tracked() + { + _fixture.DisableDeletionTracking = true; + + var messages = CreateNewStreamMessages(1); + + await _fixture.Store.AppendToStream("stream", ExpectedVersion.NoStream, messages); + + await _fixture.Store.DeleteMessage("stream", messages[0].MessageId); + + var page = await store.ReadStreamBackwards(DeletedStreamId, StreamVersion.End, 1); + + page.Messages.Length.ShouldBe(0); + } + + [Fact] + public async Task When_deletion_tracking_is_disabled_deleted_stream_should_not_be_tracked() + { + _fixture.DisableDeletionTracking = true; + + var messages = CreateNewStreamMessages(1); + + await fixture.Store.AppendToStream("stream", ExpectedVersion.NoStream, messages); + + await fixture.Store.DeleteStream("stream"); + + var page = await store.ReadStreamBackwards(DeletedStreamId, StreamVersion.End, 1); + + page.Messages.Length.ShouldBe(0); + } + } +} \ No newline at end of file diff --git a/tests/SqlStreamStore.AcceptanceTests/AcceptanceTests.cs b/tests/SqlStreamStore.AcceptanceTests/AcceptanceTests.cs index 1bb2bf218..a72fd1c7d 100644 --- a/tests/SqlStreamStore.AcceptanceTests/AcceptanceTests.cs +++ b/tests/SqlStreamStore.AcceptanceTests/AcceptanceTests.cs @@ -104,7 +104,5 @@ public static StreamMessage ExpectedStreamMessage( var id = Guid.Parse("00000000-0000-0000-0000-" + messageNumber.ToString().PadLeft(12, '0')); return new StreamMessage(streamId, id, sequenceNumber, 0, created, "type", DefaultJsonMetadata, DefaultJsonData); } - - } } diff --git a/tests/SqlStreamStore.AcceptanceTests/IStreamStoreFixture.cs b/tests/SqlStreamStore.AcceptanceTests/IStreamStoreFixture.cs index 1164684b4..d2cdbe006 100644 --- a/tests/SqlStreamStore.AcceptanceTests/IStreamStoreFixture.cs +++ b/tests/SqlStreamStore.AcceptanceTests/IStreamStoreFixture.cs @@ -12,5 +12,7 @@ public interface IStreamStoreFixture : IDisposable long MinPosition { get; set; } int MaxSubscriptionCount { get; set; } + + bool DisableDeletionTracking { get; set; } } } \ No newline at end of file diff --git a/tests/SqlStreamStore.Http.Tests/HttpClientStreamStoreFixture.cs b/tests/SqlStreamStore.Http.Tests/HttpClientStreamStoreFixture.cs index 7cc8f68bc..9908e6672 100644 --- a/tests/SqlStreamStore.Http.Tests/HttpClientStreamStoreFixture.cs +++ b/tests/SqlStreamStore.Http.Tests/HttpClientStreamStoreFixture.cs @@ -59,5 +59,11 @@ public void Dispose() public long MinPosition { get; set; } = 0; public int MaxSubscriptionCount { get; set; } = 500; + + public bool DisableDeletionTracking + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } } } \ No newline at end of file diff --git a/tests/SqlStreamStore.Http.Tests/SqlStreamStore.Http.Tests.csproj b/tests/SqlStreamStore.Http.Tests/SqlStreamStore.Http.Tests.csproj index 43bc0e65e..8cbef8e11 100644 --- a/tests/SqlStreamStore.Http.Tests/SqlStreamStore.Http.Tests.csproj +++ b/tests/SqlStreamStore.Http.Tests/SqlStreamStore.Http.Tests.csproj @@ -8,7 +8,7 @@ - + diff --git a/tests/SqlStreamStore.MsSql.Tests/MsSqlStreamStoreFixture.cs b/tests/SqlStreamStore.MsSql.Tests/MsSqlStreamStoreFixture.cs index 043108e13..9f95328ec 100644 --- a/tests/SqlStreamStore.MsSql.Tests/MsSqlStreamStoreFixture.cs +++ b/tests/SqlStreamStore.MsSql.Tests/MsSqlStreamStoreFixture.cs @@ -13,6 +13,7 @@ public sealed class MsSqlStreamStoreFixture : IStreamStoreFixture private readonly bool _deleteDatabaseOnDispose; private readonly string _databaseName; private readonly DockerMsSqlServerDatabase _databaseInstance; + private readonly MsSqlStreamStoreSettings _settings; private MsSqlStreamStoreFixture( string schema, @@ -29,6 +30,11 @@ private MsSqlStreamStoreFixture( connectionStringBuilder.MultipleActiveResultSets = true; connectionStringBuilder.InitialCatalog = _databaseName; ConnectionString = connectionStringBuilder.ToString(); + _settings = new MsSqlStreamStoreSettings(ConnectionString) + { + Schema = _schema, + GetUtcNow = () => GetUtcNow(), + }; } public MsSqlStreamStore Store { get; private set; } @@ -39,17 +45,18 @@ private MsSqlStreamStoreFixture( public int MaxSubscriptionCount { get; set; } = 500; + public bool DisableDeletionTracking + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } + IStreamStore IStreamStoreFixture.Store => Store; private async Task Init(bool createV1Schema = false) { await _databaseInstance.CreateDatabase(); - var settings = new MsSqlStreamStoreSettings(ConnectionString) - { - Schema = _schema, - GetUtcNow = () => GetUtcNow(), - }; - Store = new MsSqlStreamStore(settings); + Store = new MsSqlStreamStore(_settings); if (_createSchema) { if(createV1Schema) diff --git a/tests/SqlStreamStore.MsSql.Tests/SqlStreamStore.MsSql.Tests.csproj b/tests/SqlStreamStore.MsSql.Tests/SqlStreamStore.MsSql.Tests.csproj index 5fe7c607a..00c53140f 100644 --- a/tests/SqlStreamStore.MsSql.Tests/SqlStreamStore.MsSql.Tests.csproj +++ b/tests/SqlStreamStore.MsSql.Tests/SqlStreamStore.MsSql.Tests.csproj @@ -6,7 +6,7 @@ SqlStreamStore - + diff --git a/tests/SqlStreamStore.MsSql.V3.Tests/MsSqlStreamStoreV3Fixture.cs b/tests/SqlStreamStore.MsSql.V3.Tests/MsSqlStreamStoreV3Fixture.cs index 618e601ac..83c28719c 100644 --- a/tests/SqlStreamStore.MsSql.V3.Tests/MsSqlStreamStoreV3Fixture.cs +++ b/tests/SqlStreamStore.MsSql.V3.Tests/MsSqlStreamStoreV3Fixture.cs @@ -10,10 +10,10 @@ public sealed class MsSqlStreamStoreV3Fixture : IStreamStoreFixture private readonly bool _createSchema; public readonly string ConnectionString; private readonly string _schema; - private readonly bool _disableDeletionTracking; private readonly bool _deleteDatabaseOnDispose; private readonly string _databaseName; private readonly DockerMsSqlServerDatabase _databaseInstance; + private readonly MsSqlStreamStoreV3Settings _settings; private MsSqlStreamStoreV3Fixture( string schema, @@ -22,7 +22,6 @@ private MsSqlStreamStoreV3Fixture( bool createSchema = true) { _schema = schema; - _disableDeletionTracking = disableDeletionTracking; _deleteDatabaseOnDispose = deleteDatabaseOnDispose; _createSchema = createSchema; _databaseName = $"sss-v3-{Guid.NewGuid():n}"; @@ -32,6 +31,13 @@ private MsSqlStreamStoreV3Fixture( connectionStringBuilder.MultipleActiveResultSets = true; connectionStringBuilder.InitialCatalog = _databaseName; ConnectionString = connectionStringBuilder.ToString(); + + _settings = new MsSqlStreamStoreV3Settings(ConnectionString) + { + Schema = _schema, + GetUtcNow = () => GetUtcNow(), + DisableDeletionTracking = disableDeletionTracking + }; } IStreamStore IStreamStoreFixture.Store => Store; @@ -44,17 +50,17 @@ private MsSqlStreamStoreV3Fixture( public int MaxSubscriptionCount { get; set; } = 500; + public bool DisableDeletionTracking + { + get => _settings.DisableDeletionTracking; + set => _settings.DisableDeletionTracking = value; + } + private async Task Init() { await _databaseInstance.CreateDatabase(); - var settings = new MsSqlStreamStoreV3Settings(ConnectionString) - { - Schema = _schema, - GetUtcNow = () => GetUtcNow(), - DisableDeletionTracking = _disableDeletionTracking - }; - Store = new MsSqlStreamStoreV3(settings); - if (_createSchema) + Store = new MsSqlStreamStoreV3(_settings); + if(_createSchema) { await Store.CreateSchemaIfNotExists(); } @@ -78,19 +84,23 @@ public void Dispose() { Store?.Dispose(); - if (!_deleteDatabaseOnDispose) + if(!_deleteDatabaseOnDispose) { return; } + SqlConnection.ClearAllPools(); - using (var connection = _databaseInstance.CreateConnection()) + using(var connection = _databaseInstance.CreateConnection()) { connection.Open(); - using (var command = new SqlCommand($"ALTER DATABASE [{_databaseName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE", connection)) + using(var command = + new SqlCommand($"ALTER DATABASE [{_databaseName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE", + connection)) { command.ExecuteNonQuery(); } - using (var command = new SqlCommand($"DROP DATABASE [{_databaseName}]", connection)) + + using(var command = new SqlCommand($"DROP DATABASE [{_databaseName}]", connection)) { command.ExecuteNonQuery(); } diff --git a/tests/SqlStreamStore.MySql.Tests/MySqlStreamStoreFixture.cs b/tests/SqlStreamStore.MySql.Tests/MySqlStreamStoreFixture.cs index 0d43355a3..74f4a880c 100644 --- a/tests/SqlStreamStore.MySql.Tests/MySqlStreamStoreFixture.cs +++ b/tests/SqlStreamStore.MySql.Tests/MySqlStreamStoreFixture.cs @@ -11,6 +11,7 @@ public class MySqlStreamStoreFixture : IStreamStoreFixture private readonly string _databaseName; private readonly bool _createSchema; private readonly MySqlDatabaseManager _databaseManager; + private readonly MySqlStreamStoreSettings _settings; public string DatabaseName => _databaseName; @@ -23,10 +24,21 @@ private MySqlStreamStoreFixture( _databaseManager = new MySqlDockerDatabaseManager( testOutputHelper, _databaseName); + _settings = new MySqlStreamStoreSettings(ConnectionString) + { + GetUtcNow = () => GetUtcNow(), + ScavengeAsynchronously = false + }; } IStreamStore IStreamStoreFixture.Store => Store; + public bool DisableDeletionTracking + { + get => _settings.DisableDeletionTracking; + set => _settings.DisableDeletionTracking = value; + } + public MySqlStreamStore Store { get; private set; } public GetUtcNow GetUtcNow { get; set; } = SystemClock.GetUtcNow; @@ -40,13 +52,8 @@ private MySqlStreamStoreFixture( private async Task Init() { await _databaseManager.CreateDatabase(); - var settings = new MySqlStreamStoreSettings(ConnectionString) - { - GetUtcNow = () => GetUtcNow(), - ScavengeAsynchronously = false - }; - Store = new MySqlStreamStore(settings); + Store = new MySqlStreamStore(_settings); if(_createSchema) { diff --git a/tests/SqlStreamStore.Postgres.Tests/PostgresStreamStoreFixture.cs b/tests/SqlStreamStore.Postgres.Tests/PostgresStreamStoreFixture.cs index 6ed3fbc57..3059e5734 100644 --- a/tests/SqlStreamStore.Postgres.Tests/PostgresStreamStoreFixture.cs +++ b/tests/SqlStreamStore.Postgres.Tests/PostgresStreamStoreFixture.cs @@ -11,6 +11,7 @@ public class PostgresStreamStoreFixture : IStreamStoreFixture private readonly string _schema; private readonly bool _createSchema; private readonly PostgresDatabaseManager _databaseManager; + private readonly PostgresStreamStoreSettings _settings; private PostgresStreamStoreFixture( string schema, @@ -20,10 +21,17 @@ private PostgresStreamStoreFixture( _schema = schema; _createSchema = createSchema; _databaseManager = new PostgresDockerDatabaseManager( - testOutputHelper, + testOutputHelper, $"test_{Guid.NewGuid():n}"); + _settings = new PostgresStreamStoreSettings(ConnectionString) + { + Schema = _schema, + GetUtcNow = () => GetUtcNow(), + ScavengeAsynchronously = false + }; } + IStreamStore IStreamStoreFixture.Store => Store; public PostgresStreamStore Store { get; private set; } @@ -36,17 +44,17 @@ private PostgresStreamStoreFixture( public int MaxSubscriptionCount { get; set; } = 100; + public bool DisableDeletionTracking + { + get => _settings.DisableDeletionTracking; + set => _settings.DisableDeletionTracking = value; + } + private async Task Init() { await _databaseManager.CreateDatabase(); - var settings = new PostgresStreamStoreSettings(ConnectionString) - { - Schema = _schema, - GetUtcNow = () => GetUtcNow(), - ScavengeAsynchronously = false - }; - Store = new PostgresStreamStore(settings); + Store = new PostgresStreamStore(_settings); if(_createSchema) { diff --git a/tests/SqlStreamStore.Tests/InMemory/InMemoryStreamStoreFixture.cs b/tests/SqlStreamStore.Tests/InMemory/InMemoryStreamStoreFixture.cs index 3a228fced..82fe56b87 100644 --- a/tests/SqlStreamStore.Tests/InMemory/InMemoryStreamStoreFixture.cs +++ b/tests/SqlStreamStore.Tests/InMemory/InMemoryStreamStoreFixture.cs @@ -1,5 +1,6 @@ namespace SqlStreamStore.InMemory { + using System; using SqlStreamStore.Infrastructure; public class InMemoryStreamStoreFixture : IStreamStoreFixture @@ -21,5 +22,11 @@ public void Dispose() public long MinPosition { get; set; } = 0; public int MaxSubscriptionCount { get; set; } = 500; + + public bool DisableDeletionTracking + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } } } \ No newline at end of file diff --git a/tests/SqlStreamStore.Tests/SqlStreamStore.Tests.csproj b/tests/SqlStreamStore.Tests/SqlStreamStore.Tests.csproj index 502ecb941..ed3dd3ca6 100644 --- a/tests/SqlStreamStore.Tests/SqlStreamStore.Tests.csproj +++ b/tests/SqlStreamStore.Tests/SqlStreamStore.Tests.csproj @@ -5,7 +5,7 @@ SqlStreamStore - +