diff --git a/.github/workflows/codecov-ci b/.github/workflows/codecov-ci new file mode 100644 index 00000000..e420c7d4 --- /dev/null +++ b/.github/workflows/codecov-ci @@ -0,0 +1,4 @@ +- name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v3 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/Channels/S3/EventSourcing.Backbone.Channels.S3StoreProvider.Common/EventSourcing.Backbone.Channels.S3StoreProvider.Common.csproj b/Channels/S3/EventSourcing.Backbone.Channels.S3StoreProvider.Common/EventSourcing.Backbone.Channels.S3StoreProvider.Common.csproj index 1966cc3f..7cccc8d4 100644 --- a/Channels/S3/EventSourcing.Backbone.Channels.S3StoreProvider.Common/EventSourcing.Backbone.Channels.S3StoreProvider.Common.csproj +++ b/Channels/S3/EventSourcing.Backbone.Channels.S3StoreProvider.Common/EventSourcing.Backbone.Channels.S3StoreProvider.Common.csproj @@ -15,7 +15,7 @@ - + diff --git a/Directory.Build.props b/Directory.Build.props index b41788d2..3718ec43 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,6 @@ - 1.2.153 + 1.2.157 # 1.2.85: Breaking changes: S3Strategy was renamed to S3Storage diff --git a/EventSourcing.Backbone.Abstractions/Attributes/EventSourceDeprecateVersionAttribute.cs b/EventSourcing.Backbone.Abstractions/Attributes/EventSourceDeprecateAttribute.cs similarity index 86% rename from EventSourcing.Backbone.Abstractions/Attributes/EventSourceDeprecateVersionAttribute.cs rename to EventSourcing.Backbone.Abstractions/Attributes/EventSourceDeprecateAttribute.cs index 87e979e4..3844dad7 100644 --- a/EventSourcing.Backbone.Abstractions/Attributes/EventSourceDeprecateVersionAttribute.cs +++ b/EventSourcing.Backbone.Abstractions/Attributes/EventSourceDeprecateAttribute.cs @@ -5,13 +5,13 @@ /// Used to retired an API version /// [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] -public class EventSourceDeprecateVersionAttribute : Attribute +public class EventSourceDeprecateAttribute : Attribute { /// /// Initializes a new instance of the class. /// /// The event target type. - public EventSourceDeprecateVersionAttribute(EventsContractType type) + public EventSourceDeprecateAttribute(EventsContractType type) { Type = type; } diff --git a/Tests/EventSourcing.Backbone.IntegrationTests/Contracts/IVersionAware/IVersionAwareBase.cs b/Tests/EventSourcing.Backbone.IntegrationTests/Contracts/IVersionAware/IVersionAwareBase.cs index c045f82d..218be551 100644 --- a/Tests/EventSourcing.Backbone.IntegrationTests/Contracts/IVersionAware/IVersionAwareBase.cs +++ b/Tests/EventSourcing.Backbone.IntegrationTests/Contracts/IVersionAware/IVersionAwareBase.cs @@ -1,22 +1,20 @@ -namespace EventSourcing.Backbone.Tests.Entities -{ +namespace EventSourcing.Backbone.Tests.Entities; - /// - /// Test contract - /// - public interface IVersionAwareBase - { - //[EventSourceVersion(Retired = 4)] - ValueTask ExecuteAsync(string key, int value); - [EventSourceVersion(1)] - ValueTask ExecuteAsync(int value); - [EventSourceVersion(2)] - ValueTask ExecuteAsync(DateTime value); - [EventSourceVersion(3)] - ValueTask ExecuteAsync(string value); - [EventSourceVersion(4)] - ValueTask ExecuteAsync(TimeSpan value); - [EventSourceVersion(3)] - ValueTask NotIncludesAsync(string value); - } -} \ No newline at end of file +/// +/// Test contract +/// +public interface IVersionAwareBase +{ + ValueTask ExecuteAsync(string key, int value); + [EventSourceVersion(1)] + ValueTask ExecuteAsync(int value); + [EventSourceVersion(2)] + ValueTask ExecuteAsync(DateTime value); + [EventSourceVersion(3)] + ValueTask ExecuteAsync(string value); + [EventSourceVersion(4)] + [EventSourceDeprecate(EventsContractType.Consumer, Date = "2023-08-02", Remark = "For testing")] + ValueTask ExecuteAsync(TimeSpan value); + [EventSourceVersion(3)] + ValueTask NotIncludesAsync(string value); +} diff --git a/Tests/EventSourcing.Backbone.IntegrationTests/Contracts/IVersionAware/IVersionAwareDerivedFallback.cs b/Tests/EventSourcing.Backbone.IntegrationTests/Contracts/IVersionAware/IVersionAwareDerivedFallback.cs new file mode 100644 index 00000000..579dc726 --- /dev/null +++ b/Tests/EventSourcing.Backbone.IntegrationTests/Contracts/IVersionAware/IVersionAwareDerivedFallback.cs @@ -0,0 +1,58 @@ +#pragma warning disable S1133 // Deprecated code should be removed +using Microsoft.Extensions.Logging; + +namespace EventSourcing.Backbone.Tests.Entities; + +using Generated.VersionAwareDerivedFallback; + +/// +/// Test contract +/// +[EventsContract(EventsContractType.Producer, MinVersion = 1, VersionNaming = VersionNaming.Append)] +[EventsContract(EventsContractType.Consumer, MinVersion = 2, VersionNaming = VersionNaming.AppendUnderscore)] +[Obsolete("This interface is base for code generation, please use ISimpleEventProducer or ISimpleEventConsumer")] +public interface IVersionAwareDerivedFallback: IVersionAwareBase +{ + #region Fallback + + /// + /// Consumers the fallback. + /// Excellent for Migration scenario + /// + /// The context. + /// The target. + /// + public static async Task Fallback(IConsumerInterceptionContext ctx, IVersionAwareDerivedFallbackConsumer target) + { + ILogger logger = ctx.Logger; + ConsumerContext consumerContext = ctx.Context; + Metadata meta = consumerContext.Metadata; + + if (ctx.IsMatchExecuteAsync_V0_String_Int32_Deprecated()) + { + var data = await ctx.GetExecuteAsync_V0_String_Int32_DeprecatedAsync(); + await target.Execute_3Async(consumerContext, $"{data.key}_{data.value}"); + await ctx.AckAsync(); + return true; + } + if (ctx.IsMatchExecuteAsync_V1_Int32_Deprecated()) + { + var data = await ctx.GetExecuteAsync_V1_Int32_DeprecatedAsync(); + await target.Execute_3Async(consumerContext, data.value.ToString()); + await ctx.AckAsync(); + return true; + } + if (ctx.IsMatchExecuteAsync_V4_TimeSpan_Deprecated()) + { + var data = await ctx.GetExecuteAsync_V4_TimeSpan_DeprecatedAsync(); + await target.Execute_3Async(consumerContext, data.value.ToString()); + await ctx.AckAsync(); + return true; + } + + logger.LogWarning("Fallback didn't handle: {uri}, {signature}", meta.Uri, meta.Signature); + return false; + } + + #endregion // Fallback +} diff --git a/Tests/EventSourcing.Backbone.IntegrationTests/Contracts/IVersionAware/IVersionAwareFallback.cs b/Tests/EventSourcing.Backbone.IntegrationTests/Contracts/IVersionAware/IVersionAwareFallback.cs index 1b0f5a92..5ce0cda6 100644 --- a/Tests/EventSourcing.Backbone.IntegrationTests/Contracts/IVersionAware/IVersionAwareFallback.cs +++ b/Tests/EventSourcing.Backbone.IntegrationTests/Contracts/IVersionAware/IVersionAwareFallback.cs @@ -1,27 +1,63 @@  +using Microsoft.Extensions.Logging; -namespace EventSourcing.Backbone.Tests.Entities +namespace EventSourcing.Backbone.Tests.Entities; + +using Generated.VersionAwareFallback; + +/// +/// Test contract +/// +[EventsContract(EventsContractType.Producer, MinVersion = 1, VersionNaming = VersionNaming.Append)] +[EventsContract(EventsContractType.Consumer, MinVersion = 2, VersionNaming = VersionNaming.AppendUnderscore)] +[Obsolete("This interface is base for code generation, please use ISimpleEventProducer or ISimpleEventConsumer")] +public interface IVersionAwareFallback// : IVersionAwareBase { + #region Fallback /// - /// Test contract + /// Consumers the fallback. + /// Excellent for Migration scenario /// - [EventsContract(EventsContractType.Producer, MinVersion = 1, VersionNaming = VersionNaming.Append)] - [EventsContract(EventsContractType.Consumer, MinVersion = 2, VersionNaming = VersionNaming.AppendUnderscore)] - [Obsolete("This interface is base for code generation, please use ISimpleEventProducer or ISimpleEventConsumer", true)] - public interface IVersionAwareFallback// : IVersionAwareBase + /// The context. + /// The target. + /// + public static async Task Fallback(IConsumerInterceptionContext ctx, IVersionAwareFallbackConsumer target) { - //[EventSourceVersion(Retired = 4)] - ValueTask ExecuteAsync(string key, int value); - [EventSourceVersion(1)] - ValueTask ExecuteAsync(int value); - [EventSourceVersion(2)] - ValueTask ExecuteAsync(DateTime value); - [EventSourceVersion(3)] - ValueTask ExecuteAsync(string value); - [EventSourceVersion(4)] - ValueTask ExecuteAsync(TimeSpan value); - [EventSourceVersion(3)] - ValueTask NotIncludesAsync(string value); + ILogger logger = ctx.Logger; + ConsumerContext consumerContext = ctx.Context; + Metadata meta = consumerContext.Metadata; + + if (ctx.IsMatchExecuteAsync_V0_String_Int32_Deprecated()) + { + var data = await ctx.GetExecuteAsync_V0_String_Int32_DeprecatedAsync(); + await target.Execute_3Async(consumerContext, $"{data.key}_{data.value}"); + await ctx.AckAsync(); + return true; + } + if (ctx.IsMatchExecuteAsync_V1_Int32_Deprecated()) + { + var data = await ctx.GetExecuteAsync_V1_Int32_DeprecatedAsync(); + await target.Execute_3Async(consumerContext, data.value.ToString()); + await ctx.AckAsync(); + return true; + } + + logger.LogWarning("Fallback didn't handle: {uri}, {signature}", meta.Uri, meta.Signature); + return false; } + + #endregion // Fallback + + ValueTask ExecuteAsync(string key, int value); + [EventSourceVersion(1)] + ValueTask ExecuteAsync(int value); + [EventSourceVersion(2)] + ValueTask ExecuteAsync(DateTime value); + [EventSourceVersion(3)] + ValueTask ExecuteAsync(string value); + [EventSourceVersion(4)] + ValueTask ExecuteAsync(TimeSpan value); + [EventSourceVersion(3)] + ValueTask NotIncludesAsync(string value); } diff --git a/Tests/EventSourcing.Backbone.IntegrationTests/EndToEndVersionAware/EndToEndVersionAware_DerivedFallback_Tests.cs b/Tests/EventSourcing.Backbone.IntegrationTests/EndToEndVersionAware/EndToEndVersionAware_DerivedFallback_Tests.cs new file mode 100644 index 00000000..31dca5eb --- /dev/null +++ b/Tests/EventSourcing.Backbone.IntegrationTests/EndToEndVersionAware/EndToEndVersionAware_DerivedFallback_Tests.cs @@ -0,0 +1,69 @@ +using EventSourcing.Backbone.Building; +using EventSourcing.Backbone.Tests.Entities; + +using FakeItEasy; + +using Microsoft.Extensions.Logging; + +using Xunit; +using Xunit.Abstractions; + +namespace EventSourcing.Backbone.Tests; + +public class EndToEndVersionAware_DerivedFallback_Tests : EndToEndVersionAwareBase +{ + private readonly IVersionAwareDerivedFallbackConsumer _subscriber = A.Fake(); + + #region Ctor + + public EndToEndVersionAware_DerivedFallback_Tests( + ITestOutputHelper outputHelper, + Func? producerChannelBuilder = null, + Func? consumerChannelBuilder = null) + : base(outputHelper, producerChannelBuilder, consumerChannelBuilder) + { + A.CallTo(() => _subscriber.Execute_2Async(A.Ignored, A.Ignored)) + .ReturnsLazily(() => ValueTask.CompletedTask); + } + + #endregion // Ctor + + protected override string Name { get; } = "fallback-derived"; + + [Fact] + public async Task End2End_VersionAware_DerivedFallback_Test() + { + IVersionAwareDerivedFallbackProducer producer = + _producerBuilder + .Uri(URI) + .WithLogger(TestLogger.Create(_outputHelper)) + .BuildVersionAwareDerivedFallbackProducer(); + + var ts = TimeSpan.FromSeconds(1); + await producer.Execute4Async(ts); + await producer.Execute1Async(10); + await producer.Execute2Async(DateTime.Now); + await producer.Execute1Async(11); + + var cts = new CancellationTokenSource(); + + var subscription = + _consumerBuilder + .WithOptions(cfg => cfg with { MaxMessages = 4 }) + .WithCancellation(cts.Token) + .Uri(URI) + .WithLogger(TestLogger.Create(_outputHelper)) + .SubscribeVersionAwareDerivedFallbackConsumer(_subscriber); + + await subscription.Completion; + + A.CallTo(() => _subscriber.Execute_2Async(A.Ignored, A.Ignored)) + .MustHaveHappened(); + A.CallTo(() => _subscriber.Execute_3Async(A.Ignored, "10")) + .MustHaveHappened(); + A.CallTo(() => _subscriber.Execute_3Async(A.Ignored, "11")) + .MustHaveHappened(); + A.CallTo(() => _subscriber.Execute_3Async(A.Ignored, "00:00:01")) + .MustHaveHappened(); + } +} diff --git a/Tests/EventSourcing.Backbone.IntegrationTests/EndToEndVersionAware/EndToEndVersionAware_Fallback_Tests.cs b/Tests/EventSourcing.Backbone.IntegrationTests/EndToEndVersionAware/EndToEndVersionAware_Fallback_Tests.cs index 7ef6515e..c9406f4c 100644 --- a/Tests/EventSourcing.Backbone.IntegrationTests/EndToEndVersionAware/EndToEndVersionAware_Fallback_Tests.cs +++ b/Tests/EventSourcing.Backbone.IntegrationTests/EndToEndVersionAware/EndToEndVersionAware_Fallback_Tests.cs @@ -8,8 +8,6 @@ using Xunit; using Xunit.Abstractions; - - namespace EventSourcing.Backbone.Tests; public class EndToEndVersionAware_Fallback_Tests : EndToEndVersionAwareBase @@ -34,7 +32,7 @@ public EndToEndVersionAware_Fallback_Tests( protected override string Name { get; } = "fallback"; - [Fact(Skip = "fallback implementation is missing")] + [Fact] public async Task End2End_VersionAware_Fallback_Test() { IVersionAwareFallbackProducer producer = @@ -56,7 +54,6 @@ public async Task End2End_VersionAware_Fallback_Test() .WithCancellation(cts.Token) .Uri(URI) .WithLogger(TestLogger.Create(_outputHelper)) - // TODO: fallback .SubscribeVersionAwareFallbackConsumer(_subscriber); await subscription.Completion; @@ -65,7 +62,9 @@ public async Task End2End_VersionAware_Fallback_Test() .MustNotHaveHappened(); A.CallTo(() => _subscriber.Execute_4Async(A.Ignored, ts)) .MustHaveHappenedOnceExactly(); - - throw new NotImplementedException(); + A.CallTo(() => _subscriber.Execute_3Async(A.Ignored, "10")) + .MustHaveHappened(); + A.CallTo(() => _subscriber.Execute_3Async(A.Ignored, "11")) + .MustHaveHappened(); } } diff --git a/Tests/EventSourcing.Backbone.IntegrationTests/EventSourcing.Backbone.IntegrationTests.csproj b/Tests/EventSourcing.Backbone.IntegrationTests/EventSourcing.Backbone.IntegrationTests.csproj index 9e5f0bf0..7f4adf8c 100644 --- a/Tests/EventSourcing.Backbone.IntegrationTests/EventSourcing.Backbone.IntegrationTests.csproj +++ b/Tests/EventSourcing.Backbone.IntegrationTests/EventSourcing.Backbone.IntegrationTests.csproj @@ -35,7 +35,7 @@ - + all diff --git a/Tests/EventSourcing.Backbone.UnitTests/Contracts/IVersionAware/IVersionAwareBase.cs b/Tests/EventSourcing.Backbone.UnitTests/Contracts/IVersionAware/IVersionAwareBase.cs index f41a3d68..a97b5551 100644 --- a/Tests/EventSourcing.Backbone.UnitTests/Contracts/IVersionAware/IVersionAwareBase.cs +++ b/Tests/EventSourcing.Backbone.UnitTests/Contracts/IVersionAware/IVersionAwareBase.cs @@ -1,22 +1,20 @@ -namespace EventSourcing.Backbone.UnitTests.Entities -{ +namespace EventSourcing.Backbone.UnitTests; - /// - /// Test contract - /// - public interface IVersionAwareBase - { - //[EventSourceVersion(Retired = 4)] - ValueTask ExecuteAsync(string key, int value); - [EventSourceVersion(1)] - ValueTask ExecuteAsync(int value); - [EventSourceVersion(2)] - ValueTask ExecuteAsync(DateTime value); - [EventSourceVersion(3)] - ValueTask ExecuteAsync(string value); - [EventSourceVersion(4)] - ValueTask ExecuteAsync(TimeSpan value); - [EventSourceVersion(3)] - ValueTask NotIncludesAsync(string value); - } -} \ No newline at end of file +/// +/// Test contract +/// +public interface IVersionAwareBase +{ + ValueTask ExecuteAsync(string key, int value); + [EventSourceVersion(1)] + ValueTask ExecuteAsync(int value); + [EventSourceVersion(2)] + ValueTask ExecuteAsync(DateTime value); + [EventSourceVersion(3)] + ValueTask ExecuteAsync(string value); + [EventSourceVersion(4)] + [EventSourceDeprecate(EventsContractType.Consumer, Date = "2023-08-02", Remark = "For testing")] + ValueTask ExecuteAsync(TimeSpan value); + [EventSourceVersion(3)] + ValueTask NotIncludesAsync(string value); +} diff --git a/Tests/EventSourcing.Backbone.UnitTests/Contracts/IVersionAware/IVersionAwareDerivedFallback.cs b/Tests/EventSourcing.Backbone.UnitTests/Contracts/IVersionAware/IVersionAwareDerivedFallback.cs new file mode 100644 index 00000000..cfbbfaeb --- /dev/null +++ b/Tests/EventSourcing.Backbone.UnitTests/Contracts/IVersionAware/IVersionAwareDerivedFallback.cs @@ -0,0 +1,58 @@ +#pragma warning disable S1133 // Deprecated code should be removed +using Microsoft.Extensions.Logging; + +namespace EventSourcing.Backbone.UnitTests; + +using Generated.VersionAwareDerivedFallback; + +/// +/// Test contract +/// +[EventsContract(EventsContractType.Producer, MinVersion = 1, VersionNaming = VersionNaming.Append)] +[EventsContract(EventsContractType.Consumer, MinVersion = 2, VersionNaming = VersionNaming.AppendUnderscore)] +[Obsolete("This interface is base for code generation, please use ISimpleEventProducer or ISimpleEventConsumer")] +public interface IVersionAwareDerivedFallback: IVersionAwareBase +{ + #region Fallback + + /// + /// Consumers the fallback. + /// Excellent for Migration scenario + /// + /// The context. + /// The target. + /// + public static async Task Fallback(IConsumerInterceptionContext ctx, IVersionAwareDerivedFallbackConsumer target) + { + ILogger logger = ctx.Logger; + ConsumerContext consumerContext = ctx.Context; + Metadata meta = consumerContext.Metadata; + + if (ctx.IsMatchExecuteAsync_V0_String_Int32_Deprecated()) + { + var data = await ctx.GetExecuteAsync_V0_String_Int32_DeprecatedAsync(); + await target.Execute_3Async(consumerContext, $"{data.key}_{data.value}"); + await ctx.AckAsync(); + return true; + } + if (ctx.IsMatchExecuteAsync_V1_Int32_Deprecated()) + { + var data = await ctx.GetExecuteAsync_V1_Int32_DeprecatedAsync(); + await target.Execute_3Async(consumerContext, data.value.ToString()); + await ctx.AckAsync(); + return true; + } + if (ctx.IsMatchExecuteAsync_V4_TimeSpan_Deprecated()) + { + var data = await ctx.GetExecuteAsync_V4_TimeSpan_DeprecatedAsync(); + await target.Execute_3Async(consumerContext, data.value.ToString()); + await ctx.AckAsync(); + return true; + } + + logger.LogWarning("Fallback didn't handle: {uri}, {signature}", meta.Uri, meta.Signature); + return false; + } + + #endregion // Fallback +} diff --git a/Tests/EventSourcing.Backbone.UnitTests/Contracts/IVersionAware/IVersionAwareFallback.cs b/Tests/EventSourcing.Backbone.UnitTests/Contracts/IVersionAware/IVersionAwareFallback.cs index f2039879..f76f6e82 100644 --- a/Tests/EventSourcing.Backbone.UnitTests/Contracts/IVersionAware/IVersionAwareFallback.cs +++ b/Tests/EventSourcing.Backbone.UnitTests/Contracts/IVersionAware/IVersionAwareFallback.cs @@ -1,19 +1,16 @@ #pragma warning disable S1133 // Deprecated code should be removed - +using Microsoft.Extensions.Logging; namespace EventSourcing.Backbone.UnitTests; - using Generated.VersionAwareFallback; -using Microsoft.Extensions.Logging; - /// /// Test contract /// [EventsContract(EventsContractType.Producer, MinVersion = 1, VersionNaming = VersionNaming.Append)] [EventsContract(EventsContractType.Consumer, MinVersion = 2, VersionNaming = VersionNaming.AppendUnderscore)] -[Obsolete("This interface is base for code generation, please use ISimpleEventProducer or ISimpleEventConsumer", true)] +[Obsolete("This interface is base for code generation, please use ISimpleEventProducer or ISimpleEventConsumer")] public interface IVersionAwareFallback// : IVersionAwareBase { #region Fallback @@ -31,24 +28,24 @@ public static async Task Fallback(IConsumerInterceptionContext ctx, IVersi ConsumerContext consumerContext = ctx.Context; Metadata meta = consumerContext.Metadata; - var (succeed1, data1) = await ctx.TryGetExecuteAsync_V0_String_Int32_DeprecatedAsync(); - if (succeed1) + if (ctx.IsMatchExecuteAsync_V0_String_Int32_Deprecated()) { - await target.Execute_3Async(consumerContext, $"{data1!.value}_{data1.key}"); + var data = await ctx.GetExecuteAsync_V0_String_Int32_DeprecatedAsync(); + await target.Execute_3Async(consumerContext, $"{data.key}_{data.value}"); await ctx.AckAsync(); return true; } - var (succeed2, data2) = await ctx.TryGetExecuteAsync_V1_Int32_DeprecatedAsync(); - if (succeed2) + if (ctx.IsMatchExecuteAsync_V1_Int32_Deprecated()) { - await target.Execute_3Async(consumerContext, data2!.value.ToString()); + var data = await ctx.GetExecuteAsync_V1_Int32_DeprecatedAsync(); + await target.Execute_3Async(consumerContext, data.value.ToString()); await ctx.AckAsync(); return true; } - var (succeed3, data3) = await ctx.TryGetExecuteAsync_V4_TimeSpan_DeprecatedAsync(); - if (succeed3) + if (ctx.IsMatchExecuteAsync_V4_TimeSpan_Deprecated()) { - await target.Execute_3Async(consumerContext, data3!.value.ToString()); + var data = await ctx.GetExecuteAsync_V4_TimeSpan_DeprecatedAsync(); + await target.Execute_3Async(consumerContext, data.value.ToString()); await ctx.AckAsync(); return true; } @@ -66,7 +63,7 @@ public static async Task Fallback(IConsumerInterceptionContext ctx, IVersi [EventSourceVersion(3)] ValueTask ExecuteAsync(string value); [EventSourceVersion(4)] - [EventSourceDeprecateVersion(EventsContractType.Consumer, Date = "2023-08-02", Remark = "For testing")] + [EventSourceDeprecate(EventsContractType.Consumer, Date = "2023-08-02", Remark = "For testing")] ValueTask ExecuteAsync(TimeSpan value); [EventSourceVersion(3)] ValueTask NotIncludesAsync(string value); diff --git a/Tests/EventSourcing.Backbone.UnitTests/EndToEndVersionAware/EndToEndVersionAware_DerivedFallback_Tests.cs b/Tests/EventSourcing.Backbone.UnitTests/EndToEndVersionAware/EndToEndVersionAware_DerivedFallback_Tests.cs new file mode 100644 index 00000000..e211d9d4 --- /dev/null +++ b/Tests/EventSourcing.Backbone.UnitTests/EndToEndVersionAware/EndToEndVersionAware_DerivedFallback_Tests.cs @@ -0,0 +1,78 @@ +using System.Threading.Channels; + +using FakeItEasy; + +using Microsoft.Extensions.Logging; + +using Xunit; +using Xunit.Abstractions; + + + +namespace EventSourcing.Backbone.UnitTests; + +public class EndToEndVersionAware_DerivedFallback_Tests +{ + private readonly ITestOutputHelper _outputHelper; + private readonly IProducerBuilder _producerBuilder = ProducerBuilder.Empty; + private readonly IConsumerBuilder _consumerBuilder = ConsumerBuilder.Empty; + private readonly Func _producerChannel; + private readonly Func _consumerChannel; + private readonly Channel ch; + private readonly IVersionAwareDerivedFallbackConsumer _subscriber = A.Fake(); + + #region Ctor + + public EndToEndVersionAware_DerivedFallback_Tests(ITestOutputHelper outputHelper) + { + _outputHelper = outputHelper; + ch = Channel.CreateUnbounded(); + _producerChannel = _ => new ProducerTestChannel(ch); + _consumerChannel = _ => new ConsumerTestChannel(ch); + } + + #endregion // Ctor + + [Fact] + public async Task End2End_VersionAware_DerivedFallback_Test() + { + string URI = "testing:version:aware"; + IVersionAwareDerivedFallbackProducer producer = + _producerBuilder.UseChannel(_producerChannel) + .Uri(URI) + .WithLogger(TestLogger.Create(_outputHelper)) + .BuildVersionAwareDerivedFallbackProducer(); + + var ts = TimeSpan.FromSeconds(1); + await producer.Execute4Async(ts); + await producer.Execute1Async(1); + await producer.Execute1Async(10); + await producer.Execute1Async(11); + await producer.Execute2Async(DateTime.Now); + + var cts = new CancellationTokenSource(); + + IAsyncDisposable subscription = + _consumerBuilder.UseChannel(_consumerChannel) + //.WithOptions(consumerOptions) + .WithCancellation(cts.Token) + .Uri(URI) + .WithLogger(TestLogger.Create(_outputHelper)) + .SubscribeVersionAwareDerivedFallbackConsumer(_subscriber); + + ch.Writer.Complete(); + await subscription.DisposeAsync(); + await ch.Reader.Completion; + + A.CallTo(() => _subscriber.Execute_2Async(A.Ignored, A.Ignored)) + .MustHaveHappened(); + A.CallTo(() => _subscriber.Execute_3Async(A.Ignored, "1")) + .MustHaveHappened(); + A.CallTo(() => _subscriber.Execute_3Async(A.Ignored, "10")) + .MustHaveHappened(); + A.CallTo(() => _subscriber.Execute_3Async(A.Ignored, "11")) + .MustHaveHappened(); + A.CallTo(() => _subscriber.Execute_3Async(A.Ignored, "00:00:01")) + .MustHaveHappened(); + } +} diff --git a/Tests/EventSourcing.Backbone.UnitTests/EndToEndVersionAware/EndToEndVersionAware_Fallback_Tests.cs b/Tests/EventSourcing.Backbone.UnitTests/EndToEndVersionAware/EndToEndVersionAware_Fallback_Tests.cs index 4395ebdf..71cdf427 100644 --- a/Tests/EventSourcing.Backbone.UnitTests/EndToEndVersionAware/EndToEndVersionAware_Fallback_Tests.cs +++ b/Tests/EventSourcing.Backbone.UnitTests/EndToEndVersionAware/EndToEndVersionAware_Fallback_Tests.cs @@ -33,19 +33,19 @@ public EndToEndVersionAware_Fallback_Tests(ITestOutputHelper outputHelper) #endregion // Ctor - [Fact(Skip = "fallback implementation is missing")] + [Fact] public async Task End2End_VersionAware_Fallback_Test() { string URI = "testing:version:aware"; IVersionAwareFallbackProducer producer = _producerBuilder.UseChannel(_producerChannel) - //.WithOptions(producerOption) .Uri(URI) .WithLogger(TestLogger.Create(_outputHelper)) .BuildVersionAwareFallbackProducer(); var ts = TimeSpan.FromSeconds(1); await producer.Execute4Async(ts); + await producer.Execute1Async(1); await producer.Execute1Async(10); await producer.Execute1Async(11); await producer.Execute2Async(DateTime.Now); @@ -72,7 +72,7 @@ public async Task End2End_VersionAware_Fallback_Test() .MustHaveHappened(); A.CallTo(() => _subscriber.Execute_3Async(A.Ignored, "11")) .MustHaveHappened(); - - throw new NotImplementedException(); + A.CallTo(() => _subscriber.Execute_3Async(A.Ignored, "00:00:01")) + .MustHaveHappened(); } } diff --git a/Tests/EventSourcing.Backbone.UnitTests/EventSourcing.Backbone.UnitTests.csproj b/Tests/EventSourcing.Backbone.UnitTests/EventSourcing.Backbone.UnitTests.csproj index 4f509f39..31d12a6e 100644 --- a/Tests/EventSourcing.Backbone.UnitTests/EventSourcing.Backbone.UnitTests.csproj +++ b/Tests/EventSourcing.Backbone.UnitTests/EventSourcing.Backbone.UnitTests.csproj @@ -8,7 +8,7 @@ - + all diff --git a/Tests/EventSourcing.Backbone.UnitTests/Subscriptions/SimpleEventSubscriptionBridge.cs b/Tests/EventSourcing.Backbone.UnitTests/Subscriptions/SimpleEventSubscriptionBridge.cs index b0741248..1e30e140 100644 --- a/Tests/EventSourcing.Backbone.UnitTests/Subscriptions/SimpleEventSubscriptionBridge.cs +++ b/Tests/EventSourcing.Backbone.UnitTests/Subscriptions/SimpleEventSubscriptionBridge.cs @@ -3,7 +3,7 @@ namespace EventSourcing.Backbone { - using static SimpleEventConstants.ACTIVE; + using static SimpleEventSignatures.ACTIVE; /// /// In-Memory Channel (excellent for testing) diff --git a/Tests/EventSourcing.Backbone.UnitTests/Versioning_Const_Test.cs b/Tests/EventSourcing.Backbone.UnitTests/Versioning_Const_Test.cs index 58faca31..aa799694 100644 --- a/Tests/EventSourcing.Backbone.UnitTests/Versioning_Const_Test.cs +++ b/Tests/EventSourcing.Backbone.UnitTests/Versioning_Const_Test.cs @@ -19,10 +19,10 @@ public VersionAware_Const_Test(ITestOutputHelper outputHelper) [Fact] public void Consumer_Const_Test() { - _outputHelper.WriteLine(VersionAwareMixConstants.DEPRECATED.ExecuteAsync.V0.P_String_Int32.SignatureString); - Assert.Equal("ExecuteAsync_V0_String,Int32", VersionAwareMixConstants.DEPRECATED.ExecuteAsync.V0.P_String_Int32.SignatureString); - _outputHelper.WriteLine(VersionAwareMixConstants.ACTIVE.ExecuteAsync.V2.P_DateTime.SignatureString); - Assert.Equal("ExecuteAsync_V2_DateTime", VersionAwareMixConstants.ACTIVE.ExecuteAsync.V2.P_DateTime.SignatureString); + _outputHelper.WriteLine(VersionAwareMixSignatures.DEPRECATED.ExecuteAsync.V0.P_String_Int32.SignatureString); + Assert.Equal("ExecuteAsync_V0_String,Int32", VersionAwareMixSignatures.DEPRECATED.ExecuteAsync.V0.P_String_Int32.SignatureString); + _outputHelper.WriteLine(VersionAwareMixSignatures.ACTIVE.ExecuteAsync.V2.P_DateTime.SignatureString); + Assert.Equal("ExecuteAsync_V2_DateTime", VersionAwareMixSignatures.ACTIVE.ExecuteAsync.V2.P_DateTime.SignatureString); } } diff --git a/Tests/EventSourcing.Backbone.WebEventTest/EventSourcing.Backbone.WebEventTest.csproj b/Tests/EventSourcing.Backbone.WebEventTest/EventSourcing.Backbone.WebEventTest.csproj index ded3e792..d1e8e6cf 100644 --- a/Tests/EventSourcing.Backbone.WebEventTest/EventSourcing.Backbone.WebEventTest.csproj +++ b/Tests/EventSourcing.Backbone.WebEventTest/EventSourcing.Backbone.WebEventTest.csproj @@ -10,7 +10,7 @@ - + diff --git a/Tests/Specialized/Tests.Events.ConsumerWebTest.Service/Tests.Events.ConsumerWebTest.Service.csproj b/Tests/Specialized/Tests.Events.ConsumerWebTest.Service/Tests.Events.ConsumerWebTest.Service.csproj index 6aaf5ca7..bb89ebfb 100644 --- a/Tests/Specialized/Tests.Events.ConsumerWebTest.Service/Tests.Events.ConsumerWebTest.Service.csproj +++ b/Tests/Specialized/Tests.Events.ConsumerWebTest.Service/Tests.Events.ConsumerWebTest.Service.csproj @@ -10,7 +10,7 @@ - + diff --git a/Tests/Specialized/Tests.Events.ProducerWebTest.Service/Tests.Events.ProducerWebTest.Service.csproj b/Tests/Specialized/Tests.Events.ProducerWebTest.Service/Tests.Events.ProducerWebTest.Service.csproj index 10c6e40e..90188eae 100644 --- a/Tests/Specialized/Tests.Events.ProducerWebTest.Service/Tests.Events.ProducerWebTest.Service.csproj +++ b/Tests/Specialized/Tests.Events.ProducerWebTest.Service/Tests.Events.ProducerWebTest.Service.csproj @@ -10,7 +10,7 @@ - + diff --git a/Tests/WebSampleS3/WebSampleS3.csproj b/Tests/WebSampleS3/WebSampleS3.csproj index 9200b3b8..5975b2a1 100644 --- a/Tests/WebSampleS3/WebSampleS3.csproj +++ b/Tests/WebSampleS3/WebSampleS3.csproj @@ -7,7 +7,7 @@ - + @@ -19,7 +19,7 @@ - + diff --git a/src-gen/EventSourcing.Backbone.SrcGen.Playground/IEventsWithVersion.cs b/src-gen/EventSourcing.Backbone.SrcGen.Playground/IEventsWithVersion.cs index 892f5fac..6300fd74 100644 --- a/src-gen/EventSourcing.Backbone.SrcGen.Playground/IEventsWithVersion.cs +++ b/src-gen/EventSourcing.Backbone.SrcGen.Playground/IEventsWithVersion.cs @@ -1,16 +1,19 @@ -#pragma warning disable S1133 // Obsolete +using Microsoft.Extensions.Logging; namespace EventSourcing.Backbone.WebEventTest; -using EventSourcing.Backbone; +using System.Data; using Generated.EventsWithVersion; +using static Generated.EventsWithVersionSignatures; + -using Microsoft.Extensions.Logging; [EventsContract(EventsContractType.Producer, MinVersion = 1, VersionNaming = VersionNaming.Append)] [EventsContract(EventsContractType.Consumer, MinVersion = 1, VersionNaming = VersionNaming.Append)] -[Obsolete("This interface is base for code generation, please use ISimpleEventProducer or ISimpleEventConsumer", true)] +#pragma warning disable S1133 // Deprecated code should be removed +[Obsolete("This interface is base for code generation, please use ISimpleEventProducer or ISimpleEventConsumer")] +#pragma warning restore S1133 public interface IEventsWithVersion { /// @@ -25,29 +28,25 @@ public static async Task Fallback(IConsumerInterceptionContext ctx, IEvent ILogger logger = ctx.Logger; ConsumerContext consumerContext = ctx.Context; Metadata meta = consumerContext.Metadata; - //switch (meta.Signature.ToString()) - //{ - // case Generated.EventsWithVersion.CONSTANTS.ACTIVE.ExecuteAsync.V1.P_: - // break; - //} - var (succeed1, data1) = await ctx.TryGetExecuteAsync_V0_String_Int32_DeprecatedAsync(); - if (succeed1) + + if (ctx.IsMatchExecuteAsync_V0_String_Int32_Deprecated()) { - await target.Execute3Async(consumerContext, data1!.value.ToString()); + var data = await ctx.GetExecuteAsync_V0_String_Int32_DeprecatedAsync(); + await target.Execute3Async(consumerContext, $"{data.key}-{data.value}"); await ctx.AckAsync(); return true; } - var (succeed2, data2) = await ctx.TryGetExecuteAsync_V2_Boolean_DeprecatedAsync(); - if (succeed2) + if (ctx.IsMatchExecuteAsync_V2_Boolean_Deprecated()) { - await target.Execute3Async(consumerContext, data2!.value.ToString()); + var data = await ctx.GetExecuteAsync_V2_Boolean_DeprecatedAsync(); + await target.Execute3Async(consumerContext, data.value.ToString()); await ctx.AckAsync(); return true; } - var (succeed3, data3) = await ctx.TryGetNotIncludesAsync_V2_String_DeprecatedAsync(); - if (succeed3) + if (ctx.IsMatchNotIncludesAsync_V2_String_Deprecated()) { - await target.Execute3Async(consumerContext, data3!.value); + var data = await ctx.GetNotIncludesAsync_V2_String_DeprecatedAsync(); + await target.Execute3Async(consumerContext, data.value); await ctx.AckAsync(); return true; } @@ -99,14 +98,21 @@ public static async Task Fallback(IConsumerInterceptionContext ctx, IEvent /// /// Some remarks [EventSourceVersion(2)] - [EventSourceDeprecateVersionAttribute(EventsContractType.Consumer, Date = "2023-07-28", Remark = "sample of deprecation")] + [EventSourceDeprecateAttribute(EventsContractType.Consumer, Date = "2023-07-28", Remark = "sample of deprecation")] ValueTask ExecuteAsync(bool value); [EventSourceVersion(3)] ValueTask ExecuteAsync(string value); [EventSourceVersion(2)] - [EventSourceDeprecateVersionAttribute(EventsContractType.Producer, Date = "2023-07-27", Remark = "sample of deprecation")] - [EventSourceDeprecateVersionAttribute(EventsContractType.Consumer, Date = "2023-07-28", Remark = "sample of deprecation")] + [EventSourceDeprecateAttribute(EventsContractType.Producer, Date = "2023-07-27", Remark = "sample of deprecation")] + [EventSourceDeprecateAttribute(EventsContractType.Consumer, Date = "2023-07-28", Remark = "sample of deprecation")] ValueTask NotIncludesAsync(string value); + + [EventSourceVersion(4)] + ValueTask ExecuteAsync(params string[] values); + [EventSourceVersion(4)] + ValueTask ExecuteAsync(List values); + [EventSourceVersion(4)] + ValueTask ExecuteAsync(params int[] values); } diff --git a/src-gen/EventSourcing.Backbone.SrcGen/Generators/EntitiesAndHelpers/GenInstruction.cs b/src-gen/EventSourcing.Backbone.SrcGen/Entities/GenInstruction.cs similarity index 92% rename from src-gen/EventSourcing.Backbone.SrcGen/Generators/EntitiesAndHelpers/GenInstruction.cs rename to src-gen/EventSourcing.Backbone.SrcGen/Entities/GenInstruction.cs index 6c0a681c..33e2fa51 100644 --- a/src-gen/EventSourcing.Backbone.SrcGen/Generators/EntitiesAndHelpers/GenInstruction.cs +++ b/src-gen/EventSourcing.Backbone.SrcGen/Entities/GenInstruction.cs @@ -1,4 +1,4 @@ -namespace EventSourcing.Backbone.SrcGen.Generators.Entities +namespace EventSourcing.Backbone.SrcGen.Entities { internal class GenInstruction { diff --git a/src-gen/EventSourcing.Backbone.SrcGen/Generators/EntitiesAndHelpers/KindFilter.cs b/src-gen/EventSourcing.Backbone.SrcGen/Entities/KindFilter.cs similarity index 59% rename from src-gen/EventSourcing.Backbone.SrcGen/Generators/EntitiesAndHelpers/KindFilter.cs rename to src-gen/EventSourcing.Backbone.SrcGen/Entities/KindFilter.cs index 8e1281c4..1a530146 100644 --- a/src-gen/EventSourcing.Backbone.SrcGen/Generators/EntitiesAndHelpers/KindFilter.cs +++ b/src-gen/EventSourcing.Backbone.SrcGen/Entities/KindFilter.cs @@ -1,4 +1,4 @@ -namespace EventSourcing.Backbone.SrcGen.Generators.Entities +namespace EventSourcing.Backbone.SrcGen.Entities { internal enum KindFilter { diff --git a/src-gen/EventSourcing.Backbone.SrcGen/Generators/EntitiesAndHelpers/MethodBundle.cs b/src-gen/EventSourcing.Backbone.SrcGen/Entities/MethodBundle.cs similarity index 89% rename from src-gen/EventSourcing.Backbone.SrcGen/Generators/EntitiesAndHelpers/MethodBundle.cs rename to src-gen/EventSourcing.Backbone.SrcGen/Entities/MethodBundle.cs index 20196b8f..46bfd020 100644 --- a/src-gen/EventSourcing.Backbone.SrcGen/Generators/EntitiesAndHelpers/MethodBundle.cs +++ b/src-gen/EventSourcing.Backbone.SrcGen/Entities/MethodBundle.cs @@ -1,10 +1,8 @@ using System.Diagnostics; -using EventSourcing.Backbone.SrcGen.Entities; - using Microsoft.CodeAnalysis; -namespace EventSourcing.Backbone.SrcGen.Generators.EntitiesAndHelpers; +namespace EventSourcing.Backbone.SrcGen.Entities; /// /// Method Bundle @@ -74,8 +72,8 @@ public string FormatMethodFullName(string? nameOverride = null) string name = nameOverride ?? FullName; string versionSuffix = VersionNaming switch { - SrcGen.Entities.VersionNaming.Append => Version.ToString(), - SrcGen.Entities.VersionNaming.AppendUnderscore => $"_{Version}", + VersionNaming.Append => Version.ToString(), + VersionNaming.AppendUnderscore => $"_{Version}", _ => string.Empty }; diff --git a/src-gen/EventSourcing.Backbone.SrcGen/Generators/Concrete/BridgeIncrementalGenerator.cs b/src-gen/EventSourcing.Backbone.SrcGen/Generators/Concrete/BridgeIncrementalGenerator.cs index dbd66860..316a8cdc 100644 --- a/src-gen/EventSourcing.Backbone.SrcGen/Generators/Concrete/BridgeIncrementalGenerator.cs +++ b/src-gen/EventSourcing.Backbone.SrcGen/Generators/Concrete/BridgeIncrementalGenerator.cs @@ -1,7 +1,6 @@ using System.Reflection; using System.Text; - -using EventSourcing.Backbone.SrcGen.Generators.Entities; +using EventSourcing.Backbone.SrcGen.Entities; using EventSourcing.Backbone.SrcGen.Generators.EntitiesAndHelpers; using Microsoft.CodeAnalysis; @@ -312,7 +311,7 @@ protected GenInstruction OnGenerateConsumerBase( builder.AppendLine($"\t\t\t\tawait {mtdName}({metaParam}{prmsSep});"); } builder.AppendLine("\t\t\t\t\treturn true;"); - builder.AppendLine("\t\t\t\t}"); + builder.AppendLine("\t\t\t}"); } else { @@ -330,7 +329,10 @@ protected GenInstruction OnGenerateConsumerBase( builder.AppendLine("\t\t\tbool result = false;"); foreach (string fallbackName in fallbackNames) { - builder.AppendLine($"\t\t\tresult = await {interfaceName}.{fallbackName}(fallbackHandle, this);"); + // invoke fallbacks + builder.AppendLine("\t\t\t#pragma warning disable cs0618 // ignore calling obsolete member"); + builder.AppendLine($"\t\t\tresult = await {info.GenerateFrom}.{fallbackName}(fallbackHandle, this);"); + builder.AppendLine("\t\t\t#pragma warning restore cs0618"); } builder.AppendLine(); builder.AppendLine("\t\t\treturn result;"); diff --git a/src-gen/EventSourcing.Backbone.SrcGen/Generators/Concrete/ContractIncrementalGenerator.cs b/src-gen/EventSourcing.Backbone.SrcGen/Generators/Concrete/ContractIncrementalGenerator.cs index 19a93124..8cb20339 100644 --- a/src-gen/EventSourcing.Backbone.SrcGen/Generators/Concrete/ContractIncrementalGenerator.cs +++ b/src-gen/EventSourcing.Backbone.SrcGen/Generators/Concrete/ContractIncrementalGenerator.cs @@ -1,7 +1,5 @@ using System.Text; - -using EventSourcing.Backbone.SrcGen.Generators.Entities; -using EventSourcing.Backbone.SrcGen.Generators.EntitiesAndHelpers; +using EventSourcing.Backbone.SrcGen.Entities; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -40,7 +38,7 @@ protected override GenInstruction[] OnGenerate( string interfaceName = info.FormatName(); var bundles = info.ToBundle(compilation); - int? maxVersion = bundles.Max(m => m.Version); + int? maxVersion = bundles.Length == 0 ? 0 : bundles.Max(m => m.Version); var builder = new StringBuilder(); symbol.CopyDocumentation(builder, maxVersion, "\t"); var asm = GetType().Assembly.GetName(); @@ -48,22 +46,20 @@ protected override GenInstruction[] OnGenerate( builder.AppendLine($"\tpublic interface {interfaceName}"); builder.AppendLine("\t{"); - builder.AddInterceptors(symbol, interfaceName); + // Copy Fallback handler + // builder.AddInterceptors(symbol, interfaceName); + foreach (MethodBundle bundle in bundles) { if (bundle.Deprecated) continue; - + GenMethod(builder, bundle); } builder.AppendLine("\t}"); - var contractOnlyArg = att.ArgumentList?.Arguments.FirstOrDefault(m => m.NameEquals?.Name.Identifier.ValueText == "ContractOnly"); - var contractOnly = contractOnlyArg?.Expression.NormalizeWhitespace().ToString() == "true"; - - if (!contractOnly) - _bridge.GenerateSingle(context, compilation, info); + _bridge.GenerateSingle(context, compilation, info); return new[] { new GenInstruction(interfaceName, builder.ToString()) }; #region GetParameter diff --git a/src-gen/EventSourcing.Backbone.SrcGen/Generators/EntitiesAndHelpers/ConstantsGenerator.cs b/src-gen/EventSourcing.Backbone.SrcGen/Generators/EntitiesAndHelpers/ConstantsGenerator.cs index 3c2ce65d..3345b569 100644 --- a/src-gen/EventSourcing.Backbone.SrcGen/Generators/EntitiesAndHelpers/ConstantsGenerator.cs +++ b/src-gen/EventSourcing.Backbone.SrcGen/Generators/EntitiesAndHelpers/ConstantsGenerator.cs @@ -1,8 +1,6 @@ using System.Reflection; using System.Text; - -using EventSourcing.Backbone.SrcGen.Generators.Entities; - +using EventSourcing.Backbone.SrcGen.Entities; using Microsoft.CodeAnalysis; namespace EventSourcing.Backbone.SrcGen.Generators.EntitiesAndHelpers; @@ -31,7 +29,7 @@ internal static class ConstantsGenerator var builder = new StringBuilder(); GenVersionConstants(builder); - return new GenInstruction($"{simpleName}.Constants", builder.ToString(), $"{info.Namespace}.Generated"); + return new GenInstruction($"{simpleName}.Signatures", builder.ToString(), $"{info.Namespace}.Generated"); void GenVersionConstants(StringBuilder builder) { @@ -39,7 +37,7 @@ void GenVersionConstants(StringBuilder builder) string indent = "\t"; - builder.AppendLine($"{indent}public static class {simpleName}Constants"); + builder.AppendLine($"{indent}public static class {simpleName}Signatures"); builder.AppendLine($"{indent}{{"); indent = $"{indent}\t"; diff --git a/src-gen/EventSourcing.Backbone.SrcGen/Generators/EntitiesAndHelpers/EntityGenerator.cs b/src-gen/EventSourcing.Backbone.SrcGen/Generators/EntitiesAndHelpers/EntityGenerator.cs index e1161621..dd862138 100644 --- a/src-gen/EventSourcing.Backbone.SrcGen/Generators/EntitiesAndHelpers/EntityGenerator.cs +++ b/src-gen/EventSourcing.Backbone.SrcGen/Generators/EntitiesAndHelpers/EntityGenerator.cs @@ -1,8 +1,6 @@ using System.Reflection; using System.Text; - -using EventSourcing.Backbone.SrcGen.Generators.Entities; - +using EventSourcing.Backbone.SrcGen.Entities; using Microsoft.CodeAnalysis; namespace EventSourcing.Backbone.SrcGen.Generators.EntitiesAndHelpers @@ -61,6 +59,9 @@ internal static GenInstruction[] GenerateEntities( builder.AppendLine($"): {FAMILY}"); builder.AppendLine("\t{"); builder.AppendLine($"\t\tprivate static readonly OperationSignature _signature = new (\"{bundle.FullName}\", {bundle.Version}, \"{bundle.Parameters}\");"); + + //-----------------------------Task<(succeed, entity)> IsMatch(context) --------------------- + builder.AppendLine($"\t\tpublic static bool IsMatch(IConsumerInterceptionContext context)"); builder.AppendLine("\t\t{"); builder.AppendLine($"\t\t\tMetadata meta = context.Context.Metadata;"); @@ -69,17 +70,14 @@ internal static GenInstruction[] GenerateEntities( builder.AppendLine(); var prms = Enumerable.Range(0, psRaw.Length).Select(m => $"p{m}"); + + //-----------------------------Task GetAsync(context) --------------------- + builder.Append($"\t\tpublic "); if (psRaw.Length != 0) builder.Append($"async "); - builder.AppendLine($"static Task<(bool, {entityName}?)> TryGetAsync(IConsumerInterceptionContext context)"); + builder.AppendLine($"static Task<{entityName}> GetAsync(IConsumerInterceptionContext context)"); builder.AppendLine("\t\t{"); - builder.AppendLine($"\t\t\tif(!IsMatch(context))"); - if (psRaw.Length != 0) - builder.AppendLine($"\t\t\t\treturn (false, null);"); - else - builder.AppendLine($"\t\t\t\treturn Task.FromResult<(bool, {entityName}?)>((false, null));"); - builder.AppendLine(); int i = 0; foreach (var p in psRaw) { @@ -90,31 +88,43 @@ internal static GenInstruction[] GenerateEntities( builder.AppendLine($"\t\t\tvar data = new {entityName}({string.Join(", ", prms)});"); if (psRaw.Length != 0) - builder.AppendLine($"\t\t\treturn (true, data);"); + builder.AppendLine($"\t\t\treturn data;"); else - builder.AppendLine($"\t\t\treturn Task.FromResult<(bool, {entityName}?)>((true, data));"); + builder.AppendLine($"\t\t\treturn Task.FromResult(data);"); builder.AppendLine("\t\t}"); builder.AppendLine(); + //-----------------------------Task<(succeed, entity)> TryGetAsync(context) --------------------- + + builder.AppendLine($"\t\tpublic async static Task<(bool, {entityName}?)> TryGetAsync(IConsumerInterceptionContext context)"); + builder.AppendLine("\t\t{"); + builder.AppendLine($"\t\t\tif(!IsMatch(context))"); + builder.AppendLine($"\t\t\t\treturn (false, null);"); + builder.AppendLine(); + + builder.AppendLine($"\t\t\tvar data = await GetAsync(context);"); + builder.AppendLine($"\t\t\treturn (true, data);"); + + builder.AppendLine("\t\t}"); + builder.AppendLine(); + + //-----------------------------Task<(succeed, entity)> IsMatch(announcement) --------------------- + builder.AppendLine($"\t\tpublic static bool IsMatch(Announcement announcement)"); builder.AppendLine("\t\t{"); builder.AppendLine($"\t\t\tMetadata meta = announcement.Metadata;"); builder.AppendLine($"\t\t\treturn meta.Signature == _signature;"); builder.AppendLine("\t\t}"); + //-----------------------------Task GetAsync (bridge, announcement) --------------------- + + builder.Append($"\t\tpublic "); if (psRaw.Length != 0) builder.Append($"async "); - builder.AppendLine($"static Task<(bool, {entityName}?)> TryGetAsync(IConsumerBridge consumerBridge, Announcement announcement)"); + builder.AppendLine($"static Task<{entityName}> GetAsync(IConsumerBridge consumerBridge, Announcement announcement)"); builder.AppendLine("\t\t{"); - builder.AppendLine($"\t\t\tif(!IsMatch(announcement))"); - - if (psRaw.Length != 0) - builder.AppendLine($"\t\t\t\treturn (false, null);"); - else - builder.AppendLine($"\t\t\t\treturn Task.FromResult<(bool, {entityName}?)>((false, null));"); - builder.AppendLine(); i = 0; foreach (var p in psRaw) { @@ -125,12 +135,25 @@ internal static GenInstruction[] GenerateEntities( builder.AppendLine($"\t\t\tvar data = new {entityName}({string.Join(", ", prms)});"); if (psRaw.Length != 0) - builder.AppendLine($"\t\t\treturn (true, data);"); + builder.AppendLine($"\t\t\treturn data;"); else - builder.AppendLine($"\t\t\treturn Task.FromResult<(bool, {entityName}?)>((true, data));"); + builder.AppendLine($"\t\t\treturn Task.FromResult(data);"); builder.AppendLine("\t\t}"); + //-----------------------------Task<(succeed, entity)> TryGetAsync (bridge, announcement) --------------------- + + + builder.AppendLine($"\t\tpublic async static Task<(bool, {entityName}?)> TryGetAsync(IConsumerBridge consumerBridge, Announcement announcement)"); + builder.AppendLine("\t\t{"); + builder.AppendLine($"\t\t\tif(!IsMatch(announcement))"); + + builder.AppendLine($"\t\t\t\treturn (false, null);"); + builder.AppendLine(); + builder.AppendLine($"\t\t\tvar data = await GetAsync(consumerBridge, announcement);"); + builder.AppendLine($"\t\t\treturn (true, data);"); + builder.AppendLine("\t\t}"); + builder.AppendLine("\t}"); builder.AppendLine(); @@ -173,6 +196,8 @@ internal static void GenerateEntitiesExtensions( string deprecateAddition = bundle.Deprecated ? "_Deprecated" : string.Empty; string entityName = $"{bundle:entity}{deprecateAddition}"; + //-----------------------------Task<(succeed, entity)> TryGetENTITYAsync (context) --------------------- + builder.AppendLine($"\t\t/// "); builder.AppendLine($"\t\t/// Try to get entity of event of"); builder.AppendLine($"\t\t/// Operation:{bundle.FullName}"); @@ -182,6 +207,19 @@ internal static void GenerateEntitiesExtensions( builder.AppendLine($"\t\tpublic static Task<(bool, {entityName}?)> TryGet{entityName}Async(this IConsumerInterceptionContext context) => {entityName}.TryGetAsync(context);"); builder.AppendLine(); + //-----------------------------Task GetENTITYAsync (context) --------------------- + + builder.AppendLine($"\t\t/// "); + builder.AppendLine($"\t\t/// Get entity of event of"); + builder.AppendLine($"\t\t/// Operation:{bundle.FullName}"); + builder.AppendLine($"\t\t/// Version:{bundle.Version}"); + builder.AppendLine($"\t\t/// Parameters:{bundle.Parameters}"); + builder.AppendLine($"\t\t/// "); + builder.AppendLine($"\t\tpublic static Task<{entityName}> Get{entityName}Async(this IConsumerInterceptionContext context) => {entityName}.GetAsync(context);"); + builder.AppendLine(); + + //-----------------------------Task<(succeed, entity)> TryGetENTITYAsync (bridge, announcement) --------------------- + builder.AppendLine($"\t\t/// "); builder.AppendLine($"\t\t/// Try to get entity of event of"); builder.AppendLine($"\t\t/// Operation:{bundle.FullName}"); @@ -190,6 +228,18 @@ internal static void GenerateEntitiesExtensions( builder.AppendLine($"\t\t/// "); builder.AppendLine($"\t\tpublic static Task<(bool, {entityName}?)> TryGet{entityName}Async(this IConsumerBridge bridge, Announcement announcement) => {entityName}.TryGetAsync(bridge, announcement);"); + //-----------------------------Task GetENTITYAsync (bridge, announcement) --------------------- + + builder.AppendLine($"\t\t/// "); + builder.AppendLine($"\t\t/// Get entity of event of"); + builder.AppendLine($"\t\t/// Operation:{bundle.FullName}"); + builder.AppendLine($"\t\t/// Version:{bundle.Version}"); + builder.AppendLine($"\t\t/// Parameters:{bundle.Parameters}"); + builder.AppendLine($"\t\t/// "); + builder.AppendLine($"\t\tpublic static Task<{entityName}> Get{entityName}Async(this IConsumerBridge bridge, Announcement announcement) => {entityName}.GetAsync(bridge, announcement);"); + + //-----------------------------Task<(succeed, entity)> IsMatchENTITYAsync (context) --------------------- + builder.AppendLine($"\t\t/// "); builder.AppendLine($"\t\t/// Check if match entity of event of"); builder.AppendLine($"\t\t/// Operation:{bundle.FullName}"); @@ -199,6 +249,8 @@ internal static void GenerateEntitiesExtensions( builder.AppendLine($"\t\tpublic static bool IsMatch{entityName}(this IConsumerInterceptionContext context) => {entityName}.IsMatch(context);"); builder.AppendLine(); + //-----------------------------Task<(succeed, entity)> IsMatchENTITYAsync (bridge, announcement) --------------------- + builder.AppendLine($"\t\t/// "); builder.AppendLine($"\t\t/// Check if match entity of event of"); builder.AppendLine($"\t\t/// Operation:{bundle.FullName}"); @@ -274,6 +326,8 @@ internal static GenInstruction GenerateEntityMapper( var bundles = info.ToBundle(compilation); + //-----------------------------(cast, succeed) TryMapAsync (announcement, consumerPlan)--------------------- + builder.AppendLine("\t\t\t/// "); builder.AppendLine($"\t\t\t/// Try to map announcement"); builder.AppendLine("\t\t\t/// "); @@ -285,6 +339,7 @@ internal static GenInstruction GenerateEntityMapper( else builder.Append($"\t\t\t public async "); + builder.AppendLine($"Task<(TCast? value, bool succeed)> TryMapAsync("); builder.AppendLine($"\t\t\t\t\tAnnouncement announcement, "); builder.AppendLine($"\t\t\t\t\tIConsumerPlan consumerPlan)"); diff --git a/src-gen/EventSourcing.Backbone.SrcGen/Generators/GeneratorIncrementalBase.cs b/src-gen/EventSourcing.Backbone.SrcGen/Generators/GeneratorIncrementalBase.cs index 80ec78cf..ba1cbc74 100644 --- a/src-gen/EventSourcing.Backbone.SrcGen/Generators/GeneratorIncrementalBase.cs +++ b/src-gen/EventSourcing.Backbone.SrcGen/Generators/GeneratorIncrementalBase.cs @@ -1,8 +1,6 @@ using System.Collections.Immutable; using System.Text; - -using EventSourcing.Backbone.SrcGen.Generators.Entities; - +using EventSourcing.Backbone.SrcGen.Entities; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src-gen/EventSourcing.Backbone.SrcGen/Helper.cs b/src-gen/EventSourcing.Backbone.SrcGen/Helper.cs index 10dcc947..cb3935c1 100644 --- a/src-gen/EventSourcing.Backbone.SrcGen/Helper.cs +++ b/src-gen/EventSourcing.Backbone.SrcGen/Helper.cs @@ -1,19 +1,22 @@ using System.Text; using System.Xml.Linq; - +using Microsoft.CodeAnalysis.CSharp.Symbols; using EventSourcing.Backbone.SrcGen.Entities; -using EventSourcing.Backbone.SrcGen.Generators.EntitiesAndHelpers; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; +using System.Text.RegularExpressions; +using System.Runtime.ConstrainedExecution; namespace EventSourcing.Backbone; internal static class Helper { + private static readonly Regex NON_WORD = new Regex(@"\W"); + private static readonly Predicate DEFAULT_VERSION_PREDICATE = a => { @@ -25,8 +28,8 @@ internal static class Helper a => { var name = a.AttributeClass!.Name; - return name.EndsWith("EventSourceDeprecateVersionAttribute") || - name.EndsWith("EventSourceDeprecateVersion"); + return name.EndsWith("EventSourceDeprecateAttribute") || + name.EndsWith("EventSourceDeprecate"); }; #region Convert @@ -439,10 +442,43 @@ public static string GetParamsSignature(this ISymbol? method) { if (method is not IMethodSymbol mtdSymbol) return string.Empty; - var result = mtdSymbol.Parameters.Select(p => p.Type.Name); - if (result == null) + + var query = mtdSymbol.Parameters.Select(p => + { + string res = p.Type.ToDisplayParts() + .Aggregate(string.Empty, Aggregate); + string Aggregate(string acc, SymbolDisplayPart part) + { + if (part.Kind == SymbolDisplayPartKind.Punctuation) + { + string item = part.ToString(); + return item switch + { + "." => string.Empty, + "[" => $"{acc}_array", + _ => acc + }; + } + string separation = string.Empty; + if (acc.Length != 0 && acc[acc.Length - 1] != '_') + separation = "_"; + + var tmp = part.Symbol switch + { + IArrayTypeSymbol ats => $"{acc}{separation}{ats.ElementType}_Array", + ITypeSymbol ts => $"{acc}{separation}{ts.Name}", + _ => $"{acc}{separation}{part}", + }; + return tmp.Trim(); + } + res = NON_WORD.Replace(res, "_"); + return res; + }); + if (query == null) return string.Empty; - return string.Join(",", result); + string result = string.Join(",", query); + return result; + } #endregion // GetParamsSignature