From 0fcfc06f6e52a7e0ff9a8d44531feb9e7faad8e6 Mon Sep 17 00:00:00 2001 From: Patrick Gallik Date: Tue, 16 Jan 2024 16:01:40 +0100 Subject: [PATCH] feat: add integration projections GAWR-4534 --- StreetNameRegistry.sln | 7 + paket.dependencies | 26 +- paket.lock | 106 +- .../EF.MigrationsHelper.csproj | 1 + src/EF.MigrationsHelper/appsettings.json | 3 +- src/EF.MigrationsHelper/paket.references | 3 + .../ConsumerPostalContext.cs | 1 + .../paket.references | 2 +- .../ConsumerContext.cs | 3 +- .../IdempotentConsumerContext.cs | 1 + .../paket.references | 2 +- .../Schema.cs | 2 + .../ProducerContextMigrationFactory.cs | 3 +- .../ProducerModule.cs | 1 + .../paket.references | 1 + .../ProducerContextMigrationFactory.cs | 3 +- .../ProducerModule.cs | 1 + .../paket.references | 1 + .../BackOfficeProjectionsContext.cs | 3 +- .../ServiceCollectionExtensions.cs | 1 + .../paket.references | 2 +- .../ExtractContextMigrationFactory.cs | 3 +- .../ExtractModule.cs | 6 +- .../paket.references | 2 +- .../Converters/StreetNameMapper.cs | 107 ++ .../EventsRepository.cs | 29 + .../IEventsRepository.cs | 10 + .../Infrastructure/IntegrationModule.cs | 62 + .../Infrastructure/IntegrationOptions.cs | 8 + .../IntegrationContext.cs | 21 + .../IntegrationContextMigrationFactory.cs | 23 + .../20240116145354_Initial.Designer.cs | 272 +++ .../Migrations/20240116145354_Initial.cs | 219 +++ .../IntegrationContextModelSnapshot.cs | 270 +++ .../StreetNameLatestItem.cs | 101 + .../StreetNameLatestItemExtensions.cs | 87 + .../StreetNameLatestItemProjections.cs | 217 +++ ...ameRegistry.Projections.Integration.csproj | 14 + .../StreetNameVersion.cs | 158 ++ .../StreetNameVersionExtensions.cs | 98 + .../StreetNameVersionProjections.cs | 478 +++++ .../paket.references | 13 + .../DataMigrationsContext.cs | 3 +- .../StreetNameLastChangedListModule.cs | 1 + .../paket.references | 1 + .../LegacyExtractContextMigrationFactory.cs | 3 +- .../LegacyModule.cs | 1 + .../StreetNameSyndication.cs | 2 +- .../paket.references | 2 +- .../MigrationsHelper.cs | 1 + .../SyndicationContext.cs | 1 + .../SyndicationModule.cs | 1 + .../paket.references | 2 +- .../WfsContextMigrationFactory.cs | 3 +- .../WfsModule.cs | 1 + .../paket.references | 2 +- .../WmsContextMigrationFactory.cs | 3 +- .../WmsModule.cs | 1 + .../paket.references | 2 +- .../Infrastructure/Modules/ApiModule.cs | 40 +- .../Infrastructure/Startup.cs | 17 +- .../Projections/ProjectionsController.cs | 1 + .../StreetNameRegistry.Projector.csproj | 1 + .../appsettings.json | 9 +- .../paket.references | 8 + .../StreetNameNamesWereChangedBuilder.cs | 51 + .../StreetNameNamesWereCorrectedBuilder.cs | 51 + .../Generate/Generate.cs | 65 +- .../Integration/IntegrationTests.cs | 30 + .../StreetNameLatestItemProjectionTests.cs | 642 +++++++ .../StreetNameVersionProjectionTests.cs | 1709 +++++++++++++++++ .../StreetNameLatestItemProjectionsV2Tests.cs | 1 - .../StreetNameRegistry.Tests.csproj | 1 + 73 files changed, 4954 insertions(+), 73 deletions(-) create mode 100644 src/StreetNameRegistry.Projections.Integration/Converters/StreetNameMapper.cs create mode 100644 src/StreetNameRegistry.Projections.Integration/EventsRepository.cs create mode 100644 src/StreetNameRegistry.Projections.Integration/IEventsRepository.cs create mode 100644 src/StreetNameRegistry.Projections.Integration/Infrastructure/IntegrationModule.cs create mode 100644 src/StreetNameRegistry.Projections.Integration/Infrastructure/IntegrationOptions.cs create mode 100644 src/StreetNameRegistry.Projections.Integration/IntegrationContext.cs create mode 100644 src/StreetNameRegistry.Projections.Integration/IntegrationContextMigrationFactory.cs create mode 100644 src/StreetNameRegistry.Projections.Integration/Migrations/20240116145354_Initial.Designer.cs create mode 100644 src/StreetNameRegistry.Projections.Integration/Migrations/20240116145354_Initial.cs create mode 100644 src/StreetNameRegistry.Projections.Integration/Migrations/IntegrationContextModelSnapshot.cs create mode 100644 src/StreetNameRegistry.Projections.Integration/StreetNameLatestItem.cs create mode 100644 src/StreetNameRegistry.Projections.Integration/StreetNameLatestItemExtensions.cs create mode 100644 src/StreetNameRegistry.Projections.Integration/StreetNameLatestItemProjections.cs create mode 100644 src/StreetNameRegistry.Projections.Integration/StreetNameRegistry.Projections.Integration.csproj create mode 100644 src/StreetNameRegistry.Projections.Integration/StreetNameVersion.cs create mode 100644 src/StreetNameRegistry.Projections.Integration/StreetNameVersionExtensions.cs create mode 100644 src/StreetNameRegistry.Projections.Integration/StreetNameVersionProjections.cs create mode 100644 src/StreetNameRegistry.Projections.Integration/paket.references create mode 100644 test/StreetNameRegistry.Tests/Builders/StreetNameNamesWereChangedBuilder.cs create mode 100644 test/StreetNameRegistry.Tests/Builders/StreetNameNamesWereCorrectedBuilder.cs create mode 100644 test/StreetNameRegistry.Tests/Integration/IntegrationTests.cs create mode 100644 test/StreetNameRegistry.Tests/Integration/StreetNameLatestItemProjectionTests.cs create mode 100644 test/StreetNameRegistry.Tests/Integration/StreetNameVersionProjectionTests.cs diff --git a/StreetNameRegistry.sln b/StreetNameRegistry.sln index 27a8ba647..b6245a244 100755 --- a/StreetNameRegistry.sln +++ b/StreetNameRegistry.sln @@ -79,6 +79,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StreetNameRegistry.Snapshot EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StreetNameRegistry.Consumer.Read.Postal", "src\StreetNameRegistry.Consumer.Read.Postal\StreetNameRegistry.Consumer.Read.Postal.csproj", "{83C7D129-ACEA-4FC6-A55C-748D8D31135A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StreetNameRegistry.Projections.Integration", "src\StreetNameRegistry.Projections.Integration\StreetNameRegistry.Projections.Integration.csproj", "{E69043F1-E6C9-484C-A961-C28C33013C91}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -185,6 +187,10 @@ Global {83C7D129-ACEA-4FC6-A55C-748D8D31135A}.Debug|Any CPU.Build.0 = Debug|Any CPU {83C7D129-ACEA-4FC6-A55C-748D8D31135A}.Release|Any CPU.ActiveCfg = Release|Any CPU {83C7D129-ACEA-4FC6-A55C-748D8D31135A}.Release|Any CPU.Build.0 = Release|Any CPU + {E69043F1-E6C9-484C-A961-C28C33013C91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E69043F1-E6C9-484C-A961-C28C33013C91}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E69043F1-E6C9-484C-A961-C28C33013C91}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E69043F1-E6C9-484C-A961-C28C33013C91}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -215,6 +221,7 @@ Global {EFDF165C-DCFE-4577-A00F-04691197FB1B} = {81641B0B-BEFB-476D-8519-3774313E944B} {06F8F677-2696-4996-B4AE-B8E3B747A696} = {65EA04DE-5928-430F-92CA-24C11B6E5A00} {83C7D129-ACEA-4FC6-A55C-748D8D31135A} = {65EA04DE-5928-430F-92CA-24C11B6E5A00} + {E69043F1-E6C9-484C-A961-C28C33013C91} = {65EA04DE-5928-430F-92CA-24C11B6E5A00} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3B44FE80-30FE-47B7-A0DE-8610218FFF63} diff --git a/paket.dependencies b/paket.dependencies index fea277b20..bbc2e8230 100644 --- a/paket.dependencies +++ b/paket.dependencies @@ -17,6 +17,7 @@ nuget Microsoft.Extensions.Http.Polly 6.0.3 // For more healtchecks, look at https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks nuget AspNetCore.HealthChecks.SqlServer 6.0.2 +nuget AspNetCore.HealthChecks.NpgSql 6.0.2 nuget MediatR 12.0.1 nuget MediatR.Contracts 2.0.1 @@ -31,6 +32,10 @@ nuget Destructurama.JsonNet 2.0.0 nuget Microsoft.EntityFrameworkCore.Design 6.0.3 +nuget Npgsql 6.0.3 +nuget Npgsql.EntityFrameworkCore.PostgreSQL 6.0.3 +nuget Npgsql.EntityFrameworkCore.PostgreSQL.Design 2.0.0-preview1 + // VBR STUFF nuget Be.Vlaanderen.Basisregisters.Build.Pipeline 6.0.5 nuget Be.Vlaanderen.Basisregisters.Testing.Infrastructure.Events 3.0.0 content: true, copy_content_to_output_dir: always, copy_local: true @@ -59,16 +64,19 @@ nuget Be.Vlaanderen.Basisregisters.SnapshotVerifier 8.2.0 nuget Be.Vlaanderen.Basisregisters.EventHandling 4.2.3 nuget Be.Vlaanderen.Basisregisters.EventHandling.Autofac 4.2.3 -nuget Be.Vlaanderen.Basisregisters.ProjectionHandling.LastChangedList 11.0.7 -nuget Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore 11.0.7 -nuget Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore.Autofac 11.0.7 -nuget Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner 11.0.7 -nuget Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.Microsoft 11.0.7 -nuget Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector.Testing 11.0.7 -nuget Be.Vlaanderen.Basisregisters.ProjectionHandling.Testing.Xunit 11.0.7 -nuget Be.Vlaanderen.Basisregisters.ProjectionHandling.Syndication 11.0.7 +nuget Be.Vlaanderen.Basisregisters.ProjectionHandling.LastChangedList 12.0.1 +nuget Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore 12.0.1 +nuget Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore.Autofac 12.0.1 +nuget Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner 12.0.1 +nuget Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer 12.0.1 +nuget Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.Npgsql 12.0.1 +nuget Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector 12.0.1 +nuget Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector.Testing 12.0.1 +nuget Be.Vlaanderen.Basisregisters.ProjectionHandling.Testing.Xunit 12.0.1 +nuget Be.Vlaanderen.Basisregisters.ProjectionHandling.Syndication 12.0.1 + +nuget Be.Vlaanderen.Basisregisters.Projector 13.1.0 -nuget Be.Vlaanderen.Basisregisters.Projector 13.0.10 nuget Be.Vlaanderen.Basisregisters.DataDog.Tracing.Autofac 5.0.3 nuget Be.Vlaanderen.Basisregisters.DataDog.Tracing.AspNetCore 5.0.3 diff --git a/paket.lock b/paket.lock index 6e000ace4..37cd4d071 100644 --- a/paket.lock +++ b/paket.lock @@ -6,6 +6,9 @@ NUGET Amazon.Lambda.Core (>= 2.1) Newtonsoft.Json (>= 13.0.1) Amazon.Lambda.SQSEvents (2.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + AspNetCore.HealthChecks.NpgSql (6.0.2) + Microsoft.Extensions.Diagnostics.HealthChecks (>= 6.0.2) + Npgsql (>= 6.0) AspNetCore.HealthChecks.SqlServer (6.0.2) Microsoft.Data.SqlClient (>= 3.0.1) Microsoft.Extensions.Diagnostics.HealthChecks (>= 6.0) @@ -358,38 +361,38 @@ NUGET Microsoft.Extensions.Logging.Abstractions (>= 6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Be.Vlaanderen.Basisregisters.ProblemDetails (8.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) System.Reflection.Metadata (>= 6.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) - Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector (11.0.7) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector (12.0.1) Microsoft.EntityFrameworkCore (>= 6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) - Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector.Testing (11.0.7) - Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector (11.0.7) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) - Be.Vlaanderen.Basisregisters.ProjectionHandling.LastChangedList (11.0.7) + Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector.Testing (12.0.1) + Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector (12.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Be.Vlaanderen.Basisregisters.ProjectionHandling.LastChangedList (12.0.1) Autofac.Extensions.DependencyInjection (>= 7.2) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) - Be.Vlaanderen.Basisregisters.AggregateSource.SqlStreamStore.Autofac (>= 7.1.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Be.Vlaanderen.Basisregisters.AggregateSource.SqlStreamStore (>= 7.1.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql (>= 5.0) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) - Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner (11.0.7) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) - Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore.Autofac (11.0.7) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer (12.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore (12.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.EntityFrameworkCore.SqlServer (>= 6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.Extensions.DependencyInjection (>= 6.0) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Polly (>= 7.2.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) SqlStreamStore.MsSql (>= 1.2) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) - Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner (11.0.7) + Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner (12.0.1) Autofac.Extensions.DependencyInjection (>= 7.2) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Be.Vlaanderen.Basisregisters.EntityFrameworkCore.EntityTypeConfiguration (>= 3.0) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) - Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector (11.0.7) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) - Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore (11.0.7) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector (12.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore (12.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.EntityFrameworkCore.InMemory (>= 6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) - Microsoft.EntityFrameworkCore.SqlServer (>= 6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Microsoft.EntityFrameworkCore.Relational (>= 6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.Extensions.Configuration (>= 6.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.Extensions.Configuration.CommandLine (>= 6.0) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.Extensions.Configuration.EnvironmentVariables (>= 6.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.Extensions.Configuration.FileExtensions (>= 6.0) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.Extensions.Configuration.Json (>= 6.0) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) SqlStreamStore (>= 1.2) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) - Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.Microsoft (11.0.7) + Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.Microsoft (12.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Be.Vlaanderen.Basisregisters.DependencyInjection (>= 1.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Be.Vlaanderen.Basisregisters.EntityFrameworkCore.EntityTypeConfiguration (>= 3.0) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) - Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector (11.0.7) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) - Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore (11.0.7) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector (12.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore (12.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.EntityFrameworkCore.InMemory (>= 6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.EntityFrameworkCore.SqlServer (>= 6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.Extensions.Configuration (>= 6.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) @@ -398,28 +401,40 @@ NUGET Microsoft.Extensions.Configuration.FileExtensions (>= 6.0) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.Extensions.Configuration.Json (>= 6.0) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) SqlStreamStore (>= 1.2) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) - Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore (11.0.7) + Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.Npgsql (12.0.1) + Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector (12.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner (12.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore (12.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Npgsql.EntityFrameworkCore.PostgreSQL (>= 6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Polly (>= 7.2.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer (12.0.1) + Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector (12.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner (12.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore (12.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Microsoft.EntityFrameworkCore.SqlServer (>= 6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Polly (>= 7.2.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore (12.0.1) Be.Vlaanderen.Basisregisters.EventHandling (>= 4.2.2) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) SqlStreamStore (>= 1.2) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) - Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore.Autofac (11.0.7) + Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore.Autofac (12.0.1) Autofac.Extensions.DependencyInjection (>= 7.2) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) - Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore (11.0.7) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) - Be.Vlaanderen.Basisregisters.ProjectionHandling.Syndication (11.0.7) + Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore (12.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Be.Vlaanderen.Basisregisters.ProjectionHandling.Syndication (12.0.1) Microsoft.Extensions.Http (>= 6.0) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.Extensions.Logging (>= 6.0) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.SyndicationFeed.ReaderWriter (>= 1.0.2) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) - Be.Vlaanderen.Basisregisters.ProjectionHandling.Testing.Xunit (11.0.7) - Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector.Testing (11.0.7) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) - Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore (11.0.7) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Be.Vlaanderen.Basisregisters.ProjectionHandling.Testing.Xunit (12.0.1) + Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector.Testing (12.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore (12.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.EntityFrameworkCore (>= 6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.Extensions.Logging (>= 6.0) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) xunit (>= 2.4.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) - Be.Vlaanderen.Basisregisters.Projector (13.0.10) + Be.Vlaanderen.Basisregisters.Projector (13.1) Autofac (>= 6.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Autofac.Extensions.DependencyInjection (>= 7.2) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) - Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector (>= 11.0.7) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) - Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner (>= 11.0.7) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) - Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.Microsoft (>= 11.0.7) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector (>= 12.0) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner (>= 12.0) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.Microsoft (>= 12.0) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Dapper (>= 2.0.123) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.Data.SqlClient (>= 4.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Polly (>= 7.2.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) @@ -665,6 +680,7 @@ NUGET System.IO.Pipelines (>= 6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.Bcl.AsyncInterfaces (7.0) System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (== net472) (&& (== net6.0) (>= net462)) (&& (== net6.0) (< netstandard2.1)) + Microsoft.Bcl.HashCode (1.1.1) - restriction: || (== net472) (&& (== net6.0) (< netstandard2.1)) Microsoft.Build (17.1) Microsoft.Build.Framework (>= 17.1) Microsoft.IO.Redist (>= 6.0) - restriction: || (== net472) (&& (== net6.0) (>= net472)) @@ -736,7 +752,7 @@ NUGET System.Text.Encodings.Web (>= 4.7.2) Microsoft.Data.SqlClient.SNI (5.1) - restriction: || (== net472) (&& (== net6.0) (>= net462)) Microsoft.Data.SqlClient.SNI.runtime (5.1) - restriction: || (&& (== net472) (< net462)) (&& (== net472) (>= netstandard2.1)) (== net6.0) - Microsoft.EntityFrameworkCore (6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Microsoft.EntityFrameworkCore (6.0.3) Microsoft.EntityFrameworkCore.Abstractions (>= 6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.EntityFrameworkCore.Analyzers (>= 6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.Extensions.Caching.Memory (>= 6.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) @@ -751,9 +767,12 @@ NUGET Microsoft.EntityFrameworkCore.Relational (>= 6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.EntityFrameworkCore.InMemory (6.0.3) Microsoft.EntityFrameworkCore (>= 6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) - Microsoft.EntityFrameworkCore.Relational (6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Microsoft.EntityFrameworkCore.Relational (6.0.3) Microsoft.EntityFrameworkCore (>= 6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.Extensions.Configuration.Abstractions (>= 6.0) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Microsoft.EntityFrameworkCore.Relational.Design (2.0.0-preview1-final) + Microsoft.EntityFrameworkCore.Relational (>= 2.0.0-preview1-final) + NETStandard.Library (>= 2.0.0-preview1-25301-01) Microsoft.EntityFrameworkCore.SqlServer (6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.Data.SqlClient (>= 2.1.4) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.EntityFrameworkCore.Relational (>= 6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) @@ -1012,7 +1031,7 @@ NUGET Microsoft.Build.Utilities.Core (>= 16.10) Namotion.Reflection (2.0.10) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.CSharp (>= 4.3) - restriction: || (&& (== net472) (< net40)) (== net6.0) - NETStandard.Library (2.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + NETStandard.Library (2.0.3) Microsoft.NETCore.Platforms (>= 1.1) NetTopologySuite (2.4) System.Memory (>= 4.5.3) @@ -1042,6 +1061,31 @@ NUGET NodaTime.Serialization.JsonNet (3.0) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Newtonsoft.Json (>= 12.0.1) NodaTime (>= 3.0 < 4.0) + Npgsql (6.0.3) + Microsoft.Bcl.AsyncInterfaces (>= 6.0) - restriction: || (== net472) (&& (== net6.0) (< netstandard2.1)) + Microsoft.Bcl.HashCode (>= 1.1.1) - restriction: || (== net472) (&& (== net6.0) (< netstandard2.1)) + System.Collections.Immutable (>= 6.0) - restriction: || (== net472) (&& (== net6.0) (< netcoreapp3.1)) (&& (== net6.0) (< netstandard2.1)) + System.Diagnostics.DiagnosticSource (>= 6.0) - restriction: || (== net472) (&& (== net6.0) (< net5.0)) (&& (== net6.0) (< netcoreapp3.1)) (&& (== net6.0) (< netstandard2.1)) + System.Memory (>= 4.5.4) - restriction: || (== net472) (&& (== net6.0) (< netstandard2.1)) + System.Runtime.CompilerServices.Unsafe (>= 6.0) + System.Text.Json (>= 6.0) - restriction: || (== net472) (&& (== net6.0) (< netcoreapp3.1)) (&& (== net6.0) (< netstandard2.1)) + System.Threading.Channels (>= 6.0) - restriction: || (== net472) (&& (== net6.0) (< netcoreapp3.1)) (&& (== net6.0) (< netstandard2.1)) + System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (== net472) (&& (== net6.0) (< netstandard2.1)) + System.ValueTuple (>= 4.5) - restriction: || (== net472) (&& (== net6.0) (< netstandard2.1)) + Npgsql.EntityFrameworkCore.PostgreSQL (6.0.3) + Microsoft.EntityFrameworkCore (>= 6.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Microsoft.EntityFrameworkCore.Abstractions (>= 6.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Microsoft.EntityFrameworkCore.Relational (>= 6.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Npgsql (>= 6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Npgsql.EntityFrameworkCore.PostgreSQL.Design (2.0.0-preview1) + Microsoft.EntityFrameworkCore (>= 2.0.0-preview1-final) + Microsoft.EntityFrameworkCore.Relational (>= 2.0.0-preview1-final) + Microsoft.EntityFrameworkCore.Relational.Design (>= 2.0.0-preview1-final) + Microsoft.Extensions.DependencyInjection (>= 2.0.0-preview1-final) + Microsoft.Extensions.DependencyInjection.Abstractions (>= 2.0.0-preview1-final) + NETStandard.Library (>= 1.6.1) - restriction: || (&& (== net472) (< net46)) (== net6.0) + Npgsql (>= 3.2.2) + Npgsql.EntityFrameworkCore.PostgreSQL (>= 2.0.0-preview1) NSwag.CodeGeneration (13.15.10) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Newtonsoft.Json (>= 9.0.1) NJsonSchema (>= 10.6.10) @@ -1165,6 +1209,7 @@ NUGET Microsoft.NETCore.Targets (>= 1.1) - restriction: || (&& (== net472) (< net45)) (== net6.0) System.Runtime (>= 4.3) - restriction: || (&& (== net472) (< net45)) (== net6.0) System.Collections.Immutable (6.0) + System.Memory (>= 4.5.4) - restriction: || (== net472) (&& (== net6.0) (>= net461)) System.Runtime.CompilerServices.Unsafe (>= 6.0) System.Collections.NonGeneric (4.3) - restriction: || (&& (== net472) (< net35)) (== net6.0) System.Diagnostics.Debug (>= 4.3) - restriction: || (&& (== net472) (< net46)) (== net6.0) @@ -1225,6 +1270,7 @@ NUGET Microsoft.NETCore.Targets (>= 1.1) - restriction: || (&& (== net472) (< net45)) (== net6.0) System.Runtime (>= 4.3) - restriction: || (&& (== net472) (< net45)) (== net6.0) System.Diagnostics.DiagnosticSource (6.0) + System.Memory (>= 4.5.4) - restriction: || (== net472) (&& (== net6.0) (>= net461)) (&& (== net6.0) (< net5.0)) System.Runtime.CompilerServices.Unsafe (>= 6.0) System.Diagnostics.EventLog (7.0) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) System.Diagnostics.TraceSource (4.3) - restriction: || (&& (== net472) (< net35)) (== net6.0) @@ -1431,6 +1477,8 @@ NUGET System.Threading (4.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) System.Runtime (>= 4.3) - restriction: || (&& (== net472) (< net45)) (== net6.0) System.Threading.Tasks (>= 4.3) - restriction: || (&& (== net472) (< net45)) (== net6.0) + System.Threading.Channels (8.0) - restriction: || (== net472) (&& (== net6.0) (< netcoreapp3.1)) (&& (== net6.0) (< netstandard2.1)) + System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (== net472) (&& (== net6.0) (>= net462)) (&& (== net6.0) (< netstandard2.1)) System.Threading.Tasks (4.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.NETCore.Platforms (>= 1.1) - restriction: || (&& (== net472) (< net45)) (== net6.0) Microsoft.NETCore.Targets (>= 1.1) - restriction: || (&& (== net472) (< net45)) (== net6.0) @@ -1438,7 +1486,7 @@ NUGET System.Threading.Tasks.Dataflow (6.0) System.Threading.Tasks.Extensions (4.5.4) System.Runtime.CompilerServices.Unsafe (>= 4.5.3) - restriction: || (== net472) (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp2.1)) (&& (== net6.0) (< netstandard1.0)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (>= wp8)) - System.ValueTuple (4.5) - restriction: || (== net472) (&& (== net6.0) (>= net461)) + System.ValueTuple (4.5) - restriction: || (== net472) (&& (== net6.0) (< netstandard2.1)) System.Windows.Extensions (7.0) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) System.Drawing.Common (>= 7.0) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) System.Xml.ReaderWriter (4.3.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) diff --git a/src/EF.MigrationsHelper/EF.MigrationsHelper.csproj b/src/EF.MigrationsHelper/EF.MigrationsHelper.csproj index dd39c1b8a..512735149 100644 --- a/src/EF.MigrationsHelper/EF.MigrationsHelper.csproj +++ b/src/EF.MigrationsHelper/EF.MigrationsHelper.csproj @@ -37,6 +37,7 @@ + diff --git a/src/EF.MigrationsHelper/appsettings.json b/src/EF.MigrationsHelper/appsettings.json index 9d4500e31..975b3a57c 100644 --- a/src/EF.MigrationsHelper/appsettings.json +++ b/src/EF.MigrationsHelper/appsettings.json @@ -14,7 +14,8 @@ "LastChangedListAdmin": "x", "BackOffice": "x", "ProducerProjectionsAdmin": "x", - "ConsumerPostalAdmin": "x" + "ConsumerPostalAdmin": "x", + "IntegrationProjectionsAdmin": "x" }, "Serilog": { diff --git a/src/EF.MigrationsHelper/paket.references b/src/EF.MigrationsHelper/paket.references index 5c40e19ca..4b1d50b35 100644 --- a/src/EF.MigrationsHelper/paket.references +++ b/src/EF.MigrationsHelper/paket.references @@ -1 +1,4 @@ Microsoft.EntityFrameworkCore.Design + +Npgsql.EntityFrameworkCore.PostgreSQL +Npgsql.EntityFrameworkCore.PostgreSQL.Design \ No newline at end of file diff --git a/src/StreetNameRegistry.Consumer.Read.Postal/ConsumerPostalContext.cs b/src/StreetNameRegistry.Consumer.Read.Postal/ConsumerPostalContext.cs index b3e69c03c..3729c48c6 100644 --- a/src/StreetNameRegistry.Consumer.Read.Postal/ConsumerPostalContext.cs +++ b/src/StreetNameRegistry.Consumer.Read.Postal/ConsumerPostalContext.cs @@ -6,6 +6,7 @@ namespace StreetNameRegistry.Consumer.Read.Postal using System.Threading.Tasks; using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using StreetNameRegistry.Infrastructure; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; diff --git a/src/StreetNameRegistry.Consumer.Read.Postal/paket.references b/src/StreetNameRegistry.Consumer.Read.Postal/paket.references index 99790f33d..1a22f5f07 100644 --- a/src/StreetNameRegistry.Consumer.Read.Postal/paket.references +++ b/src/StreetNameRegistry.Consumer.Read.Postal/paket.references @@ -9,7 +9,7 @@ Be.Vlaanderen.Basisregisters.GrAr.Contracts Be.Vlaanderen.Basisregisters.MessageHandling.Kafka.Consumer Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector -Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner +Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer Destructurama.JsonNet diff --git a/src/StreetNameRegistry.Consumer/ConsumerContext.cs b/src/StreetNameRegistry.Consumer/ConsumerContext.cs index b9e7242d1..6a1e54cf6 100644 --- a/src/StreetNameRegistry.Consumer/ConsumerContext.cs +++ b/src/StreetNameRegistry.Consumer/ConsumerContext.cs @@ -1,6 +1,7 @@ namespace StreetNameRegistry.Consumer { using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer; using Microsoft.EntityFrameworkCore; using Municipality; using StreetNameRegistry.Infrastructure; @@ -21,7 +22,7 @@ public ConsumerContext(DbContextOptions options) public override string ProjectionStateSchema => Schema.ConsumerProjections; } - public class ConsumerContextFactory : RunnerDbContextMigrationFactory + public class ConsumerContextFactory : SqlServerRunnerDbContextMigrationFactory { public ConsumerContextFactory() : this("ConsumerAdmin") diff --git a/src/StreetNameRegistry.Consumer/IdempotentConsumerContext.cs b/src/StreetNameRegistry.Consumer/IdempotentConsumerContext.cs index 15192af11..602587790 100644 --- a/src/StreetNameRegistry.Consumer/IdempotentConsumerContext.cs +++ b/src/StreetNameRegistry.Consumer/IdempotentConsumerContext.cs @@ -4,6 +4,7 @@ using System.IO; using Be.Vlaanderen.Basisregisters.MessageHandling.Kafka.Consumer.SqlServer; using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; using Microsoft.Extensions.Configuration; diff --git a/src/StreetNameRegistry.Consumer/paket.references b/src/StreetNameRegistry.Consumer/paket.references index ab691cc01..0baa43e4c 100644 --- a/src/StreetNameRegistry.Consumer/paket.references +++ b/src/StreetNameRegistry.Consumer/paket.references @@ -8,7 +8,7 @@ Be.Vlaanderen.Basisregisters.EventHandling.Autofac Be.Vlaanderen.Basisregisters.GrAr.Contracts Be.Vlaanderen.Basisregisters.MessageHandling.Kafka.Simple Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector -Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.Microsoft +Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore.Autofac Be.Vlaanderen.Basisregisters.Projector diff --git a/src/StreetNameRegistry.Infrastructure/Schema.cs b/src/StreetNameRegistry.Infrastructure/Schema.cs index d1a75ca3e..d7bf86a41 100644 --- a/src/StreetNameRegistry.Infrastructure/Schema.cs +++ b/src/StreetNameRegistry.Infrastructure/Schema.cs @@ -18,6 +18,7 @@ public static class Schema public const string BackOfficeProjections = "StreetNameRegistryBackOfficeProjections"; public const string Producer = "StreetNameRegistryProducer"; public const string ProducerSnapshotOslo = "StreetNameRegistryProducerSnapshotOslo"; + public const string Integration = "integration_streetname"; } public static class MigrationTables @@ -36,5 +37,6 @@ public static class MigrationTables public const string BackOfficeProjections = "__EFMigrationsHistoryBackOfficeProjections"; public const string Producer = "__EFMigrationsHistoryProducer"; public const string ProducerSnapshotOslo = "__EFMigrationsHistoryProducerSnapshotOslo"; + public const string Integration = "__EFMigrationsHistory"; } } diff --git a/src/StreetNameRegistry.Producer.Snapshot.Oslo/ProducerContextMigrationFactory.cs b/src/StreetNameRegistry.Producer.Snapshot.Oslo/ProducerContextMigrationFactory.cs index 3a2d64aa8..381b65eed 100644 --- a/src/StreetNameRegistry.Producer.Snapshot.Oslo/ProducerContextMigrationFactory.cs +++ b/src/StreetNameRegistry.Producer.Snapshot.Oslo/ProducerContextMigrationFactory.cs @@ -1,10 +1,11 @@ namespace StreetNameRegistry.Producer.Snapshot.Oslo { using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer; using Microsoft.EntityFrameworkCore; using StreetNameRegistry.Infrastructure; - public class ProducerContextMigrationFactory : RunnerDbContextMigrationFactory + public class ProducerContextMigrationFactory : SqlServerRunnerDbContextMigrationFactory { public ProducerContextMigrationFactory() : base("ProducerProjectionsAdmin", HistoryConfiguration) { } diff --git a/src/StreetNameRegistry.Producer.Snapshot.Oslo/ProducerModule.cs b/src/StreetNameRegistry.Producer.Snapshot.Oslo/ProducerModule.cs index 99d32b9da..7d8e0fb14 100644 --- a/src/StreetNameRegistry.Producer.Snapshot.Oslo/ProducerModule.cs +++ b/src/StreetNameRegistry.Producer.Snapshot.Oslo/ProducerModule.cs @@ -4,6 +4,7 @@ namespace StreetNameRegistry.Producer.Snapshot.Oslo using Autofac; using Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql.EntityFrameworkCore; using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; diff --git a/src/StreetNameRegistry.Producer.Snapshot.Oslo/paket.references b/src/StreetNameRegistry.Producer.Snapshot.Oslo/paket.references index c33433df4..7efba64d4 100644 --- a/src/StreetNameRegistry.Producer.Snapshot.Oslo/paket.references +++ b/src/StreetNameRegistry.Producer.Snapshot.Oslo/paket.references @@ -4,6 +4,7 @@ Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql Be.Vlaanderen.Basisregisters.GrAr.Legacy Be.Vlaanderen.Basisregisters.GrAr.Oslo Be.Vlaanderen.BasisRegisters.MessageHandling.Kafka.Producer +Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore.Autofac Be.Vlaanderen.Basisregisters.Projector diff --git a/src/StreetNameRegistry.Producer/ProducerContextMigrationFactory.cs b/src/StreetNameRegistry.Producer/ProducerContextMigrationFactory.cs index 63a75b3af..68e6f7fce 100644 --- a/src/StreetNameRegistry.Producer/ProducerContextMigrationFactory.cs +++ b/src/StreetNameRegistry.Producer/ProducerContextMigrationFactory.cs @@ -1,10 +1,11 @@ namespace StreetNameRegistry.Producer { using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer; using Microsoft.EntityFrameworkCore; using StreetNameRegistry.Infrastructure; - public class ProducerContextMigrationFactory : RunnerDbContextMigrationFactory + public class ProducerContextMigrationFactory : SqlServerRunnerDbContextMigrationFactory { public ProducerContextMigrationFactory() : base("ProducerProjectionsAdmin", HistoryConfiguration) { } diff --git a/src/StreetNameRegistry.Producer/ProducerModule.cs b/src/StreetNameRegistry.Producer/ProducerModule.cs index 7044f9d78..c9dcf29ff 100644 --- a/src/StreetNameRegistry.Producer/ProducerModule.cs +++ b/src/StreetNameRegistry.Producer/ProducerModule.cs @@ -4,6 +4,7 @@ namespace StreetNameRegistry.Producer using Autofac; using Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql.EntityFrameworkCore; using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; diff --git a/src/StreetNameRegistry.Producer/paket.references b/src/StreetNameRegistry.Producer/paket.references index 99a96432d..89a611453 100644 --- a/src/StreetNameRegistry.Producer/paket.references +++ b/src/StreetNameRegistry.Producer/paket.references @@ -3,6 +3,7 @@ Be.Vlaanderen.Basisregisters.EventHandling.Autofac Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql Be.Vlaanderen.Basisregisters.GrAr.Contracts Be.Vlaanderen.BasisRegisters.MessageHandling.Kafka.Producer +Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore.Autofac Be.Vlaanderen.Basisregisters.Projector diff --git a/src/StreetNameRegistry.Projections.BackOffice/BackOfficeProjectionsContext.cs b/src/StreetNameRegistry.Projections.BackOffice/BackOfficeProjectionsContext.cs index ee3a43311..0accec909 100644 --- a/src/StreetNameRegistry.Projections.BackOffice/BackOfficeProjectionsContext.cs +++ b/src/StreetNameRegistry.Projections.BackOffice/BackOfficeProjectionsContext.cs @@ -1,6 +1,7 @@ namespace StreetNameRegistry.Projections.BackOffice { using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer; using Microsoft.EntityFrameworkCore; using StreetNameRegistry.Infrastructure; @@ -16,7 +17,7 @@ public BackOfficeProjectionsContext(DbContextOptions + public sealed class BackOfficeProjectionsContextMigrationFactory : SqlServerRunnerDbContextMigrationFactory { public BackOfficeProjectionsContextMigrationFactory() : base("BackOfficeProjectionsAdmin", HistoryConfiguration) { } diff --git a/src/StreetNameRegistry.Projections.BackOffice/Infrastructure/ServiceCollectionExtensions.cs b/src/StreetNameRegistry.Projections.BackOffice/Infrastructure/ServiceCollectionExtensions.cs index be82e9e07..03634d3d6 100644 --- a/src/StreetNameRegistry.Projections.BackOffice/Infrastructure/ServiceCollectionExtensions.cs +++ b/src/StreetNameRegistry.Projections.BackOffice/Infrastructure/ServiceCollectionExtensions.cs @@ -3,6 +3,7 @@ namespace StreetNameRegistry.Projections.BackOffice.Infrastructure using System; using Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql.EntityFrameworkCore; using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; diff --git a/src/StreetNameRegistry.Projections.BackOffice/paket.references b/src/StreetNameRegistry.Projections.BackOffice/paket.references index 42805d354..cf7da55b2 100644 --- a/src/StreetNameRegistry.Projections.BackOffice/paket.references +++ b/src/StreetNameRegistry.Projections.BackOffice/paket.references @@ -1,6 +1,6 @@ Be.Vlaanderen.Basisregisters.EventHandling.Autofac Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql -Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner +Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore.Autofac Be.Vlaanderen.Basisregisters.Projector diff --git a/src/StreetNameRegistry.Projections.Extract/ExtractContextMigrationFactory.cs b/src/StreetNameRegistry.Projections.Extract/ExtractContextMigrationFactory.cs index 7380d82a0..703475597 100644 --- a/src/StreetNameRegistry.Projections.Extract/ExtractContextMigrationFactory.cs +++ b/src/StreetNameRegistry.Projections.Extract/ExtractContextMigrationFactory.cs @@ -1,10 +1,11 @@ namespace StreetNameRegistry.Projections.Extract { using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer; using Infrastructure; using Microsoft.EntityFrameworkCore; - public sealed class ExtractContextMigrationFactory : RunnerDbContextMigrationFactory + public sealed class ExtractContextMigrationFactory : SqlServerRunnerDbContextMigrationFactory { public ExtractContextMigrationFactory() : base("ExtractProjectionsAdmin", HistoryConfiguration) diff --git a/src/StreetNameRegistry.Projections.Extract/ExtractModule.cs b/src/StreetNameRegistry.Projections.Extract/ExtractModule.cs index 1d50ff300..1933768d3 100755 --- a/src/StreetNameRegistry.Projections.Extract/ExtractModule.cs +++ b/src/StreetNameRegistry.Projections.Extract/ExtractModule.cs @@ -1,11 +1,11 @@ namespace StreetNameRegistry.Projections.Extract { using System; - using Microsoft.Data.SqlClient; - using Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql.EntityFrameworkCore; using Autofac; - using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; + using Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql.EntityFrameworkCore; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using Infrastructure; + using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; diff --git a/src/StreetNameRegistry.Projections.Extract/paket.references b/src/StreetNameRegistry.Projections.Extract/paket.references index 2e474ab95..1647ab389 100644 --- a/src/StreetNameRegistry.Projections.Extract/paket.references +++ b/src/StreetNameRegistry.Projections.Extract/paket.references @@ -1,6 +1,6 @@ Be.Vlaanderen.Basisregisters.EventHandling.Autofac Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql -Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner +Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore Be.Vlaanderen.Basisregisters.Shaperon diff --git a/src/StreetNameRegistry.Projections.Integration/Converters/StreetNameMapper.cs b/src/StreetNameRegistry.Projections.Integration/Converters/StreetNameMapper.cs new file mode 100644 index 000000000..f5ec41e7b --- /dev/null +++ b/src/StreetNameRegistry.Projections.Integration/Converters/StreetNameMapper.cs @@ -0,0 +1,107 @@ +namespace StreetNameRegistry.Projections.Integration.Converters +{ + using System; + using Be.Vlaanderen.Basisregisters.GrAr.Legacy.Straatnaam; + using Municipality; + using Language = StreetName.Language; + + public static class StreetNameMapper + { + public static string Map(this StreetNameStatus status) + { + switch (status) + { + case StreetNameStatus.Proposed: + return StraatnaamStatus.Voorgesteld.ToString(); + case StreetNameStatus.Current: + return StraatnaamStatus.InGebruik.ToString(); + case StreetNameStatus.Retired: + return StraatnaamStatus.Gehistoreerd.ToString(); + case StreetNameStatus.Rejected: + return StraatnaamStatus.Afgekeurd.ToString(); + default: + throw new ArgumentOutOfRangeException(nameof(status), status, null); + } + } + + public static void UpdateNameByLanguage(this StreetNameVersion item, Language? language, string value) + { + switch (language) + { + case Language.Dutch: + item.NameDutch = value; + break; + case Language.French: + item.NameFrench = value; + break; + case Language.German: + item.NameGerman = value; + break; + case Language.English: + item.NameEnglish = value; + break; + default: throw new InvalidOperationException($"Name language '{language}' has no mapping."); + } + } + + public static void UpdateHomonymAdditionByLanguage(this StreetNameVersion item, Language? language, string value) + { + switch (language) + { + case Language.Dutch: + item.HomonymAdditionDutch = value; + break; + case Language.French: + item.HomonymAdditionFrench = value; + break; + case Language.German: + item.HomonymAdditionGerman = value; + break; + case Language.English: + item.HomonymAdditionEnglish = value; + break; + default: throw new InvalidOperationException($"HomonymAddition language '{language}' has no mapping."); + } + } + + public static void UpdateNameByLanguage(this StreetNameVersion item, StreetNameRegistry.Municipality.Language language, string value) + { + switch (language) + { + case StreetNameRegistry.Municipality.Language.Dutch: + item.NameDutch = value; + break; + case StreetNameRegistry.Municipality.Language.French: + item.NameFrench = value; + break; + case StreetNameRegistry.Municipality.Language.German: + item.NameGerman = value; + break; + case StreetNameRegistry.Municipality.Language.English: + item.NameEnglish = value; + break; + default: throw new InvalidOperationException($"Name language '{language}' has no mapping."); + } + } + + public static void UpdateHomonymAdditionByLanguage(this StreetNameVersion item, StreetNameRegistry.Municipality.Language language, string value) + { + switch (language) + { + case StreetNameRegistry.Municipality.Language.Dutch: + item.HomonymAdditionDutch = value; + break; + case StreetNameRegistry.Municipality.Language.French: + item.HomonymAdditionFrench = value; + break; + case StreetNameRegistry.Municipality.Language.German: + item.HomonymAdditionGerman = value; + break; + case StreetNameRegistry.Municipality.Language.English: + item.HomonymAdditionEnglish = value; + break; + default: throw new InvalidOperationException($"HomonymAddition language '{language}' has no mapping."); + } + } + } +} diff --git a/src/StreetNameRegistry.Projections.Integration/EventsRepository.cs b/src/StreetNameRegistry.Projections.Integration/EventsRepository.cs new file mode 100644 index 000000000..00d6f31a1 --- /dev/null +++ b/src/StreetNameRegistry.Projections.Integration/EventsRepository.cs @@ -0,0 +1,29 @@ +namespace StreetNameRegistry.Projections.Integration +{ + using System; + using System.Threading.Tasks; + using Dapper; + using Microsoft.Data.SqlClient; + + public class EventsRepository : IEventsRepository + + { + private readonly string _eventsConnectionString; + + public EventsRepository(string eventsConnectionString) + { + _eventsConnectionString = eventsConnectionString; + } + + public async Task GetPersistentLocalId(Guid addressId) + { + await using var connection = new SqlConnection(_eventsConnectionString); + var sql = @$"SELECT Json_Value(JsonData, '$.persistentLocalId') AS ""PersistentLocalId"" + FROM [streetname-registry-events].[StreetNameRegistry].[Streams] as s + inner join [streetname-registry-events].[StreetNameRegistry].[Messages] as m on s.IdInternal = m.StreamIdInternal and m.[Type] = 'StreetNamePersistentLocalIdentifierWasAssigned' + where s.Id = '{addressId}'"; + + return await connection.QuerySingleOrDefaultAsync(sql); + } + } +} diff --git a/src/StreetNameRegistry.Projections.Integration/IEventsRepository.cs b/src/StreetNameRegistry.Projections.Integration/IEventsRepository.cs new file mode 100644 index 000000000..586eed3c5 --- /dev/null +++ b/src/StreetNameRegistry.Projections.Integration/IEventsRepository.cs @@ -0,0 +1,10 @@ +namespace StreetNameRegistry.Projections.Integration +{ + using System; + using System.Threading.Tasks; + + public interface IEventsRepository + { + Task GetPersistentLocalId(Guid addressId); + } +} diff --git a/src/StreetNameRegistry.Projections.Integration/Infrastructure/IntegrationModule.cs b/src/StreetNameRegistry.Projections.Integration/Infrastructure/IntegrationModule.cs new file mode 100644 index 000000000..7fe69e995 --- /dev/null +++ b/src/StreetNameRegistry.Projections.Integration/Infrastructure/IntegrationModule.cs @@ -0,0 +1,62 @@ +namespace StreetNameRegistry.Projections.Integration.Infrastructure +{ + using System; + using Autofac; + using Microsoft.EntityFrameworkCore; + using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Logging; + using StreetNameRegistry.Infrastructure; + + public class IntegrationModule : Module + { + public IntegrationModule( + IConfiguration configuration, + IServiceCollection services, + ILoggerFactory loggerFactory) + { + var logger = loggerFactory.CreateLogger(); + var connectionString = configuration.GetConnectionString("IntegrationProjections"); + services.AddScoped(_ => new EventsRepository(configuration.GetConnectionString("events"))); + + var hasConnectionString = !string.IsNullOrWhiteSpace(connectionString); + if (hasConnectionString) + RunOnNpgSqlServer(services, connectionString); + else + RunInMemoryDb(services, loggerFactory, logger); + + logger.LogInformation( + "Added {Context} to services:" + + Environment.NewLine + + "\tSchema: {Schema}" + + Environment.NewLine + + "\tTableName: {TableName}", + nameof(IntegrationContext), Schema.Integration, MigrationTables.Integration); + } + + private static void RunOnNpgSqlServer( + IServiceCollection services, + string connectionString) + { + services + .AddNpgsql(connectionString, sqlServerOptions => + { + sqlServerOptions.EnableRetryOnFailure(); + sqlServerOptions.MigrationsHistoryTable(MigrationTables.Integration, Schema.Integration); + }); + } + + private static void RunInMemoryDb( + IServiceCollection services, + ILoggerFactory loggerFactory, + ILogger logger) + { + services + .AddDbContext(options => options + .UseLoggerFactory(loggerFactory) + .UseInMemoryDatabase(Guid.NewGuid().ToString(), _ => { })); + + logger.LogWarning("Running InMemory for {Context}!", nameof(IntegrationContext)); + } + } +} diff --git a/src/StreetNameRegistry.Projections.Integration/Infrastructure/IntegrationOptions.cs b/src/StreetNameRegistry.Projections.Integration/Infrastructure/IntegrationOptions.cs new file mode 100644 index 000000000..20eed2f61 --- /dev/null +++ b/src/StreetNameRegistry.Projections.Integration/Infrastructure/IntegrationOptions.cs @@ -0,0 +1,8 @@ +namespace StreetNameRegistry.Projections.Integration.Infrastructure +{ + public class IntegrationOptions + { + public string Namespace { get; set; } + public bool Enabled { get; set; } + } +} diff --git a/src/StreetNameRegistry.Projections.Integration/IntegrationContext.cs b/src/StreetNameRegistry.Projections.Integration/IntegrationContext.cs new file mode 100644 index 000000000..44ef52279 --- /dev/null +++ b/src/StreetNameRegistry.Projections.Integration/IntegrationContext.cs @@ -0,0 +1,21 @@ +namespace StreetNameRegistry.Projections.Integration +{ + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; + using Microsoft.EntityFrameworkCore; + using StreetNameRegistry.Infrastructure; + + public class IntegrationContext : RunnerDbContext + { + public override string ProjectionStateSchema => Schema.Integration; + + public DbSet StreetNameLatestItems => Set(); + public DbSet StreetNameVersions => Set(); + + // This needs to be here to please EF + public IntegrationContext() { } + + // This needs to be DbContextOptions for Autofac! + public IntegrationContext(DbContextOptions options) + : base(options) { } + } +} diff --git a/src/StreetNameRegistry.Projections.Integration/IntegrationContextMigrationFactory.cs b/src/StreetNameRegistry.Projections.Integration/IntegrationContextMigrationFactory.cs new file mode 100644 index 000000000..df0382ae5 --- /dev/null +++ b/src/StreetNameRegistry.Projections.Integration/IntegrationContextMigrationFactory.cs @@ -0,0 +1,23 @@ +namespace StreetNameRegistry.Projections.Integration +{ + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.Npgsql; + using Microsoft.EntityFrameworkCore; + using StreetNameRegistry.Infrastructure; + + public class IntegrationContextMigrationFactory : NpgsqlRunnerDbContextMigrationFactory + { + public IntegrationContextMigrationFactory() + : base("IntegrationProjectionsAdmin", HistoryConfiguration) + { } + + private static MigrationHistoryConfiguration HistoryConfiguration => + new MigrationHistoryConfiguration + { + Schema = Schema.Integration, + Table = MigrationTables.Integration + }; + + protected override IntegrationContext CreateContext(DbContextOptions migrationContextOptions) + => new IntegrationContext(migrationContextOptions); + } +} diff --git a/src/StreetNameRegistry.Projections.Integration/Migrations/20240116145354_Initial.Designer.cs b/src/StreetNameRegistry.Projections.Integration/Migrations/20240116145354_Initial.Designer.cs new file mode 100644 index 000000000..aaefe59f4 --- /dev/null +++ b/src/StreetNameRegistry.Projections.Integration/Migrations/20240116145354_Initial.Designer.cs @@ -0,0 +1,272 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using StreetNameRegistry.Projections.Integration; + +#nullable disable + +namespace StreetNameRegistry.Projections.Integration.Migrations +{ + [DbContext(typeof(IntegrationContext))] + [Migration("20240116145354_Initial")] + partial class Initial + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.ProjectionStates.ProjectionStateItem", b => + { + b.Property("Name") + .HasColumnType("text"); + + b.Property("DesiredState") + .HasColumnType("text"); + + b.Property("DesiredStateChangedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ErrorMessage") + .HasColumnType("text"); + + b.Property("Position") + .HasColumnType("bigint"); + + b.HasKey("Name"); + + b.ToTable("ProjectionStates", "integration_streetname"); + }); + + modelBuilder.Entity("StreetNameRegistry.Projections.Integration.StreetNameLatestItem", b => + { + b.Property("PersistentLocalId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("persistent_local_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("PersistentLocalId")); + + b.Property("HomonymAdditionDutch") + .HasColumnType("text") + .HasColumnName("homonym_addition_dutch"); + + b.Property("HomonymAdditionEnglish") + .HasColumnType("text") + .HasColumnName("homonym_addition_english"); + + b.Property("HomonymAdditionFrench") + .HasColumnType("text") + .HasColumnName("homonym_addition_french"); + + b.Property("HomonymAdditionGerman") + .HasColumnType("text") + .HasColumnName("homonym_addition_german"); + + b.Property("IsRemoved") + .HasColumnType("boolean") + .HasColumnName("is_removed"); + + b.Property("MunicipalityId") + .HasColumnType("uuid") + .HasColumnName("municipality_id"); + + b.Property("NameDutch") + .HasColumnType("text") + .HasColumnName("name_dutch"); + + b.Property("NameEnglish") + .HasColumnType("text") + .HasColumnName("name_english"); + + b.Property("NameFrench") + .HasColumnType("text") + .HasColumnName("name_french"); + + b.Property("NameGerman") + .HasColumnType("text") + .HasColumnName("name_german"); + + b.Property("Namespace") + .IsRequired() + .HasColumnType("text") + .HasColumnName("namespace"); + + b.Property("NisCode") + .HasColumnType("text") + .HasColumnName("nis_code"); + + b.Property("OsloStatus") + .IsRequired() + .HasColumnType("text") + .HasColumnName("oslo_status"); + + b.Property("Puri") + .IsRequired() + .HasColumnType("text") + .HasColumnName("puri"); + + b.Property("Status") + .HasColumnType("integer") + .HasColumnName("status"); + + b.Property("VersionAsString") + .IsRequired() + .HasColumnType("text") + .HasColumnName("version_as_string"); + + b.Property("VersionTimestampAsDateTimeOffset") + .HasColumnType("timestamp with time zone") + .HasColumnName("version_timestamp"); + + b.HasKey("PersistentLocalId") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("IsRemoved"); + + b.HasIndex("MunicipalityId"); + + b.HasIndex("NameDutch"); + + b.HasIndex("NameEnglish"); + + b.HasIndex("NameFrench"); + + b.HasIndex("NameGerman"); + + b.HasIndex("NisCode"); + + b.HasIndex("OsloStatus"); + + b.HasIndex("PersistentLocalId"); + + b.HasIndex("Status"); + + b.ToTable("streetname_latest_items", "integration_streetname"); + }); + + modelBuilder.Entity("StreetNameRegistry.Projections.Integration.StreetNameVersion", b => + { + b.Property("Position") + .HasColumnType("bigint") + .HasColumnName("position"); + + b.Property("PersistentLocalId") + .HasColumnType("integer") + .HasColumnName("persistent_local_id"); + + b.Property("CreatedOnAsString") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreatedOnTimestampAsDateTimeOffset") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on_timestamp"); + + b.Property("HomonymAdditionDutch") + .HasColumnType("text") + .HasColumnName("homonym_addition_dutch"); + + b.Property("HomonymAdditionEnglish") + .HasColumnType("text") + .HasColumnName("homonym_addition_english"); + + b.Property("HomonymAdditionFrench") + .HasColumnType("text") + .HasColumnName("homonym_addition_french"); + + b.Property("HomonymAdditionGerman") + .HasColumnType("text") + .HasColumnName("homonym_addition_german"); + + b.Property("IsRemoved") + .HasColumnType("boolean") + .HasColumnName("is_removed"); + + b.Property("MunicipalityId") + .HasColumnType("uuid") + .HasColumnName("municipality_id"); + + b.Property("NameDutch") + .HasColumnType("text") + .HasColumnName("name_dutch"); + + b.Property("NameEnglish") + .HasColumnType("text") + .HasColumnName("name_english"); + + b.Property("NameFrench") + .HasColumnType("text") + .HasColumnName("name_french"); + + b.Property("NameGerman") + .HasColumnType("text") + .HasColumnName("name_german"); + + b.Property("Namespace") + .IsRequired() + .HasColumnType("text") + .HasColumnName("namespace"); + + b.Property("NisCode") + .HasColumnType("text") + .HasColumnName("nis_code"); + + b.Property("OsloStatus") + .HasColumnType("text") + .HasColumnName("oslo_status"); + + b.Property("Puri") + .IsRequired() + .HasColumnType("text") + .HasColumnName("puri"); + + b.Property("Status") + .HasColumnType("integer") + .HasColumnName("status"); + + b.Property("StreetNameId") + .HasColumnType("uuid") + .HasColumnName("streetname_id"); + + b.Property("VersionAsString") + .IsRequired() + .HasColumnType("text") + .HasColumnName("version_as_string"); + + b.Property("VersionTimestampAsDateTimeOffset") + .HasColumnType("timestamp with time zone") + .HasColumnName("version_timestamp"); + + b.HasKey("Position", "PersistentLocalId"); + + b.HasIndex("IsRemoved"); + + b.HasIndex("MunicipalityId"); + + b.HasIndex("NisCode"); + + b.HasIndex("OsloStatus"); + + b.HasIndex("PersistentLocalId"); + + b.HasIndex("Status"); + + b.HasIndex("StreetNameId"); + + b.HasIndex("VersionTimestampAsDateTimeOffset"); + + b.ToTable("streetname_versions", "integration_streetname"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/StreetNameRegistry.Projections.Integration/Migrations/20240116145354_Initial.cs b/src/StreetNameRegistry.Projections.Integration/Migrations/20240116145354_Initial.cs new file mode 100644 index 000000000..18155e765 --- /dev/null +++ b/src/StreetNameRegistry.Projections.Integration/Migrations/20240116145354_Initial.cs @@ -0,0 +1,219 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace StreetNameRegistry.Projections.Integration.Migrations +{ + public partial class Initial : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.EnsureSchema( + name: "integration_streetname"); + + migrationBuilder.CreateTable( + name: "ProjectionStates", + schema: "integration_streetname", + columns: table => new + { + Name = table.Column(type: "text", nullable: false), + Position = table.Column(type: "bigint", nullable: false), + DesiredState = table.Column(type: "text", nullable: true), + DesiredStateChangedAt = table.Column(type: "timestamp with time zone", nullable: true), + ErrorMessage = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_ProjectionStates", x => x.Name); + }); + + migrationBuilder.CreateTable( + name: "streetname_latest_items", + schema: "integration_streetname", + columns: table => new + { + persistent_local_id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + municipality_id = table.Column(type: "uuid", nullable: false), + status = table.Column(type: "integer", nullable: false), + oslo_status = table.Column(type: "text", nullable: false), + nis_code = table.Column(type: "text", nullable: true), + name_dutch = table.Column(type: "text", nullable: true), + name_french = table.Column(type: "text", nullable: true), + name_german = table.Column(type: "text", nullable: true), + name_english = table.Column(type: "text", nullable: true), + homonym_addition_dutch = table.Column(type: "text", nullable: true), + homonym_addition_french = table.Column(type: "text", nullable: true), + homonym_addition_german = table.Column(type: "text", nullable: true), + homonym_addition_english = table.Column(type: "text", nullable: true), + is_removed = table.Column(type: "boolean", nullable: false), + puri = table.Column(type: "text", nullable: false), + @namespace = table.Column(name: "namespace", type: "text", nullable: false), + version_as_string = table.Column(type: "text", nullable: false), + version_timestamp = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_streetname_latest_items", x => x.persistent_local_id); + }); + + migrationBuilder.CreateTable( + name: "streetname_versions", + schema: "integration_streetname", + columns: table => new + { + position = table.Column(type: "bigint", nullable: false), + persistent_local_id = table.Column(type: "integer", nullable: false), + municipality_id = table.Column(type: "uuid", nullable: false), + streetname_id = table.Column(type: "uuid", nullable: true), + status = table.Column(type: "integer", nullable: true), + oslo_status = table.Column(type: "text", nullable: true), + nis_code = table.Column(type: "text", nullable: true), + name_dutch = table.Column(type: "text", nullable: true), + name_french = table.Column(type: "text", nullable: true), + name_german = table.Column(type: "text", nullable: true), + name_english = table.Column(type: "text", nullable: true), + homonym_addition_dutch = table.Column(type: "text", nullable: true), + homonym_addition_french = table.Column(type: "text", nullable: true), + homonym_addition_german = table.Column(type: "text", nullable: true), + homonym_addition_english = table.Column(type: "text", nullable: true), + is_removed = table.Column(type: "boolean", nullable: false), + puri = table.Column(type: "text", nullable: false), + @namespace = table.Column(name: "namespace", type: "text", nullable: false), + version_as_string = table.Column(type: "text", nullable: false), + version_timestamp = table.Column(type: "timestamp with time zone", nullable: false), + CreatedOnAsString = table.Column(type: "text", nullable: false), + created_on_timestamp = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_streetname_versions", x => new { x.position, x.persistent_local_id }); + }); + + migrationBuilder.CreateIndex( + name: "IX_streetname_latest_items_is_removed", + schema: "integration_streetname", + table: "streetname_latest_items", + column: "is_removed"); + + migrationBuilder.CreateIndex( + name: "IX_streetname_latest_items_municipality_id", + schema: "integration_streetname", + table: "streetname_latest_items", + column: "municipality_id"); + + migrationBuilder.CreateIndex( + name: "IX_streetname_latest_items_name_dutch", + schema: "integration_streetname", + table: "streetname_latest_items", + column: "name_dutch"); + + migrationBuilder.CreateIndex( + name: "IX_streetname_latest_items_name_english", + schema: "integration_streetname", + table: "streetname_latest_items", + column: "name_english"); + + migrationBuilder.CreateIndex( + name: "IX_streetname_latest_items_name_french", + schema: "integration_streetname", + table: "streetname_latest_items", + column: "name_french"); + + migrationBuilder.CreateIndex( + name: "IX_streetname_latest_items_name_german", + schema: "integration_streetname", + table: "streetname_latest_items", + column: "name_german"); + + migrationBuilder.CreateIndex( + name: "IX_streetname_latest_items_nis_code", + schema: "integration_streetname", + table: "streetname_latest_items", + column: "nis_code"); + + migrationBuilder.CreateIndex( + name: "IX_streetname_latest_items_oslo_status", + schema: "integration_streetname", + table: "streetname_latest_items", + column: "oslo_status"); + + migrationBuilder.CreateIndex( + name: "IX_streetname_latest_items_persistent_local_id", + schema: "integration_streetname", + table: "streetname_latest_items", + column: "persistent_local_id"); + + migrationBuilder.CreateIndex( + name: "IX_streetname_latest_items_status", + schema: "integration_streetname", + table: "streetname_latest_items", + column: "status"); + + migrationBuilder.CreateIndex( + name: "IX_streetname_versions_is_removed", + schema: "integration_streetname", + table: "streetname_versions", + column: "is_removed"); + + migrationBuilder.CreateIndex( + name: "IX_streetname_versions_municipality_id", + schema: "integration_streetname", + table: "streetname_versions", + column: "municipality_id"); + + migrationBuilder.CreateIndex( + name: "IX_streetname_versions_nis_code", + schema: "integration_streetname", + table: "streetname_versions", + column: "nis_code"); + + migrationBuilder.CreateIndex( + name: "IX_streetname_versions_oslo_status", + schema: "integration_streetname", + table: "streetname_versions", + column: "oslo_status"); + + migrationBuilder.CreateIndex( + name: "IX_streetname_versions_persistent_local_id", + schema: "integration_streetname", + table: "streetname_versions", + column: "persistent_local_id"); + + migrationBuilder.CreateIndex( + name: "IX_streetname_versions_status", + schema: "integration_streetname", + table: "streetname_versions", + column: "status"); + + migrationBuilder.CreateIndex( + name: "IX_streetname_versions_streetname_id", + schema: "integration_streetname", + table: "streetname_versions", + column: "streetname_id"); + + migrationBuilder.CreateIndex( + name: "IX_streetname_versions_version_timestamp", + schema: "integration_streetname", + table: "streetname_versions", + column: "version_timestamp"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "ProjectionStates", + schema: "integration_streetname"); + + migrationBuilder.DropTable( + name: "streetname_latest_items", + schema: "integration_streetname"); + + migrationBuilder.DropTable( + name: "streetname_versions", + schema: "integration_streetname"); + } + } +} diff --git a/src/StreetNameRegistry.Projections.Integration/Migrations/IntegrationContextModelSnapshot.cs b/src/StreetNameRegistry.Projections.Integration/Migrations/IntegrationContextModelSnapshot.cs new file mode 100644 index 000000000..891dfbe09 --- /dev/null +++ b/src/StreetNameRegistry.Projections.Integration/Migrations/IntegrationContextModelSnapshot.cs @@ -0,0 +1,270 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using StreetNameRegistry.Projections.Integration; + +#nullable disable + +namespace StreetNameRegistry.Projections.Integration.Migrations +{ + [DbContext(typeof(IntegrationContext))] + partial class IntegrationContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.ProjectionStates.ProjectionStateItem", b => + { + b.Property("Name") + .HasColumnType("text"); + + b.Property("DesiredState") + .HasColumnType("text"); + + b.Property("DesiredStateChangedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ErrorMessage") + .HasColumnType("text"); + + b.Property("Position") + .HasColumnType("bigint"); + + b.HasKey("Name"); + + b.ToTable("ProjectionStates", "integration_streetname"); + }); + + modelBuilder.Entity("StreetNameRegistry.Projections.Integration.StreetNameLatestItem", b => + { + b.Property("PersistentLocalId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("persistent_local_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("PersistentLocalId")); + + b.Property("HomonymAdditionDutch") + .HasColumnType("text") + .HasColumnName("homonym_addition_dutch"); + + b.Property("HomonymAdditionEnglish") + .HasColumnType("text") + .HasColumnName("homonym_addition_english"); + + b.Property("HomonymAdditionFrench") + .HasColumnType("text") + .HasColumnName("homonym_addition_french"); + + b.Property("HomonymAdditionGerman") + .HasColumnType("text") + .HasColumnName("homonym_addition_german"); + + b.Property("IsRemoved") + .HasColumnType("boolean") + .HasColumnName("is_removed"); + + b.Property("MunicipalityId") + .HasColumnType("uuid") + .HasColumnName("municipality_id"); + + b.Property("NameDutch") + .HasColumnType("text") + .HasColumnName("name_dutch"); + + b.Property("NameEnglish") + .HasColumnType("text") + .HasColumnName("name_english"); + + b.Property("NameFrench") + .HasColumnType("text") + .HasColumnName("name_french"); + + b.Property("NameGerman") + .HasColumnType("text") + .HasColumnName("name_german"); + + b.Property("Namespace") + .IsRequired() + .HasColumnType("text") + .HasColumnName("namespace"); + + b.Property("NisCode") + .HasColumnType("text") + .HasColumnName("nis_code"); + + b.Property("OsloStatus") + .IsRequired() + .HasColumnType("text") + .HasColumnName("oslo_status"); + + b.Property("Puri") + .IsRequired() + .HasColumnType("text") + .HasColumnName("puri"); + + b.Property("Status") + .HasColumnType("integer") + .HasColumnName("status"); + + b.Property("VersionAsString") + .IsRequired() + .HasColumnType("text") + .HasColumnName("version_as_string"); + + b.Property("VersionTimestampAsDateTimeOffset") + .HasColumnType("timestamp with time zone") + .HasColumnName("version_timestamp"); + + b.HasKey("PersistentLocalId") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("IsRemoved"); + + b.HasIndex("MunicipalityId"); + + b.HasIndex("NameDutch"); + + b.HasIndex("NameEnglish"); + + b.HasIndex("NameFrench"); + + b.HasIndex("NameGerman"); + + b.HasIndex("NisCode"); + + b.HasIndex("OsloStatus"); + + b.HasIndex("PersistentLocalId"); + + b.HasIndex("Status"); + + b.ToTable("streetname_latest_items", "integration_streetname"); + }); + + modelBuilder.Entity("StreetNameRegistry.Projections.Integration.StreetNameVersion", b => + { + b.Property("Position") + .HasColumnType("bigint") + .HasColumnName("position"); + + b.Property("PersistentLocalId") + .HasColumnType("integer") + .HasColumnName("persistent_local_id"); + + b.Property("CreatedOnAsString") + .IsRequired() + .HasColumnType("text"); + + b.Property("CreatedOnTimestampAsDateTimeOffset") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on_timestamp"); + + b.Property("HomonymAdditionDutch") + .HasColumnType("text") + .HasColumnName("homonym_addition_dutch"); + + b.Property("HomonymAdditionEnglish") + .HasColumnType("text") + .HasColumnName("homonym_addition_english"); + + b.Property("HomonymAdditionFrench") + .HasColumnType("text") + .HasColumnName("homonym_addition_french"); + + b.Property("HomonymAdditionGerman") + .HasColumnType("text") + .HasColumnName("homonym_addition_german"); + + b.Property("IsRemoved") + .HasColumnType("boolean") + .HasColumnName("is_removed"); + + b.Property("MunicipalityId") + .HasColumnType("uuid") + .HasColumnName("municipality_id"); + + b.Property("NameDutch") + .HasColumnType("text") + .HasColumnName("name_dutch"); + + b.Property("NameEnglish") + .HasColumnType("text") + .HasColumnName("name_english"); + + b.Property("NameFrench") + .HasColumnType("text") + .HasColumnName("name_french"); + + b.Property("NameGerman") + .HasColumnType("text") + .HasColumnName("name_german"); + + b.Property("Namespace") + .IsRequired() + .HasColumnType("text") + .HasColumnName("namespace"); + + b.Property("NisCode") + .HasColumnType("text") + .HasColumnName("nis_code"); + + b.Property("OsloStatus") + .HasColumnType("text") + .HasColumnName("oslo_status"); + + b.Property("Puri") + .IsRequired() + .HasColumnType("text") + .HasColumnName("puri"); + + b.Property("Status") + .HasColumnType("integer") + .HasColumnName("status"); + + b.Property("StreetNameId") + .HasColumnType("uuid") + .HasColumnName("streetname_id"); + + b.Property("VersionAsString") + .IsRequired() + .HasColumnType("text") + .HasColumnName("version_as_string"); + + b.Property("VersionTimestampAsDateTimeOffset") + .HasColumnType("timestamp with time zone") + .HasColumnName("version_timestamp"); + + b.HasKey("Position", "PersistentLocalId"); + + b.HasIndex("IsRemoved"); + + b.HasIndex("MunicipalityId"); + + b.HasIndex("NisCode"); + + b.HasIndex("OsloStatus"); + + b.HasIndex("PersistentLocalId"); + + b.HasIndex("Status"); + + b.HasIndex("StreetNameId"); + + b.HasIndex("VersionTimestampAsDateTimeOffset"); + + b.ToTable("streetname_versions", "integration_streetname"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/StreetNameRegistry.Projections.Integration/StreetNameLatestItem.cs b/src/StreetNameRegistry.Projections.Integration/StreetNameLatestItem.cs new file mode 100644 index 000000000..1a0ffc0e0 --- /dev/null +++ b/src/StreetNameRegistry.Projections.Integration/StreetNameLatestItem.cs @@ -0,0 +1,101 @@ +namespace StreetNameRegistry.Projections.Integration +{ + using System; + using Be.Vlaanderen.Basisregisters.GrAr.Common; + using Be.Vlaanderen.Basisregisters.Utilities; + using Microsoft.EntityFrameworkCore; + using Microsoft.EntityFrameworkCore.Metadata.Builders; + using Municipality; + using NodaTime; + using StreetNameRegistry.Infrastructure; + + public sealed class StreetNameLatestItem + { + public const string VersionTimestampBackingPropertyName = nameof(VersionTimestampAsDateTimeOffset); + + public int PersistentLocalId { get; set; } + public Guid MunicipalityId { get; set; } + public StreetNameStatus Status { get; set; } + public string OsloStatus { get; set; } + + public string? NisCode { get; set; } + + public string? NameDutch { get; set; } + public string? NameFrench { get; set; } + public string? NameGerman { get; set; } + public string? NameEnglish { get; set; } + + public string? HomonymAdditionDutch { get; set; } + public string? HomonymAdditionFrench { get; set; } + public string? HomonymAdditionGerman { get; set; } + public string? HomonymAdditionEnglish { get; set; } + + public bool IsRemoved { get; set; } + + public string Puri { get; set; } + public string Namespace { get; set; } + public string VersionAsString { get; set; } + private DateTimeOffset VersionTimestampAsDateTimeOffset { get; set; } + + public Instant VersionTimestamp + { + get => Instant.FromDateTimeOffset(VersionTimestampAsDateTimeOffset); + set + { + VersionTimestampAsDateTimeOffset = value.ToDateTimeOffset(); + VersionAsString = new Rfc3339SerializableDateTimeOffset(value.ToBelgianDateTimeOffset()).ToString(); + } + } + + public StreetNameLatestItem() + { } + } + + public sealed class StreetNameLatestItemConfiguration : IEntityTypeConfiguration + { + internal const string TableName = "streetname_latest_items"; + + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable(TableName, Schema.Integration) + .HasKey(x => x.PersistentLocalId) + .IsClustered(); + builder.Property(x => x.PersistentLocalId).HasColumnName("persistent_local_id"); + + builder.Property(x => x.MunicipalityId).HasColumnName("municipality_id"); + builder.Property(x => x.NisCode).HasColumnName("nis_code"); + builder.Property(x => x.Status).HasColumnName("status"); + builder.Property(x => x.OsloStatus).HasColumnName("oslo_status"); + + builder.Property(x => x.NameDutch).HasColumnName("name_dutch"); + builder.Property(x => x.NameFrench).HasColumnName("name_french"); + builder.Property(x => x.NameGerman).HasColumnName("name_german"); + builder.Property(x => x.NameEnglish).HasColumnName("name_english"); + + builder.Property(x => x.HomonymAdditionDutch).HasColumnName("homonym_addition_dutch"); + builder.Property(x => x.HomonymAdditionFrench).HasColumnName("homonym_addition_french"); + builder.Property(x => x.HomonymAdditionGerman).HasColumnName("homonym_addition_german"); + builder.Property(x => x.HomonymAdditionEnglish).HasColumnName("homonym_addition_english"); + + builder.Property(x => x.IsRemoved).HasColumnName("is_removed"); + + builder.Property(x => x.Puri).HasColumnName("puri"); + builder.Property(x => x.Namespace).HasColumnName("namespace"); + builder.Property(x => x.VersionAsString).HasColumnName("version_as_string"); + builder.Property(StreetNameLatestItem.VersionTimestampBackingPropertyName).HasColumnName("version_timestamp"); + + builder.Ignore(x => x.VersionTimestamp); + + builder.HasIndex(x => x.PersistentLocalId); + builder.HasIndex(x => x.MunicipalityId); + builder.HasIndex(x => x.NisCode); + builder.HasIndex(x => x.Status); + builder.HasIndex(x => x.OsloStatus); + builder.HasIndex(x => x.NameDutch); + builder.HasIndex(x => x.NameEnglish); + builder.HasIndex(x => x.NameFrench); + builder.HasIndex(x => x.NameGerman); + builder.HasIndex(x => x.IsRemoved); + } + } +} diff --git a/src/StreetNameRegistry.Projections.Integration/StreetNameLatestItemExtensions.cs b/src/StreetNameRegistry.Projections.Integration/StreetNameLatestItemExtensions.cs new file mode 100644 index 000000000..3f3a41739 --- /dev/null +++ b/src/StreetNameRegistry.Projections.Integration/StreetNameLatestItemExtensions.cs @@ -0,0 +1,87 @@ +namespace StreetNameRegistry.Projections.Integration +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using System.Threading; + using System.Threading.Tasks; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector; + using Municipality; + + public static class StreetNameLatestItemExtensions + { + public static async Task FindAndUpdateStreetNameLatestItem( + this IntegrationContext context, + int persistentLocalId, + Action updateFunc, + CancellationToken ct) + { + var streetName = await context + .StreetNameLatestItems + .FindAsync(persistentLocalId, cancellationToken: ct); + + if (streetName == null) + throw DatabaseItemNotFound(persistentLocalId); + + updateFunc(streetName); + } + + public static void UpdateNameByLanguage(this StreetNameLatestItem entity, IDictionary streetNameNames) + { + foreach (var (language, streetNameName) in streetNameNames) + { + switch (language) + { + case Language.Dutch: + entity.NameDutch = streetNameName; + break; + + case Language.French: + entity.NameFrench = streetNameName; + break; + + case Language.German: + entity.NameGerman = streetNameName; + break; + + case Language.English: + entity.NameEnglish = streetNameName; + break; + + default: + throw new ArgumentOutOfRangeException(nameof(language), streetNameName, null); + } + } + } + + public static void UpdateHomonymAdditionByLanguage(this StreetNameLatestItem entity, IDictionary homonymAdditions) + { + foreach (var (language, homonymAddition) in homonymAdditions) + { + switch (language) + { + case Language.Dutch: + entity.HomonymAdditionDutch = homonymAddition; + break; + + case Language.French: + entity.HomonymAdditionFrench = homonymAddition; + break; + + case Language.German: + entity.HomonymAdditionGerman = homonymAddition; + break; + + case Language.English: + entity.HomonymAdditionEnglish = homonymAddition; + break; + default: + throw new ArgumentOutOfRangeException(nameof(language), language, null); + } + } + } + + private static ProjectionItemNotFoundException DatabaseItemNotFound(int persistentLocalId) + => new ProjectionItemNotFoundException(persistentLocalId.ToString(CultureInfo.InvariantCulture)); + } +} diff --git a/src/StreetNameRegistry.Projections.Integration/StreetNameLatestItemProjections.cs b/src/StreetNameRegistry.Projections.Integration/StreetNameLatestItemProjections.cs new file mode 100644 index 000000000..6557b6f3d --- /dev/null +++ b/src/StreetNameRegistry.Projections.Integration/StreetNameLatestItemProjections.cs @@ -0,0 +1,217 @@ +namespace StreetNameRegistry.Projections.Integration +{ + using System; + using System.Linq; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore; + using Converters; + using Infrastructure; + using Microsoft.EntityFrameworkCore; + using Microsoft.Extensions.Options; + using Municipality; + using Municipality.Events; + + [ConnectedProjectionName("Integratie straatnaam latest item")] + [ConnectedProjectionDescription("Projectie die de laatste straatnaam data voor de integratie database bijhoudt.")] + public class StreetNameLatestItemProjections : ConnectedProjection + { + public StreetNameLatestItemProjections(IOptions options) + { + When>(async (context, message, ct) => + { + var streetNamePersistentLocalIds = await context.StreetNameLatestItems.Where(x => x.MunicipalityId == message.Message.MunicipalityId) + .Select(x => x.PersistentLocalId) + .ToListAsync(ct); + + foreach (var persistentLocalId in streetNamePersistentLocalIds) + { + await context.FindAndUpdateStreetNameLatestItem(persistentLocalId, item => + { + item.NisCode = message.Message.NisCode; + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + } + }); + + When>(async (context, message, ct) => + { + var item = new StreetNameLatestItem + { + PersistentLocalId = message.Message.PersistentLocalId, + MunicipalityId = message.Message.MunicipalityId, + Status = message.Message.Status, + OsloStatus = message.Message.Status.Map(), + NisCode = message.Message.NisCode, + IsRemoved = message.Message.IsRemoved, + VersionTimestamp = message.Message.Provenance.Timestamp, + Namespace = options.Value.Namespace, + Puri = $"{options.Value.Namespace}/{message.Message.PersistentLocalId}", + }; + + item.UpdateNameByLanguage(message.Message.Names); + item.UpdateHomonymAdditionByLanguage(message.Message.HomonymAdditions); + + await context + .StreetNameLatestItems + .AddAsync(item, ct); + }); + + When>(async (context, message, ct) => + { + var item = new StreetNameLatestItem + { + PersistentLocalId = message.Message.PersistentLocalId, + MunicipalityId = message.Message.MunicipalityId, + Status = StreetNameStatus.Proposed, + OsloStatus = StreetNameStatus.Proposed.Map(), + NisCode = message.Message.NisCode, + IsRemoved = false, + VersionTimestamp = message.Message.Provenance.Timestamp, + Namespace = options.Value.Namespace, + Puri = $"{options.Value.Namespace}/{message.Message.PersistentLocalId}", + }; + + item.UpdateNameByLanguage(message.Message.StreetNameNames); + + await context + .StreetNameLatestItems + .AddAsync(item, ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateStreetNameLatestItem(message.Message.PersistentLocalId, item => + { + item.Status = StreetNameStatus.Current; + item.OsloStatus = StreetNameStatus.Current.Map(); + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateStreetNameLatestItem(message.Message.PersistentLocalId, item => + { + item.Status = StreetNameStatus.Proposed; + item.OsloStatus = StreetNameStatus.Proposed.Map(); + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateStreetNameLatestItem(message.Message.PersistentLocalId, item => + { + item.Status = StreetNameStatus.Rejected; + item.OsloStatus = StreetNameStatus.Rejected.Map(); + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateStreetNameLatestItem(message.Message.PersistentLocalId, item => + { + item.Status = StreetNameStatus.Proposed; + item.OsloStatus = StreetNameStatus.Proposed.Map(); + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateStreetNameLatestItem(message.Message.PersistentLocalId, item => + { + item.Status = StreetNameStatus.Retired; + item.OsloStatus = StreetNameStatus.Retired.Map(); + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateStreetNameLatestItem(message.Message.PersistentLocalId, item => + { + item.Status = StreetNameStatus.Retired; + item.OsloStatus = StreetNameStatus.Retired.Map(); + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateStreetNameLatestItem(message.Message.PersistentLocalId, item => + { + item.Status = StreetNameStatus.Current; + item.OsloStatus = StreetNameStatus.Current.Map(); + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateStreetNameLatestItem(message.Message.PersistentLocalId, item => + { + item.UpdateNameByLanguage(message.Message.StreetNameNames); + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateStreetNameLatestItem(message.Message.PersistentLocalId, item => + { + item.UpdateNameByLanguage(message.Message.StreetNameNames); + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateStreetNameLatestItem(message.Message.PersistentLocalId, item => + { + item.UpdateHomonymAdditionByLanguage(message.Message.HomonymAdditions); + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateStreetNameLatestItem(message.Message.PersistentLocalId, item => + { + foreach (var language in message.Message.Languages) + { + switch (language) + { + case Language.Dutch: + item.HomonymAdditionDutch = null; + break; + case Language.French: + item.HomonymAdditionFrench = null; + break; + case Language.German: + item.HomonymAdditionGerman = null; + break; + case Language.English: + item.HomonymAdditionEnglish = null; + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateStreetNameLatestItem(message.Message.PersistentLocalId, item => + { + item.IsRemoved = true; + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + }); + } + } +} diff --git a/src/StreetNameRegistry.Projections.Integration/StreetNameRegistry.Projections.Integration.csproj b/src/StreetNameRegistry.Projections.Integration/StreetNameRegistry.Projections.Integration.csproj new file mode 100644 index 000000000..398bcdb7c --- /dev/null +++ b/src/StreetNameRegistry.Projections.Integration/StreetNameRegistry.Projections.Integration.csproj @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/StreetNameRegistry.Projections.Integration/StreetNameVersion.cs b/src/StreetNameRegistry.Projections.Integration/StreetNameVersion.cs new file mode 100644 index 000000000..7d0c417a7 --- /dev/null +++ b/src/StreetNameRegistry.Projections.Integration/StreetNameVersion.cs @@ -0,0 +1,158 @@ +namespace StreetNameRegistry.Projections.Integration +{ + using System; + using Be.Vlaanderen.Basisregisters.GrAr.Common; + using Be.Vlaanderen.Basisregisters.Utilities; + using Microsoft.EntityFrameworkCore; + using Microsoft.EntityFrameworkCore.Metadata.Builders; + using Municipality; + using NodaTime; + using StreetNameRegistry.Infrastructure; + + public sealed class StreetNameVersion + { + public const string VersionTimestampBackingPropertyName = nameof(VersionTimestampAsDateTimeOffset); + public const string CreatedOnTimestampBackingPropertyName = nameof(CreatedOnTimestampAsDateTimeOffset); + + public long Position { get; set; } + public int PersistentLocalId { get; set; } + public Guid MunicipalityId { get; set; } + public Guid? StreetNameId { get; set; } + public StreetNameStatus? Status { get; set; } + public string? OsloStatus { get; set; } + public string? NisCode { get; set; } + + public string? NameDutch { get; set; } + public string? NameFrench { get; set; } + public string? NameGerman { get; set; } + public string? NameEnglish { get; set; } + + public string? HomonymAdditionDutch { get; set; } + public string? HomonymAdditionFrench { get; set; } + public string? HomonymAdditionGerman { get; set; } + public string? HomonymAdditionEnglish { get; set; } + + public bool IsRemoved { get; set; } + + public string Puri { get; set; } + public string Namespace { get; set; } + public string VersionAsString { get; set; } + private DateTimeOffset VersionTimestampAsDateTimeOffset { get; set; } + + public Instant VersionTimestamp + { + get => Instant.FromDateTimeOffset(VersionTimestampAsDateTimeOffset); + set + { + VersionTimestampAsDateTimeOffset = value.ToDateTimeOffset(); + VersionAsString = new Rfc3339SerializableDateTimeOffset(value.ToBelgianDateTimeOffset()).ToString(); + } + } + + public string CreatedOnAsString { get; set; } + private DateTimeOffset CreatedOnTimestampAsDateTimeOffset { get; set; } + + public Instant CreatedOnTimestamp + { + get => Instant.FromDateTimeOffset(CreatedOnTimestampAsDateTimeOffset); + set + { + CreatedOnTimestampAsDateTimeOffset = value.ToDateTimeOffset(); + CreatedOnAsString = new Rfc3339SerializableDateTimeOffset(value.ToBelgianDateTimeOffset()).ToString(); + } + } + + public StreetNameVersion() + { } + + public StreetNameVersion CloneAndApplyEventInfo( + long newPosition, + Instant lastChangedOn, + Action editFunc) + { + var newItem = new StreetNameVersion + { + PersistentLocalId = PersistentLocalId, + MunicipalityId = MunicipalityId, + StreetNameId = StreetNameId, + Position = newPosition, + NisCode = NisCode, + Status = Status, + OsloStatus = OsloStatus, + + NameDutch = NameDutch, + NameFrench = NameFrench, + NameGerman = NameGerman, + NameEnglish = NameEnglish, + + HomonymAdditionDutch = HomonymAdditionDutch, + HomonymAdditionFrench = HomonymAdditionFrench, + HomonymAdditionGerman = HomonymAdditionGerman, + HomonymAdditionEnglish = HomonymAdditionEnglish, + + IsRemoved = IsRemoved, + + Puri = Puri, + Namespace = Namespace, + VersionTimestamp = lastChangedOn, + CreatedOnTimestamp = CreatedOnTimestamp + }; + + editFunc(newItem); + + return newItem; + } + } + + public sealed class StreetNameVersionConfiguration : IEntityTypeConfiguration + { + internal const string TableName = "streetname_versions"; + + public void Configure(EntityTypeBuilder builder) + { + builder.Property(x => x.Position).HasColumnName("position"); + builder.ToTable(TableName, Schema.Integration) + .HasKey(x => new { x.Position, x.PersistentLocalId}); + + builder.Property(x => x.PersistentLocalId).HasColumnName("persistent_local_id"); + builder.Property(x => x.StreetNameId).HasColumnName("streetname_id"); + builder.Property(x => x.MunicipalityId).HasColumnName("municipality_id"); + builder.Property(x => x.NisCode).HasColumnName("nis_code"); + builder.Property(x => x.Status).HasColumnName("status"); + builder.Property(x => x.OsloStatus).HasColumnName("oslo_status"); + + builder.Property(x => x.NameDutch).HasColumnName("name_dutch"); + builder.Property(x => x.NameFrench).HasColumnName("name_french"); + builder.Property(x => x.NameGerman).HasColumnName("name_german"); + builder.Property(x => x.NameEnglish).HasColumnName("name_english"); + + builder.Property(x => x.HomonymAdditionDutch).HasColumnName("homonym_addition_dutch"); + builder.Property(x => x.HomonymAdditionFrench).HasColumnName("homonym_addition_french"); + builder.Property(x => x.HomonymAdditionGerman).HasColumnName("homonym_addition_german"); + builder.Property(x => x.HomonymAdditionEnglish).HasColumnName("homonym_addition_english"); + + builder.Property(x => x.IsRemoved).HasColumnName("is_removed"); + + builder.Property(x => x.Puri).HasColumnName("puri"); + builder.Property(x => x.Namespace).HasColumnName("namespace"); + + builder.Property(x => x.VersionAsString).HasColumnName("version_as_string"); + builder.Property(StreetNameVersion.VersionTimestampBackingPropertyName).HasColumnName("version_timestamp"); + + builder.Ignore(x => x.CreatedOnTimestamp); + builder.Property(StreetNameVersion.CreatedOnTimestampBackingPropertyName).HasColumnName("created_on_timestamp"); + + + builder.Ignore(x => x.VersionTimestamp); + + builder.HasIndex(x => x.PersistentLocalId); + builder.HasIndex(x => x.StreetNameId); + builder.HasIndex(x => x.MunicipalityId); + builder.HasIndex(x => x.NisCode); + builder.HasIndex(x => x.Status); + builder.HasIndex(x => x.OsloStatus); + builder.HasIndex(x => x.IsRemoved); + builder.HasIndex(StreetNameVersion.VersionTimestampBackingPropertyName); + } + } +} diff --git a/src/StreetNameRegistry.Projections.Integration/StreetNameVersionExtensions.cs b/src/StreetNameRegistry.Projections.Integration/StreetNameVersionExtensions.cs new file mode 100644 index 000000000..a08385ec3 --- /dev/null +++ b/src/StreetNameRegistry.Projections.Integration/StreetNameVersionExtensions.cs @@ -0,0 +1,98 @@ +namespace StreetNameRegistry.Projections.Integration +{ + using System; + using System.Globalization; + using System.Linq; + using System.Threading; + using System.Threading.Tasks; + using Be.Vlaanderen.Basisregisters.EventHandling; + using Be.Vlaanderen.Basisregisters.GrAr.Provenance; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore; + using Microsoft.EntityFrameworkCore; + + public static class StreetNameVersionExtensions + { + public static async Task NewStreetNameVersion( + this IntegrationContext context, + Guid streetNameId, + Envelope message, + Action applyEventInfoOn, + CancellationToken ct) where T : IHasProvenance, IMessage + { + var item = await context.LatestPosition(streetNameId, ct); + + if (item == null) + throw DatabaseItemNotFound(streetNameId); + + var version = item.CloneAndApplyEventInfo( + message.Position, + message.Message.Provenance.Timestamp, + applyEventInfoOn); + + await context + .StreetNameVersions + .AddAsync(version, ct); + } + + public static async Task NewStreetNameVersion( + this IntegrationContext context, + int persistentLocalId, + Envelope message, + Action applyEventInfoOn, + CancellationToken ct) where T : IHasProvenance, IMessage + { + var item = await context.LatestPosition(persistentLocalId, ct); + + if (item == null) + throw DatabaseItemNotFound(persistentLocalId); + + var version = item.CloneAndApplyEventInfo( + message.Position, + message.Message.Provenance.Timestamp, + applyEventInfoOn); + + await context + .StreetNameVersions + .AddAsync(version, ct); + } + + private static async Task LatestPosition( + this IntegrationContext context, + int persistentLocalId, + CancellationToken ct) + => context + .StreetNameVersions + .Local + .Where(x => x.PersistentLocalId == persistentLocalId) + .OrderByDescending(x => x.Position) + .FirstOrDefault() + ?? await context + .StreetNameVersions + .Where(x => x.PersistentLocalId == persistentLocalId) + .OrderByDescending(x => x.Position) + .FirstOrDefaultAsync(ct); + + private static async Task LatestPosition( + this IntegrationContext context, + Guid streetNameId, + CancellationToken ct) + => context + .StreetNameVersions + .Local + .Where(x => x.StreetNameId == streetNameId) + .OrderByDescending(x => x.Position) + .FirstOrDefault() + ?? await context + .StreetNameVersions + .Where(x => x.StreetNameId == streetNameId) + .OrderByDescending(x => x.Position) + .FirstOrDefaultAsync(ct); + + private static ProjectionItemNotFoundException DatabaseItemNotFound(int persistentLocalId) + => new ProjectionItemNotFoundException(persistentLocalId.ToString(CultureInfo.InvariantCulture)); + + private static ProjectionItemNotFoundException DatabaseItemNotFound(Guid streetNameId) + => new ProjectionItemNotFoundException(streetNameId.ToString("D")); + } +} diff --git a/src/StreetNameRegistry.Projections.Integration/StreetNameVersionProjections.cs b/src/StreetNameRegistry.Projections.Integration/StreetNameVersionProjections.cs new file mode 100644 index 000000000..20602800c --- /dev/null +++ b/src/StreetNameRegistry.Projections.Integration/StreetNameVersionProjections.cs @@ -0,0 +1,478 @@ +namespace StreetNameRegistry.Projections.Integration +{ + using System; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore; + using Converters; + using Infrastructure; + using Microsoft.Extensions.Options; + using Municipality.Events; + using Municipality; + using StreetName.Events; + using System.Linq; + using Microsoft.EntityFrameworkCore; + + [ConnectedProjectionName("Integratie straatnaam versie")] + [ConnectedProjectionDescription("Projectie die de laatste straatnaam data voor de integratie database bijhoudt.")] + public class StreetNameVersionProjections : ConnectedProjection + { + public StreetNameVersionProjections( + IOptions options, + IEventsRepository eventsRepository) + { + #region Legacy + + When>(async (context, message, ct) => + { + var persistentLocalId = await eventsRepository.GetPersistentLocalId(message.Message.StreetNameId); + + if (!persistentLocalId.HasValue) + { + throw new InvalidOperationException($"No persistent local id found for {message.Message.StreetNameId}"); + } + + await context + .StreetNameVersions + .AddAsync( + new StreetNameVersion + { + PersistentLocalId = persistentLocalId.Value, + StreetNameId = message.Message.StreetNameId, + MunicipalityId = message.Message.MunicipalityId, + NisCode = message.Message.NisCode, + Position = message.Position, + VersionTimestamp = message.Message.Provenance.Timestamp, + CreatedOnTimestamp = message.Message.Provenance.Timestamp, + Namespace = options.Value.Namespace, + Puri = $"{options.Value.Namespace}/{persistentLocalId}" + }, ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion( + message.Message.StreetNameId, + message, + entity => { entity.UpdateNameByLanguage(message.Message.Language, message.Message.Name); }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion( + message.Message.StreetNameId, + message, + entity => { entity.UpdateNameByLanguage(message.Message.Language, message.Message.Name); }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion( + message.Message.StreetNameId, + message, + entity => { entity.UpdateNameByLanguage(message.Message.Language, string.Empty); }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion( + message.Message.StreetNameId, + message, + entity => { entity.UpdateNameByLanguage(message.Message.Language, string.Empty); }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion( + message.Message.StreetNameId, + message, + entity => { entity.UpdateHomonymAdditionByLanguage(message.Message.Language, message.Message.HomonymAddition); }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion( + message.Message.StreetNameId, + message, + entity => { entity.UpdateHomonymAdditionByLanguage(message.Message.Language, message.Message.HomonymAddition); }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion( + message.Message.StreetNameId, + message, + entity => { entity.UpdateHomonymAdditionByLanguage(message.Message.Language, string.Empty); }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion( + message.Message.StreetNameId, + message, + entity => { entity.UpdateHomonymAdditionByLanguage(message.Message.Language, string.Empty); }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion( + message.Message.StreetNameId, + message, + _ => { }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion( + message.Message.StreetNameId, + message, + _ => { }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion( + message.Message.StreetNameId, + message, + item => + { + item.IsRemoved = true; + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion( + message.Message.StreetNameId, + message, + entity => { entity.PersistentLocalId = message.Message.PersistentLocalId; }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion( + message.Message.StreetNameId, + message, + entity => + { + entity.Status = StreetNameStatus.Current; + entity.OsloStatus = StreetNameStatus.Current.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion( + message.Message.StreetNameId, + message, + entity => + { + entity.Status = StreetNameStatus.Proposed; + entity.OsloStatus = StreetNameStatus.Proposed.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion( + message.Message.StreetNameId, + message, + entity => + { + entity.Status = StreetNameStatus.Retired; + entity.OsloStatus = StreetNameStatus.Retired.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion( + message.Message.StreetNameId, + message, + entity => + { + entity.Status = StreetNameStatus.Current; + entity.OsloStatus = StreetNameStatus.Current.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion( + message.Message.StreetNameId, + message, + entity => + { + entity.Status = StreetNameStatus.Proposed; + entity.OsloStatus = StreetNameStatus.Proposed.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion( + message.Message.StreetNameId, + message, + entity => + { + entity.Status = StreetNameStatus.Retired; + entity.OsloStatus = StreetNameStatus.Retired.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion( + message.Message.StreetNameId, + message, + entity => + { + entity.Status = null; + entity.OsloStatus = null; + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion( + message.Message.StreetNameId, + message, + entity => + { + entity.Status = null; + entity.OsloStatus = null; + }, + ct); + }); + + #endregion + + When>(async (context, message, ct) => + { + var streetNamePersistentLocalIds = await context.StreetNameVersions.Where(x => x.MunicipalityId == message.Message.MunicipalityId) + .Select(x => x.PersistentLocalId) + .ToListAsync(ct); + + foreach (var persistentLocalId in streetNamePersistentLocalIds) + { + await context.NewStreetNameVersion(persistentLocalId, message, item => + { + item.NisCode = message.Message.NisCode; + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + } + }); + + When>(async (context, message, ct) => + { + var item = new StreetNameVersion + { + MunicipalityId = message.Message.MunicipalityId, + PersistentLocalId = message.Message.PersistentLocalId, + NisCode = message.Message.NisCode, + VersionTimestamp = message.Message.Provenance.Timestamp, + IsRemoved = message.Message.IsRemoved, + CreatedOnTimestamp = message.Message.Provenance.Timestamp, + Namespace = options.Value.Namespace, + Puri = $"{options.Value.Namespace}/{message.Message.PersistentLocalId}" + }; + + item.Position = message.Position; + item.Status = message.Message.Status; + item.OsloStatus = message.Message.Status.Map(); + + foreach (var (language, value) in message.Message.Names) + item.UpdateNameByLanguage(language, value); + foreach (var (language, value) in message.Message.HomonymAdditions) + item.UpdateHomonymAdditionByLanguage(language, value); + + await context + .StreetNameVersions + .AddAsync(item, ct); + }); + + When>(async (context, message, ct) => + { + var item = new StreetNameVersion + { + MunicipalityId = message.Message.MunicipalityId, + PersistentLocalId = message.Message.PersistentLocalId, + NisCode = message.Message.NisCode, + VersionTimestamp = message.Message.Provenance.Timestamp, + IsRemoved = false, + CreatedOnTimestamp = message.Message.Provenance.Timestamp, + Namespace = options.Value.Namespace, + Puri = $"{options.Value.Namespace}/{message.Message.PersistentLocalId}" + }; + + item.Position = message.Position; + item.Status = StreetNameStatus.Proposed; + item.OsloStatus = StreetNameStatus.Proposed.Map(); + + foreach (var (language, value) in message.Message.StreetNameNames) + item.UpdateNameByLanguage(language, value); + + await context + .StreetNameVersions + .AddAsync(item, ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion(message.Message.PersistentLocalId, message, item => + { + item.Status = StreetNameStatus.Current; + item.OsloStatus = StreetNameStatus.Current.Map(); + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion(message.Message.PersistentLocalId, message, item => + { + item.Status = StreetNameStatus.Proposed; + item.OsloStatus = StreetNameStatus.Proposed.Map(); + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion(message.Message.PersistentLocalId, message, item => + { + item.Status = StreetNameStatus.Rejected; + item.OsloStatus = StreetNameStatus.Rejected.Map(); + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion(message.Message.PersistentLocalId, message, item => + { + item.Status = StreetNameStatus.Proposed; + item.OsloStatus = StreetNameStatus.Proposed.Map(); + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion(message.Message.PersistentLocalId, message, item => + { + item.Status = StreetNameStatus.Retired; + item.OsloStatus = StreetNameStatus.Retired.Map(); + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion(message.Message.PersistentLocalId, message, item => + { + item.Status = StreetNameStatus.Retired; + item.OsloStatus = StreetNameStatus.Retired.Map(); + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion(message.Message.PersistentLocalId, message, item => + { + item.Status = StreetNameStatus.Current; + item.OsloStatus = StreetNameStatus.Current.Map(); + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion(message.Message.PersistentLocalId, message, item => + { + foreach (var (language, value) in message.Message.StreetNameNames) + item.UpdateNameByLanguage(language, value); + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion(message.Message.PersistentLocalId, message, item => + { + foreach (var (language, value) in message.Message.StreetNameNames) + item.UpdateNameByLanguage(language, value); + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion(message.Message.PersistentLocalId, message, item => + { + foreach (var (language, value) in message.Message.HomonymAdditions) + item.UpdateHomonymAdditionByLanguage(language, value); + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion(message.Message.PersistentLocalId, message, item => + { + item.Position = message.Position; + foreach (var language in message.Message.Languages) + { + switch (language) + { + case Language.Dutch: + item.HomonymAdditionDutch = null; + break; + case Language.French: + item.HomonymAdditionFrench = null; + break; + case Language.German: + item.HomonymAdditionGerman = null; + break; + case Language.English: + item.HomonymAdditionEnglish = null; + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + }); + + When>(async (context, message, ct) => + { + await context.NewStreetNameVersion(message.Message.PersistentLocalId, message, item => + { + item.IsRemoved = true; + item.VersionTimestamp = message.Message.Provenance.Timestamp; + }, ct); + }); + } + } +} diff --git a/src/StreetNameRegistry.Projections.Integration/paket.references b/src/StreetNameRegistry.Projections.Integration/paket.references new file mode 100644 index 000000000..9bc9c8a37 --- /dev/null +++ b/src/StreetNameRegistry.Projections.Integration/paket.references @@ -0,0 +1,13 @@ +Be.Vlaanderen.Basisregisters.AggregateSource +Be.Vlaanderen.Basisregisters.EventHandling.Autofac +Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql +Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.Npgsql +Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore.Autofac + +Dapper + +Be.Vlaanderen.Basisregisters.GrAr.Common +Be.Vlaanderen.Basisregisters.GrAr.Legacy + +SourceLink.Embed.AllSourceFiles +SourceLink.Copy.PdbFiles diff --git a/src/StreetNameRegistry.Projections.LastChangedList/DataMigrationsContext.cs b/src/StreetNameRegistry.Projections.LastChangedList/DataMigrationsContext.cs index dbf05aa81..deddeec1c 100644 --- a/src/StreetNameRegistry.Projections.LastChangedList/DataMigrationsContext.cs +++ b/src/StreetNameRegistry.Projections.LastChangedList/DataMigrationsContext.cs @@ -5,6 +5,7 @@ namespace StreetNameRegistry.Projections.LastChangedList using System.Threading.Tasks; using Be.Vlaanderen.Basisregisters.ProjectionHandling.LastChangedList; using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer; using Infrastructure; using Microsoft.EntityFrameworkCore; @@ -37,7 +38,7 @@ public override Task SetErrorMessage(string projectionName, string? errorMessage } } - public class DataMigrationContextMigrationFactory : RunnerDbContextMigrationFactory + public class DataMigrationContextMigrationFactory : SqlServerRunnerDbContextMigrationFactory { private static MigrationHistoryConfiguration HistoryConfiguration => new MigrationHistoryConfiguration diff --git a/src/StreetNameRegistry.Projections.LastChangedList/StreetNameLastChangedListModule.cs b/src/StreetNameRegistry.Projections.LastChangedList/StreetNameLastChangedListModule.cs index 3593f8f77..8064219ae 100644 --- a/src/StreetNameRegistry.Projections.LastChangedList/StreetNameLastChangedListModule.cs +++ b/src/StreetNameRegistry.Projections.LastChangedList/StreetNameLastChangedListModule.cs @@ -4,6 +4,7 @@ namespace StreetNameRegistry.Projections.LastChangedList using Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql.EntityFrameworkCore; using Be.Vlaanderen.Basisregisters.ProjectionHandling.LastChangedList; using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using Infrastructure; using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; diff --git a/src/StreetNameRegistry.Projections.LastChangedList/paket.references b/src/StreetNameRegistry.Projections.LastChangedList/paket.references index 3efe86e85..036bb6329 100644 --- a/src/StreetNameRegistry.Projections.LastChangedList/paket.references +++ b/src/StreetNameRegistry.Projections.LastChangedList/paket.references @@ -5,6 +5,7 @@ Microsoft.Extensions.Configuration.EnvironmentVariables Microsoft.Extensions.Configuration.Json Be.Vlaanderen.Basisregisters.ProjectionHandling.LastChangedList +Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore SourceLink.Embed.AllSourceFiles diff --git a/src/StreetNameRegistry.Projections.Legacy/LegacyExtractContextMigrationFactory.cs b/src/StreetNameRegistry.Projections.Legacy/LegacyExtractContextMigrationFactory.cs index d031eaa1e..b2a3f7328 100644 --- a/src/StreetNameRegistry.Projections.Legacy/LegacyExtractContextMigrationFactory.cs +++ b/src/StreetNameRegistry.Projections.Legacy/LegacyExtractContextMigrationFactory.cs @@ -1,10 +1,11 @@ namespace StreetNameRegistry.Projections.Legacy { using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer; using Infrastructure; using Microsoft.EntityFrameworkCore; - public sealed class LegacyContextMigrationFactory : RunnerDbContextMigrationFactory + public sealed class LegacyContextMigrationFactory : SqlServerRunnerDbContextMigrationFactory { public LegacyContextMigrationFactory() : base("LegacyProjectionsAdmin", HistoryConfiguration) diff --git a/src/StreetNameRegistry.Projections.Legacy/LegacyModule.cs b/src/StreetNameRegistry.Projections.Legacy/LegacyModule.cs index 4bd364f09..0d41b04be 100755 --- a/src/StreetNameRegistry.Projections.Legacy/LegacyModule.cs +++ b/src/StreetNameRegistry.Projections.Legacy/LegacyModule.cs @@ -5,6 +5,7 @@ namespace StreetNameRegistry.Projections.Legacy using Autofac; using Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql.EntityFrameworkCore; using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using Infrastructure; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; diff --git a/src/StreetNameRegistry.Projections.Legacy/StreetNameSyndication/StreetNameSyndication.cs b/src/StreetNameRegistry.Projections.Legacy/StreetNameSyndication/StreetNameSyndication.cs index 56e500fc8..ee2d5323e 100755 --- a/src/StreetNameRegistry.Projections.Legacy/StreetNameSyndication/StreetNameSyndication.cs +++ b/src/StreetNameRegistry.Projections.Legacy/StreetNameSyndication/StreetNameSyndication.cs @@ -2,7 +2,7 @@ namespace StreetNameRegistry.Projections.Legacy.StreetNameSyndication { using System; using Be.Vlaanderen.Basisregisters.GrAr.Provenance; - using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using Infrastructure; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/StreetNameRegistry.Projections.Legacy/paket.references b/src/StreetNameRegistry.Projections.Legacy/paket.references index 73ae53e77..3208c53dd 100644 --- a/src/StreetNameRegistry.Projections.Legacy/paket.references +++ b/src/StreetNameRegistry.Projections.Legacy/paket.references @@ -1,6 +1,6 @@ Be.Vlaanderen.Basisregisters.EventHandling.Autofac Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql -Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner +Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore Be.Vlaanderen.Basisregisters.GrAr.Common diff --git a/src/StreetNameRegistry.Projections.Syndication/MigrationsHelper.cs b/src/StreetNameRegistry.Projections.Syndication/MigrationsHelper.cs index 04ced26bc..f29c089f0 100755 --- a/src/StreetNameRegistry.Projections.Syndication/MigrationsHelper.cs +++ b/src/StreetNameRegistry.Projections.Syndication/MigrationsHelper.cs @@ -8,6 +8,7 @@ namespace StreetNameRegistry.Projections.Syndication using Microsoft.Extensions.Logging; using Polly; using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using Infrastructure; public sealed class MigrationsLogger { } diff --git a/src/StreetNameRegistry.Projections.Syndication/SyndicationContext.cs b/src/StreetNameRegistry.Projections.Syndication/SyndicationContext.cs index f6f463573..1c6d4f9a1 100755 --- a/src/StreetNameRegistry.Projections.Syndication/SyndicationContext.cs +++ b/src/StreetNameRegistry.Projections.Syndication/SyndicationContext.cs @@ -4,6 +4,7 @@ namespace StreetNameRegistry.Projections.Syndication using System.IO; using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; using Microsoft.Extensions.Configuration; diff --git a/src/StreetNameRegistry.Projections.Syndication/SyndicationModule.cs b/src/StreetNameRegistry.Projections.Syndication/SyndicationModule.cs index be5d89aa9..39e1152b6 100755 --- a/src/StreetNameRegistry.Projections.Syndication/SyndicationModule.cs +++ b/src/StreetNameRegistry.Projections.Syndication/SyndicationModule.cs @@ -8,6 +8,7 @@ namespace StreetNameRegistry.Projections.Syndication using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; using Be.Vlaanderen.Basisregisters.ProjectionHandling.Syndication; using Autofac; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using Infrastructure; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; diff --git a/src/StreetNameRegistry.Projections.Syndication/paket.references b/src/StreetNameRegistry.Projections.Syndication/paket.references index 50ae752ca..52ab6d870 100755 --- a/src/StreetNameRegistry.Projections.Syndication/paket.references +++ b/src/StreetNameRegistry.Projections.Syndication/paket.references @@ -19,7 +19,7 @@ Microsoft.SyndicationFeed.ReaderWriter Be.Vlaanderen.Basisregisters.EventHandling.Autofac Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql -Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner +Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore.Autofac Be.Vlaanderen.Basisregisters.ProjectionHandling.Syndication diff --git a/src/StreetNameRegistry.Projections.Wfs/WfsContextMigrationFactory.cs b/src/StreetNameRegistry.Projections.Wfs/WfsContextMigrationFactory.cs index c59c4c67d..6ca6aa414 100644 --- a/src/StreetNameRegistry.Projections.Wfs/WfsContextMigrationFactory.cs +++ b/src/StreetNameRegistry.Projections.Wfs/WfsContextMigrationFactory.cs @@ -1,10 +1,11 @@ namespace StreetNameRegistry.Projections.Wfs { using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer; using Infrastructure; using Microsoft.EntityFrameworkCore; - public sealed class WfsContextMigrationFactory : RunnerDbContextMigrationFactory + public sealed class WfsContextMigrationFactory : SqlServerRunnerDbContextMigrationFactory { public WfsContextMigrationFactory() : base("WfsProjectionsAdmin", HistoryConfiguration) diff --git a/src/StreetNameRegistry.Projections.Wfs/WfsModule.cs b/src/StreetNameRegistry.Projections.Wfs/WfsModule.cs index 238fbc672..3096dac10 100755 --- a/src/StreetNameRegistry.Projections.Wfs/WfsModule.cs +++ b/src/StreetNameRegistry.Projections.Wfs/WfsModule.cs @@ -10,6 +10,7 @@ namespace StreetNameRegistry.Projections.Wfs using Microsoft.Data.SqlClient; using Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql.EntityFrameworkCore; using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; public sealed class WfsModule : Module { diff --git a/src/StreetNameRegistry.Projections.Wfs/paket.references b/src/StreetNameRegistry.Projections.Wfs/paket.references index 27194cff1..036ff38a6 100644 --- a/src/StreetNameRegistry.Projections.Wfs/paket.references +++ b/src/StreetNameRegistry.Projections.Wfs/paket.references @@ -1,6 +1,6 @@ Be.Vlaanderen.Basisregisters.EventHandling.Autofac Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql -Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner +Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore.Autofac Be.Vlaanderen.Basisregisters.GrAr.Common diff --git a/src/StreetNameRegistry.Projections.Wms/WmsContextMigrationFactory.cs b/src/StreetNameRegistry.Projections.Wms/WmsContextMigrationFactory.cs index 42e576b48..ad96ea5b5 100644 --- a/src/StreetNameRegistry.Projections.Wms/WmsContextMigrationFactory.cs +++ b/src/StreetNameRegistry.Projections.Wms/WmsContextMigrationFactory.cs @@ -1,10 +1,11 @@ namespace StreetNameRegistry.Projections.Wms { using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer; using Infrastructure; using Microsoft.EntityFrameworkCore; - public sealed class WmsContextMigrationFactory : RunnerDbContextMigrationFactory + public sealed class WmsContextMigrationFactory : SqlServerRunnerDbContextMigrationFactory { public WmsContextMigrationFactory() : base("WmsProjectionsAdmin", HistoryConfiguration) diff --git a/src/StreetNameRegistry.Projections.Wms/WmsModule.cs b/src/StreetNameRegistry.Projections.Wms/WmsModule.cs index c29781a42..cb6d75b07 100755 --- a/src/StreetNameRegistry.Projections.Wms/WmsModule.cs +++ b/src/StreetNameRegistry.Projections.Wms/WmsModule.cs @@ -10,6 +10,7 @@ namespace StreetNameRegistry.Projections.Wms using Microsoft.Data.SqlClient; using Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql.EntityFrameworkCore; using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; public sealed class WmsModule : Module { diff --git a/src/StreetNameRegistry.Projections.Wms/paket.references b/src/StreetNameRegistry.Projections.Wms/paket.references index 27194cff1..036ff38a6 100644 --- a/src/StreetNameRegistry.Projections.Wms/paket.references +++ b/src/StreetNameRegistry.Projections.Wms/paket.references @@ -1,6 +1,6 @@ Be.Vlaanderen.Basisregisters.EventHandling.Autofac Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql -Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner +Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore.Autofac Be.Vlaanderen.Basisregisters.GrAr.Common diff --git a/src/StreetNameRegistry.Projector/Infrastructure/Modules/ApiModule.cs b/src/StreetNameRegistry.Projector/Infrastructure/Modules/ApiModule.cs index 3a69b69d9..2b1c834a3 100644 --- a/src/StreetNameRegistry.Projector/Infrastructure/Modules/ApiModule.cs +++ b/src/StreetNameRegistry.Projector/Infrastructure/Modules/ApiModule.cs @@ -1,6 +1,5 @@ namespace StreetNameRegistry.Projector.Infrastructure.Modules { - using System; using Autofac; using Autofac.Extensions.DependencyInjection; using Be.Vlaanderen.Basisregisters.Api.Exceptions; @@ -23,17 +22,18 @@ namespace StreetNameRegistry.Projector.Infrastructure.Modules using StreetNameRegistry.Infrastructure; using StreetNameRegistry.Projections.Extract; using StreetNameRegistry.Projections.Extract.StreetNameExtract; + using StreetNameRegistry.Projections.Integration; + using StreetNameRegistry.Projections.Integration.Infrastructure; using StreetNameRegistry.Projections.LastChangedList; using StreetNameRegistry.Projections.Legacy; - using StreetNameRegistry.Projections.Legacy.StreetNameDetail; using StreetNameRegistry.Projections.Legacy.StreetNameDetailV2; - using StreetNameRegistry.Projections.Legacy.StreetNameList; using StreetNameRegistry.Projections.Legacy.StreetNameListV2; - using StreetNameRegistry.Projections.Legacy.StreetNameName; using StreetNameRegistry.Projections.Legacy.StreetNameNameV2; + using StreetNameRegistry.Projections.Legacy.StreetNameSyndication; using StreetNameRegistry.Projections.Wfs; + using StreetNameRegistry.Projections.Wfs.StreetNameHelperV2; using StreetNameRegistry.Projections.Wms; - using StreetNameRegistry.Projections.Legacy.StreetNameSyndication; + using LastChangedListContextMigrationFactory = StreetNameRegistry.Projections.LastChangedList.LastChangedListContextMigrationFactory; public sealed class ApiModule : Module { @@ -83,6 +83,30 @@ private void RegisterProjectionSetup(ContainerBuilder builder) RegisterLegacyProjectionsV2(builder); RegisterWfsProjectionsV2(builder); RegisterWmsProjectionsV2(builder); + if(_configuration.GetSection("Integration").GetValue("Enabled", false)) + RegisterIntegrationProjections(builder); + } + + private void RegisterIntegrationProjections(ContainerBuilder builder) + { + builder.RegisterModule( + new IntegrationModule( + _configuration, + _services, + _loggerFactory)); + + builder + .RegisterProjectionMigrator( + _configuration, + _loggerFactory) + .RegisterProjections( + context => new StreetNameLatestItemProjections(context.Resolve>()), + ConnectedProjectionSettings.Default) + .RegisterProjections( + context => new StreetNameVersionProjections( + context.Resolve>(), + context.Resolve()), + ConnectedProjectionSettings.Default); } private void RegisterExtractProjectionsV2(ContainerBuilder builder) @@ -116,7 +140,7 @@ private void RegisterLastChangedProjections(ContainerBuilder builder) _loggerFactory)); builder - .RegisterProjectionMigrator( + .RegisterProjectionMigrator( _configuration, _loggerFactory) .RegisterProjectionMigrator( @@ -160,8 +184,8 @@ private void RegisterWfsProjectionsV2(ContainerBuilder builder) .RegisterProjectionMigrator( _configuration, _loggerFactory) - .RegisterProjections(() => - new StreetNameRegistry.Projections.Wfs.StreetNameHelperV2.StreetNameHelperV2Projections(), + .RegisterProjections(() => + new StreetNameHelperV2Projections(), wfsProjectionSettings); } diff --git a/src/StreetNameRegistry.Projector/Infrastructure/Startup.cs b/src/StreetNameRegistry.Projector/Infrastructure/Startup.cs index 230704b0a..d8409b529 100755 --- a/src/StreetNameRegistry.Projector/Infrastructure/Startup.cs +++ b/src/StreetNameRegistry.Projector/Infrastructure/Startup.cs @@ -26,6 +26,7 @@ namespace StreetNameRegistry.Projector.Infrastructure using StreetNameRegistry.Projections.Wfs; using StreetNameRegistry.Projections.Wms; using Microsoft.OpenApi.Models; + using StreetNameRegistry.Projections.Integration.Infrastructure; /// Represents the startup process for the application. public class Startup @@ -96,12 +97,23 @@ public IServiceProvider ConfigureServices(IServiceCollection services) .GetSection("ConnectionStrings") .GetChildren(); - foreach (var connectionString in connectionStrings) + if (!_configuration.GetSection("Integration").GetValue("Enabled", false)) + connectionStrings = connectionStrings + .Where(x => !x.Key.StartsWith("Integration", StringComparison.OrdinalIgnoreCase)) + .ToList(); + + foreach (var connectionString in connectionStrings.Where(x => !x.Value.Contains("host", StringComparison.OrdinalIgnoreCase))) health.AddSqlServer( connectionString.Value, name: $"sqlserver-{connectionString.Key.ToLowerInvariant()}", tags: new[] { DatabaseTag, "sql", "sqlserver" }); + foreach (var connectionString in connectionStrings.Where(x => x.Value.Contains("host", StringComparison.OrdinalIgnoreCase))) + health.AddNpgSql( + connectionString.Value, + name: $"npgsql-{connectionString.Key.ToLowerInvariant()}", + tags: new[] {DatabaseTag, "sql", "npgsql"}); + health.AddDbContextCheck( $"dbcontext-{nameof(ExtractContext).ToLowerInvariant()}", tags: new[] { DatabaseTag, "sql", "sqlserver" }); @@ -124,7 +136,8 @@ public IServiceProvider ConfigureServices(IServiceCollection services) } } }) - .Configure(_configuration.GetSection("Extract")); + .Configure(_configuration.GetSection("Extract")) + .Configure(_configuration.GetSection("Integration")); var containerBuilder = new ContainerBuilder(); containerBuilder.RegisterModule(new LoggingModule(_configuration, services)); diff --git a/src/StreetNameRegistry.Projector/Projections/ProjectionsController.cs b/src/StreetNameRegistry.Projector/Projections/ProjectionsController.cs index 31fb21306..5c6576846 100644 --- a/src/StreetNameRegistry.Projector/Projections/ProjectionsController.cs +++ b/src/StreetNameRegistry.Projector/Projections/ProjectionsController.cs @@ -22,6 +22,7 @@ public ProjectionsController( RegisterConnectionString(Schema.Extract, configuration.GetConnectionString("ExtractProjections")); RegisterConnectionString(Schema.Wfs, configuration.GetConnectionString("WfsProjections")); RegisterConnectionString(Schema.Wms, configuration.GetConnectionString("WmsProjections")); + RegisterConnectionString(Schema.Integration, configuration.GetConnectionString("IntegrationProjections")); } } } diff --git a/src/StreetNameRegistry.Projector/StreetNameRegistry.Projector.csproj b/src/StreetNameRegistry.Projector/StreetNameRegistry.Projector.csproj index 2224f605f..f64a8ca27 100644 --- a/src/StreetNameRegistry.Projector/StreetNameRegistry.Projector.csproj +++ b/src/StreetNameRegistry.Projector/StreetNameRegistry.Projector.csproj @@ -33,6 +33,7 @@ + diff --git a/src/StreetNameRegistry.Projector/appsettings.json b/src/StreetNameRegistry.Projector/appsettings.json index a03f71e9d..8e33da08a 100755 --- a/src/StreetNameRegistry.Projector/appsettings.json +++ b/src/StreetNameRegistry.Projector/appsettings.json @@ -12,7 +12,9 @@ "WmsProjections": "Server=(localdb)\\mssqllocaldb;Database=EFProviders.InMemory.StreetNameRegistry;Trusted_Connection=True;TrustServerCertificate=True;", "WmsProjectionsAdmin": "Server=(localdb)\\mssqllocaldb;Database=EFProviders.InMemory.StreetNameRegistry;Trusted_Connection=True;TrustServerCertificate=True;", "Syndication": "Server=(localdb)\\mssqllocaldb;Database=EFProviders.InMemory.StreetNameRegistry;Trusted_Connection=True;TrustServerCertificate=True;", - "Consumer": "Server=(localdb)\\mssqllocaldb;Database=EFProviders.InMemory.StreetNameRegistry;Trusted_Connection=True;TrustServerCertificate=True;" + "Consumer": "Server=(localdb)\\mssqllocaldb;Database=EFProviders.InMemory.StreetNameRegistry;Trusted_Connection=True;TrustServerCertificate=True;", + "IntegrationProjections": ".", + "IntegrationProjectionsAdmin": "." }, "DataDog": { @@ -23,6 +25,11 @@ "BaseUrl": "https://api.staging-basisregisters.vlaanderen/", + "Integration": { + "Namespace": "https://data.vlaanderen.be/id/straatnaam", + "Enabled": false + }, + "Extract": { "DataVlaanderenNamespace": "https://data.vlaanderen.be/id/straatnaam" }, diff --git a/src/StreetNameRegistry.Projector/paket.references b/src/StreetNameRegistry.Projector/paket.references index 59a1f45c0..fdbe0dc3c 100644 --- a/src/StreetNameRegistry.Projector/paket.references +++ b/src/StreetNameRegistry.Projector/paket.references @@ -1,9 +1,17 @@ +Be.Vlaanderen.Basisregisters.AggregateSource Be.Vlaanderen.Basisregisters.Api Be.Vlaanderen.Basisregisters.EventHandling.Autofac Be.Vlaanderen.Basisregisters.Projector +NodaTime + +Npgsql +Npgsql.EntityFrameworkCore.PostgreSQL + AspNetCore.HealthChecks.SqlServer +AspNetCore.HealthChecks.NpgSql + Dapper SourceLink.Embed.AllSourceFiles diff --git a/test/StreetNameRegistry.Tests/Builders/StreetNameNamesWereChangedBuilder.cs b/test/StreetNameRegistry.Tests/Builders/StreetNameNamesWereChangedBuilder.cs new file mode 100644 index 000000000..de7ea274a --- /dev/null +++ b/test/StreetNameRegistry.Tests/Builders/StreetNameNamesWereChangedBuilder.cs @@ -0,0 +1,51 @@ +namespace StreetNameRegistry.Tests.Builders +{ + using Be.Vlaanderen.Basisregisters.GrAr.Provenance; + using global::AutoFixture; + using Municipality; + using Municipality.Events; + + public class StreetNameNamesWereChangedBuilder + { + private readonly Fixture _fixture; + private MunicipalityId? _municipalityId; + private PersistentLocalId? _persistentLocalId; + private Names? _names; + + public StreetNameNamesWereChangedBuilder(Fixture fixture) + { + _fixture = fixture; + } + + public StreetNameNamesWereChangedBuilder WithMunicipalityId(MunicipalityId municipalityId) + { + _municipalityId = municipalityId; + return this; + } + + public StreetNameNamesWereChangedBuilder WithPersistentLocalId(int persistentLocalId) + { + _persistentLocalId = new PersistentLocalId(persistentLocalId); + return this; + } + + public StreetNameNamesWereChangedBuilder WithNames(Names names) + { + _names = names; + return this; + } + + public StreetNameNamesWereChanged Build() + { + var streetNameNamesWereCorrected = new StreetNameNamesWereChanged( + _municipalityId ?? _fixture.Create(), + _persistentLocalId ?? _fixture.Create(), + _names ?? _fixture.Create() + ); + + ((ISetProvenance)streetNameNamesWereCorrected).SetProvenance(_fixture.Create()); + + return streetNameNamesWereCorrected; + } + } +} diff --git a/test/StreetNameRegistry.Tests/Builders/StreetNameNamesWereCorrectedBuilder.cs b/test/StreetNameRegistry.Tests/Builders/StreetNameNamesWereCorrectedBuilder.cs new file mode 100644 index 000000000..f8701affa --- /dev/null +++ b/test/StreetNameRegistry.Tests/Builders/StreetNameNamesWereCorrectedBuilder.cs @@ -0,0 +1,51 @@ +namespace StreetNameRegistry.Tests.Builders +{ + using Be.Vlaanderen.Basisregisters.GrAr.Provenance; + using global::AutoFixture; + using Municipality; + using Municipality.Events; + + public class StreetNameNamesWereCorrectedBuilder + { + private readonly Fixture _fixture; + private MunicipalityId? _municipalityId; + private PersistentLocalId? _persistentLocalId; + private Names? _names; + + public StreetNameNamesWereCorrectedBuilder(Fixture fixture) + { + _fixture = fixture; + } + + public StreetNameNamesWereCorrectedBuilder WithMunicipalityId(MunicipalityId municipalityId) + { + _municipalityId = municipalityId; + return this; + } + + public StreetNameNamesWereCorrectedBuilder WithPersistentLocalId(int persistentLocalId) + { + _persistentLocalId = new PersistentLocalId(persistentLocalId); + return this; + } + + public StreetNameNamesWereCorrectedBuilder WithNames(Names names) + { + _names = names; + return this; + } + + public StreetNameNamesWereCorrected Build() + { + var streetNameNamesWereCorrected = new StreetNameNamesWereCorrected( + _municipalityId ?? _fixture.Create(), + _persistentLocalId ?? _fixture.Create(), + _names ?? _fixture.Create() + ); + + ((ISetProvenance)streetNameNamesWereCorrected).SetProvenance(_fixture.Create()); + + return streetNameNamesWereCorrected; + } + } +} diff --git a/test/StreetNameRegistry.Tests/Generate/Generate.cs b/test/StreetNameRegistry.Tests/Generate/Generate.cs index 163113ab3..e2943865f 100755 --- a/test/StreetNameRegistry.Tests/Generate/Generate.cs +++ b/test/StreetNameRegistry.Tests/Generate/Generate.cs @@ -219,7 +219,7 @@ public static Generator StreetNameWithHomonymString(string homonymAdditi return new Generator(r => StreetNameString.Select(s => s + "_" + homonymAddition).Generate(r)); } - + public static Generator This(T t) => new Generator(r => t); public static class EventsFor @@ -310,6 +310,24 @@ public static StreetNameWasNamed WithProvenance(this StreetNameWasNamed e, Prove return newEvent; } + public static StreetNameNameWasCorrected WithName(this StreetNameNameWasCorrected e, string name) + { + return new StreetNameNameWasCorrected(new StreetNameId(e.StreetNameId), new StreetNameName(name, e.Language)); + } + + public static StreetNameNameWasCorrected WithLanguage(this StreetNameNameWasCorrected e, Language? language) + { + return new StreetNameNameWasCorrected(new StreetNameId(e.StreetNameId), new StreetNameName(e.Name, language)); + } + + public static StreetNameNameWasCorrected WithProvenance(this StreetNameNameWasCorrected e, Provenance provenance) + { + var newEvent = new StreetNameNameWasCorrected(new StreetNameId(e.StreetNameId), new StreetNameName(e.Name, e.Language)); + ((ISetProvenance)newEvent).SetProvenance(provenance); + + return newEvent; + } + public static StreetNameNameWasCleared WithId(this StreetNameNameWasCleared e, Guid id) { return new StreetNameNameWasCleared(new StreetNameId(id), e.Language); @@ -327,6 +345,51 @@ public static StreetNameNameWasCleared WithProvenance(this StreetNameNameWasClea return newEvent; } +public static StreetNameNameWasCorrectedToCleared WithId(this StreetNameNameWasCorrectedToCleared e, Guid id) + { + return new StreetNameNameWasCorrectedToCleared(new StreetNameId(id), e.Language); + } + + public static StreetNameNameWasCorrectedToCleared WithLanguage(this StreetNameNameWasCorrectedToCleared e, Language? language) + { + return new StreetNameNameWasCorrectedToCleared(new StreetNameId(e.StreetNameId), language); + } + + public static StreetNameNameWasCorrectedToCleared WithProvenance(this StreetNameNameWasCorrectedToCleared e, Provenance provenance) + { + var newEvent = new StreetNameNameWasCorrectedToCleared(new StreetNameId(e.StreetNameId), e.Language); + ((ISetProvenance)newEvent).SetProvenance(provenance); + + return newEvent; + } + + public static StreetNameHomonymAdditionWasDefined WithHomonymAddition(this StreetNameHomonymAdditionWasDefined e, StreetNameHomonymAddition homonymAddition, Provenance provenance) + { + var newEvent = new StreetNameHomonymAdditionWasDefined(new StreetNameId(e.StreetNameId), homonymAddition); + ((ISetProvenance)newEvent).SetProvenance(provenance); + return newEvent; + } + + public static StreetNameHomonymAdditionWasCleared WithLanguage(this StreetNameHomonymAdditionWasCleared e, Language language, Provenance provenance) + { + var newEvent = new StreetNameHomonymAdditionWasCleared(new StreetNameId(e.StreetNameId), language); + ((ISetProvenance)newEvent).SetProvenance(provenance); + return newEvent; + } + + public static StreetNameHomonymAdditionWasCorrectedToCleared WithLanguage(this StreetNameHomonymAdditionWasCorrectedToCleared e, Language language, Provenance provenance) + { + var newEvent = new StreetNameHomonymAdditionWasCorrectedToCleared(new StreetNameId(e.StreetNameId), language); + ((ISetProvenance)newEvent).SetProvenance(provenance); + return newEvent; + } + + public static StreetNameHomonymAdditionWasCorrected WithHomonymAddition(this StreetNameHomonymAdditionWasCorrected e, StreetNameHomonymAddition homonymAddition, Provenance provenance) + { + var newEvent = new StreetNameHomonymAdditionWasCorrected(new StreetNameId(e.StreetNameId), homonymAddition); + ((ISetProvenance)newEvent).SetProvenance(provenance); + return newEvent; + } public static StreetNameBecameComplete WithId(this StreetNameBecameComplete e, Guid id) { diff --git a/test/StreetNameRegistry.Tests/Integration/IntegrationTests.cs b/test/StreetNameRegistry.Tests/Integration/IntegrationTests.cs new file mode 100644 index 000000000..740fa9dfb --- /dev/null +++ b/test/StreetNameRegistry.Tests/Integration/IntegrationTests.cs @@ -0,0 +1,30 @@ +namespace StreetNameRegistry.Tests.Integration +{ + using System; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Testing; + using Microsoft.EntityFrameworkCore; + using Projections.Integration; + + public abstract class IntegrationProjectionTest + where TProjection : ConnectedProjection + { + protected ConnectedProjectionTest Sut { get; } + + protected IntegrationProjectionTest() + { + Sut = new ConnectedProjectionTest(CreateContext, CreateProjection); + } + + protected virtual IntegrationContext CreateContext() + { + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase(Guid.NewGuid().ToString()) + .Options; + + return new IntegrationContext(options); + } + + protected abstract TProjection CreateProjection(); + } +} diff --git a/test/StreetNameRegistry.Tests/Integration/StreetNameLatestItemProjectionTests.cs b/test/StreetNameRegistry.Tests/Integration/StreetNameLatestItemProjectionTests.cs new file mode 100644 index 000000000..aca677445 --- /dev/null +++ b/test/StreetNameRegistry.Tests/Integration/StreetNameLatestItemProjectionTests.cs @@ -0,0 +1,642 @@ +namespace StreetNameRegistry.Tests.Integration +{ + using System.Collections.Generic; + using System.Threading.Tasks; + using AutoFixture; + using Be.Vlaanderen.Basisregisters.GrAr.Common.Pipes; + using Be.Vlaanderen.Basisregisters.GrAr.Legacy.Straatnaam; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore; + using Builders; + using FluentAssertions; + using global::AutoFixture; + using Microsoft.Extensions.Options; + using Municipality; + using Municipality.Events; + using Projections.Integration; + using Projections.Integration.Infrastructure; + using Xunit; + + public class StreetNameLatestItemProjectionTests : IntegrationProjectionTest + { + private const string Namespace = "https://data.vlaanderen.be/id/straatnaam"; + private readonly Fixture _fixture; + + public StreetNameLatestItemProjectionTests() + { + _fixture = new Fixture(); + _fixture.Customize(new InfrastructureCustomization()); + _fixture.Customize(new WithFixedPersistentLocalId()); + _fixture.Customize(new WithFixedMunicipalityId()); + } + + [Fact] + public async Task WhenMunicipalityNisCodeWasChanged() + { + var streetNameWasMigratedToMunicipality = new StreetNameWasMigratedToMunicipalityBuilder(_fixture) + .Build(); + + var municipalityNisCodeWasChanged = _fixture.Create(); + + var position = _fixture.Create(); + + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + var secondMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasMigratedToMunicipality, metadata)), + new Envelope(new Envelope(municipalityNisCodeWasChanged, secondMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameLatestItems.FindAsync(streetNameWasMigratedToMunicipality.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.Status.Should().Be(streetNameWasMigratedToMunicipality.Status); + expectedLatestItem.NisCode.Should().Be(municipalityNisCodeWasChanged.NisCode); + expectedLatestItem.MunicipalityId.Should().Be(streetNameWasMigratedToMunicipality.MunicipalityId); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameWasMigratedToMunicipality.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(municipalityNisCodeWasChanged.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameWasMigratedToMunicipality() + { + var streetNameWasMigratedToMunicipality = new StreetNameWasMigratedToMunicipalityBuilder(_fixture) + .WithNames(new Names + { + new("Bergstraat", Language.Dutch), + new("Rue De Montaigne", Language.French), + new("Mountain street", Language.English), + new("Bergstraat de", Language.German), + }) + .WithHomonymAdditions(new HomonymAdditions(new[] + { + new StreetNameHomonymAddition("ABC", Language.Dutch), + new StreetNameHomonymAddition("DEF", Language.French), + new StreetNameHomonymAddition("AZE", Language.English), + new StreetNameHomonymAddition("QSD", Language.German), + })) + .Build(); + + var position = _fixture.Create(); + + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + await Sut + .Given(new Envelope(new Envelope(streetNameWasMigratedToMunicipality, metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameLatestItems.FindAsync(streetNameWasMigratedToMunicipality.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.Status.Should().Be(streetNameWasMigratedToMunicipality.Status); + expectedLatestItem.NisCode.Should().Be(streetNameWasMigratedToMunicipality.NisCode); + expectedLatestItem.IsRemoved.Should().Be(streetNameWasMigratedToMunicipality.IsRemoved); + expectedLatestItem.MunicipalityId.Should().Be(streetNameWasMigratedToMunicipality.MunicipalityId); + + expectedLatestItem.NameDutch.Should().Be("Bergstraat"); + expectedLatestItem.NameFrench.Should().Be("Rue De Montaigne"); + expectedLatestItem.NameEnglish.Should().Be("Mountain street"); + expectedLatestItem.NameGerman.Should().Be("Bergstraat de"); + + expectedLatestItem.HomonymAdditionDutch.Should().Be("ABC"); + expectedLatestItem.HomonymAdditionFrench.Should().Be("DEF"); + expectedLatestItem.HomonymAdditionEnglish.Should().Be("AZE"); + expectedLatestItem.HomonymAdditionGerman.Should().Be("QSD"); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameWasMigratedToMunicipality.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasMigratedToMunicipality.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameWasProposedV2() + { + var streetNameWasProposedV2 = new StreetNameWasProposedV2Builder(_fixture) + .WithNames(new Names + { + new("Bergstraat", Language.Dutch), + new("Rue De Montaigne", Language.French), + new("Mountain street", Language.English), + new("Bergstraat de", Language.German), + }) + .Build(); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + + await Sut + .Given(new Envelope(new Envelope(streetNameWasProposedV2, firstEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameLatestItems.FindAsync(streetNameWasProposedV2.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.Status.Should().Be(StreetNameStatus.Proposed); + expectedLatestItem.OsloStatus.Should().Be(StraatnaamStatus.Voorgesteld.ToString()); + expectedLatestItem.NisCode.Should().Be(streetNameWasProposedV2.NisCode); + expectedLatestItem.MunicipalityId.Should().Be(streetNameWasProposedV2.MunicipalityId); + + expectedLatestItem.IsRemoved.Should().BeFalse(); + + expectedLatestItem.NameDutch.Should().Be("Bergstraat"); + expectedLatestItem.NameFrench.Should().Be("Rue De Montaigne"); + expectedLatestItem.NameEnglish.Should().Be("Mountain street"); + expectedLatestItem.NameGerman.Should().Be("Bergstraat de"); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameWasProposedV2.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasProposedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameWasApproved() + { + var streetNameWasMigratedToMunicipality = _fixture.Create(); + var streetNameWasApproved = _fixture.Create(); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasMigratedToMunicipality, firstEventMetadata)), + new Envelope(new Envelope(streetNameWasApproved, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameLatestItems.FindAsync(streetNameWasApproved.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.Status.Should().Be(StreetNameStatus.Current); + expectedLatestItem.OsloStatus.Should().Be(StraatnaamStatus.InGebruik.ToString()); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameWasApproved.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasApproved.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameWasCorrectedFromApprovedToProposed() + { + var streetNameWasMigratedToMunicipality = _fixture.Create(); + var streetNameWasCorrectedFromApprovedToProposed = _fixture.Create(); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasMigratedToMunicipality, firstEventMetadata)), + new Envelope(new Envelope(streetNameWasCorrectedFromApprovedToProposed, + secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameLatestItems.FindAsync(streetNameWasCorrectedFromApprovedToProposed.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.Status.Should().Be(StreetNameStatus.Proposed); + expectedLatestItem.OsloStatus.Should().Be(StraatnaamStatus.Voorgesteld.ToString()); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameWasCorrectedFromApprovedToProposed.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasCorrectedFromApprovedToProposed.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameWasRejected() + { + var streetNameWasMigratedToMunicipality = _fixture.Create(); + var streetNameWasRejected = _fixture.Create(); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasMigratedToMunicipality, firstEventMetadata)), + new Envelope(new Envelope(streetNameWasRejected, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameLatestItems.FindAsync(streetNameWasRejected.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.Status.Should().Be(StreetNameStatus.Rejected); + expectedLatestItem.OsloStatus.Should().Be(StraatnaamStatus.Afgekeurd.ToString()); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameWasRejected.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasRejected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameWasCorrectedFromRejectedToProposed() + { + var streetNameWasMigratedToMunicipality = _fixture.Create(); + var streetNameWasCorrectedFromRejectedToProposed = _fixture.Create(); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasMigratedToMunicipality, firstEventMetadata)), + new Envelope(new Envelope(streetNameWasCorrectedFromRejectedToProposed, + secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameLatestItems.FindAsync(streetNameWasCorrectedFromRejectedToProposed.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.Status.Should().Be(StreetNameStatus.Proposed); + expectedLatestItem.OsloStatus.Should().Be(StraatnaamStatus.Voorgesteld.ToString()); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameWasCorrectedFromRejectedToProposed.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasCorrectedFromRejectedToProposed.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameWasRetiredV2() + { + var streetNameWasMigratedToMunicipality = _fixture.Create(); + var streetNameWasRetiredV2 = _fixture.Create(); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasMigratedToMunicipality, firstEventMetadata)), + new Envelope(new Envelope(streetNameWasRetiredV2, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameLatestItems.FindAsync(streetNameWasRetiredV2.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.Status.Should().Be(StreetNameStatus.Retired); + expectedLatestItem.OsloStatus.Should().Be(StraatnaamStatus.Gehistoreerd.ToString()); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameWasRetiredV2.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasRetiredV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameWasRenamed() + { + var streetNameWasMigratedToMunicipality = _fixture.Create(); + var streetNameWasRenamed = _fixture.Create(); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasMigratedToMunicipality, firstEventMetadata)), + new Envelope(new Envelope(streetNameWasRenamed, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameLatestItems.FindAsync(streetNameWasRenamed.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.Status.Should().Be(StreetNameStatus.Retired); + expectedLatestItem.OsloStatus.Should().Be(StraatnaamStatus.Gehistoreerd.ToString()); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameWasRenamed.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasRenamed.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameWasCorrectedFromRetiredToCurrent() + { + var streetNameWasMigratedToMunicipality = _fixture.Create(); + var streetNameWasCorrectedFromRetiredToCurrent = _fixture.Create(); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasMigratedToMunicipality, firstEventMetadata)), + new Envelope(new Envelope(streetNameWasCorrectedFromRetiredToCurrent, + secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameLatestItems.FindAsync(streetNameWasCorrectedFromRetiredToCurrent.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.Status.Should().Be(StreetNameStatus.Current); + expectedLatestItem.OsloStatus.Should().Be(StraatnaamStatus.InGebruik.ToString()); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameWasCorrectedFromRetiredToCurrent.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasCorrectedFromRetiredToCurrent.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameNamesWereCorrected() + { + var streetNameWasMigratedToMunicipality = _fixture.Create(); + var streetNameNamesWereCorrected = new StreetNameNamesWereCorrectedBuilder(_fixture) + .WithNames(new Names + { + new("Bergstraat", Language.Dutch), + new("Rue De Montaigne", Language.French), + new("Mountain street", Language.English), + new("Bergstraat de", Language.German), + }) + .Build(); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasMigratedToMunicipality, firstEventMetadata)), + new Envelope(new Envelope(streetNameNamesWereCorrected, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameLatestItems.FindAsync(streetNameNamesWereCorrected.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + + expectedLatestItem!.NameDutch.Should().Be("Bergstraat"); + expectedLatestItem.NameFrench.Should().Be("Rue De Montaigne"); + expectedLatestItem.NameEnglish.Should().Be("Mountain street"); + expectedLatestItem.NameGerman.Should().Be("Bergstraat de"); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameNamesWereCorrected.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameNamesWereCorrected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameNamesWereChanged() + { + var streetNameWasMigratedToMunicipality = _fixture.Create(); + var streetNameNamesWereChanged = new StreetNameNamesWereChangedBuilder(_fixture) + .WithNames(new Names + { + new("Bergstraat", Language.Dutch), + new("Rue De Montaigne", Language.French), + new("Mountain street", Language.English), + new("Bergstraat de", Language.German), + }) + .Build(); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasMigratedToMunicipality, firstEventMetadata)), + new Envelope(new Envelope(streetNameNamesWereChanged, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameLatestItems.FindAsync(streetNameNamesWereChanged.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + + expectedLatestItem!.NameDutch.Should().Be("Bergstraat"); + expectedLatestItem.NameFrench.Should().Be("Rue De Montaigne"); + expectedLatestItem.NameEnglish.Should().Be("Mountain street"); + expectedLatestItem.NameGerman.Should().Be("Bergstraat de"); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameNamesWereChanged.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameNamesWereChanged.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameHomonymAdditionsWereCorrected() + { + var streetNameWasMigratedToMunicipality = _fixture.Create(); + var streetNameHomonymAdditionsWereCorrected = new StreetNameHomonymAdditionsWereCorrectedBuilder(_fixture) + .WithHomonymAdditions(new HomonymAdditions(new[] + { + new StreetNameHomonymAddition("ABC", Language.Dutch), + new StreetNameHomonymAddition("DEF", Language.French), + new StreetNameHomonymAddition("AZE", Language.English), + new StreetNameHomonymAddition("QSD", Language.German), + })) + .Build(); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasMigratedToMunicipality, firstEventMetadata)), + new Envelope(new Envelope(streetNameHomonymAdditionsWereCorrected, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameLatestItems.FindAsync(streetNameHomonymAdditionsWereCorrected.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + + expectedLatestItem!.HomonymAdditionDutch.Should().Be("ABC"); + expectedLatestItem.HomonymAdditionFrench.Should().Be("DEF"); + expectedLatestItem.HomonymAdditionEnglish.Should().Be("AZE"); + expectedLatestItem.HomonymAdditionGerman.Should().Be("QSD"); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameHomonymAdditionsWereCorrected.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameHomonymAdditionsWereCorrected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameHomonymAdditionsWereRemoved() + { + var streetNameWasMigratedToMunicipality = new StreetNameWasMigratedToMunicipalityBuilder(_fixture) + .WithHomonymAdditions(new HomonymAdditions(new[] + { + new StreetNameHomonymAddition("ABC", Language.Dutch), + new StreetNameHomonymAddition("DEF", Language.French), + new StreetNameHomonymAddition("AZE", Language.English), + new StreetNameHomonymAddition("QSD", Language.German), + })) + .Build(); + var streetNameHomonymAdditionsWereCorrected = new StreetNameHomonymAdditionsWereRemovedBuilder(_fixture) + .WithLanguages(new List + { + Language.Dutch, + Language.French, + Language.English, + Language.German + }) + .Build(); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasMigratedToMunicipality, firstEventMetadata)), + new Envelope(new Envelope(streetNameHomonymAdditionsWereCorrected, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameLatestItems.FindAsync(streetNameHomonymAdditionsWereCorrected.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + + expectedLatestItem!.HomonymAdditionDutch.Should().BeNull(); + expectedLatestItem.HomonymAdditionFrench.Should().BeNull(); + expectedLatestItem.HomonymAdditionEnglish.Should().BeNull(); + expectedLatestItem.HomonymAdditionGerman.Should().BeNull(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameHomonymAdditionsWereCorrected.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameHomonymAdditionsWereCorrected.Provenance.Timestamp); + }); + } + + + protected override StreetNameLatestItemProjections CreateProjection() + => new StreetNameLatestItemProjections( + new OptionsWrapper(new IntegrationOptions { Namespace = Namespace })); + } +} diff --git a/test/StreetNameRegistry.Tests/Integration/StreetNameVersionProjectionTests.cs b/test/StreetNameRegistry.Tests/Integration/StreetNameVersionProjectionTests.cs new file mode 100644 index 000000000..c9e27ae71 --- /dev/null +++ b/test/StreetNameRegistry.Tests/Integration/StreetNameVersionProjectionTests.cs @@ -0,0 +1,1709 @@ +namespace StreetNameRegistry.Tests.Integration +{ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + using AutoFixture; + using Be.Vlaanderen.Basisregisters.GrAr.Common.Pipes; + using Be.Vlaanderen.Basisregisters.GrAr.Legacy.Straatnaam; + using Be.Vlaanderen.Basisregisters.GrAr.Provenance; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore; + using Builders; + using FluentAssertions; + using Generate; + using global::AutoFixture; + using Microsoft.EntityFrameworkCore; + using Microsoft.Extensions.Options; + using Moq; + using Municipality; + using Municipality.Events; + using Projections.Integration; + using Projections.Integration.Converters; + using Projections.Integration.Infrastructure; + using StreetName.Events; + using Xunit; + + public class StreetNameVersionProjectionTests : IntegrationProjectionTest + { + private const string Namespace = "https://data.vlaanderen.be/id/straatnaam"; + private readonly Fixture _fixture; + private readonly Mock _eventsRepositoryMock; + + public StreetNameVersionProjectionTests() + { + _fixture = new Fixture(); + _fixture.Customize(new InfrastructureCustomization()); + _fixture.Customize(new WithFixedPersistentLocalId()); + _fixture.Customize(new WithFixedStreetNameId()); + _fixture.Customize(new WithFixedMunicipalityId()); + + _eventsRepositoryMock = new Mock(); + } + + [Fact] + public async Task WhenMunicipalityNisCodeWasChanged() + { + var streetNameWasMigratedToMunicipality = new StreetNameWasMigratedToMunicipalityBuilder(_fixture) + .Build(); + + var municipalityNisCodeWasChanged = _fixture.Create(); + + var position = _fixture.Create(); + + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + var secondMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1} + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasMigratedToMunicipality, metadata)), + new Envelope(new Envelope(municipalityNisCodeWasChanged, secondMetadata))) + .Then(async ct => + { + var streetNameVersion = + await ct.StreetNameVersions.FindAsync(position + 1, streetNameWasMigratedToMunicipality.PersistentLocalId); + streetNameVersion.Should().NotBeNull(); + streetNameVersion!.Status.Should().Be(streetNameWasMigratedToMunicipality.Status); + streetNameVersion.NisCode.Should().Be(municipalityNisCodeWasChanged.NisCode); + streetNameVersion.MunicipalityId.Should().Be(streetNameWasMigratedToMunicipality.MunicipalityId); + + streetNameVersion.Namespace.Should().Be(Namespace); + streetNameVersion.Puri.Should().Be($"{Namespace}/{streetNameWasMigratedToMunicipality.PersistentLocalId}"); + streetNameVersion.VersionTimestamp.Should().Be(municipalityNisCodeWasChanged.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameWasMigratedToMunicipality() + { + var streetNameWasMigratedToMunicipality = new StreetNameWasMigratedToMunicipalityBuilder(_fixture) + .WithNames(new Names + { + new("Bergstraat", Language.Dutch), + new("Rue De Montaigne", Language.French), + new("Mountain street", Language.English), + new("Bergstraat de", Language.German), + }) + .WithHomonymAdditions(new HomonymAdditions(new[] + { + new StreetNameHomonymAddition("ABC", Language.Dutch), + new StreetNameHomonymAddition("DEF", Language.French), + new StreetNameHomonymAddition("AZE", Language.English), + new StreetNameHomonymAddition("QSD", Language.German), + })) + .Build(); + + var position = _fixture.Create(); + + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + await Sut + .Given(new Envelope(new Envelope(streetNameWasMigratedToMunicipality, metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions.FindAsync(position, streetNameWasMigratedToMunicipality.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.Status.Should().Be(streetNameWasMigratedToMunicipality.Status); + expectedLatestItem.OsloStatus.Should().Be(streetNameWasMigratedToMunicipality.Status.Map()); + expectedLatestItem.NisCode.Should().Be(streetNameWasMigratedToMunicipality.NisCode); + expectedLatestItem.IsRemoved.Should().Be(streetNameWasMigratedToMunicipality.IsRemoved); + expectedLatestItem.MunicipalityId.Should().Be(streetNameWasMigratedToMunicipality.MunicipalityId); + + expectedLatestItem.NameDutch.Should().Be("Bergstraat"); + expectedLatestItem.NameFrench.Should().Be("Rue De Montaigne"); + expectedLatestItem.NameEnglish.Should().Be("Mountain street"); + expectedLatestItem.NameGerman.Should().Be("Bergstraat de"); + + expectedLatestItem.HomonymAdditionDutch.Should().Be("ABC"); + expectedLatestItem.HomonymAdditionFrench.Should().Be("DEF"); + expectedLatestItem.HomonymAdditionEnglish.Should().Be("AZE"); + expectedLatestItem.HomonymAdditionGerman.Should().Be("QSD"); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameWasMigratedToMunicipality.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasMigratedToMunicipality.Provenance.Timestamp); + expectedLatestItem.CreatedOnTimestamp.Should().Be(streetNameWasMigratedToMunicipality.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameWasProposedV2() + { + var streetNameWasProposedV2 = new StreetNameWasProposedV2Builder(_fixture) + .WithNames(new Names + { + new("Bergstraat", Language.Dutch), + new("Rue De Montaigne", Language.French), + new("Mountain street", Language.English), + new("Bergstraat de", Language.German), + }) + .Build(); + + var position = _fixture.Create(); + + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + await Sut + .Given(new Envelope(new Envelope(streetNameWasProposedV2, metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions.FindAsync(position, streetNameWasProposedV2.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.Status.Should().Be(StreetNameStatus.Proposed); + expectedLatestItem.OsloStatus.Should().Be("Voorgesteld"); + expectedLatestItem.NisCode.Should().Be(streetNameWasProposedV2.NisCode); + expectedLatestItem.MunicipalityId.Should().Be(streetNameWasProposedV2.MunicipalityId); + + expectedLatestItem.NameDutch.Should().Be("Bergstraat"); + expectedLatestItem.NameFrench.Should().Be("Rue De Montaigne"); + expectedLatestItem.NameEnglish.Should().Be("Mountain street"); + expectedLatestItem.NameGerman.Should().Be("Bergstraat de"); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameWasProposedV2.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasProposedV2.Provenance.Timestamp); + expectedLatestItem.CreatedOnTimestamp.Should().Be(streetNameWasProposedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameWasApproved() + { + var streetNameWasProposedV2 = new StreetNameWasProposedV2Builder(_fixture) + .Build(); + + var streetNameWasApproved = new StreetNameWasApprovedBuilder(_fixture) + .Build(); + + var position = _fixture.Create(); + + var firstEvenMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasProposedV2, firstEvenMetadata)), + new Envelope(new Envelope(streetNameWasApproved, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions.FindAsync(position + 1, streetNameWasProposedV2.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.Status.Should().Be(StreetNameStatus.Current); + expectedLatestItem.OsloStatus.Should().Be("InGebruik"); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameWasProposedV2.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasApproved.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameWasCorrectedFromApprovedToProposed() + { + var streetNameWasProposedV2 = new StreetNameWasProposedV2Builder(_fixture) + .Build(); + + var streetNameWasCorrectedFromApprovedToProposed = _fixture.Create(); + + var position = _fixture.Create(); + + var firstEvenMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasProposedV2, firstEvenMetadata)), + new Envelope(new Envelope(streetNameWasCorrectedFromApprovedToProposed, + secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions.FindAsync(position + 1, streetNameWasProposedV2.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.Status.Should().Be(StreetNameStatus.Proposed); + expectedLatestItem.OsloStatus.Should().Be("Voorgesteld"); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameWasProposedV2.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasCorrectedFromApprovedToProposed.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameWasRejected() + { + var streetNameWasProposedV2 = new StreetNameWasProposedV2Builder(_fixture) + .Build(); + + var streetNameWasRejected = _fixture.Create(); + + var position = _fixture.Create(); + + var firstEvenMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasProposedV2, firstEvenMetadata)), + new Envelope(new Envelope(streetNameWasRejected, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions.FindAsync(position + 1, streetNameWasProposedV2.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.Status.Should().Be(StreetNameStatus.Rejected); + expectedLatestItem.OsloStatus.Should().Be("Afgekeurd"); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameWasProposedV2.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasRejected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameWasCorrectedFromRejectedToProposed() + { + var streetNameWasProposedV2 = new StreetNameWasProposedV2Builder(_fixture) + .Build(); + + var streetNameWasCorrectedFromRejectedToProposed = _fixture.Create(); + + var position = _fixture.Create(); + + var firstEvenMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasProposedV2, firstEvenMetadata)), + new Envelope(new Envelope(streetNameWasCorrectedFromRejectedToProposed, + secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions.FindAsync(position + 1, streetNameWasProposedV2.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.Status.Should().Be(StreetNameStatus.Proposed); + expectedLatestItem.OsloStatus.Should().Be("Voorgesteld"); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameWasProposedV2.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasCorrectedFromRejectedToProposed.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameWasRetiredV2() + { + var streetNameWasProposedV2 = new StreetNameWasProposedV2Builder(_fixture) + .Build(); + + var streetNameWasRetiredV2 = _fixture.Create(); + + var position = _fixture.Create(); + + var firstEvenMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasProposedV2, firstEvenMetadata)), + new Envelope(new Envelope(streetNameWasRetiredV2, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions.FindAsync(position + 1, streetNameWasProposedV2.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.Status.Should().Be(StreetNameStatus.Retired); + expectedLatestItem.OsloStatus.Should().Be("Gehistoreerd"); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameWasProposedV2.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasRetiredV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameWasRenamed() + { + var streetNameWasProposedV2 = new StreetNameWasProposedV2Builder(_fixture) + .Build(); + + var streetNameWasRenamed = _fixture.Create(); + + var position = _fixture.Create(); + + var firstEvenMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasProposedV2, firstEvenMetadata)), + new Envelope(new Envelope(streetNameWasRenamed, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions.FindAsync(position + 1, streetNameWasProposedV2.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.Status.Should().Be(StreetNameStatus.Retired); + expectedLatestItem.OsloStatus.Should().Be("Gehistoreerd"); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameWasProposedV2.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasRenamed.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameWasCorrectedFromRetiredToCurrent() + { + var streetNameWasProposedV2 = new StreetNameWasProposedV2Builder(_fixture) + .Build(); + + var streetNameWasCorrectedFromRetiredToCurrent = _fixture.Create(); + + var position = _fixture.Create(); + + var firstEvenMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasProposedV2, firstEvenMetadata)), + new Envelope(new Envelope(streetNameWasCorrectedFromRetiredToCurrent, + secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions.FindAsync(position + 1, streetNameWasProposedV2.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.Status.Should().Be(StreetNameStatus.Current); + expectedLatestItem.OsloStatus.Should().Be(StraatnaamStatus.InGebruik.ToString()); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameWasProposedV2.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasCorrectedFromRetiredToCurrent.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameNamesWereCorrected() + { + var streetNameWasProposedV2 = new StreetNameWasProposedV2Builder(_fixture) + .Build(); + + var streetNameNamesWereCorrected = new StreetNameNamesWereCorrectedBuilder(_fixture) + .WithNames(new Names + { + new("Bergstraat", Language.Dutch), + new("Rue De Montaigne", Language.French), + new("Mountain street", Language.English), + new("Bergstraat de", Language.German), + }) + .Build(); + + var position = _fixture.Create(); + + var firstEvenMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasProposedV2, firstEvenMetadata)), + new Envelope(new Envelope(streetNameNamesWereCorrected, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions.FindAsync(position + 1, streetNameWasProposedV2.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + + expectedLatestItem!.NameDutch.Should().Be("Bergstraat"); + expectedLatestItem.NameFrench.Should().Be("Rue De Montaigne"); + expectedLatestItem.NameEnglish.Should().Be("Mountain street"); + expectedLatestItem.NameGerman.Should().Be("Bergstraat de"); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameWasProposedV2.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameNamesWereCorrected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameNamesWereChanged() + { + var streetNameWasProposedV2 = new StreetNameWasProposedV2Builder(_fixture) + .Build(); + + var streetNameNamesWereChanged = new StreetNameNamesWereChangedBuilder(_fixture) + .WithNames(new Names + { + new("Bergstraat", Language.Dutch), + new("Rue De Montaigne", Language.French), + new("Mountain street", Language.English), + new("Bergstraat de", Language.German), + }).Build(); + + var position = _fixture.Create(); + + var firstEvenMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasProposedV2, firstEvenMetadata)), + new Envelope(new Envelope(streetNameNamesWereChanged, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions.FindAsync(position + 1, streetNameWasProposedV2.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + + expectedLatestItem!.NameDutch.Should().Be("Bergstraat"); + expectedLatestItem.NameFrench.Should().Be("Rue De Montaigne"); + expectedLatestItem.NameEnglish.Should().Be("Mountain street"); + expectedLatestItem.NameGerman.Should().Be("Bergstraat de"); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameWasProposedV2.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameNamesWereChanged.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameHomonymAdditionsWereCorrected() + { + var streetNameWasProposedV2 = new StreetNameWasProposedV2Builder(_fixture) + .Build(); + + var streetNameHomonymAdditionsWereCorrected = new StreetNameHomonymAdditionsWereCorrectedBuilder(_fixture) + .WithHomonymAdditions(new HomonymAdditions(new[] + { + new StreetNameHomonymAddition("ABC", Language.Dutch), + new StreetNameHomonymAddition("DEF", Language.French), + new StreetNameHomonymAddition("AZE", Language.English), + new StreetNameHomonymAddition("QSD", Language.German), + })).Build(); + + var position = _fixture.Create(); + + var firstEvenMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasProposedV2, firstEvenMetadata)), + new Envelope(new Envelope(streetNameHomonymAdditionsWereCorrected, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions.FindAsync(position + 1, streetNameWasProposedV2.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + + expectedLatestItem!.HomonymAdditionDutch.Should().Be("ABC"); + expectedLatestItem.HomonymAdditionFrench.Should().Be("DEF"); + expectedLatestItem.HomonymAdditionEnglish.Should().Be("AZE"); + expectedLatestItem.HomonymAdditionGerman.Should().Be("QSD"); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameWasProposedV2.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameHomonymAdditionsWereCorrected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameHomonymAdditionsWereRemoved() + { + var streetNameWasProposedV2 = new StreetNameWasProposedV2Builder(_fixture) + .Build(); + + var streetNameHomonymAdditionsWereCorrected = new StreetNameHomonymAdditionsWereRemovedBuilder(_fixture) + .WithLanguages(new List() + { + Language.Dutch, + Language.French, + Language.English, + Language.German, + }).Build(); + + var position = _fixture.Create(); + + var firstEvenMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasProposedV2, firstEvenMetadata)), + new Envelope(new Envelope(streetNameHomonymAdditionsWereCorrected, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions.FindAsync(position + 1, streetNameWasProposedV2.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + + expectedLatestItem!.HomonymAdditionDutch.Should().BeNull(); + expectedLatestItem.HomonymAdditionFrench.Should().BeNull(); + expectedLatestItem.HomonymAdditionEnglish.Should().BeNull(); + expectedLatestItem.HomonymAdditionGerman.Should().BeNull(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameWasProposedV2.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameHomonymAdditionsWereCorrected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameWasRemovedV2() + { + var streetNameWasProposedV2 = new StreetNameWasProposedV2Builder(_fixture) + .Build(); + + var streetNameWasRemovedV2 = _fixture.Create(); + + var position = _fixture.Create(); + + var firstEvenMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasProposedV2, firstEvenMetadata)), + new Envelope(new Envelope(streetNameWasRemovedV2, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions.FindAsync(position + 1, streetNameWasProposedV2.PersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + + expectedLatestItem!.IsRemoved.Should().BeTrue(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{streetNameWasProposedV2.PersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasRemovedV2.Provenance.Timestamp); + }); + } + + #region Legacy + + [Fact] + public async Task WhenStreetNameWasRegistered() + { + var streetNameWasRegistered = _fixture.Create(); + var persistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetPersistentLocalId(streetNameWasRegistered.StreetNameId)) + .ReturnsAsync(persistentLocalId); + + var position = _fixture.Create(); + + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + await Sut + .Given(new Envelope(new Envelope(streetNameWasRegistered, metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions.FirstAsync(x => x.StreetNameId == streetNameWasRegistered.StreetNameId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem.PersistentLocalId.Should().Be(persistentLocalId); + expectedLatestItem.NisCode.Should().Be(streetNameWasRegistered.NisCode); + expectedLatestItem.Position.Should().Be(position); + expectedLatestItem.MunicipalityId.Should().Be(streetNameWasRegistered.MunicipalityId); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{persistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasRegistered.Provenance.Timestamp); + expectedLatestItem.CreatedOnTimestamp.Should().Be(streetNameWasRegistered.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameWasNamed() + { + var streetNameWasRegistered = _fixture.Create(); + var streetNameWasNamed = _fixture.Create() + .WithLanguage(StreetName.Language.Dutch) + .WithName("straat") + .WithProvenance(_fixture.Create()); + + var persistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetPersistentLocalId(streetNameWasRegistered.StreetNameId)) + .ReturnsAsync(persistentLocalId); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(streetNameWasNamed, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions + .FirstAsync(x => x.StreetNameId == streetNameWasRegistered.StreetNameId && x.Position == position + 1); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem.PersistentLocalId.Should().Be(persistentLocalId); + expectedLatestItem.NisCode.Should().Be(streetNameWasRegistered.NisCode); + + expectedLatestItem.NameDutch.Should().Be("straat"); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{persistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasNamed.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameNameWasCorrected() + { + var streetNameWasRegistered = _fixture.Create(); + var streetNameNameWasCorrected = _fixture.Create() + .WithLanguage(StreetName.Language.Dutch) + .WithName("straat") + .WithProvenance(_fixture.Create()); + + var persistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetPersistentLocalId(streetNameWasRegistered.StreetNameId)) + .ReturnsAsync(persistentLocalId); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(streetNameNameWasCorrected, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions + .FirstAsync(x => x.StreetNameId == streetNameWasRegistered.StreetNameId && + x.Position == position + 1); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem.PersistentLocalId.Should().Be(persistentLocalId); + expectedLatestItem.NisCode.Should().Be(streetNameWasRegistered.NisCode); + + expectedLatestItem.NameDutch.Should().Be("straat"); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{persistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameNameWasCorrected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameNameWasCleared() + { + var streetNameWasRegistered = _fixture.Create(); + var streetNameNameWasCleared = _fixture.Create() + .WithLanguage(StreetName.Language.Dutch) + .WithProvenance(_fixture.Create()); + + var persistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetPersistentLocalId(streetNameWasRegistered.StreetNameId)) + .ReturnsAsync(persistentLocalId); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(streetNameNameWasCleared, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions + .FirstAsync(x => x.StreetNameId == streetNameWasRegistered.StreetNameId && + x.Position == position + 1); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem.PersistentLocalId.Should().Be(persistentLocalId); + expectedLatestItem.NisCode.Should().Be(streetNameWasRegistered.NisCode); + + expectedLatestItem.NameDutch.Should().BeEmpty(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{persistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameNameWasCleared.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameNameWasCorrectedToCleared() + { + var streetNameWasRegistered = _fixture.Create(); + var streetNameNameWasCorrectedToCleared = _fixture.Create() + .WithLanguage(StreetName.Language.Dutch) + .WithProvenance(_fixture.Create()); + + var persistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetPersistentLocalId(streetNameWasRegistered.StreetNameId)) + .ReturnsAsync(persistentLocalId); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(streetNameNameWasCorrectedToCleared, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions + .FirstAsync(x => x.StreetNameId == streetNameWasRegistered.StreetNameId && + x.Position == position + 1); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem.PersistentLocalId.Should().Be(persistentLocalId); + expectedLatestItem.NisCode.Should().Be(streetNameWasRegistered.NisCode); + + expectedLatestItem.NameDutch.Should().BeEmpty(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{persistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameNameWasCorrectedToCleared.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameHomonymAdditionWasDefined() + { + var streetNameWasRegistered = _fixture.Create(); + var streetNameHomonymAdditionWasDefined = _fixture.Create() + .WithHomonymAddition(new StreetName.StreetNameHomonymAddition("ABC", StreetName.Language.Dutch), _fixture.Create()); + + var persistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetPersistentLocalId(streetNameWasRegistered.StreetNameId)) + .ReturnsAsync(persistentLocalId); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(streetNameHomonymAdditionWasDefined, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions + .FirstAsync(x => x.StreetNameId == streetNameWasRegistered.StreetNameId && + x.Position == position + 1); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem.PersistentLocalId.Should().Be(persistentLocalId); + expectedLatestItem.NisCode.Should().Be(streetNameWasRegistered.NisCode); + + expectedLatestItem.HomonymAdditionDutch.Should().Be("ABC"); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{persistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameHomonymAdditionWasDefined.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameHomonymAdditionWasCorrected() + { + var streetNameWasRegistered = _fixture.Create(); + var streetNameHomonymAdditionWasCorrected = _fixture.Create() + .WithHomonymAddition(new StreetName.StreetNameHomonymAddition("ABC", StreetName.Language.Dutch), _fixture.Create()); + + var persistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetPersistentLocalId(streetNameWasRegistered.StreetNameId)) + .ReturnsAsync(persistentLocalId); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(streetNameHomonymAdditionWasCorrected, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions + .FirstAsync(x => x.StreetNameId == streetNameWasRegistered.StreetNameId && + x.Position == position + 1); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem.PersistentLocalId.Should().Be(persistentLocalId); + expectedLatestItem.NisCode.Should().Be(streetNameWasRegistered.NisCode); + + expectedLatestItem.HomonymAdditionDutch.Should().Be("ABC"); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{persistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameHomonymAdditionWasCorrected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameHomonymAdditionWasCleared() + { + var streetNameWasRegistered = _fixture.Create(); + var streetNameHomonymAdditionWasDefined = _fixture.Create() + .WithHomonymAddition(new StreetName.StreetNameHomonymAddition("ABC", StreetName.Language.Dutch), _fixture.Create()); + var streetNameHomonymAdditionWasCleared = _fixture.Create() + .WithLanguage(StreetName.Language.Dutch, _fixture.Create()); + + var persistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetPersistentLocalId(streetNameWasRegistered.StreetNameId)) + .ReturnsAsync(persistentLocalId); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + var thirdEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 2 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(streetNameHomonymAdditionWasDefined, secondEventMetadata)), + new Envelope(new Envelope(streetNameHomonymAdditionWasCleared, thirdEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions + .FirstAsync(x => x.StreetNameId == streetNameWasRegistered.StreetNameId && + x.Position == position + 2); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem.PersistentLocalId.Should().Be(persistentLocalId); + expectedLatestItem.NisCode.Should().Be(streetNameWasRegistered.NisCode); + + expectedLatestItem.HomonymAdditionDutch.Should().BeEmpty(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{persistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameHomonymAdditionWasCleared.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameHomonymAdditionWasCorrectedToCleared() + { + var streetNameWasRegistered = _fixture.Create(); + var streetNameHomonymAdditionWasDefined = _fixture.Create() + .WithHomonymAddition(new StreetName.StreetNameHomonymAddition("ABC", StreetName.Language.Dutch), _fixture.Create()); + var streetNameHomonymAdditionWasCorrectedToCleared = _fixture.Create() + .WithLanguage(StreetName.Language.Dutch, _fixture.Create()); + + var persistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetPersistentLocalId(streetNameWasRegistered.StreetNameId)) + .ReturnsAsync(persistentLocalId); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + var thirdEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 2 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(streetNameHomonymAdditionWasDefined, secondEventMetadata)), + new Envelope(new Envelope(streetNameHomonymAdditionWasCorrectedToCleared, + thirdEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions + .FirstAsync(x => x.StreetNameId == streetNameWasRegistered.StreetNameId && + x.Position == position + 2); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem.PersistentLocalId.Should().Be(persistentLocalId); + expectedLatestItem.NisCode.Should().Be(streetNameWasRegistered.NisCode); + + expectedLatestItem.HomonymAdditionDutch.Should().BeEmpty(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{persistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameHomonymAdditionWasCorrectedToCleared.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameBecameComplete() + { + var streetNameWasRegistered = _fixture.Create(); + var streetNameBecameComplete = _fixture.Create(); + + var persistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetPersistentLocalId(streetNameWasRegistered.StreetNameId)) + .ReturnsAsync(persistentLocalId); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(streetNameBecameComplete, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions + .FirstAsync(x => x.StreetNameId == streetNameWasRegistered.StreetNameId && + x.Position == position + 1); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem.PersistentLocalId.Should().Be(persistentLocalId); + expectedLatestItem.NisCode.Should().Be(streetNameWasRegistered.NisCode); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{persistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameBecameComplete.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameBecameIncomplete() + { + var streetNameWasRegistered = _fixture.Create(); + var streetNameBecameIncomplete = _fixture.Create(); + + var persistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetPersistentLocalId(streetNameWasRegistered.StreetNameId)) + .ReturnsAsync(persistentLocalId); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(streetNameBecameIncomplete, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions + .FirstAsync(x => x.StreetNameId == streetNameWasRegistered.StreetNameId && + x.Position == position + 1); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem.PersistentLocalId.Should().Be(persistentLocalId); + expectedLatestItem.NisCode.Should().Be(streetNameWasRegistered.NisCode); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{persistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameBecameIncomplete.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameWasRemoved() + { + var streetNameWasRegistered = _fixture.Create(); + var streetNameWasRemoved = _fixture.Create(); + + var persistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetPersistentLocalId(streetNameWasRegistered.StreetNameId)) + .ReturnsAsync(persistentLocalId); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(streetNameWasRemoved, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions + .FirstAsync(x => x.StreetNameId == streetNameWasRegistered.StreetNameId && + x.Position == position + 1); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem.PersistentLocalId.Should().Be(persistentLocalId); + expectedLatestItem.NisCode.Should().Be(streetNameWasRegistered.NisCode); + expectedLatestItem.IsRemoved.Should().BeTrue(); + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{persistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasRemoved.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNamePersistentLocalIdWasAssigned() + { + var streetNameWasRegistered = _fixture.Create(); + var streetNamePersistentLocalIdWasAssigned = _fixture.Create(); + + var persistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetPersistentLocalId(streetNameWasRegistered.StreetNameId)) + .ReturnsAsync(persistentLocalId); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(streetNamePersistentLocalIdWasAssigned, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions + .FirstAsync(x => x.StreetNameId == streetNameWasRegistered.StreetNameId && + x.Position == position + 1); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem.PersistentLocalId.Should().Be(persistentLocalId); + expectedLatestItem.NisCode.Should().Be(streetNameWasRegistered.NisCode); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{persistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNamePersistentLocalIdWasAssigned.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameBecameCurrent() + { + var streetNameWasRegistered = _fixture.Create(); + var streetNameBecameCurrent = _fixture.Create(); + + var persistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetPersistentLocalId(streetNameWasRegistered.StreetNameId)) + .ReturnsAsync(persistentLocalId); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(streetNameBecameCurrent, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions + .FirstAsync(x => x.StreetNameId == streetNameWasRegistered.StreetNameId && + x.Position == position + 1); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem.PersistentLocalId.Should().Be(persistentLocalId); + expectedLatestItem.NisCode.Should().Be(streetNameWasRegistered.NisCode); + + expectedLatestItem.Status.Should().Be(StreetNameStatus.Current); + expectedLatestItem.OsloStatus.Should().Be(StraatnaamStatus.InGebruik.ToString()); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{persistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameBecameCurrent.Provenance.Timestamp); + }); + } + + + [Fact] + public async Task WhenStreetNameWasProposed() + { + var streetNameWasRegistered = _fixture.Create(); + var streetNameWasProposed = _fixture.Create(); + + var persistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetPersistentLocalId(streetNameWasRegistered.StreetNameId)) + .ReturnsAsync(persistentLocalId); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(streetNameWasProposed, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions + .FirstAsync(x => x.StreetNameId == streetNameWasRegistered.StreetNameId && + x.Position == position + 1); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem.PersistentLocalId.Should().Be(persistentLocalId); + expectedLatestItem.NisCode.Should().Be(streetNameWasRegistered.NisCode); + + expectedLatestItem.Status.Should().Be(StreetNameStatus.Proposed); + expectedLatestItem.OsloStatus.Should().Be(StraatnaamStatus.Voorgesteld.ToString()); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{persistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasProposed.Provenance.Timestamp); + }); + } + + + [Fact] + public async Task WhenStreetNameWasStreetNameWasRetired() + { + var streetNameWasRegistered = _fixture.Create(); + var streetNameWasRetired = _fixture.Create(); + + var persistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetPersistentLocalId(streetNameWasRegistered.StreetNameId)) + .ReturnsAsync(persistentLocalId); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(streetNameWasRetired, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions + .FirstAsync(x => x.StreetNameId == streetNameWasRegistered.StreetNameId && + x.Position == position + 1); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem.PersistentLocalId.Should().Be(persistentLocalId); + expectedLatestItem.NisCode.Should().Be(streetNameWasRegistered.NisCode); + + expectedLatestItem.Status.Should().Be(StreetNameStatus.Retired); + expectedLatestItem.OsloStatus.Should().Be(StraatnaamStatus.Gehistoreerd.ToString()); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{persistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasRetired.Provenance.Timestamp); + }); + } + + + [Fact] + public async Task WhenStreetNameWasCorrectedToCurrent() + { + var streetNameWasRegistered = _fixture.Create(); + var streetNameWasCorrectedToCurrent = _fixture.Create(); + + var persistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetPersistentLocalId(streetNameWasRegistered.StreetNameId)) + .ReturnsAsync(persistentLocalId); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(streetNameWasCorrectedToCurrent, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions + .FirstAsync(x => x.StreetNameId == streetNameWasRegistered.StreetNameId && + x.Position == position + 1); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem.PersistentLocalId.Should().Be(persistentLocalId); + expectedLatestItem.NisCode.Should().Be(streetNameWasRegistered.NisCode); + + expectedLatestItem.Status.Should().Be(StreetNameStatus.Current); + expectedLatestItem.OsloStatus.Should().Be(StraatnaamStatus.InGebruik.ToString()); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{persistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasCorrectedToCurrent.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameWasCorrectedToProposed() + { + var streetNameWasRegistered = _fixture.Create(); + var streetNameWasCorrectedToProposed = _fixture.Create(); + + var persistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetPersistentLocalId(streetNameWasRegistered.StreetNameId)) + .ReturnsAsync(persistentLocalId); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(streetNameWasCorrectedToProposed, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions + .FirstAsync(x => x.StreetNameId == streetNameWasRegistered.StreetNameId && + x.Position == position + 1); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem.PersistentLocalId.Should().Be(persistentLocalId); + expectedLatestItem.NisCode.Should().Be(streetNameWasRegistered.NisCode); + + expectedLatestItem.Status.Should().Be(StreetNameStatus.Proposed); + expectedLatestItem.OsloStatus.Should().Be(StraatnaamStatus.Voorgesteld.ToString()); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{persistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasCorrectedToProposed.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameWasCorrectedToRetired() + { + var streetNameWasRegistered = _fixture.Create(); + var streetNameWasCorrectedToRetired = _fixture.Create(); + + var persistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetPersistentLocalId(streetNameWasRegistered.StreetNameId)) + .ReturnsAsync(persistentLocalId); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(streetNameWasCorrectedToRetired, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions + .FirstAsync(x => x.StreetNameId == streetNameWasRegistered.StreetNameId && + x.Position == position + 1); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem.PersistentLocalId.Should().Be(persistentLocalId); + expectedLatestItem.NisCode.Should().Be(streetNameWasRegistered.NisCode); + + expectedLatestItem.Status.Should().Be(StreetNameStatus.Retired); + expectedLatestItem.OsloStatus.Should().Be(StraatnaamStatus.Gehistoreerd.ToString()); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{persistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameWasCorrectedToRetired.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameStatusWasRemoved() + { + var streetNameWasRegistered = _fixture.Create(); + var streetNameStatusWasRemoved = _fixture.Create(); + + var persistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetPersistentLocalId(streetNameWasRegistered.StreetNameId)) + .ReturnsAsync(persistentLocalId); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(streetNameStatusWasRemoved, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions + .FirstAsync(x => x.StreetNameId == streetNameWasRegistered.StreetNameId && + x.Position == position + 1); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem.PersistentLocalId.Should().Be(persistentLocalId); + expectedLatestItem.NisCode.Should().Be(streetNameWasRegistered.NisCode); + + expectedLatestItem.Status.Should().BeNull(); + expectedLatestItem.OsloStatus.Should().BeNull(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{persistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameStatusWasRemoved.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenStreetNameStatusWasCorrectedToRemoved() + { + var streetNameWasRegistered = _fixture.Create(); + var streetNameStatusWasCorrectedToRemoved = _fixture.Create(); + + var persistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetPersistentLocalId(streetNameWasRegistered.StreetNameId)) + .ReturnsAsync(persistentLocalId); + + var position = _fixture.Create(); + + var firstEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var secondEventMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(streetNameWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(streetNameStatusWasCorrectedToRemoved, secondEventMetadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.StreetNameVersions + .FirstAsync(x => x.StreetNameId == streetNameWasRegistered.StreetNameId && + x.Position == position + 1); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem.PersistentLocalId.Should().Be(persistentLocalId); + expectedLatestItem.NisCode.Should().Be(streetNameWasRegistered.NisCode); + + expectedLatestItem.Status.Should().BeNull(); + expectedLatestItem.OsloStatus.Should().BeNull(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.Puri.Should().Be($"{Namespace}/{persistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(streetNameStatusWasCorrectedToRemoved.Provenance.Timestamp); + }); + } + + #endregion + + protected override StreetNameVersionProjections CreateProjection() + => new StreetNameVersionProjections( + new OptionsWrapper(new IntegrationOptions { Namespace = Namespace }), _eventsRepositoryMock.Object); + } +} diff --git a/test/StreetNameRegistry.Tests/ProjectionTests/StreetNameLatestItemProjectionsV2Tests.cs b/test/StreetNameRegistry.Tests/ProjectionTests/StreetNameLatestItemProjectionsV2Tests.cs index 2c4688395..9e2bcd658 100644 --- a/test/StreetNameRegistry.Tests/ProjectionTests/StreetNameLatestItemProjectionsV2Tests.cs +++ b/test/StreetNameRegistry.Tests/ProjectionTests/StreetNameLatestItemProjectionsV2Tests.cs @@ -380,7 +380,6 @@ await Sut }); } - [Fact] public async Task WhenStreetNameNamesWereCorrected_ThenStreetNameNamesWereCorrected() { diff --git a/test/StreetNameRegistry.Tests/StreetNameRegistry.Tests.csproj b/test/StreetNameRegistry.Tests/StreetNameRegistry.Tests.csproj index ccc37eec6..c20032878 100644 --- a/test/StreetNameRegistry.Tests/StreetNameRegistry.Tests.csproj +++ b/test/StreetNameRegistry.Tests/StreetNameRegistry.Tests.csproj @@ -12,6 +12,7 @@ +