From ccd35e1129f14cd298bd96684e3be24998e20b06 Mon Sep 17 00:00:00 2001 From: emalfroy <109064991+emalfroy@users.noreply.github.com> Date: Mon, 15 Jan 2024 14:33:55 +0100 Subject: [PATCH] feat: add integration projections GAWR-4535 --- AddressRegistry.sln | 15 + paket.dependencies | 26 +- paket.lock | 117 +- .../MunicipalityConsumerContext.cs | 1 + .../paket.references | 2 +- .../StreetNameConsumerContext.cs | 1 + .../paket.references | 2 +- .../ConsumerContext.cs | 3 +- .../IdempotentConsumerContext.cs | 1 + src/AddressRegistry.Consumer/paket.references | 2 +- src/AddressRegistry.Infrastructure/Schema.cs | 2 + .../ProducerContextMigrationFactory.cs | 4 +- .../ProducerModule.cs | 1 + .../paket.references | 2 +- .../ProducerContextMigrationFactory.cs | 6 +- .../ProducerModule.cs | 4 +- src/AddressRegistry.Producer/paket.references | 2 +- .../BackOfficeProjectionsContext.cs | 3 +- .../ServiceCollectionExtensions.cs | 1 + .../paket.references | 2 +- .../ExtractContextMigrationFactory.cs | 3 +- .../ExtractModule.cs | 3 +- .../paket.references | 2 +- .../AddressLatestItem.cs | 100 + .../AddressLatestItemExtensions.cs | 31 + .../AddressLatestItemProjection.cs | 662 ++++ ...essRegistry.Projections.Integration.csproj | 13 + .../AddressVersion.cs | 163 + .../AddressVersionExtension.cs | 105 + .../AddressVersionProjection.cs | 894 ++++++ .../Convertors/AddressMapper.cs | 115 + .../EventsRepository.cs | 29 + .../IEventsRepository.cs | 10 + .../Infrastructure/IntegrationModule.cs | 63 + .../Infrastructure/IntegrationOptions.cs | 8 + .../IntegrationContext.cs | 21 + .../IntegrationContextMigrationFactory.cs | 30 + .../20240115132131_Initial.Designer.cs | 279 ++ .../Migrations/20240115132131_Initial.cs | 239 ++ .../IntegrationContextModelSnapshot.cs | 277 ++ .../Properties/AssemblyInfo.cs | 7 + .../paket.references | 16 + .../AddressLastChangedListModule.cs | 1 + .../DataMigrationsContext.cs | 3 +- .../AddressSyndication/AddressSyndication.cs | 3 +- .../LegacyContextMigrationFactory.cs | 4 +- .../LegacyModule.cs | 1 + .../paket.references | 2 +- .../MigrationsHelper.cs | 1 + .../SyndicationContext.cs | 1 + .../SyndicationModule.cs | 1 + .../paket.references | 2 +- .../WfsContextMigrationFactory.cs | 4 +- .../WfsModule.cs | 1 + .../paket.references | 2 +- .../WmsContextMigrationFactory.cs | 4 +- .../WmsModule.cs | 1 + .../paket.references | 2 +- .../AddressRegistry.Projector.csproj | 1 + .../Infrastructure/Modules/ApiModule.cs | 25 + .../Infrastructure/Startup.cs | 18 +- .../Projections/ProjectionsController.cs | 1 + .../appsettings.json | 9 +- .../paket.references | 6 + .../EF.MigrationHelper.csproj | 2 +- src/EF.MigrationsHelper/appsettings.json | 3 +- src/EF.MigrationsHelper/paket.references | 5 +- .../AddressRegistry.Tests.csproj | 1 + .../AddressPositionWasCorrectedExtensions.cs | 42 + .../AddressWasPositionedExtensions.cs | 42 + .../AddressWasProposedV2Extensions.cs | 19 + .../Integration/AddressLatestItemTests.cs | 1495 +++++++++ .../Integration/AddressVersionTests.cs | 2745 +++++++++++++++++ .../Integration/IntegrationTest.cs | 30 + 74 files changed, 7669 insertions(+), 75 deletions(-) create mode 100644 src/AddressRegistry.Projections.Integration/AddressLatestItem.cs create mode 100644 src/AddressRegistry.Projections.Integration/AddressLatestItemExtensions.cs create mode 100644 src/AddressRegistry.Projections.Integration/AddressLatestItemProjection.cs create mode 100644 src/AddressRegistry.Projections.Integration/AddressRegistry.Projections.Integration.csproj create mode 100644 src/AddressRegistry.Projections.Integration/AddressVersion.cs create mode 100644 src/AddressRegistry.Projections.Integration/AddressVersionExtension.cs create mode 100644 src/AddressRegistry.Projections.Integration/AddressVersionProjection.cs create mode 100644 src/AddressRegistry.Projections.Integration/Convertors/AddressMapper.cs create mode 100644 src/AddressRegistry.Projections.Integration/EventsRepository.cs create mode 100644 src/AddressRegistry.Projections.Integration/IEventsRepository.cs create mode 100644 src/AddressRegistry.Projections.Integration/Infrastructure/IntegrationModule.cs create mode 100644 src/AddressRegistry.Projections.Integration/Infrastructure/IntegrationOptions.cs create mode 100644 src/AddressRegistry.Projections.Integration/IntegrationContext.cs create mode 100644 src/AddressRegistry.Projections.Integration/IntegrationContextMigrationFactory.cs create mode 100644 src/AddressRegistry.Projections.Integration/Migrations/20240115132131_Initial.Designer.cs create mode 100644 src/AddressRegistry.Projections.Integration/Migrations/20240115132131_Initial.cs create mode 100644 src/AddressRegistry.Projections.Integration/Migrations/IntegrationContextModelSnapshot.cs create mode 100644 src/AddressRegistry.Projections.Integration/Properties/AssemblyInfo.cs create mode 100644 src/AddressRegistry.Projections.Integration/paket.references create mode 100644 test/AddressRegistry.Tests/EventExtensions/AddressPositionWasCorrectedExtensions.cs create mode 100644 test/AddressRegistry.Tests/EventExtensions/AddressWasPositionedExtensions.cs create mode 100644 test/AddressRegistry.Tests/Integration/AddressLatestItemTests.cs create mode 100644 test/AddressRegistry.Tests/Integration/AddressVersionTests.cs create mode 100644 test/AddressRegistry.Tests/Integration/IntegrationTest.cs diff --git a/AddressRegistry.sln b/AddressRegistry.sln index cd285f8f3..939d0d52e 100755 --- a/AddressRegistry.sln +++ b/AddressRegistry.sln @@ -82,6 +82,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AddressRegistry.Projections EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AddressRegistry.Snapshot.Verifier", "src\AddressRegistry.Snapshot.Verifier\AddressRegistry.Snapshot.Verifier.csproj", "{A607F83B-F1E8-4E72-A8B6-084CF88CFC58}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AddressRegistry.Projections.Integration", "src\AddressRegistry.Projections.Integration\AddressRegistry.Projections.Integration.csproj", "{2DB2F86A-510A-4DB1-97F8-1F3CACF06391}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -416,6 +418,18 @@ Global {A607F83B-F1E8-4E72-A8B6-084CF88CFC58}.Release|x64.Build.0 = Release|Any CPU {A607F83B-F1E8-4E72-A8B6-084CF88CFC58}.Release|x86.ActiveCfg = Release|Any CPU {A607F83B-F1E8-4E72-A8B6-084CF88CFC58}.Release|x86.Build.0 = Release|Any CPU + {2DB2F86A-510A-4DB1-97F8-1F3CACF06391}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2DB2F86A-510A-4DB1-97F8-1F3CACF06391}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2DB2F86A-510A-4DB1-97F8-1F3CACF06391}.Debug|x64.ActiveCfg = Debug|Any CPU + {2DB2F86A-510A-4DB1-97F8-1F3CACF06391}.Debug|x64.Build.0 = Debug|Any CPU + {2DB2F86A-510A-4DB1-97F8-1F3CACF06391}.Debug|x86.ActiveCfg = Debug|Any CPU + {2DB2F86A-510A-4DB1-97F8-1F3CACF06391}.Debug|x86.Build.0 = Debug|Any CPU + {2DB2F86A-510A-4DB1-97F8-1F3CACF06391}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2DB2F86A-510A-4DB1-97F8-1F3CACF06391}.Release|Any CPU.Build.0 = Release|Any CPU + {2DB2F86A-510A-4DB1-97F8-1F3CACF06391}.Release|x64.ActiveCfg = Release|Any CPU + {2DB2F86A-510A-4DB1-97F8-1F3CACF06391}.Release|x64.Build.0 = Release|Any CPU + {2DB2F86A-510A-4DB1-97F8-1F3CACF06391}.Release|x86.ActiveCfg = Release|Any CPU + {2DB2F86A-510A-4DB1-97F8-1F3CACF06391}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -448,6 +462,7 @@ Global {5DC2D5A0-DB8B-45CA-BD94-E9F731A5EF68} = {C2F8FF63-7A48-4179-A720-86206C42F496} {3465E905-8935-41F4-A09D-952BB37DE8C7} = {C2F8FF63-7A48-4179-A720-86206C42F496} {A607F83B-F1E8-4E72-A8B6-084CF88CFC58} = {C2F8FF63-7A48-4179-A720-86206C42F496} + {2DB2F86A-510A-4DB1-97F8-1F3CACF06391} = {C2F8FF63-7A48-4179-A720-86206C42F496} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {2EB87445-E263-4E1E-89CC-3839170028E5} diff --git a/paket.dependencies b/paket.dependencies index 249058e19..0500c5328 100644 --- a/paket.dependencies +++ b/paket.dependencies @@ -11,6 +11,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 AsyncEnumerator 4.0.2 nuget Dapper 2.0.123 @@ -25,6 +26,11 @@ nuget NetTopologySuite 2.4.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 +nuget Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite 6.0.3 + nuget RestSharp 107.3.0 nuget GeoJSON.NET 1.2.19 @@ -55,15 +61,17 @@ nuget Be.Vlaanderen.Basisregisters.CommandHandling.SqlStreamStore 8.3.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.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.Projector 13.0.10 +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.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.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 be23a8889..9fe251e49 100644 --- a/paket.lock +++ b/paket.lock @@ -6,6 +6,9 @@ NUGET Amazon.Lambda.Core (>= 2.0) Newtonsoft.Json (>= 9.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) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) 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) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + 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) @@ -670,7 +685,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) (>= net47)) (&& (== 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 +751,7 @@ NUGET System.Text.Encoding.CodePages (>= 5.0) - restriction: || (&& (== net472) (< net461)) (&& (== net472) (>= netstandard2.1)) (== net6.0) System.Text.Encodings.Web (>= 4.7.2) Microsoft.Data.SqlClient.SNI.runtime (4.0) - restriction: || (&& (== net472) (>= net6.0)) (== 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 +766,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) @@ -1001,10 +1019,12 @@ 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) + NetTopologySuite.IO.PostGis (2.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + NetTopologySuite (>= 2.0 < 3.0.0-A) NetTopologySuite.IO.SqlServerBytes (2.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) NetTopologySuite (>= 2.0 < 3.0.0-A) Newtonsoft.Json (13.0.1) @@ -1031,6 +1051,37 @@ 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) + Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite (6.0.3) + Npgsql.EntityFrameworkCore.PostgreSQL (>= 6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Npgsql.NetTopologySuite (>= 6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Npgsql.NetTopologySuite (6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + NetTopologySuite.IO.PostGis (>= 2.1) + Npgsql (>= 6.0.3) NSwag.CodeGeneration (13.15.10) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Newtonsoft.Json (>= 9.0.1) NJsonSchema (>= 10.6.10) @@ -1156,6 +1207,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) @@ -1215,7 +1267,8 @@ NUGET Microsoft.NETCore.Platforms (>= 1.1) - restriction: || (&& (== net472) (< net45)) (== net6.0) Microsoft.NETCore.Targets (>= 1.1) - restriction: || (&& (== net472) (< net45)) (== net6.0) System.Runtime (>= 4.3) - restriction: || (&& (== net472) (< net45)) (== net6.0) - System.Diagnostics.DiagnosticSource (6.0) - restriction: || (&& (== net472) (>= net6.0)) (== 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 (6.0) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) System.Diagnostics.TraceSource (4.3) - restriction: || (&& (== net472) (< net35)) (== net6.0) @@ -1417,6 +1470,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) @@ -1424,7 +1479,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/AddressRegistry.Consumer.Read.Municipality/MunicipalityConsumerContext.cs b/src/AddressRegistry.Consumer.Read.Municipality/MunicipalityConsumerContext.cs index 77b43cb3a..81223e113 100644 --- a/src/AddressRegistry.Consumer.Read.Municipality/MunicipalityConsumerContext.cs +++ b/src/AddressRegistry.Consumer.Read.Municipality/MunicipalityConsumerContext.cs @@ -8,6 +8,7 @@ namespace AddressRegistry.Consumer.Read.Municipality using Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector; 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/AddressRegistry.Consumer.Read.Municipality/paket.references b/src/AddressRegistry.Consumer.Read.Municipality/paket.references index 3ce5de7b0..c71a4a1b1 100644 --- a/src/AddressRegistry.Consumer.Read.Municipality/paket.references +++ b/src/AddressRegistry.Consumer.Read.Municipality/paket.references @@ -8,7 +8,7 @@ Be.Vlaanderen.Basisregisters.DataDog.Tracing.SqlStreamStore Be.Vlaanderen.Basisregisters.EntityFrameworkCore.EntityTypeConfiguration Be.Vlaanderen.Basisregisters.GrAr.Contracts Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector -Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner +Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer Be.Vlaanderen.Basisregisters.MessageHandling.Kafka.Consumer diff --git a/src/AddressRegistry.Consumer.Read.StreetName/StreetNameConsumerContext.cs b/src/AddressRegistry.Consumer.Read.StreetName/StreetNameConsumerContext.cs index 6a75af5ba..1b22c8cb6 100644 --- a/src/AddressRegistry.Consumer.Read.StreetName/StreetNameConsumerContext.cs +++ b/src/AddressRegistry.Consumer.Read.StreetName/StreetNameConsumerContext.cs @@ -10,6 +10,7 @@ namespace AddressRegistry.Consumer.Read.StreetName using Be.Vlaanderen.Basisregisters.MessageHandling.Kafka.Consumer.SqlServer; using Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector; 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/AddressRegistry.Consumer.Read.StreetName/paket.references b/src/AddressRegistry.Consumer.Read.StreetName/paket.references index 1f690d831..bb33d1aa2 100644 --- a/src/AddressRegistry.Consumer.Read.StreetName/paket.references +++ b/src/AddressRegistry.Consumer.Read.StreetName/paket.references @@ -12,7 +12,7 @@ Be.Vlaanderen.Basisregisters.GrAr.Contracts Be.Vlaanderen.Basisregisters.MessageHandling.Kafka.Consumer.SqlServer Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector -Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner +Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer Serilog Serilog.Settings.Configuration diff --git a/src/AddressRegistry.Consumer/ConsumerContext.cs b/src/AddressRegistry.Consumer/ConsumerContext.cs index add5de4f6..74019acef 100644 --- a/src/AddressRegistry.Consumer/ConsumerContext.cs +++ b/src/AddressRegistry.Consumer/ConsumerContext.cs @@ -4,6 +4,7 @@ namespace AddressRegistry.Consumer using Microsoft.EntityFrameworkCore; using StreetName; using AddressRegistry.Infrastructure; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer; public class ConsumerContext : RunnerDbContext { @@ -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/AddressRegistry.Consumer/IdempotentConsumerContext.cs b/src/AddressRegistry.Consumer/IdempotentConsumerContext.cs index 2ae2b5184..26cfec14f 100644 --- a/src/AddressRegistry.Consumer/IdempotentConsumerContext.cs +++ b/src/AddressRegistry.Consumer/IdempotentConsumerContext.cs @@ -8,6 +8,7 @@ namespace AddressRegistry.Consumer using Microsoft.Extensions.Configuration; using System.IO; using System; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; public class IdempotentConsumerContext : SqlServerConsumerDbContext { diff --git a/src/AddressRegistry.Consumer/paket.references b/src/AddressRegistry.Consumer/paket.references index c9c783f04..80c442b61 100644 --- a/src/AddressRegistry.Consumer/paket.references +++ b/src/AddressRegistry.Consumer/paket.references @@ -8,7 +8,7 @@ Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql Be.Vlaanderen.Basisregisters.EntityFrameworkCore.EntityTypeConfiguration Be.Vlaanderen.Basisregisters.GrAr.Contracts Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector -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/AddressRegistry.Infrastructure/Schema.cs b/src/AddressRegistry.Infrastructure/Schema.cs index 9944048ca..fff464d2c 100755 --- a/src/AddressRegistry.Infrastructure/Schema.cs +++ b/src/AddressRegistry.Infrastructure/Schema.cs @@ -19,6 +19,7 @@ public static class Schema public const string Wms = "wms.address"; public const string Producer = "AddressRegistryProducer"; public const string ProducerSnapshotOslo = "AddressRegistryProducerSnapshotOslo"; + public const string Integration = "integration_address"; } public static class MigrationTables @@ -38,6 +39,7 @@ public static class MigrationTables public const string Wms = "__EFMigrationsHistoryWmsAddress"; public const string Producer = "__EFMigrationsHistoryProducer"; public const string ProducerSnapshotOslo = "__EFMigrationsHistoryProducerSnapshotOslo"; + public const string Integration = "__EFMigrationsHistory"; } } diff --git a/src/AddressRegistry.Producer.Snapshot.Oslo/ProducerContextMigrationFactory.cs b/src/AddressRegistry.Producer.Snapshot.Oslo/ProducerContextMigrationFactory.cs index 43b93ac68..0755f686b 100644 --- a/src/AddressRegistry.Producer.Snapshot.Oslo/ProducerContextMigrationFactory.cs +++ b/src/AddressRegistry.Producer.Snapshot.Oslo/ProducerContextMigrationFactory.cs @@ -3,8 +3,10 @@ namespace AddressRegistry.Producer.Snapshot.Oslo using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; using Microsoft.EntityFrameworkCore; using AddressRegistry.Infrastructure; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.Microsoft; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer; - public class ProducerContextMigrationFactory : RunnerDbContextMigrationFactory + public class ProducerContextMigrationFactory : SqlServerRunnerDbContextMigrationFactory { public ProducerContextMigrationFactory() : base("ProducerProjectionsAdmin", HistoryConfiguration) { } diff --git a/src/AddressRegistry.Producer.Snapshot.Oslo/ProducerModule.cs b/src/AddressRegistry.Producer.Snapshot.Oslo/ProducerModule.cs index 1b1cff6c5..6a05342db 100644 --- a/src/AddressRegistry.Producer.Snapshot.Oslo/ProducerModule.cs +++ b/src/AddressRegistry.Producer.Snapshot.Oslo/ProducerModule.cs @@ -10,6 +10,7 @@ namespace AddressRegistry.Producer.Snapshot.Oslo using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using AddressRegistry.Infrastructure; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; public class ProducerModule : Module { diff --git a/src/AddressRegistry.Producer.Snapshot.Oslo/paket.references b/src/AddressRegistry.Producer.Snapshot.Oslo/paket.references index b065da96a..7efba64d4 100644 --- a/src/AddressRegistry.Producer.Snapshot.Oslo/paket.references +++ b/src/AddressRegistry.Producer.Snapshot.Oslo/paket.references @@ -4,7 +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 +Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore.Autofac Be.Vlaanderen.Basisregisters.Projector diff --git a/src/AddressRegistry.Producer/ProducerContextMigrationFactory.cs b/src/AddressRegistry.Producer/ProducerContextMigrationFactory.cs index 4b6ec3f9e..ffefd15e9 100644 --- a/src/AddressRegistry.Producer/ProducerContextMigrationFactory.cs +++ b/src/AddressRegistry.Producer/ProducerContextMigrationFactory.cs @@ -1,10 +1,10 @@ namespace AddressRegistry.Producer { - using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; - using Microsoft.EntityFrameworkCore; using AddressRegistry.Infrastructure; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer; + using Microsoft.EntityFrameworkCore; - public class ProducerContextMigrationFactory : RunnerDbContextMigrationFactory + public class ProducerContextMigrationFactory : SqlServerRunnerDbContextMigrationFactory { public ProducerContextMigrationFactory() : base("ProducerProjectionsAdmin", HistoryConfiguration) { } diff --git a/src/AddressRegistry.Producer/ProducerModule.cs b/src/AddressRegistry.Producer/ProducerModule.cs index 9107b446f..b0516637f 100644 --- a/src/AddressRegistry.Producer/ProducerModule.cs +++ b/src/AddressRegistry.Producer/ProducerModule.cs @@ -1,15 +1,15 @@ namespace AddressRegistry.Producer { using System; + using AddressRegistry.Infrastructure; 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; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; - using AddressRegistry.Infrastructure; public class ProducerModule : Module { diff --git a/src/AddressRegistry.Producer/paket.references b/src/AddressRegistry.Producer/paket.references index 39e599820..89a611453 100644 --- a/src/AddressRegistry.Producer/paket.references +++ b/src/AddressRegistry.Producer/paket.references @@ -3,7 +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 +Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore.Autofac Be.Vlaanderen.Basisregisters.Projector diff --git a/src/AddressRegistry.Projections.BackOffice/BackOfficeProjectionsContext.cs b/src/AddressRegistry.Projections.BackOffice/BackOfficeProjectionsContext.cs index b2a4f61c2..d6b65b68c 100644 --- a/src/AddressRegistry.Projections.BackOffice/BackOfficeProjectionsContext.cs +++ b/src/AddressRegistry.Projections.BackOffice/BackOfficeProjectionsContext.cs @@ -3,6 +3,7 @@ namespace AddressRegistry.Projections.BackOffice using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; using Microsoft.EntityFrameworkCore; using AddressRegistry.Infrastructure; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer; public class BackOfficeProjectionsContext : RunnerDbContext { @@ -16,7 +17,7 @@ public BackOfficeProjectionsContext(DbContextOptions + public sealed class BackOfficeProjectionsContextMigrationFactory : SqlServerRunnerDbContextMigrationFactory { public BackOfficeProjectionsContextMigrationFactory() : base("BackOfficeProjectionsAdmin", HistoryConfiguration) { } diff --git a/src/AddressRegistry.Projections.BackOffice/Infrastructure/ServiceCollectionExtensions.cs b/src/AddressRegistry.Projections.BackOffice/Infrastructure/ServiceCollectionExtensions.cs index 24b6de504..a533f028e 100644 --- a/src/AddressRegistry.Projections.BackOffice/Infrastructure/ServiceCollectionExtensions.cs +++ b/src/AddressRegistry.Projections.BackOffice/Infrastructure/ServiceCollectionExtensions.cs @@ -9,6 +9,7 @@ namespace AddressRegistry.Projections.BackOffice.Infrastructure using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using AddressRegistry.Infrastructure; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; public static class ServiceCollectionExtensions { diff --git a/src/AddressRegistry.Projections.BackOffice/paket.references b/src/AddressRegistry.Projections.BackOffice/paket.references index 42805d354..cf7da55b2 100644 --- a/src/AddressRegistry.Projections.BackOffice/paket.references +++ b/src/AddressRegistry.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/AddressRegistry.Projections.Extract/ExtractContextMigrationFactory.cs b/src/AddressRegistry.Projections.Extract/ExtractContextMigrationFactory.cs index 12fd356f6..8de799c98 100644 --- a/src/AddressRegistry.Projections.Extract/ExtractContextMigrationFactory.cs +++ b/src/AddressRegistry.Projections.Extract/ExtractContextMigrationFactory.cs @@ -1,10 +1,11 @@ namespace AddressRegistry.Projections.Extract { using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer; using Infrastructure; using Microsoft.EntityFrameworkCore; - public class ExtractContextMigrationFactory : RunnerDbContextMigrationFactory + public class ExtractContextMigrationFactory : SqlServerRunnerDbContextMigrationFactory { public ExtractContextMigrationFactory() : base("ExtractProjectionsAdmin", HistoryConfiguration) diff --git a/src/AddressRegistry.Projections.Extract/ExtractModule.cs b/src/AddressRegistry.Projections.Extract/ExtractModule.cs index 8572b8aa6..c18067f8d 100755 --- a/src/AddressRegistry.Projections.Extract/ExtractModule.cs +++ b/src/AddressRegistry.Projections.Extract/ExtractModule.cs @@ -5,6 +5,7 @@ namespace AddressRegistry.Projections.Extract using Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql.EntityFrameworkCore; using Autofac; using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using Be.Vlaanderen.Basisregisters.ProjectionHandling.Syndication; using Infrastructure; using Microsoft.EntityFrameworkCore; @@ -55,7 +56,7 @@ private static void RunOnSqlServer( { if (enableRetry) sqlServerOptions.EnableRetryOnFailure(); - + sqlServerOptions.MigrationsHistoryTable(MigrationTables.Extract, Schema.Extract); }) .UseExtendedSqlServerMigrations()); diff --git a/src/AddressRegistry.Projections.Extract/paket.references b/src/AddressRegistry.Projections.Extract/paket.references index 773d934b5..c907d67e8 100644 --- a/src/AddressRegistry.Projections.Extract/paket.references +++ b/src/AddressRegistry.Projections.Extract/paket.references @@ -1,7 +1,7 @@ Be.Vlaanderen.Basisregisters.AggregateSource 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 Be.Vlaanderen.Basisregisters.Shaperon diff --git a/src/AddressRegistry.Projections.Integration/AddressLatestItem.cs b/src/AddressRegistry.Projections.Integration/AddressLatestItem.cs new file mode 100644 index 000000000..7aff48ab6 --- /dev/null +++ b/src/AddressRegistry.Projections.Integration/AddressLatestItem.cs @@ -0,0 +1,100 @@ +namespace AddressRegistry.Projections.Integration +{ + using System; + using AddressRegistry.Infrastructure; + using Be.Vlaanderen.Basisregisters.GrAr.Common; + using Be.Vlaanderen.Basisregisters.Utilities; + using Microsoft.EntityFrameworkCore; + using Microsoft.EntityFrameworkCore.Metadata.Builders; + using NetTopologySuite.Geometries; + using NodaTime; + using StreetName; + + public sealed class AddressLatestItem + { + public const string VersionTimestampBackingPropertyName = nameof(VersionTimestampAsDateTimeOffset); + + public int PersistentLocalId { get; set; } + public string? PostalCode { get; set; } + public int? StreetNamePersistentLocalId { get; set; } + public AddressStatus Status { get; set; } + public string? OsloStatus { get; set; } + public string? HouseNumber { get; set; } + public string? BoxNumber { get; set; } + public Geometry? Geometry { get; set; } + public GeometryMethod PositionMethod { get; set; } + public string? OsloPositionMethod { get; set; } + public GeometrySpecification PositionSpecification { get; set; } + public string? OsloPositionSpecification { get; set; } + public bool? OfficiallyAssigned { get; set; } + public bool Removed { get; set; } + public string? PuriId { 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 AddressLatestItem() + { } + } + + public sealed class AddressLatestItemConfiguration : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + const string tableName = "address_latest_items"; + + builder + .ToTable(tableName, Schema.Integration) // to schema per type + .HasKey(x => x.PersistentLocalId); + + builder.Property(x => x.PersistentLocalId).ValueGeneratedNever(); + + builder.Property(x => x.PersistentLocalId).HasColumnName("persistent_local_id"); + builder.Property(x => x.PostalCode).HasColumnName("postal_code"); + builder.Property(x => x.StreetNamePersistentLocalId).HasColumnName("street_name_persistent_local_id"); + builder.Property(x => x.Status).HasColumnName("status"); + builder.Property(x => x.OsloStatus).HasColumnName("oslo_status"); + builder.Property(x => x.HouseNumber).HasColumnName("house_number"); + builder.Property(x => x.BoxNumber).HasColumnName("box_number"); + + builder.Property(x => x.Geometry).HasColumnName("geometry"); + + builder.Property(x => x.PositionMethod).HasColumnName("position_method"); + builder.Property(x => x.OsloPositionMethod).HasColumnName("oslo_position_method"); + builder.Property(x => x.PositionSpecification).HasColumnName("position_specification"); + builder.Property(x => x.OsloPositionSpecification).HasColumnName("oslo_position_specification"); + builder.Property(x => x.OfficiallyAssigned).HasColumnName("officially_assigned"); + builder.Property(x => x.Removed).HasColumnName("removed"); + builder.Property(x => x.PuriId).HasColumnName("puri_id"); + builder.Property(x => x.Namespace).HasColumnName("namespace"); + builder.Property(x => x.VersionAsString).HasColumnName("version_as_string"); + builder.Property(AddressLatestItem.VersionTimestampBackingPropertyName).HasColumnName("version_timestamp"); + + builder.Ignore(x => x.VersionTimestamp); + + builder.Property(x => x.PersistentLocalId).IsRequired(); + builder.HasIndex(x => x.PersistentLocalId); + + builder.HasIndex(x => x.Geometry).HasMethod("GIST"); + + builder.HasIndex(x => x.StreetNamePersistentLocalId); + builder.HasIndex(x => x.Status); + builder.HasIndex(x => x.OsloStatus); + builder.HasIndex(x => x.PostalCode); + builder.HasIndex(x => x.HouseNumber); + builder.HasIndex(x => x.BoxNumber); + builder.HasIndex(x => x.Removed); + } + } +} diff --git a/src/AddressRegistry.Projections.Integration/AddressLatestItemExtensions.cs b/src/AddressRegistry.Projections.Integration/AddressLatestItemExtensions.cs new file mode 100644 index 000000000..c8f1e3236 --- /dev/null +++ b/src/AddressRegistry.Projections.Integration/AddressLatestItemExtensions.cs @@ -0,0 +1,31 @@ +namespace AddressRegistry.Projections.Integration +{ + using System; + using System.Threading; + using System.Threading.Tasks; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector; + + public static class AddressLatestItemExtensions + { + public static async Task FindAndUpdateAddressLatestItem(this IntegrationContext context, + int persistentLocalId, + long position, + Action updateFunc, + CancellationToken ct) + { + var addressLatestItem = await context + .AddressLatestItems + .FindAsync(persistentLocalId, cancellationToken: ct); + + if (addressLatestItem == null) + throw DatabaseItemNotFound(new PersistentLocalId(persistentLocalId)); + + updateFunc(addressLatestItem); + + return addressLatestItem; + } + + private static ProjectionItemNotFoundException DatabaseItemNotFound(PersistentLocalId persistentLocalId) + => new ProjectionItemNotFoundException(persistentLocalId); + } +} diff --git a/src/AddressRegistry.Projections.Integration/AddressLatestItemProjection.cs b/src/AddressRegistry.Projections.Integration/AddressLatestItemProjection.cs new file mode 100644 index 000000000..29397a77a --- /dev/null +++ b/src/AddressRegistry.Projections.Integration/AddressLatestItemProjection.cs @@ -0,0 +1,662 @@ +namespace AddressRegistry.Projections.Integration +{ + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore; + using Be.Vlaanderen.Basisregisters.Utilities.HexByteConvertor; + using Convertors; + using Infrastructure; + using Microsoft.Extensions.Options; + using NodaTime; + using StreetName; + using StreetName.Events; + + [ConnectedProjectionName("Integratie adres latest item")] + [ConnectedProjectionDescription("Projectie die de laatste adres data voor de integratie database bijhoudt.")] + public sealed class AddressLatestItemProjections : ConnectedProjection + { + public AddressLatestItemProjections(IOptions options) + { + // StreetName + When>(async (context, message, ct) => + { + foreach (var addressPersistentLocalId in message.Message.AddressPersistentLocalIds) + { + await context.FindAndUpdateAddressLatestItem( + addressPersistentLocalId, + message.Position, + item => { UpdateVersionTimestampIfNewer(item, message.Message.Provenance.Timestamp); }, + ct); + } + }); + + When>(async (context, message, ct) => + { + foreach (var addressPersistentLocalId in message.Message.AddressPersistentLocalIds) + { + await context.FindAndUpdateAddressLatestItem( + addressPersistentLocalId, + message.Position, + item => { UpdateVersionTimestampIfNewer(item, message.Message.Provenance.Timestamp); }, + ct); + } + }); + + When>(async (context, message, ct) => + { + foreach (var addressPersistentLocalId in message.Message.AddressPersistentLocalIds) + { + await context.FindAndUpdateAddressLatestItem( + addressPersistentLocalId, + message.Position, + item => { UpdateVersionTimestampIfNewer(item, message.Message.Provenance.Timestamp); }, + ct); + } + }); + + // Address + When>(async (context, message, ct) => + { + var geometry = WKBReaderFactory.CreateForLegacy().Read(message.Message.ExtendedWkbGeometry.ToByteArray()); + + var addressLatestItem = new AddressLatestItem() + { + PersistentLocalId = message.Message.AddressPersistentLocalId, + PostalCode = message.Message.PostalCode, + StreetNamePersistentLocalId = message.Message.StreetNamePersistentLocalId, + Status = message.Message.Status, + OsloStatus = message.Message.Status.Map(), + HouseNumber = message.Message.HouseNumber, + BoxNumber = message.Message.BoxNumber, + Geometry = geometry, + PositionMethod = message.Message.GeometryMethod, + OsloPositionMethod = message.Message.GeometryMethod.ToPositieGeometrieMethode(), + PositionSpecification = message.Message.GeometrySpecification, + OsloPositionSpecification = message.Message.GeometrySpecification.ToPositieSpecificatie(), + OfficiallyAssigned = message.Message.OfficiallyAssigned, + Removed = message.Message.IsRemoved, + VersionTimestamp = message.Message.Provenance.Timestamp, + Namespace = options.Value.Namespace, + PuriId = $"{options.Value.Namespace}/{message.Message.AddressPersistentLocalId}", + }; + + await context + .AddressLatestItems + .AddAsync(addressLatestItem, ct); + }); + + When>(async (context, message, ct) => + { + var geometry = WKBReaderFactory.CreateForLegacy().Read(message.Message.ExtendedWkbGeometry.ToByteArray()); + + var addressLatestItem = new AddressLatestItem() + { + PersistentLocalId = message.Message.AddressPersistentLocalId, + PostalCode = message.Message.PostalCode, + StreetNamePersistentLocalId = message.Message.StreetNamePersistentLocalId, + Status = AddressStatus.Proposed, + OsloStatus = AddressStatus.Proposed.Map(), + HouseNumber = message.Message.HouseNumber, + BoxNumber = message.Message.BoxNumber, + Geometry = geometry, + PositionMethod = message.Message.GeometryMethod, + OsloPositionMethod = message.Message.GeometryMethod.ToPositieGeometrieMethode(), + PositionSpecification = message.Message.GeometrySpecification, + OsloPositionSpecification = message.Message.GeometrySpecification.ToPositieSpecificatie(), + OfficiallyAssigned = true, + Removed = false, + VersionTimestamp = message.Message.Provenance.Timestamp, + Namespace = options.Value.Namespace, + PuriId = $"{options.Value.Namespace}/{message.Message.AddressPersistentLocalId}", + }; + + await context + .AddressLatestItems + .AddAsync(addressLatestItem, ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.Status = AddressStatus.Current; + item.OsloStatus = AddressStatus.Current.Map(); + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.Status = AddressStatus.Proposed; + item.OsloStatus = AddressStatus.Proposed.Map(); + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.Status = AddressStatus.Proposed; + item.OsloStatus = AddressStatus.Proposed.Map(); + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.Status = AddressStatus.Rejected; + item.OsloStatus = AddressStatus.Rejected.Map(); + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.Status = AddressStatus.Rejected; + item.OsloStatus = AddressStatus.Rejected.Map(); + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.Status = AddressStatus.Rejected; + item.OsloStatus = AddressStatus.Rejected.Map(); + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.Status = AddressStatus.Rejected; + item.OsloStatus = AddressStatus.Rejected.Map(); + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.Status = AddressStatus.Retired; + item.OsloStatus = AddressStatus.Retired.Map(); + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.Status = AddressStatus.Rejected; + item.OsloStatus = AddressStatus.Rejected.Map(); + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.OfficiallyAssigned = false; + item.Status = AddressStatus.Current; + item.OsloStatus = AddressStatus.Current.Map(); + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.OfficiallyAssigned = true; + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.Status = AddressStatus.Retired; + item.OsloStatus = AddressStatus.Retired.Map(); + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.Status = AddressStatus.Retired; + item.OsloStatus = AddressStatus.Retired.Map(); + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.Status = AddressStatus.Retired; + item.OsloStatus = AddressStatus.Retired.Map(); + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.Status = AddressStatus.Current; + item.OsloStatus = AddressStatus.Current.Map(); + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.PostalCode = message.Message.PostalCode; + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + + foreach (var boxNumberPersistentLocalId in message.Message.BoxNumberPersistentLocalIds) + { + await context.FindAndUpdateAddressLatestItem( + boxNumberPersistentLocalId, + message.Position, + boxNumberItem => + { + boxNumberItem.PostalCode = message.Message.PostalCode; + UpdateVersionTimestamp(boxNumberItem, message.Message.Provenance.Timestamp); + }, + ct); + } + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.PostalCode = message.Message.PostalCode; + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + + foreach (var boxNumberPersistentLocalId in message.Message.BoxNumberPersistentLocalIds) + { + await context.FindAndUpdateAddressLatestItem( + boxNumberPersistentLocalId, + message.Position, + boxNumberItem => + { + boxNumberItem.PostalCode = message.Message.PostalCode; + UpdateVersionTimestamp(boxNumberItem, message.Message.Provenance.Timestamp); + }, + ct); + } + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.HouseNumber = message.Message.HouseNumber; + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + + foreach (var boxNumberPersistentLocalId in message.Message.BoxNumberPersistentLocalIds) + { + await context.FindAndUpdateAddressLatestItem( + boxNumberPersistentLocalId, + message.Position, + boxNumberItem => + { + boxNumberItem.HouseNumber = message.Message.HouseNumber; + UpdateVersionTimestamp(boxNumberItem, message.Message.Provenance.Timestamp); + }, + ct); + } + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.BoxNumber = message.Message.BoxNumber; + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + + When>(async (context, message, ct) => + { + var geometry = WKBReaderFactory.CreateForLegacy().Read(message.Message.ExtendedWkbGeometry.ToByteArray()); + + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.PositionMethod = message.Message.GeometryMethod; + item.OsloPositionMethod = message.Message.GeometryMethod.ToPositieGeometrieMethode(); + item.PositionSpecification = message.Message.GeometrySpecification; + item.OsloPositionSpecification = message.Message.GeometrySpecification.ToPositieSpecificatie(); + item.Geometry = geometry; + + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + + When>(async (context, message, ct) => + { + var geometry = WKBReaderFactory.CreateForLegacy().Read(message.Message.ExtendedWkbGeometry.ToByteArray()); + + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.PositionMethod = message.Message.GeometryMethod; + item.OsloPositionMethod = message.Message.GeometryMethod.ToPositieGeometrieMethode(); + item.PositionSpecification = message.Message.GeometrySpecification; + item.OsloPositionSpecification = message.Message.GeometrySpecification.ToPositieSpecificatie(); + item.Geometry = geometry; + + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + + When>(async (context, message, ct) => + { + var geometry = WKBReaderFactory.CreateForLegacy() + .Read(message.Message.ReaddressedHouseNumber.SourceExtendedWkbGeometry.ToByteArray()); + + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.Status = message.Message.ReaddressedHouseNumber.SourceStatus; + item.OsloStatus = message.Message.ReaddressedHouseNumber.SourceStatus.Map(); + item.HouseNumber = message.Message.ReaddressedHouseNumber.DestinationHouseNumber; + item.PostalCode = message.Message.ReaddressedHouseNumber.SourcePostalCode; + item.OfficiallyAssigned = message.Message.ReaddressedHouseNumber.SourceIsOfficiallyAssigned; + item.PositionMethod = message.Message.ReaddressedHouseNumber.SourceGeometryMethod; + item.OsloPositionMethod = message.Message.ReaddressedHouseNumber.SourceGeometryMethod.ToPositieGeometrieMethode(); + item.PositionSpecification = message.Message.ReaddressedHouseNumber.SourceGeometrySpecification; + item.OsloPositionSpecification = message.Message.ReaddressedHouseNumber.SourceGeometrySpecification.ToPositieSpecificatie(); + item.Geometry = geometry; + + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + + foreach (var readdressedBoxNumber in message.Message.ReaddressedBoxNumbers) + { + var boxNumberGeometry = WKBReaderFactory.CreateForLegacy() + .Read(message.Message.ReaddressedHouseNumber.SourceExtendedWkbGeometry.ToByteArray()); + + await context.FindAndUpdateAddressLatestItem( + readdressedBoxNumber.DestinationAddressPersistentLocalId, + message.Position, + item => + { + item.Status = readdressedBoxNumber.SourceStatus; + item.OsloStatus = readdressedBoxNumber.SourceStatus.Map(); + item.HouseNumber = readdressedBoxNumber.DestinationHouseNumber; + item.BoxNumber = readdressedBoxNumber.SourceBoxNumber; + item.PostalCode = readdressedBoxNumber.SourcePostalCode; + item.OfficiallyAssigned = readdressedBoxNumber.SourceIsOfficiallyAssigned; + item.PositionMethod = readdressedBoxNumber.SourceGeometryMethod; + item.OsloPositionMethod = readdressedBoxNumber.SourceGeometryMethod.ToPositieGeometrieMethode(); + item.PositionSpecification = readdressedBoxNumber.SourceGeometrySpecification; + item.OsloPositionSpecification = readdressedBoxNumber.SourceGeometrySpecification.ToPositieSpecificatie(); + item.Geometry = boxNumberGeometry; + + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + } + }); + + When>(async (context, message, ct) => + { + var geometry = WKBReaderFactory.CreateForLegacy().Read(message.Message.ExtendedWkbGeometry.ToByteArray()); + + var addressLatestItem = new AddressLatestItem + { + PersistentLocalId = message.Message.AddressPersistentLocalId, + PostalCode = message.Message.PostalCode, + StreetNamePersistentLocalId = message.Message.StreetNamePersistentLocalId, + Status = AddressStatus.Proposed, + OsloStatus = AddressStatus.Proposed.Map(), + HouseNumber = message.Message.HouseNumber, + BoxNumber = message.Message.BoxNumber, + Geometry = geometry, + PositionMethod = message.Message.GeometryMethod, + OsloPositionMethod = message.Message.GeometryMethod.ToPositieGeometrieMethode(), + PositionSpecification = message.Message.GeometrySpecification, + OsloPositionSpecification = message.Message.GeometrySpecification.ToPositieSpecificatie(), + OfficiallyAssigned = true, + Removed = false, + VersionTimestamp = message.Message.Provenance.Timestamp, + Namespace = options.Value.Namespace, + PuriId = $"{options.Value.Namespace}/{message.Message.AddressPersistentLocalId}", + }; + + await context + .AddressLatestItems + .AddAsync(addressLatestItem, ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.Status = AddressStatus.Rejected; + item.OsloStatus = AddressStatus.Rejected.Map(); + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.Status = AddressStatus.Retired; + item.OsloStatus = AddressStatus.Retired.Map(); + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.Removed = true; + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.Removed = true; + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.Removed = true; + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.Status = AddressStatus.Proposed; + item.OsloStatus = AddressStatus.Proposed.Map(); + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.OfficiallyAssigned = false; + item.Status = AddressStatus.Current; + item.OsloStatus = AddressStatus.Current.Map(); + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateAddressLatestItem( + message.Message.AddressPersistentLocalId, + message.Position, + item => + { + item.OfficiallyAssigned = true; + UpdateVersionTimestamp(item, message.Message.Provenance.Timestamp); + }, + ct); + }); + } + + private static void UpdateVersionTimestampIfNewer(AddressLatestItem addressLatestItem, Instant versionTimestamp) + { + if (versionTimestamp > addressLatestItem.VersionTimestamp) + { + addressLatestItem.VersionTimestamp = versionTimestamp; + } + } + + private static void UpdateVersionTimestamp(AddressLatestItem addressLatestItem, Instant versionTimestamp) + => addressLatestItem.VersionTimestamp = versionTimestamp; + } +} diff --git a/src/AddressRegistry.Projections.Integration/AddressRegistry.Projections.Integration.csproj b/src/AddressRegistry.Projections.Integration/AddressRegistry.Projections.Integration.csproj new file mode 100644 index 000000000..5ed1c0f18 --- /dev/null +++ b/src/AddressRegistry.Projections.Integration/AddressRegistry.Projections.Integration.csproj @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/AddressRegistry.Projections.Integration/AddressVersion.cs b/src/AddressRegistry.Projections.Integration/AddressVersion.cs new file mode 100644 index 000000000..f92954fec --- /dev/null +++ b/src/AddressRegistry.Projections.Integration/AddressVersion.cs @@ -0,0 +1,163 @@ +namespace AddressRegistry.Projections.Integration +{ + using System; + using Be.Vlaanderen.Basisregisters.GrAr.Common; + using Be.Vlaanderen.Basisregisters.Utilities; + using Microsoft.EntityFrameworkCore; + using Microsoft.EntityFrameworkCore.Metadata.Builders; + using AddressRegistry.Infrastructure; + using NetTopologySuite.Geometries; + using NodaTime; + using StreetName; + + public sealed class AddressVersion + { + public const string VersionTimestampBackingPropertyName = nameof(VersionTimestampAsDateTimeOffset); + public const string CreatedOnTimestampBackingPropertyName = nameof(CreatedOnTimestampAsDateTimeOffset); + + public long Position { get; set; } + + public int PersistentLocalId { get; set; } + public Guid? AddressId { get; set; } + public string? PostalCode { get; set; } + public int? StreetNamePersistentLocalId { get; set; } + public Guid? StreetNameId { get; set; } + public AddressStatus? Status { get; set; } + public string? OsloStatus { get; set; } + public string? HouseNumber { get; set; } + public string? BoxNumber { get; set; } + public Geometry? Geometry { get; set; } + public GeometryMethod? PositionMethod { get; set; } + public string? OsloPositionMethod { get; set; } + public GeometrySpecification? PositionSpecification { get; set; } + public string? OsloPositionSpecification { get; set; } + public bool? OfficiallyAssigned { get; set; } + public bool Removed { get; set; } + public string? PuriId { 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 AddressVersion() + { } + + public AddressVersion CloneAndApplyEventInfo( + long newPosition, + Instant lastChangedOn, + Action editFunc) + { + var newItem = new AddressVersion + { + Position = newPosition, + PersistentLocalId = PersistentLocalId, + AddressId = AddressId, + PostalCode = PostalCode, + StreetNamePersistentLocalId = StreetNamePersistentLocalId, + StreetNameId = StreetNameId, + Status = Status, + OsloStatus = OsloStatus, + HouseNumber = HouseNumber, + BoxNumber = BoxNumber, + Geometry = Geometry, + PositionMethod = PositionMethod, + PositionSpecification = PositionSpecification, + OfficiallyAssigned = OfficiallyAssigned, + Removed = Removed, + PuriId = PuriId, + Namespace = Namespace, + VersionTimestamp = lastChangedOn, + CreatedOnTimestamp = CreatedOnTimestamp + }; + + editFunc(newItem); + + return newItem; + } + } + + public sealed class AddressVersionConfiguration : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + const string tableName = "address_versions"; + + builder + .ToTable(tableName, Schema.Integration) // to schema per type + .HasKey(x => new { x.Position, x.PersistentLocalId}); + + builder.Property(x => x.Position).ValueGeneratedNever(); + + builder.Property(x => x.AddressId).HasColumnName("address_id"); + builder.Property(x => x.Position).HasColumnName("position"); + builder.Property(x => x.PersistentLocalId).HasColumnName("persistent_local_id"); + builder.Property(x => x.PostalCode).HasColumnName("postal_code"); + builder.Property(x => x.StreetNamePersistentLocalId).HasColumnName("street_name_persistent_local_id"); + builder.Property(x => x.StreetNameId).HasColumnName("street_name_id"); + builder.Property(x => x.Status).HasColumnName("status"); + builder.Property(x => x.OsloStatus).HasColumnName("oslo_status"); + builder.Property(x => x.HouseNumber).HasColumnName("house_number"); + builder.Property(x => x.BoxNumber).HasColumnName("box_number"); + + builder.Property(x => x.Geometry).HasColumnName("geometry"); + + builder.Property(x => x.PositionMethod).HasColumnName("position_method"); + builder.Property(x => x.OsloPositionMethod).HasColumnName("oslo_position_method"); + builder.Property(x => x.PositionSpecification).HasColumnName("position_specification"); + builder.Property(x => x.OsloPositionSpecification).HasColumnName("oslo_position_specification"); + builder.Property(x => x.OfficiallyAssigned).HasColumnName("officially_assigned"); + builder.Property(x => x.Removed).HasColumnName("removed"); + builder.Property(x => x.PuriId).HasColumnName("puri_id"); + builder.Property(x => x.Namespace).HasColumnName("namespace"); + builder.Property(x => x.VersionAsString).HasColumnName("version_as_string"); + builder.Property(x => x.CreatedOnAsString).HasColumnName("created_on_as_string"); + + builder.Ignore(x => x.VersionTimestamp); + builder.Property(AddressVersion.VersionTimestampBackingPropertyName).HasColumnName("version_timestamp"); + + builder.Ignore(x => x.CreatedOnTimestamp); + builder.Property(AddressVersion.CreatedOnTimestampBackingPropertyName).HasColumnName("created_on_timestamp"); + + + builder.Property(x => x.PersistentLocalId).IsRequired(); + builder.HasIndex(x => x.PersistentLocalId); + + builder.HasIndex(x => x.Geometry).HasMethod("GIST"); + + builder.HasIndex(x => x.StreetNamePersistentLocalId); + builder.HasIndex(x => x.StreetNameId); + builder.HasIndex(x => x.AddressId); + builder.HasIndex(x => x.Status); + builder.HasIndex(x => x.OsloStatus); + builder.HasIndex(x => x.PostalCode); + builder.HasIndex(x => x.HouseNumber); + builder.HasIndex(x => x.BoxNumber); + builder.HasIndex(x => x.Removed); + builder.HasIndex(AddressVersion.VersionTimestampBackingPropertyName); + } + } +} diff --git a/src/AddressRegistry.Projections.Integration/AddressVersionExtension.cs b/src/AddressRegistry.Projections.Integration/AddressVersionExtension.cs new file mode 100644 index 000000000..09071229b --- /dev/null +++ b/src/AddressRegistry.Projections.Integration/AddressVersionExtension.cs @@ -0,0 +1,105 @@ +namespace AddressRegistry.Projections.Integration +{ + using System; + 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 AddressVersionExtensions + { + public static async Task CreateNewAddressVersion( + this IntegrationContext context, + PersistentLocalId persistentLocalId, + Envelope message, + Action applyEventInfoOn, + CancellationToken ct) where T : IHasProvenance, IMessage + { + var addressVersion = await context.LatestPosition(persistentLocalId, ct); + + if (addressVersion is null) + { + throw DatabaseItemNotFound(persistentLocalId); + } + + var provenance = message.Message.Provenance; + + var newAddressVersion = addressVersion.CloneAndApplyEventInfo( + message.Position, + provenance.Timestamp, + applyEventInfoOn); + + await context + .AddressVersions + .AddAsync(newAddressVersion, ct); + } + + public static async Task CreateNewAddressVersion( + this IntegrationContext context, + Guid addressId, + Envelope message, + Action applyEventInfoOn, + CancellationToken ct) where T : IHasProvenance, IMessage + { + var addressVersion = await context.LatestPosition(addressId, ct); + + if (addressVersion is null) + { + throw DatabaseItemNotFound(addressId); + } + + var provenance = message.Message.Provenance; + + var newAddressVersion = addressVersion.CloneAndApplyEventInfo( + message.Position, + provenance.Timestamp, + applyEventInfoOn); + + await context + .AddressVersions + .AddAsync(newAddressVersion, ct); + } + + private static async Task LatestPosition( + this IntegrationContext context, + PersistentLocalId persistentLocalId, + CancellationToken ct) + => context + .AddressVersions + .Local + .Where(x => x.PersistentLocalId == persistentLocalId) + .OrderByDescending(x => x.Position) + .FirstOrDefault() + ?? await context + .AddressVersions + .Where(x => x.PersistentLocalId == persistentLocalId) + .OrderByDescending(x => x.Position) + .FirstOrDefaultAsync(ct); + + static async Task LatestPosition( + this IntegrationContext context, + Guid addressId, + CancellationToken ct) + => context + .AddressVersions + .Local + .Where(x => x.AddressId == addressId) + .OrderByDescending(x => x.Position) + .FirstOrDefault() + ?? await context + .AddressVersions + .Where(x => x.AddressId == addressId) + .OrderByDescending(x => x.Position) + .FirstOrDefaultAsync(ct); + + private static ProjectionItemNotFoundException DatabaseItemNotFound(PersistentLocalId persistentLocalId) + => new(persistentLocalId.ToString()); + + private static ProjectionItemNotFoundException DatabaseItemNotFound(Guid addressId) + => new(addressId.ToString()); + } +} diff --git a/src/AddressRegistry.Projections.Integration/AddressVersionProjection.cs b/src/AddressRegistry.Projections.Integration/AddressVersionProjection.cs new file mode 100644 index 000000000..a223191c9 --- /dev/null +++ b/src/AddressRegistry.Projections.Integration/AddressVersionProjection.cs @@ -0,0 +1,894 @@ +namespace AddressRegistry.Projections.Integration +{ + using System; + using Address.Events; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore; + using Be.Vlaanderen.Basisregisters.Utilities.HexByteConvertor; + using Convertors; + using Infrastructure; + using Microsoft.Extensions.Options; + using NetTopologySuite.Index.HPRtree; + using StreetName; + using StreetName.Events; + + [ConnectedProjectionName("Integratie adres versie")] + [ConnectedProjectionDescription("Projectie die de laatste adres data voor de integratie database bijhoudt.")] + public sealed class AddressVersionProjections : ConnectedProjection + { + public AddressVersionProjections(IOptions options, IEventsRepository eventsRepository) + { + // Address + When>(async (context, message, ct) => + { + var geometry = WKBReaderFactory.CreateForLegacy().Read(message.Message.ExtendedWkbGeometry.ToByteArray()); + + var addressVersion = new AddressVersion + { + Position = message.Position, + PersistentLocalId = message.Message.AddressPersistentLocalId, + PostalCode = message.Message.PostalCode, + StreetNamePersistentLocalId = message.Message.StreetNamePersistentLocalId, + Status = message.Message.Status, + OsloStatus = message.Message.Status.Map(), + HouseNumber = message.Message.HouseNumber, + BoxNumber = message.Message.BoxNumber, + Geometry = geometry, + PositionMethod = message.Message.GeometryMethod, + OsloPositionMethod = message.Message.GeometryMethod.ToPositieGeometrieMethode(), + PositionSpecification = message.Message.GeometrySpecification, + OsloPositionSpecification = message.Message.GeometrySpecification.ToPositieSpecificatie(), + OfficiallyAssigned = message.Message.OfficiallyAssigned, + Removed = message.Message.IsRemoved, + VersionTimestamp = message.Message.Provenance.Timestamp, + CreatedOnTimestamp = message.Message.Provenance.Timestamp, + Namespace = options.Value.Namespace, + PuriId = $"{options.Value.Namespace}/{message.Message.AddressPersistentLocalId}", + }; + + await context.AddressVersions.AddAsync(addressVersion, ct); + }); + + When>(async (context, message, ct) => + { + var geometry = WKBReaderFactory.CreateForLegacy().Read(message.Message.ExtendedWkbGeometry.ToByteArray()); + + var addressVersion = new AddressVersion() + { + Position = message.Position, + PersistentLocalId = message.Message.AddressPersistentLocalId, + PostalCode = message.Message.PostalCode, + StreetNamePersistentLocalId = message.Message.StreetNamePersistentLocalId, + Status = AddressStatus.Proposed, + OsloStatus = AddressStatus.Proposed.Map(), + HouseNumber = message.Message.HouseNumber, + BoxNumber = message.Message.BoxNumber, + Geometry = geometry, + PositionMethod = message.Message.GeometryMethod, + OsloPositionMethod = message.Message.GeometryMethod.ToPositieGeometrieMethode(), + PositionSpecification = message.Message.GeometrySpecification, + OsloPositionSpecification = message.Message.GeometrySpecification.ToPositieSpecificatie(), + OfficiallyAssigned = true, + Removed = false, + VersionTimestamp = message.Message.Provenance.Timestamp, + CreatedOnTimestamp = message.Message.Provenance.Timestamp, + Namespace = options.Value.Namespace, + PuriId = $"{options.Value.Namespace}/{message.Message.AddressPersistentLocalId}", + }; + + await context.AddressVersions.AddAsync(addressVersion, ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => + { + item.Status = AddressStatus.Current; + item.OsloStatus = AddressStatus.Current.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => + { + item.Status = AddressStatus.Proposed; + item.OsloStatus = AddressStatus.Proposed.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => + { + item.Status = AddressStatus.Proposed; + item.OsloStatus = AddressStatus.Proposed.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => + { + item.Status = AddressStatus.Rejected; + item.OsloStatus = AddressStatus.Rejected.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => + { + item.Status = AddressStatus.Rejected; + item.OsloStatus = AddressStatus.Rejected.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => + { + item.Status = AddressStatus.Rejected; + item.OsloStatus = AddressStatus.Rejected.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => + { + item.Status = AddressStatus.Rejected; + item.OsloStatus = AddressStatus.Rejected.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => + { + item.Status = AddressStatus.Retired; + item.OsloStatus = AddressStatus.Retired.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => + { + item.Status = AddressStatus.Rejected; + item.OsloStatus = AddressStatus.Rejected.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => + { + item.OfficiallyAssigned = false; + item.Status = AddressStatus.Current; + item.OsloStatus = AddressStatus.Current.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => { item.OfficiallyAssigned = true; }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => + { + item.Status = AddressStatus.Retired; + item.OsloStatus = AddressStatus.Retired.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => + { + item.Status = AddressStatus.Retired; + item.OsloStatus = AddressStatus.Retired.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => + { + item.Status = AddressStatus.Retired; + item.OsloStatus = AddressStatus.Retired.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => + { + item.Status = AddressStatus.Current; + item.OsloStatus = AddressStatus.Current.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => { item.PostalCode = message.Message.PostalCode; }, + ct); + + foreach (var boxNumberPersistentLocalId in message.Message.BoxNumberPersistentLocalIds) + { + await context.CreateNewAddressVersion( + new PersistentLocalId(boxNumberPersistentLocalId), + message, + boxNumberItem => { boxNumberItem.PostalCode = message.Message.PostalCode; }, + ct); + } + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => { item.PostalCode = message.Message.PostalCode; }, + ct); + + foreach (var boxNumberPersistentLocalId in message.Message.BoxNumberPersistentLocalIds) + { + await context.CreateNewAddressVersion( + new PersistentLocalId(boxNumberPersistentLocalId), + message, + boxNumberItem => { boxNumberItem.PostalCode = message.Message.PostalCode; }, + ct); + } + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => { item.HouseNumber = message.Message.HouseNumber; }, + ct); + + foreach (var boxNumberPersistentLocalId in message.Message.BoxNumberPersistentLocalIds) + { + await context.CreateNewAddressVersion( + new PersistentLocalId(boxNumberPersistentLocalId), + message, + boxNumberItem => { boxNumberItem.HouseNumber = message.Message.HouseNumber; }, + ct); + } + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => { item.BoxNumber = message.Message.BoxNumber; }, + ct); + }); + + When>(async (context, message, ct) => + { + var geometry = WKBReaderFactory.CreateForLegacy().Read(message.Message.ExtendedWkbGeometry.ToByteArray()); + + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => + { + item.PositionMethod = message.Message.GeometryMethod; + item.OsloPositionMethod = message.Message.GeometryMethod.ToPositieGeometrieMethode(); + item.PositionSpecification = message.Message.GeometrySpecification; + item.OsloPositionSpecification = message.Message.GeometrySpecification.ToPositieSpecificatie(); + item.Geometry = geometry; + }, + ct); + }); + + When>(async (context, message, ct) => + { + var geometry = WKBReaderFactory.CreateForLegacy().Read(message.Message.ExtendedWkbGeometry.ToByteArray()); + + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => + { + item.PositionMethod = message.Message.GeometryMethod; + item.OsloPositionMethod = message.Message.GeometryMethod.ToPositieGeometrieMethode(); + item.PositionSpecification = message.Message.GeometrySpecification; + item.OsloPositionSpecification = message.Message.GeometrySpecification.ToPositieSpecificatie(); + item.Geometry = geometry; + }, + ct); + }); + + When>(async (context, message, ct) => + { + var geometry = WKBReaderFactory.CreateForLegacy() + .Read(message.Message.ReaddressedHouseNumber.SourceExtendedWkbGeometry.ToByteArray()); + + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => + { + item.Status = message.Message.ReaddressedHouseNumber.SourceStatus; + item.OsloStatus = message.Message.ReaddressedHouseNumber.SourceStatus.Map(); + item.HouseNumber = message.Message.ReaddressedHouseNumber.DestinationHouseNumber; + item.PostalCode = message.Message.ReaddressedHouseNumber.SourcePostalCode; + item.OfficiallyAssigned = message.Message.ReaddressedHouseNumber.SourceIsOfficiallyAssigned; + item.PositionMethod = message.Message.ReaddressedHouseNumber.SourceGeometryMethod; + item.OsloPositionMethod = message.Message.ReaddressedHouseNumber.SourceGeometryMethod.ToPositieGeometrieMethode(); + item.PositionSpecification = message.Message.ReaddressedHouseNumber.SourceGeometrySpecification; + item.OsloPositionSpecification = message.Message.ReaddressedHouseNumber.SourceGeometrySpecification.ToPositieSpecificatie(); + item.Geometry = geometry; + }, + ct); + + foreach (var readdressedBoxNumber in message.Message.ReaddressedBoxNumbers) + { + var boxNumberGeometry = WKBReaderFactory.CreateForLegacy() + .Read(message.Message.ReaddressedHouseNumber.SourceExtendedWkbGeometry.ToByteArray()); + + await context.CreateNewAddressVersion( + new PersistentLocalId(readdressedBoxNumber.DestinationAddressPersistentLocalId), + message, + item => + { + item.Status = readdressedBoxNumber.SourceStatus; + item.OsloStatus = readdressedBoxNumber.SourceStatus.Map(); + item.HouseNumber = readdressedBoxNumber.DestinationHouseNumber; + item.BoxNumber = readdressedBoxNumber.SourceBoxNumber; + item.PostalCode = readdressedBoxNumber.SourcePostalCode; + item.OfficiallyAssigned = readdressedBoxNumber.SourceIsOfficiallyAssigned; + item.PositionMethod = readdressedBoxNumber.SourceGeometryMethod; + item.OsloPositionMethod = readdressedBoxNumber.SourceGeometryMethod.ToPositieGeometrieMethode(); + item.PositionSpecification = readdressedBoxNumber.SourceGeometrySpecification; + item.OsloPositionSpecification = readdressedBoxNumber.SourceGeometrySpecification.ToPositieSpecificatie(); + item.Geometry = boxNumberGeometry; + }, + ct); + } + }); + + When>(async (context, message, ct) => + { + var geometry = WKBReaderFactory.CreateForLegacy().Read(message.Message.ExtendedWkbGeometry.ToByteArray()); + + var addressDetailItemV2 = new AddressVersion + { + Position = message.Position, + PersistentLocalId = new PersistentLocalId(message.Message.AddressPersistentLocalId), + PostalCode = message.Message.PostalCode, + StreetNamePersistentLocalId = message.Message.StreetNamePersistentLocalId, + Status = AddressStatus.Proposed, + OsloStatus = AddressStatus.Proposed.Map(), + HouseNumber = message.Message.HouseNumber, + BoxNumber = message.Message.BoxNumber, + Geometry = geometry, + PositionMethod = message.Message.GeometryMethod, + OsloPositionMethod = message.Message.GeometryMethod.ToPositieGeometrieMethode(), + PositionSpecification = message.Message.GeometrySpecification, + OsloPositionSpecification = message.Message.GeometrySpecification.ToPositieSpecificatie(), + OfficiallyAssigned = true, + Removed = false, + VersionTimestamp = message.Message.Provenance.Timestamp, + CreatedOnTimestamp = message.Message.Provenance.Timestamp, + Namespace = options.Value.Namespace, + PuriId = $"{options.Value.Namespace}/{message.Message.AddressPersistentLocalId}", + }; + + await context + .AddressVersions + .AddAsync(addressDetailItemV2, ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => + { + item.Status = AddressStatus.Rejected; + item.OsloStatus = AddressStatus.Rejected.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => + { + item.Status = AddressStatus.Retired; + item.OsloStatus = AddressStatus.Retired.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => { item.Removed = true; }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => { item.Removed = true; }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => { item.Removed = true; }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => + { + item.Status = AddressStatus.Proposed; + item.OsloStatus = AddressStatus.Proposed.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => + { + item.OfficiallyAssigned = false; + item.Status = AddressStatus.Current; + item.OsloStatus = AddressStatus.Current.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + new PersistentLocalId(message.Message.AddressPersistentLocalId), + message, + item => { item.OfficiallyAssigned = true; }, + ct); + }); + + #region Legacy + + When>(async (context, message, ct) => + { + var addressPersistentLocalId = await eventsRepository.GetAddressPersistentLocalId(message.Message.AddressId); + + if (!addressPersistentLocalId.HasValue) + { + throw new InvalidOperationException($"No persistent local id found for {message.Message.AddressId}"); + } + + var address = new AddressVersion + { + PersistentLocalId = addressPersistentLocalId.Value, + AddressId = message.Message.AddressId, + StreetNameId = message.Message.StreetNameId, + HouseNumber = message.Message.HouseNumber, + PuriId = $"{options.Value.Namespace}/{addressPersistentLocalId}", + Namespace = options.Value.Namespace, + VersionTimestamp = message.Message.Provenance.Timestamp, + CreatedOnTimestamp = message.Message.Provenance.Timestamp, + }; + + await context.AddressVersions.AddAsync(address, ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + _ => { }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => + { + item.Status = AddressStatus.Current; + item.OsloStatus = AddressStatus.Current.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + _ => { }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => { item.OfficiallyAssigned = false; }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => { item.HouseNumber = message.Message.HouseNumber; }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => { item.HouseNumber = message.Message.HouseNumber; }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => { item.OfficiallyAssigned = null; }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => + { + item.PersistentLocalId = message.Message.PersistentLocalId; + }, + ct); + }); + + When>(async (context, message, ct) => + { + var geometry = WKBReaderFactory.CreateForLegacy() + .Read(message.Message.ExtendedWkbGeometry.ToByteArray()); + + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => + { + item.PositionMethod = message.Message.GeometryMethod.ToGeometryMethod(); + item.OsloPositionMethod = message.Message.GeometryMethod.ToPositieGeometrieMethode(); + item.PositionSpecification = message.Message.GeometrySpecification.ToGeometrySpecification(); + item.OsloPositionSpecification = message.Message.GeometrySpecification.ToPositieSpecificatie(); + item.Geometry = geometry; + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => + { + item.Geometry = null; + item.PositionMethod = null; + item.OsloPositionMethod = null; + item.PositionSpecification = null; + item.OsloPositionSpecification = null; + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => { item.PostalCode = message.Message.PostalCode; }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => { item.PostalCode = message.Message.PostalCode; }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => { item.PostalCode = null; }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => { item.Status = null; }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => { item.Status = null; }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + _ => { }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + _ => { }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => + { + item.Status = AddressStatus.Current; + item.OsloStatus = AddressStatus.Current.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => { item.OfficiallyAssigned = false; }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => { item.OfficiallyAssigned = true; }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => + { + item.Status = AddressStatus.Proposed; + item.OsloStatus = AddressStatus.Proposed.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => + { + item.Status = AddressStatus.Retired; + item.OsloStatus = AddressStatus.Retired.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => { item.OfficiallyAssigned = true; }, + ct); + }); + + When>(async (context, message, ct) => + { + var geometry = WKBReaderFactory.CreateForLegacy() + .Read(message.Message.ExtendedWkbGeometry.ToByteArray()); + + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => + { + item.PositionMethod = message.Message.GeometryMethod.ToGeometryMethod(); + item.OsloPositionMethod = message.Message.GeometryMethod.ToPositieGeometrieMethode(); + item.PositionSpecification = message.Message.GeometrySpecification.ToGeometrySpecification(); + item.OsloPositionSpecification = message.Message.GeometrySpecification.ToPositieSpecificatie(); + item.Geometry = geometry; + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => + { + item.Status = AddressStatus.Proposed; + item.OsloStatus = AddressStatus.Proposed.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => { item.Removed = true; }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => + { + item.Status = AddressStatus.Retired; + item.OsloStatus = AddressStatus.Retired.Map(); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => { item.BoxNumber = message.Message.BoxNumber; }, + ct); + }); + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => { item.BoxNumber = message.Message.BoxNumber; }, + ct); + }); + When>(async (context, message, ct) => + { + await context.CreateNewAddressVersion( + message.Message.AddressId, + message, + item => { item.BoxNumber = null; }, + ct); + }); + + #endregion + } + } +} diff --git a/src/AddressRegistry.Projections.Integration/Convertors/AddressMapper.cs b/src/AddressRegistry.Projections.Integration/Convertors/AddressMapper.cs new file mode 100644 index 000000000..94f6300bb --- /dev/null +++ b/src/AddressRegistry.Projections.Integration/Convertors/AddressMapper.cs @@ -0,0 +1,115 @@ +namespace AddressRegistry.Projections.Integration.Convertors +{ + using System; + using System.Text; + using System.Xml; + using AddressRegistry.StreetName; + using Be.Vlaanderen.Basisregisters.GrAr.Common.SpatialTools.GeometryCoordinates; + using Be.Vlaanderen.Basisregisters.GrAr.Legacy; + using Be.Vlaanderen.Basisregisters.GrAr.Legacy.Adres; + using NetTopologySuite.Geometries; + using NetTopologySuite.Utilities; + + public static class AddressMapper + { + public static string Map(this AddressStatus status) + { + switch (status) + { + case AddressStatus.Proposed: return AdresStatus.Voorgesteld.ToString(); + case AddressStatus.Current: return AdresStatus.InGebruik.ToString(); + case AddressStatus.Retired: return AdresStatus.Gehistoreerd.ToString(); + case AddressStatus.Rejected: return AdresStatus.Afgekeurd.ToString(); + default: + throw new ArgumentOutOfRangeException(nameof(status), status, null); + } + } + + public static string ToPositieGeometrieMethode(this GeometryMethod method) + { + return method switch + { + GeometryMethod.DerivedFromObject => PositieGeometrieMethode.AfgeleidVanObject.ToString(), + GeometryMethod.Interpolated => PositieGeometrieMethode.Geinterpoleerd.ToString(), + GeometryMethod.AppointedByAdministrator => PositieGeometrieMethode.AangeduidDoorBeheerder.ToString(), + _ => PositieGeometrieMethode.AangeduidDoorBeheerder.ToString() + }; + } + + public static string ToPositieGeometrieMethode(this Address.GeometryMethod method) + { + return method switch + { + Address.GeometryMethod.DerivedFromObject => PositieGeometrieMethode.AfgeleidVanObject.ToString(), + Address.GeometryMethod.Interpolated => PositieGeometrieMethode.Geinterpoleerd.ToString(), + Address.GeometryMethod.AppointedByAdministrator => PositieGeometrieMethode.AangeduidDoorBeheerder.ToString(), + _ => PositieGeometrieMethode.AangeduidDoorBeheerder.ToString() + }; + } + + public static GeometryMethod ToGeometryMethod(this Address.GeometryMethod method) + { + return method switch + { + Address.GeometryMethod.DerivedFromObject => GeometryMethod.DerivedFromObject, + Address.GeometryMethod.Interpolated => GeometryMethod.Interpolated, + Address.GeometryMethod.AppointedByAdministrator => GeometryMethod.AppointedByAdministrator, + _ => GeometryMethod.AppointedByAdministrator + }; + } + + public static string ToPositieSpecificatie(this GeometrySpecification specification) + { + return specification switch + { + GeometrySpecification.Street => PositieSpecificatie.Straat.ToString(), + GeometrySpecification.Parcel => PositieSpecificatie.Perceel.ToString(), + GeometrySpecification.Lot => PositieSpecificatie.Lot.ToString(), + GeometrySpecification.Stand => PositieSpecificatie.Standplaats.ToString(), + GeometrySpecification.Berth => PositieSpecificatie.Ligplaats.ToString(), + GeometrySpecification.Building => PositieSpecificatie.Gebouw.ToString(), + GeometrySpecification.BuildingUnit => PositieSpecificatie.Gebouweenheid.ToString(), + GeometrySpecification.Entry => PositieSpecificatie.Ingang.ToString(), + GeometrySpecification.RoadSegment => PositieSpecificatie.Wegsegment.ToString(), + GeometrySpecification.Municipality => PositieSpecificatie.Gemeente.ToString(), + _ => PositieSpecificatie.Gemeente.ToString() + }; + } + + public static string ToPositieSpecificatie(this Address.GeometrySpecification specification) + { + return specification switch + { + Address.GeometrySpecification.Street => PositieSpecificatie.Straat.ToString(), + Address.GeometrySpecification.Parcel => PositieSpecificatie.Perceel.ToString(), + Address.GeometrySpecification.Lot => PositieSpecificatie.Lot.ToString(), + Address.GeometrySpecification.Stand => PositieSpecificatie.Standplaats.ToString(), + Address.GeometrySpecification.Berth => PositieSpecificatie.Ligplaats.ToString(), + Address.GeometrySpecification.Building => PositieSpecificatie.Gebouw.ToString(), + Address.GeometrySpecification.BuildingUnit => PositieSpecificatie.Gebouweenheid.ToString(), + Address.GeometrySpecification.Entry => PositieSpecificatie.Ingang.ToString(), + Address.GeometrySpecification.RoadSegment => PositieSpecificatie.Wegsegment.ToString(), + Address.GeometrySpecification.Municipality => PositieSpecificatie.Gemeente.ToString(), + _ => PositieSpecificatie.Gemeente.ToString() + }; + } + + public static GeometrySpecification ToGeometrySpecification(this Address.GeometrySpecification specification) + { + return specification switch + { + Address.GeometrySpecification.Street => GeometrySpecification.Street, + Address.GeometrySpecification.Parcel => GeometrySpecification.Parcel, + Address.GeometrySpecification.Lot => GeometrySpecification.Lot, + Address.GeometrySpecification.Stand => GeometrySpecification.Stand, + Address.GeometrySpecification.Berth => GeometrySpecification.Berth, + Address.GeometrySpecification.Building => GeometrySpecification.Building, + Address.GeometrySpecification.BuildingUnit => GeometrySpecification.BuildingUnit, + Address.GeometrySpecification.Entry => GeometrySpecification.Entry, + Address.GeometrySpecification.RoadSegment => GeometrySpecification.RoadSegment, + Address.GeometrySpecification.Municipality => GeometrySpecification.Municipality, + _ => GeometrySpecification.Municipality + }; + } + } +} diff --git a/src/AddressRegistry.Projections.Integration/EventsRepository.cs b/src/AddressRegistry.Projections.Integration/EventsRepository.cs new file mode 100644 index 000000000..20f3473f7 --- /dev/null +++ b/src/AddressRegistry.Projections.Integration/EventsRepository.cs @@ -0,0 +1,29 @@ +namespace AddressRegistry.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 GetAddressPersistentLocalId(Guid addressId) + { + await using var connection = new SqlConnection(_eventsConnectionString); + var sql = @$"SELECT Json_Value(JsonData, '$.persistentLocalId') AS ""AddressPersistentLocalId"" + FROM [address-registry-events].[AddressRegistry].[Streams] as s + inner join [address-registry-events].[AddressRegistry].[Messages] as m on s.IdInternal = m.StreamIdInternal and m.[Type] = 'AddressPersistentLocalIdentifierWasAssigned' + where s.Id = '{addressId}'"; + + return await connection.QuerySingleOrDefaultAsync(sql); + } + } +} diff --git a/src/AddressRegistry.Projections.Integration/IEventsRepository.cs b/src/AddressRegistry.Projections.Integration/IEventsRepository.cs new file mode 100644 index 000000000..80529503a --- /dev/null +++ b/src/AddressRegistry.Projections.Integration/IEventsRepository.cs @@ -0,0 +1,10 @@ +namespace AddressRegistry.Projections.Integration +{ + using System; + using System.Threading.Tasks; + + public interface IEventsRepository + { + Task GetAddressPersistentLocalId(Guid addressId); + } +} diff --git a/src/AddressRegistry.Projections.Integration/Infrastructure/IntegrationModule.cs b/src/AddressRegistry.Projections.Integration/Infrastructure/IntegrationModule.cs new file mode 100644 index 000000000..5f163b417 --- /dev/null +++ b/src/AddressRegistry.Projections.Integration/Infrastructure/IntegrationModule.cs @@ -0,0 +1,63 @@ +namespace AddressRegistry.Projections.Integration.Infrastructure +{ + using System; + using AddressRegistry.Infrastructure; + using Autofac; + using Microsoft.EntityFrameworkCore; + using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Logging; + + public class IntegrationModule : Module + { + public IntegrationModule( + IConfiguration configuration, + IServiceCollection services, + ILoggerFactory loggerFactory) + { + var logger = loggerFactory.CreateLogger(); + services.AddScoped(_ => new EventsRepository(configuration.GetConnectionString("events"))); + var connectionString = configuration.GetConnectionString("IntegrationProjections"); + + 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 backofficeProjectionsConnectionString) + { + services + .AddNpgsql(backofficeProjectionsConnectionString, sqlServerOptions => + { + sqlServerOptions.EnableRetryOnFailure(); + sqlServerOptions.MigrationsHistoryTable(MigrationTables.Integration, Schema.Integration); + sqlServerOptions.UseNetTopologySuite(); + }); + } + + 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/AddressRegistry.Projections.Integration/Infrastructure/IntegrationOptions.cs b/src/AddressRegistry.Projections.Integration/Infrastructure/IntegrationOptions.cs new file mode 100644 index 000000000..ec5b48a7c --- /dev/null +++ b/src/AddressRegistry.Projections.Integration/Infrastructure/IntegrationOptions.cs @@ -0,0 +1,8 @@ +namespace AddressRegistry.Projections.Integration.Infrastructure +{ + public class IntegrationOptions + { + public string Namespace { get; set; } + public bool Enabled { get; set; } + } +} diff --git a/src/AddressRegistry.Projections.Integration/IntegrationContext.cs b/src/AddressRegistry.Projections.Integration/IntegrationContext.cs new file mode 100644 index 000000000..76c587d50 --- /dev/null +++ b/src/AddressRegistry.Projections.Integration/IntegrationContext.cs @@ -0,0 +1,21 @@ +namespace AddressRegistry.Projections.Integration +{ + using AddressRegistry.Infrastructure; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; + using Microsoft.EntityFrameworkCore; + + public class IntegrationContext : RunnerDbContext + { + public override string ProjectionStateSchema => Schema.Integration; + + public DbSet AddressLatestItems => Set(); + public DbSet AddressVersions => 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/AddressRegistry.Projections.Integration/IntegrationContextMigrationFactory.cs b/src/AddressRegistry.Projections.Integration/IntegrationContextMigrationFactory.cs new file mode 100644 index 000000000..6a37d39d8 --- /dev/null +++ b/src/AddressRegistry.Projections.Integration/IntegrationContextMigrationFactory.cs @@ -0,0 +1,30 @@ +namespace AddressRegistry.Projections.Integration +{ + using AddressRegistry.Infrastructure; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.Npgsql; + using Microsoft.EntityFrameworkCore; + using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure; + + public class IntegrationContextMigrationFactory : NpgsqlRunnerDbContextMigrationFactory + { + public IntegrationContextMigrationFactory() + : base("IntegrationProjectionsAdmin", HistoryConfiguration) { } + + private static MigrationHistoryConfiguration HistoryConfiguration => + new MigrationHistoryConfiguration + { + Schema = Schema.Integration, + Table = MigrationTables.Integration + }; + + protected override void ConfigureSqlServerOptions(NpgsqlDbContextOptionsBuilder serverOptions) + { + serverOptions.UseNetTopologySuite(); + base.ConfigureSqlServerOptions(serverOptions); + } + + protected override IntegrationContext CreateContext( + DbContextOptions migrationContextOptions) => + new IntegrationContext(migrationContextOptions); + } +} diff --git a/src/AddressRegistry.Projections.Integration/Migrations/20240115132131_Initial.Designer.cs b/src/AddressRegistry.Projections.Integration/Migrations/20240115132131_Initial.Designer.cs new file mode 100644 index 000000000..7ded088bb --- /dev/null +++ b/src/AddressRegistry.Projections.Integration/Migrations/20240115132131_Initial.Designer.cs @@ -0,0 +1,279 @@ +// +using System; +using AddressRegistry.Projections.Integration; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NetTopologySuite.Geometries; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace AddressRegistry.Projections.Integration.Migrations +{ + [DbContext(typeof(IntegrationContext))] + [Migration("20240115132131_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("AddressRegistry.Projections.Integration.AddressLatestItem", b => + { + b.Property("PersistentLocalId") + .HasColumnType("integer") + .HasColumnName("persistent_local_id"); + + b.Property("BoxNumber") + .HasColumnType("text") + .HasColumnName("box_number"); + + b.Property("Geometry") + .HasColumnType("geometry") + .HasColumnName("geometry"); + + b.Property("HouseNumber") + .HasColumnType("text") + .HasColumnName("house_number"); + + b.Property("Namespace") + .HasColumnType("text") + .HasColumnName("namespace"); + + b.Property("OfficiallyAssigned") + .HasColumnType("boolean") + .HasColumnName("officially_assigned"); + + b.Property("OsloPositionMethod") + .HasColumnType("text") + .HasColumnName("oslo_position_method"); + + b.Property("OsloPositionSpecification") + .HasColumnType("text") + .HasColumnName("oslo_position_specification"); + + b.Property("OsloStatus") + .HasColumnType("text") + .HasColumnName("oslo_status"); + + b.Property("PositionMethod") + .HasColumnType("integer") + .HasColumnName("position_method"); + + b.Property("PositionSpecification") + .HasColumnType("integer") + .HasColumnName("position_specification"); + + b.Property("PostalCode") + .HasColumnType("text") + .HasColumnName("postal_code"); + + b.Property("PuriId") + .HasColumnType("text") + .HasColumnName("puri_id"); + + b.Property("Removed") + .HasColumnType("boolean") + .HasColumnName("removed"); + + b.Property("Status") + .HasColumnType("integer") + .HasColumnName("status"); + + b.Property("StreetNamePersistentLocalId") + .HasColumnType("integer") + .HasColumnName("street_name_persistent_local_id"); + + b.Property("VersionAsString") + .IsRequired() + .HasColumnType("text") + .HasColumnName("version_as_string"); + + b.Property("VersionTimestampAsDateTimeOffset") + .HasColumnType("timestamp with time zone") + .HasColumnName("version_timestamp"); + + b.HasKey("PersistentLocalId"); + + b.HasIndex("BoxNumber"); + + b.HasIndex("Geometry"); + + NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex("Geometry"), "GIST"); + + b.HasIndex("HouseNumber"); + + b.HasIndex("OsloStatus"); + + b.HasIndex("PersistentLocalId"); + + b.HasIndex("PostalCode"); + + b.HasIndex("Removed"); + + b.HasIndex("Status"); + + b.HasIndex("StreetNamePersistentLocalId"); + + b.ToTable("address_latest_items", "integration_address"); + }); + + modelBuilder.Entity("AddressRegistry.Projections.Integration.AddressVersion", b => + { + b.Property("Position") + .HasColumnType("bigint") + .HasColumnName("position"); + + b.Property("PersistentLocalId") + .HasColumnType("integer") + .HasColumnName("persistent_local_id"); + + b.Property("AddressId") + .HasColumnType("uuid") + .HasColumnName("address_id"); + + b.Property("BoxNumber") + .HasColumnType("text") + .HasColumnName("box_number"); + + b.Property("CreatedOnAsString") + .IsRequired() + .HasColumnType("text") + .HasColumnName("created_on_as_string"); + + b.Property("CreatedOnTimestampAsDateTimeOffset") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on_timestamp"); + + b.Property("Geometry") + .HasColumnType("geometry") + .HasColumnName("geometry"); + + b.Property("HouseNumber") + .HasColumnType("text") + .HasColumnName("house_number"); + + b.Property("Namespace") + .HasColumnType("text") + .HasColumnName("namespace"); + + b.Property("OfficiallyAssigned") + .HasColumnType("boolean") + .HasColumnName("officially_assigned"); + + b.Property("OsloPositionMethod") + .HasColumnType("text") + .HasColumnName("oslo_position_method"); + + b.Property("OsloPositionSpecification") + .HasColumnType("text") + .HasColumnName("oslo_position_specification"); + + b.Property("OsloStatus") + .HasColumnType("text") + .HasColumnName("oslo_status"); + + b.Property("PositionMethod") + .HasColumnType("integer") + .HasColumnName("position_method"); + + b.Property("PositionSpecification") + .HasColumnType("integer") + .HasColumnName("position_specification"); + + b.Property("PostalCode") + .HasColumnType("text") + .HasColumnName("postal_code"); + + b.Property("PuriId") + .HasColumnType("text") + .HasColumnName("puri_id"); + + b.Property("Removed") + .HasColumnType("boolean") + .HasColumnName("removed"); + + b.Property("Status") + .HasColumnType("integer") + .HasColumnName("status"); + + b.Property("StreetNameId") + .HasColumnType("uuid") + .HasColumnName("street_name_id"); + + b.Property("StreetNamePersistentLocalId") + .HasColumnType("integer") + .HasColumnName("street_name_persistent_local_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("AddressId"); + + b.HasIndex("BoxNumber"); + + b.HasIndex("Geometry"); + + NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex("Geometry"), "GIST"); + + b.HasIndex("HouseNumber"); + + b.HasIndex("OsloStatus"); + + b.HasIndex("PersistentLocalId"); + + b.HasIndex("PostalCode"); + + b.HasIndex("Removed"); + + b.HasIndex("Status"); + + b.HasIndex("StreetNameId"); + + b.HasIndex("StreetNamePersistentLocalId"); + + b.HasIndex("VersionTimestampAsDateTimeOffset"); + + b.ToTable("address_versions", "integration_address"); + }); + + 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_address"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/AddressRegistry.Projections.Integration/Migrations/20240115132131_Initial.cs b/src/AddressRegistry.Projections.Integration/Migrations/20240115132131_Initial.cs new file mode 100644 index 000000000..5abd4a1e1 --- /dev/null +++ b/src/AddressRegistry.Projections.Integration/Migrations/20240115132131_Initial.cs @@ -0,0 +1,239 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using NetTopologySuite.Geometries; + +#nullable disable + +namespace AddressRegistry.Projections.Integration.Migrations +{ + public partial class Initial : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.EnsureSchema( + name: "integration_address"); + + migrationBuilder.CreateTable( + name: "address_latest_items", + schema: "integration_address", + columns: table => new + { + persistent_local_id = table.Column(type: "integer", nullable: false), + postal_code = table.Column(type: "text", nullable: true), + street_name_persistent_local_id = table.Column(type: "integer", nullable: true), + status = table.Column(type: "integer", nullable: false), + oslo_status = table.Column(type: "text", nullable: true), + house_number = table.Column(type: "text", nullable: true), + box_number = table.Column(type: "text", nullable: true), + geometry = table.Column(type: "geometry", nullable: true), + position_method = table.Column(type: "integer", nullable: false), + oslo_position_method = table.Column(type: "text", nullable: true), + position_specification = table.Column(type: "integer", nullable: false), + oslo_position_specification = table.Column(type: "text", nullable: true), + officially_assigned = table.Column(type: "boolean", nullable: true), + removed = table.Column(type: "boolean", nullable: false), + puri_id = table.Column(type: "text", nullable: true), + @namespace = table.Column(name: "namespace", type: "text", nullable: true), + 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_address_latest_items", x => x.persistent_local_id); + }); + + migrationBuilder.CreateTable( + name: "address_versions", + schema: "integration_address", + columns: table => new + { + position = table.Column(type: "bigint", nullable: false), + persistent_local_id = table.Column(type: "integer", nullable: false), + address_id = table.Column(type: "uuid", nullable: true), + postal_code = table.Column(type: "text", nullable: true), + street_name_persistent_local_id = table.Column(type: "integer", nullable: true), + street_name_id = table.Column(type: "uuid", nullable: true), + status = table.Column(type: "integer", nullable: true), + oslo_status = table.Column(type: "text", nullable: true), + house_number = table.Column(type: "text", nullable: true), + box_number = table.Column(type: "text", nullable: true), + geometry = table.Column(type: "geometry", nullable: true), + position_method = table.Column(type: "integer", nullable: true), + oslo_position_method = table.Column(type: "text", nullable: true), + position_specification = table.Column(type: "integer", nullable: true), + oslo_position_specification = table.Column(type: "text", nullable: true), + officially_assigned = table.Column(type: "boolean", nullable: true), + removed = table.Column(type: "boolean", nullable: false), + puri_id = table.Column(type: "text", nullable: true), + @namespace = table.Column(name: "namespace", type: "text", nullable: true), + version_as_string = table.Column(type: "text", nullable: false), + version_timestamp = table.Column(type: "timestamp with time zone", nullable: false), + created_on_as_string = table.Column(type: "text", nullable: false), + created_on_timestamp = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_address_versions", x => new { x.position, x.persistent_local_id }); + }); + + migrationBuilder.CreateTable( + name: "ProjectionStates", + schema: "integration_address", + 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.CreateIndex( + name: "IX_address_latest_items_box_number", + schema: "integration_address", + table: "address_latest_items", + column: "box_number"); + + migrationBuilder.CreateIndex( + name: "IX_address_latest_items_geometry", + schema: "integration_address", + table: "address_latest_items", + column: "geometry") + .Annotation("Npgsql:IndexMethod", "GIST"); + + migrationBuilder.CreateIndex( + name: "IX_address_latest_items_house_number", + schema: "integration_address", + table: "address_latest_items", + column: "house_number"); + + migrationBuilder.CreateIndex( + name: "IX_address_latest_items_oslo_status", + schema: "integration_address", + table: "address_latest_items", + column: "oslo_status"); + + migrationBuilder.CreateIndex( + name: "IX_address_latest_items_persistent_local_id", + schema: "integration_address", + table: "address_latest_items", + column: "persistent_local_id"); + + migrationBuilder.CreateIndex( + name: "IX_address_latest_items_postal_code", + schema: "integration_address", + table: "address_latest_items", + column: "postal_code"); + + migrationBuilder.CreateIndex( + name: "IX_address_latest_items_removed", + schema: "integration_address", + table: "address_latest_items", + column: "removed"); + + migrationBuilder.CreateIndex( + name: "IX_address_latest_items_status", + schema: "integration_address", + table: "address_latest_items", + column: "status"); + + migrationBuilder.CreateIndex( + name: "IX_address_latest_items_street_name_persistent_local_id", + schema: "integration_address", + table: "address_latest_items", + column: "street_name_persistent_local_id"); + + migrationBuilder.CreateIndex( + name: "IX_address_versions_address_id", + schema: "integration_address", + table: "address_versions", + column: "address_id"); + + migrationBuilder.CreateIndex( + name: "IX_address_versions_box_number", + schema: "integration_address", + table: "address_versions", + column: "box_number"); + + migrationBuilder.CreateIndex( + name: "IX_address_versions_geometry", + schema: "integration_address", + table: "address_versions", + column: "geometry") + .Annotation("Npgsql:IndexMethod", "GIST"); + + migrationBuilder.CreateIndex( + name: "IX_address_versions_house_number", + schema: "integration_address", + table: "address_versions", + column: "house_number"); + + migrationBuilder.CreateIndex( + name: "IX_address_versions_oslo_status", + schema: "integration_address", + table: "address_versions", + column: "oslo_status"); + + migrationBuilder.CreateIndex( + name: "IX_address_versions_persistent_local_id", + schema: "integration_address", + table: "address_versions", + column: "persistent_local_id"); + + migrationBuilder.CreateIndex( + name: "IX_address_versions_postal_code", + schema: "integration_address", + table: "address_versions", + column: "postal_code"); + + migrationBuilder.CreateIndex( + name: "IX_address_versions_removed", + schema: "integration_address", + table: "address_versions", + column: "removed"); + + migrationBuilder.CreateIndex( + name: "IX_address_versions_status", + schema: "integration_address", + table: "address_versions", + column: "status"); + + migrationBuilder.CreateIndex( + name: "IX_address_versions_street_name_id", + schema: "integration_address", + table: "address_versions", + column: "street_name_id"); + + migrationBuilder.CreateIndex( + name: "IX_address_versions_street_name_persistent_local_id", + schema: "integration_address", + table: "address_versions", + column: "street_name_persistent_local_id"); + + migrationBuilder.CreateIndex( + name: "IX_address_versions_version_timestamp", + schema: "integration_address", + table: "address_versions", + column: "version_timestamp"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "address_latest_items", + schema: "integration_address"); + + migrationBuilder.DropTable( + name: "address_versions", + schema: "integration_address"); + + migrationBuilder.DropTable( + name: "ProjectionStates", + schema: "integration_address"); + } + } +} diff --git a/src/AddressRegistry.Projections.Integration/Migrations/IntegrationContextModelSnapshot.cs b/src/AddressRegistry.Projections.Integration/Migrations/IntegrationContextModelSnapshot.cs new file mode 100644 index 000000000..4c084565c --- /dev/null +++ b/src/AddressRegistry.Projections.Integration/Migrations/IntegrationContextModelSnapshot.cs @@ -0,0 +1,277 @@ +// +using System; +using AddressRegistry.Projections.Integration; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NetTopologySuite.Geometries; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace AddressRegistry.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("AddressRegistry.Projections.Integration.AddressLatestItem", b => + { + b.Property("PersistentLocalId") + .HasColumnType("integer") + .HasColumnName("persistent_local_id"); + + b.Property("BoxNumber") + .HasColumnType("text") + .HasColumnName("box_number"); + + b.Property("Geometry") + .HasColumnType("geometry") + .HasColumnName("geometry"); + + b.Property("HouseNumber") + .HasColumnType("text") + .HasColumnName("house_number"); + + b.Property("Namespace") + .HasColumnType("text") + .HasColumnName("namespace"); + + b.Property("OfficiallyAssigned") + .HasColumnType("boolean") + .HasColumnName("officially_assigned"); + + b.Property("OsloPositionMethod") + .HasColumnType("text") + .HasColumnName("oslo_position_method"); + + b.Property("OsloPositionSpecification") + .HasColumnType("text") + .HasColumnName("oslo_position_specification"); + + b.Property("OsloStatus") + .HasColumnType("text") + .HasColumnName("oslo_status"); + + b.Property("PositionMethod") + .HasColumnType("integer") + .HasColumnName("position_method"); + + b.Property("PositionSpecification") + .HasColumnType("integer") + .HasColumnName("position_specification"); + + b.Property("PostalCode") + .HasColumnType("text") + .HasColumnName("postal_code"); + + b.Property("PuriId") + .HasColumnType("text") + .HasColumnName("puri_id"); + + b.Property("Removed") + .HasColumnType("boolean") + .HasColumnName("removed"); + + b.Property("Status") + .HasColumnType("integer") + .HasColumnName("status"); + + b.Property("StreetNamePersistentLocalId") + .HasColumnType("integer") + .HasColumnName("street_name_persistent_local_id"); + + b.Property("VersionAsString") + .IsRequired() + .HasColumnType("text") + .HasColumnName("version_as_string"); + + b.Property("VersionTimestampAsDateTimeOffset") + .HasColumnType("timestamp with time zone") + .HasColumnName("version_timestamp"); + + b.HasKey("PersistentLocalId"); + + b.HasIndex("BoxNumber"); + + b.HasIndex("Geometry"); + + NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex("Geometry"), "GIST"); + + b.HasIndex("HouseNumber"); + + b.HasIndex("OsloStatus"); + + b.HasIndex("PersistentLocalId"); + + b.HasIndex("PostalCode"); + + b.HasIndex("Removed"); + + b.HasIndex("Status"); + + b.HasIndex("StreetNamePersistentLocalId"); + + b.ToTable("address_latest_items", "integration_address"); + }); + + modelBuilder.Entity("AddressRegistry.Projections.Integration.AddressVersion", b => + { + b.Property("Position") + .HasColumnType("bigint") + .HasColumnName("position"); + + b.Property("PersistentLocalId") + .HasColumnType("integer") + .HasColumnName("persistent_local_id"); + + b.Property("AddressId") + .HasColumnType("uuid") + .HasColumnName("address_id"); + + b.Property("BoxNumber") + .HasColumnType("text") + .HasColumnName("box_number"); + + b.Property("CreatedOnAsString") + .IsRequired() + .HasColumnType("text") + .HasColumnName("created_on_as_string"); + + b.Property("CreatedOnTimestampAsDateTimeOffset") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on_timestamp"); + + b.Property("Geometry") + .HasColumnType("geometry") + .HasColumnName("geometry"); + + b.Property("HouseNumber") + .HasColumnType("text") + .HasColumnName("house_number"); + + b.Property("Namespace") + .HasColumnType("text") + .HasColumnName("namespace"); + + b.Property("OfficiallyAssigned") + .HasColumnType("boolean") + .HasColumnName("officially_assigned"); + + b.Property("OsloPositionMethod") + .HasColumnType("text") + .HasColumnName("oslo_position_method"); + + b.Property("OsloPositionSpecification") + .HasColumnType("text") + .HasColumnName("oslo_position_specification"); + + b.Property("OsloStatus") + .HasColumnType("text") + .HasColumnName("oslo_status"); + + b.Property("PositionMethod") + .HasColumnType("integer") + .HasColumnName("position_method"); + + b.Property("PositionSpecification") + .HasColumnType("integer") + .HasColumnName("position_specification"); + + b.Property("PostalCode") + .HasColumnType("text") + .HasColumnName("postal_code"); + + b.Property("PuriId") + .HasColumnType("text") + .HasColumnName("puri_id"); + + b.Property("Removed") + .HasColumnType("boolean") + .HasColumnName("removed"); + + b.Property("Status") + .HasColumnType("integer") + .HasColumnName("status"); + + b.Property("StreetNameId") + .HasColumnType("uuid") + .HasColumnName("street_name_id"); + + b.Property("StreetNamePersistentLocalId") + .HasColumnType("integer") + .HasColumnName("street_name_persistent_local_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("AddressId"); + + b.HasIndex("BoxNumber"); + + b.HasIndex("Geometry"); + + NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex("Geometry"), "GIST"); + + b.HasIndex("HouseNumber"); + + b.HasIndex("OsloStatus"); + + b.HasIndex("PersistentLocalId"); + + b.HasIndex("PostalCode"); + + b.HasIndex("Removed"); + + b.HasIndex("Status"); + + b.HasIndex("StreetNameId"); + + b.HasIndex("StreetNamePersistentLocalId"); + + b.HasIndex("VersionTimestampAsDateTimeOffset"); + + b.ToTable("address_versions", "integration_address"); + }); + + 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_address"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/AddressRegistry.Projections.Integration/Properties/AssemblyInfo.cs b/src/AddressRegistry.Projections.Integration/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..a18ca4106 --- /dev/null +++ b/src/AddressRegistry.Projections.Integration/Properties/AssemblyInfo.cs @@ -0,0 +1,7 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyDescription("AddressRegistry Integration Projections")] + +[assembly: ComVisible(false)] +[assembly: Guid("07f621e5-c937-4da1-b226-4b3b13404f47")] diff --git a/src/AddressRegistry.Projections.Integration/paket.references b/src/AddressRegistry.Projections.Integration/paket.references new file mode 100644 index 000000000..793b2956b --- /dev/null +++ b/src/AddressRegistry.Projections.Integration/paket.references @@ -0,0 +1,16 @@ +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 + +Npgsql.EntityFrameworkCore.PostgreSQL.Design +Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite + +Be.Vlaanderen.Basisregisters.GrAr.Common +Be.Vlaanderen.Basisregisters.GrAr.Legacy + +SourceLink.Embed.AllSourceFiles +SourceLink.Copy.PdbFiles diff --git a/src/AddressRegistry.Projections.LastChangedList/AddressLastChangedListModule.cs b/src/AddressRegistry.Projections.LastChangedList/AddressLastChangedListModule.cs index 241a10e77..06346371b 100644 --- a/src/AddressRegistry.Projections.LastChangedList/AddressLastChangedListModule.cs +++ b/src/AddressRegistry.Projections.LastChangedList/AddressLastChangedListModule.cs @@ -4,6 +4,7 @@ namespace AddressRegistry.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/AddressRegistry.Projections.LastChangedList/DataMigrationsContext.cs b/src/AddressRegistry.Projections.LastChangedList/DataMigrationsContext.cs index 3b12d692c..0676dfe6e 100644 --- a/src/AddressRegistry.Projections.LastChangedList/DataMigrationsContext.cs +++ b/src/AddressRegistry.Projections.LastChangedList/DataMigrationsContext.cs @@ -5,6 +5,7 @@ namespace AddressRegistry.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; @@ -42,7 +43,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/AddressRegistry.Projections.Legacy/AddressSyndication/AddressSyndication.cs b/src/AddressRegistry.Projections.Legacy/AddressSyndication/AddressSyndication.cs index a40694783..b67d45f07 100755 --- a/src/AddressRegistry.Projections.Legacy/AddressSyndication/AddressSyndication.cs +++ b/src/AddressRegistry.Projections.Legacy/AddressSyndication/AddressSyndication.cs @@ -4,6 +4,7 @@ namespace AddressRegistry.Projections.Legacy.AddressSyndication using StreetName; 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; @@ -112,7 +113,7 @@ public AddressSyndicationItem CloneAndApplyEventInfoForBoxNumber( item.Status = addressBoxNumberSyndicationHelper.Status; item.IsComplete = addressBoxNumberSyndicationHelper.IsComplete; item.IsOfficiallyAssigned = addressBoxNumberSyndicationHelper.IsOfficiallyAssigned; - + applyEventInfoOn(item); }); diff --git a/src/AddressRegistry.Projections.Legacy/LegacyContextMigrationFactory.cs b/src/AddressRegistry.Projections.Legacy/LegacyContextMigrationFactory.cs index cdc317e90..f9ee95ea3 100755 --- a/src/AddressRegistry.Projections.Legacy/LegacyContextMigrationFactory.cs +++ b/src/AddressRegistry.Projections.Legacy/LegacyContextMigrationFactory.cs @@ -1,10 +1,10 @@ namespace AddressRegistry.Projections.Legacy { - using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer; using Infrastructure; using Microsoft.EntityFrameworkCore; - public class LegacyContextMigrationFactory : RunnerDbContextMigrationFactory + public class LegacyContextMigrationFactory : SqlServerRunnerDbContextMigrationFactory { public LegacyContextMigrationFactory() : base("LegacyProjectionsAdmin", HistoryConfiguration) { } diff --git a/src/AddressRegistry.Projections.Legacy/LegacyModule.cs b/src/AddressRegistry.Projections.Legacy/LegacyModule.cs index cae013cb5..35d7f92e7 100755 --- a/src/AddressRegistry.Projections.Legacy/LegacyModule.cs +++ b/src/AddressRegistry.Projections.Legacy/LegacyModule.cs @@ -5,6 +5,7 @@ namespace AddressRegistry.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 Be.Vlaanderen.Basisregisters.ProjectionHandling.Syndication; using Infrastructure; using Microsoft.EntityFrameworkCore; diff --git a/src/AddressRegistry.Projections.Legacy/paket.references b/src/AddressRegistry.Projections.Legacy/paket.references index 99af1e30e..61cdf3f63 100755 --- a/src/AddressRegistry.Projections.Legacy/paket.references +++ b/src/AddressRegistry.Projections.Legacy/paket.references @@ -3,7 +3,7 @@ Microsoft.SyndicationFeed.ReaderWriter Be.Vlaanderen.Basisregisters.AggregateSource Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql Be.Vlaanderen.Basisregisters.EventHandling -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/AddressRegistry.Projections.Syndication/MigrationsHelper.cs b/src/AddressRegistry.Projections.Syndication/MigrationsHelper.cs index 5a3730d0b..8da126a44 100644 --- a/src/AddressRegistry.Projections.Syndication/MigrationsHelper.cs +++ b/src/AddressRegistry.Projections.Syndication/MigrationsHelper.cs @@ -5,6 +5,7 @@ namespace AddressRegistry.Projections.Syndication using System.Threading; using System.Threading.Tasks; using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using Infrastructure; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; diff --git a/src/AddressRegistry.Projections.Syndication/SyndicationContext.cs b/src/AddressRegistry.Projections.Syndication/SyndicationContext.cs index 31fbcf69c..98e6f991d 100755 --- a/src/AddressRegistry.Projections.Syndication/SyndicationContext.cs +++ b/src/AddressRegistry.Projections.Syndication/SyndicationContext.cs @@ -5,6 +5,7 @@ namespace AddressRegistry.Projections.Syndication using AddressLink; using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using Infrastructure; using Microsoft.EntityFrameworkCore; using Municipality; diff --git a/src/AddressRegistry.Projections.Syndication/SyndicationModule.cs b/src/AddressRegistry.Projections.Syndication/SyndicationModule.cs index 21a9f29e3..ecea19a64 100755 --- a/src/AddressRegistry.Projections.Syndication/SyndicationModule.cs +++ b/src/AddressRegistry.Projections.Syndication/SyndicationModule.cs @@ -7,6 +7,7 @@ namespace AddressRegistry.Projections.Syndication using Be.Vlaanderen.Basisregisters.DataDog.Tracing.Http; using Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql.EntityFrameworkCore; using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using Be.Vlaanderen.Basisregisters.ProjectionHandling.Syndication; using Infrastructure; using Microsoft.EntityFrameworkCore; diff --git a/src/AddressRegistry.Projections.Syndication/paket.references b/src/AddressRegistry.Projections.Syndication/paket.references index de059e654..2be7514cc 100755 --- a/src/AddressRegistry.Projections.Syndication/paket.references +++ b/src/AddressRegistry.Projections.Syndication/paket.references @@ -21,7 +21,7 @@ Microsoft.EntityFrameworkCore.Design Microsoft.SyndicationFeed.ReaderWriter Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql -Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner +Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer Be.Vlaanderen.Basisregisters.ProjectionHandling.Syndication Be.Vlaanderen.Basisregisters.Shaperon diff --git a/src/AddressRegistry.Projections.Wfs/WfsContextMigrationFactory.cs b/src/AddressRegistry.Projections.Wfs/WfsContextMigrationFactory.cs index a0db1870b..85d479c63 100755 --- a/src/AddressRegistry.Projections.Wfs/WfsContextMigrationFactory.cs +++ b/src/AddressRegistry.Projections.Wfs/WfsContextMigrationFactory.cs @@ -1,11 +1,11 @@ namespace AddressRegistry.Projections.Wfs { - using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer; using Infrastructure; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; - public class WfsContextMigrationFactory : RunnerDbContextMigrationFactory + public class WfsContextMigrationFactory : SqlServerRunnerDbContextMigrationFactory { public WfsContextMigrationFactory() : base("WfsProjectionsAdmin", HistoryConfiguration) { } diff --git a/src/AddressRegistry.Projections.Wfs/WfsModule.cs b/src/AddressRegistry.Projections.Wfs/WfsModule.cs index d9e1a0c03..0c4cb71ab 100755 --- a/src/AddressRegistry.Projections.Wfs/WfsModule.cs +++ b/src/AddressRegistry.Projections.Wfs/WfsModule.cs @@ -5,6 +5,7 @@ namespace AddressRegistry.Projections.Wfs 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 Be.Vlaanderen.Basisregisters.ProjectionHandling.Syndication; using Infrastructure; using Microsoft.EntityFrameworkCore; diff --git a/src/AddressRegistry.Projections.Wfs/paket.references b/src/AddressRegistry.Projections.Wfs/paket.references index 614f7888c..7c3b3b15c 100755 --- a/src/AddressRegistry.Projections.Wfs/paket.references +++ b/src/AddressRegistry.Projections.Wfs/paket.references @@ -3,7 +3,7 @@ Microsoft.SyndicationFeed.ReaderWriter Be.Vlaanderen.Basisregisters.EventHandling.Autofac Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql Be.Vlaanderen.Basisregisters.EventHandling -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/AddressRegistry.Projections.Wms/WmsContextMigrationFactory.cs b/src/AddressRegistry.Projections.Wms/WmsContextMigrationFactory.cs index 7bd3feec8..bb73c5d54 100755 --- a/src/AddressRegistry.Projections.Wms/WmsContextMigrationFactory.cs +++ b/src/AddressRegistry.Projections.Wms/WmsContextMigrationFactory.cs @@ -1,11 +1,11 @@ namespace AddressRegistry.Projections.Wms { - using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer; using Infrastructure; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; - public class WmsContextMigrationFactory : RunnerDbContextMigrationFactory + public class WmsContextMigrationFactory : SqlServerRunnerDbContextMigrationFactory { public WmsContextMigrationFactory() : base("WmsProjectionsAdmin", HistoryConfiguration) { } diff --git a/src/AddressRegistry.Projections.Wms/WmsModule.cs b/src/AddressRegistry.Projections.Wms/WmsModule.cs index 840597fd5..a7cc5d781 100755 --- a/src/AddressRegistry.Projections.Wms/WmsModule.cs +++ b/src/AddressRegistry.Projections.Wms/WmsModule.cs @@ -5,6 +5,7 @@ namespace AddressRegistry.Projections.Wms 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 Be.Vlaanderen.Basisregisters.ProjectionHandling.Syndication; using Infrastructure; using Microsoft.EntityFrameworkCore; diff --git a/src/AddressRegistry.Projections.Wms/paket.references b/src/AddressRegistry.Projections.Wms/paket.references index 0ecc83213..9e69a6f87 100755 --- a/src/AddressRegistry.Projections.Wms/paket.references +++ b/src/AddressRegistry.Projections.Wms/paket.references @@ -2,7 +2,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/AddressRegistry.Projector/AddressRegistry.Projector.csproj b/src/AddressRegistry.Projector/AddressRegistry.Projector.csproj index c5a6e9402..54f4ea5bf 100755 --- a/src/AddressRegistry.Projector/AddressRegistry.Projector.csproj +++ b/src/AddressRegistry.Projector/AddressRegistry.Projector.csproj @@ -31,6 +31,7 @@ + diff --git a/src/AddressRegistry.Projector/Infrastructure/Modules/ApiModule.cs b/src/AddressRegistry.Projector/Infrastructure/Modules/ApiModule.cs index b8fc0acf9..eb38ee8b3 100755 --- a/src/AddressRegistry.Projector/Infrastructure/Modules/ApiModule.cs +++ b/src/AddressRegistry.Projector/Infrastructure/Modules/ApiModule.cs @@ -5,6 +5,8 @@ namespace AddressRegistry.Projector.Infrastructure.Modules using AddressRegistry.Projections.Extract.AddressCrabHouseNumberIdExtract; using AddressRegistry.Projections.Extract.AddressCrabSubaddressIdExtract; using AddressRegistry.Projections.Extract.AddressExtract; + using AddressRegistry.Projections.Integration; + using AddressRegistry.Projections.Integration.Infrastructure; using AddressRegistry.Projections.LastChangedList; using AddressRegistry.Projections.Legacy; using AddressRegistry.Projections.Legacy.AddressDetail; @@ -90,6 +92,29 @@ private void RegisterProjectionSetup(ContainerBuilder builder) RegisterWmsProjectionsV2(builder); // RegisterWfsProjections(builder); //TODO: Remove when Wfs has been filled in staging // RegisterWmsProjections(builder); //TODO: Remove when Wms has been filled in staging + 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 AddressVersionProjections(context.Resolve>(), + context.Resolve()), + ConnectedProjectionSettings.Default) + .RegisterProjections( + context => new AddressLatestItemProjections(context.Resolve>()), + ConnectedProjectionSettings.Default); } private void RegisterExtractProjections(ContainerBuilder builder) diff --git a/src/AddressRegistry.Projector/Infrastructure/Startup.cs b/src/AddressRegistry.Projector/Infrastructure/Startup.cs index d2e7052aa..3dc249d25 100755 --- a/src/AddressRegistry.Projector/Infrastructure/Startup.cs +++ b/src/AddressRegistry.Projector/Infrastructure/Startup.cs @@ -6,6 +6,7 @@ namespace AddressRegistry.Projector.Infrastructure using System.Threading; using AddressRegistry.Infrastructure.Modules; using AddressRegistry.Projections.Extract; + using AddressRegistry.Projections.Integration.Infrastructure; using AddressRegistry.Projections.Legacy; using AddressRegistry.Projections.Wfs; using AddressRegistry.Projections.Wms; @@ -96,7 +97,13 @@ 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, @@ -104,6 +111,12 @@ public IServiceProvider ConfigureServices(IServiceCollection services) 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"}); @@ -126,7 +139,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/AddressRegistry.Projector/Projections/ProjectionsController.cs b/src/AddressRegistry.Projector/Projections/ProjectionsController.cs index 63b108073..0c92717dd 100644 --- a/src/AddressRegistry.Projector/Projections/ProjectionsController.cs +++ b/src/AddressRegistry.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/AddressRegistry.Projector/appsettings.json b/src/AddressRegistry.Projector/appsettings.json index 39b849760..0792e9c0e 100755 --- a/src/AddressRegistry.Projector/appsettings.json +++ b/src/AddressRegistry.Projector/appsettings.json @@ -14,7 +14,14 @@ "Syndication": "Server=(localdb)\\mssqllocaldb;Database=EFProviders.InMemory.AddressRegistry;Trusted_Connection=True;TrustServerCertificate=True;", "Consumer": "Server=(localdb)\\mssqllocaldb;Database=EFProviders.InMemory.AddressNameRegistry;Trusted_Connection=True;TrustServerCertificate=True;", "ConsumerMunicipality": "Server=(localdb)\\mssqllocaldb;Database=EFProviders.InMemory.AddressRegistry;Trusted_Connection=True;TrustServerCertificate=True;", - "ConsumerStreetName": "Server=(localdb)\\mssqllocaldb;Database=EFProviders.InMemory.AddressRegistry;Trusted_Connection=True;TrustServerCertificate=True;" + "ConsumerStreetName": "Server=(localdb)\\mssqllocaldb;Database=EFProviders.InMemory.AddressRegistry;Trusted_Connection=True;TrustServerCertificate=True;", + "IntegrationProjections": ".", + "IntegrationProjectionsAdmin": "." + }, + + "Integration": { + "Namespace": "https://data.vlaanderen.be/id/adres", + "Enabled": false }, "DataDog": { diff --git a/src/AddressRegistry.Projector/paket.references b/src/AddressRegistry.Projector/paket.references index 8f353a425..792222f38 100644 --- a/src/AddressRegistry.Projector/paket.references +++ b/src/AddressRegistry.Projector/paket.references @@ -2,7 +2,13 @@ Be.Vlaanderen.Basisregisters.Api Be.Vlaanderen.Basisregisters.EventHandling.Autofac Be.Vlaanderen.Basisregisters.Projector +Npgsql +Npgsql.EntityFrameworkCore.PostgreSQL +Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite + AspNetCore.HealthChecks.SqlServer +AspNetCore.HealthChecks.NpgSql + Dapper SourceLink.Embed.AllSourceFiles diff --git a/src/EF.MigrationsHelper/EF.MigrationHelper.csproj b/src/EF.MigrationsHelper/EF.MigrationHelper.csproj index 128f2802d..768787020 100644 --- a/src/EF.MigrationsHelper/EF.MigrationHelper.csproj +++ b/src/EF.MigrationsHelper/EF.MigrationHelper.csproj @@ -26,6 +26,7 @@ + @@ -33,7 +34,6 @@ - diff --git a/src/EF.MigrationsHelper/appsettings.json b/src/EF.MigrationsHelper/appsettings.json index 0f3ada5a1..253e3a7fd 100644 --- a/src/EF.MigrationsHelper/appsettings.json +++ b/src/EF.MigrationsHelper/appsettings.json @@ -12,7 +12,8 @@ "SyndicationProjectionsAdmin": "x", "Sequences": "x", "BackOffice": "x", - "BackOfficeProjectionsAdmin": "x" + "BackOfficeProjectionsAdmin": "x", + "IntegrationProjectionsAdmin": "x" }, "Logging": { diff --git a/src/EF.MigrationsHelper/paket.references b/src/EF.MigrationsHelper/paket.references index 2ccd1f4fb..e74a40cfb 100644 --- a/src/EF.MigrationsHelper/paket.references +++ b/src/EF.MigrationsHelper/paket.references @@ -1,4 +1,7 @@ Microsoft.EntityFrameworkCore.Design +Npgsql.EntityFrameworkCore.PostgreSQL +Npgsql.EntityFrameworkCore.PostgreSQL.Design + SourceLink.Embed.AllSourceFiles -SourceLink.Copy.PdbFiles \ No newline at end of file +SourceLink.Copy.PdbFiles diff --git a/test/AddressRegistry.Tests/AddressRegistry.Tests.csproj b/test/AddressRegistry.Tests/AddressRegistry.Tests.csproj index 5cabb1b4b..83eb3bc76 100755 --- a/test/AddressRegistry.Tests/AddressRegistry.Tests.csproj +++ b/test/AddressRegistry.Tests/AddressRegistry.Tests.csproj @@ -10,6 +10,7 @@ + diff --git a/test/AddressRegistry.Tests/EventExtensions/AddressPositionWasCorrectedExtensions.cs b/test/AddressRegistry.Tests/EventExtensions/AddressPositionWasCorrectedExtensions.cs new file mode 100644 index 000000000..119bebf1c --- /dev/null +++ b/test/AddressRegistry.Tests/EventExtensions/AddressPositionWasCorrectedExtensions.cs @@ -0,0 +1,42 @@ +namespace AddressRegistry.Tests.EventExtensions +{ + using System; + using Address; + using Address.Events; + using Be.Vlaanderen.Basisregisters.GrAr.Provenance; + + public static class AddressPositionWasCorrectedExtensions + { + public static AddressPositionWasCorrected WithAddressId( + this AddressPositionWasCorrected @event, + Guid addressId) + { + var geometry = new AddressGeometry( + @event.GeometryMethod, + @event.GeometrySpecification, + new ExtendedWkbGeometry(@event.ExtendedWkbGeometry)); + var newEvent = new AddressPositionWasCorrected( + new AddressId(addressId), + geometry); + ((ISetProvenance)newEvent).SetProvenance(@event.Provenance.ToProvenance()); + + return newEvent; + } + + public static AddressPositionWasCorrected WithExtendedWkbGeometry( + this AddressPositionWasCorrected @event, + ExtendedWkbGeometry extendedWkbGeometry) + { + var geometry = new AddressGeometry( + @event.GeometryMethod, + @event.GeometrySpecification, + extendedWkbGeometry); + var newEvent = new AddressPositionWasCorrected( + new AddressId(@event.AddressId), + geometry); + ((ISetProvenance)newEvent).SetProvenance(@event.Provenance.ToProvenance()); + + return newEvent; + } + } +} diff --git a/test/AddressRegistry.Tests/EventExtensions/AddressWasPositionedExtensions.cs b/test/AddressRegistry.Tests/EventExtensions/AddressWasPositionedExtensions.cs new file mode 100644 index 000000000..1bba94761 --- /dev/null +++ b/test/AddressRegistry.Tests/EventExtensions/AddressWasPositionedExtensions.cs @@ -0,0 +1,42 @@ +namespace AddressRegistry.Tests.EventExtensions +{ + using System; + using Address; + using Address.Events; + using Be.Vlaanderen.Basisregisters.GrAr.Provenance; + + public static class AddressWasPositionedExtensions + { + public static AddressWasPositioned WithAddressId( + this AddressWasPositioned @event, + Guid addressId) + { + var geometry = new AddressGeometry( + @event.GeometryMethod, + @event.GeometrySpecification, + new ExtendedWkbGeometry(@event.ExtendedWkbGeometry)); + var newEvent = new AddressWasPositioned( + new AddressId(addressId), + geometry); + ((ISetProvenance)newEvent).SetProvenance(@event.Provenance.ToProvenance()); + + return newEvent; + } + + public static AddressWasPositioned WithExtendedWkbGeometry( + this AddressWasPositioned @event, + ExtendedWkbGeometry extendedWkbGeometry) + { + var geometry = new AddressGeometry( + @event.GeometryMethod, + @event.GeometrySpecification, + extendedWkbGeometry); + var newEvent = new AddressWasPositioned( + new AddressId(@event.AddressId), + geometry); + ((ISetProvenance)newEvent).SetProvenance(@event.Provenance.ToProvenance()); + + return newEvent; + } + } +} diff --git a/test/AddressRegistry.Tests/EventExtensions/AddressWasProposedV2Extensions.cs b/test/AddressRegistry.Tests/EventExtensions/AddressWasProposedV2Extensions.cs index c99165293..e5cb2d60d 100644 --- a/test/AddressRegistry.Tests/EventExtensions/AddressWasProposedV2Extensions.cs +++ b/test/AddressRegistry.Tests/EventExtensions/AddressWasProposedV2Extensions.cs @@ -71,6 +71,25 @@ public static AddressWasProposedV2 WithAddressPersistentLocalId( return newEvent; } + public static AddressWasProposedV2 WithAddressPersistentLocalId( + this AddressWasProposedV2 @event, + int addressPersistentLocalId) + { + var newEvent = new AddressWasProposedV2( + new StreetNamePersistentLocalId(@event.StreetNamePersistentLocalId), + new AddressPersistentLocalId(addressPersistentLocalId), + @event.ParentPersistentLocalId is not null ? new AddressPersistentLocalId(@event.ParentPersistentLocalId.Value) : null, + new PostalCode(@event.PostalCode), + new HouseNumber(@event.HouseNumber), + @event.BoxNumber is not null ? new BoxNumber(@event.BoxNumber) : null, + @event.GeometryMethod, + @event.GeometrySpecification, + new ExtendedWkbGeometry(@event.ExtendedWkbGeometry)); + ((ISetProvenance)newEvent).SetProvenance(@event.Provenance.ToProvenance()); + + return newEvent; + } + public static AddressWasProposedV2 WithParentAddressPersistentLocalId( this AddressWasProposedV2 @event, AddressPersistentLocalId? parentAddressPersistentLocalId) diff --git a/test/AddressRegistry.Tests/Integration/AddressLatestItemTests.cs b/test/AddressRegistry.Tests/Integration/AddressLatestItemTests.cs new file mode 100644 index 000000000..4bf6241d9 --- /dev/null +++ b/test/AddressRegistry.Tests/Integration/AddressLatestItemTests.cs @@ -0,0 +1,1495 @@ +namespace AddressRegistry.Tests.Integration +{ + using System.Collections.Generic; + using System.Threading.Tasks; + using Api.BackOffice.Abstractions; + using AutoFixture; + using Be.Vlaanderen.Basisregisters.GrAr.Common.Pipes; + using Be.Vlaanderen.Basisregisters.GrAr.Provenance; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore; + using Be.Vlaanderen.Basisregisters.Utilities.HexByteConvertor; + using EventExtensions; + using FluentAssertions; + using global::AutoFixture; + using Microsoft.Extensions.Options; + using Projections.Integration; + using Projections.Integration.Convertors; + using Projections.Integration.Infrastructure; + using StreetName; + using StreetName.DataStructures; + using StreetName.Events; + using Xunit; + + public sealed class AddressLatestItemTests : IntegrationProjectionTest + { + private const string Namespace = "https://data.vlaanderen.be/id/adres"; + private readonly Fixture _fixture; + + public AddressLatestItemTests() + { + _fixture = new Fixture(); + _fixture.Customize(new InfrastructureCustomization()); + _fixture.Customize(new WithValidHouseNumber()); + _fixture.Customize(new WithExtendedWkbGeometry()); + _fixture.Customize(new WithFixedAddressPersistentLocalId()); + _fixture.Customize(new WithFixedStreetNamePersistentLocalId()); + } + + [Fact] + public async Task WhenAddressWasMigratedToStreetName() + { + var addressWasMigratedToStreetName = _fixture.Create() + .WithStatus(AddressStatus.Proposed); + var geometry = WKBReaderFactory.CreateForLegacy().Read(addressWasMigratedToStreetName.ExtendedWkbGeometry.ToByteArray()); + + var position = _fixture.Create(); + + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + await Sut + .Given(new Envelope(new Envelope(addressWasMigratedToStreetName, metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressWasMigratedToStreetName.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should().Be(addressWasMigratedToStreetName.StreetNamePersistentLocalId); + expectedLatestItem.HouseNumber.Should().Be(addressWasMigratedToStreetName.HouseNumber); + expectedLatestItem.BoxNumber.Should().Be(addressWasMigratedToStreetName.BoxNumber); + expectedLatestItem.PostalCode.Should().Be(addressWasMigratedToStreetName.PostalCode); + expectedLatestItem.Status.Should().Be(addressWasMigratedToStreetName.Status); + expectedLatestItem.OsloStatus.Should().Be(addressWasMigratedToStreetName.Status.Map()); + expectedLatestItem.OfficiallyAssigned.Should().Be(addressWasMigratedToStreetName.OfficiallyAssigned); + expectedLatestItem.PositionMethod.Should().Be(addressWasMigratedToStreetName.GeometryMethod); + expectedLatestItem.OsloPositionMethod.Should().Be(addressWasMigratedToStreetName.GeometryMethod.ToPositieGeometrieMethode()); + expectedLatestItem.PositionSpecification.Should().Be(addressWasMigratedToStreetName.GeometrySpecification); + expectedLatestItem.OsloPositionSpecification.Should() + .Be(addressWasMigratedToStreetName.GeometrySpecification.ToPositieSpecificatie()); + expectedLatestItem.Removed.Should().Be(addressWasMigratedToStreetName.IsRemoved); + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressWasMigratedToStreetName.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressWasMigratedToStreetName.Provenance.Timestamp); + expectedLatestItem.Geometry.Should().BeEquivalentTo(geometry); + }); + } + + [Fact] + public async Task WhenAddressWasProposedV2() + { + var addressWasProposedV2 = _fixture.Create(); + + var position = _fixture.Create(); + + var geometry = WKBReaderFactory.CreateForLegacy().Read(addressWasProposedV2.ExtendedWkbGeometry.ToByteArray()); + + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + await Sut + .Given(new Envelope(new Envelope(addressWasProposedV2, metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressWasProposedV2.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should().Be(addressWasProposedV2.StreetNamePersistentLocalId); + expectedLatestItem.HouseNumber.Should().Be(addressWasProposedV2.HouseNumber); + expectedLatestItem.BoxNumber.Should().Be(addressWasProposedV2.BoxNumber); + expectedLatestItem.PostalCode.Should().Be(addressWasProposedV2.PostalCode); + expectedLatestItem.Status.Should().Be(AddressStatus.Proposed); + expectedLatestItem.OsloStatus.Should().Be(AddressStatus.Proposed.Map()); + expectedLatestItem.OfficiallyAssigned.Should().Be(true); + expectedLatestItem.PositionMethod.Should().Be(addressWasProposedV2.GeometryMethod); + expectedLatestItem.OsloPositionMethod.Should().Be(addressWasProposedV2.GeometryMethod.ToPositieGeometrieMethode()); + expectedLatestItem.PositionSpecification.Should().Be(addressWasProposedV2.GeometrySpecification); + expectedLatestItem.OsloPositionSpecification.Should().Be(addressWasProposedV2.GeometrySpecification.ToPositieSpecificatie()); + expectedLatestItem.Removed.Should().Be(false); + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressWasProposedV2.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressWasProposedV2.Provenance.Timestamp); + expectedLatestItem.Geometry.Should().BeEquivalentTo(geometry); + }); + } + + [Fact] + public async Task WhenAddressWasApproved() + { + var addressWasApproved = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create(); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasApproved, metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressWasApproved.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should().Be(addressWasApproved.StreetNamePersistentLocalId); + expectedLatestItem.Status.Should().Be(AddressStatus.Current); + expectedLatestItem.OsloStatus.Should().Be(AddressStatus.Current.Map()); + expectedLatestItem.OfficiallyAssigned.Should().BeTrue(); + expectedLatestItem.Removed.Should().BeFalse(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressWasApproved.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressWasApproved.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasCorrectedFromApprovedToProposed() + { + var addressWasCorrectedFromApprovedToProposed = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create(); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasCorrectedFromApprovedToProposed, metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressWasCorrectedFromApprovedToProposed.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should() + .Be(addressWasCorrectedFromApprovedToProposed.StreetNamePersistentLocalId); + expectedLatestItem.Status.Should().Be(AddressStatus.Proposed); + expectedLatestItem.OsloStatus.Should().Be(AddressStatus.Proposed.Map()); + expectedLatestItem.OfficiallyAssigned.Should().BeTrue(); + expectedLatestItem.Removed.Should().BeFalse(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressWasCorrectedFromApprovedToProposed.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressWasCorrectedFromApprovedToProposed.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasCorrectedFromApprovedToProposedBecauseHouseNumberWasCorrected() + { + var addressWasCorrectedFromApprovedToProposedBecauseHouseNumberWasCorrected = + _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create(); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope( + new Envelope(addressWasCorrectedFromApprovedToProposedBecauseHouseNumberWasCorrected, metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressWasCorrectedFromApprovedToProposedBecauseHouseNumberWasCorrected + .AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should() + .Be(addressWasCorrectedFromApprovedToProposedBecauseHouseNumberWasCorrected.StreetNamePersistentLocalId); + expectedLatestItem.Status.Should().Be(AddressStatus.Proposed); + expectedLatestItem.OsloStatus.Should().Be(AddressStatus.Proposed.Map()); + expectedLatestItem.OfficiallyAssigned.Should().BeTrue(); + expectedLatestItem.Removed.Should().BeFalse(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should() + .Be($"{Namespace}/{addressWasCorrectedFromApprovedToProposedBecauseHouseNumberWasCorrected.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should() + .Be(addressWasCorrectedFromApprovedToProposedBecauseHouseNumberWasCorrected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRejected() + { + var addressWasRejected = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create(); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRejected, metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressWasRejected.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should().Be(addressWasRejected.StreetNamePersistentLocalId); + expectedLatestItem.Status.Should().Be(AddressStatus.Rejected); + expectedLatestItem.OsloStatus.Should().Be(AddressStatus.Rejected.Map()); + expectedLatestItem.OfficiallyAssigned.Should().BeTrue(); + expectedLatestItem.Removed.Should().BeFalse(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressWasRejected.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressWasRejected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRejectedBecauseHouseNumberWasRejected() + { + var addressWasRejectedBecauseHouseNumberWasRejected = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create(); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRejectedBecauseHouseNumberWasRejected, + metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressWasRejectedBecauseHouseNumberWasRejected.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should() + .Be(addressWasRejectedBecauseHouseNumberWasRejected.StreetNamePersistentLocalId); + expectedLatestItem.Status.Should().Be(AddressStatus.Rejected); + expectedLatestItem.OsloStatus.Should().Be(AddressStatus.Rejected.Map()); + expectedLatestItem.OfficiallyAssigned.Should().BeTrue(); + expectedLatestItem.Removed.Should().BeFalse(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressWasRejectedBecauseHouseNumberWasRejected.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressWasRejectedBecauseHouseNumberWasRejected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRejectedBecauseHouseNumberWasRetired() + { + var addressWasRejectedBecauseHouseNumberWasRetired = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create(); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRejectedBecauseHouseNumberWasRetired, + metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressWasRejectedBecauseHouseNumberWasRetired.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should() + .Be(addressWasRejectedBecauseHouseNumberWasRetired.StreetNamePersistentLocalId); + expectedLatestItem.Status.Should().Be(AddressStatus.Rejected); + expectedLatestItem.OsloStatus.Should().Be(AddressStatus.Rejected.Map()); + expectedLatestItem.OfficiallyAssigned.Should().BeTrue(); + expectedLatestItem.Removed.Should().BeFalse(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressWasRejectedBecauseHouseNumberWasRetired.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressWasRejectedBecauseHouseNumberWasRetired.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRejectedBecauseStreetNameWasRejected() + { + var addressWasRejectedBecauseStreetNameWasRejected = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create(); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRejectedBecauseStreetNameWasRejected, + metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressWasRejectedBecauseStreetNameWasRejected.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should() + .Be(addressWasRejectedBecauseStreetNameWasRejected.StreetNamePersistentLocalId); + expectedLatestItem.Status.Should().Be(AddressStatus.Rejected); + expectedLatestItem.OsloStatus.Should().Be(AddressStatus.Rejected.Map()); + expectedLatestItem.OfficiallyAssigned.Should().BeTrue(); + expectedLatestItem.Removed.Should().BeFalse(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressWasRejectedBecauseStreetNameWasRejected.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressWasRejectedBecauseStreetNameWasRejected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRetiredBecauseStreetNameWasRejected() + { + var addressWasRetiredBecauseStreetNameWasRejected = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create(); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRetiredBecauseStreetNameWasRejected, + metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressWasRetiredBecauseStreetNameWasRejected.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should() + .Be(addressWasRetiredBecauseStreetNameWasRejected.StreetNamePersistentLocalId); + expectedLatestItem.Status.Should().Be(AddressStatus.Retired); + expectedLatestItem.OsloStatus.Should().Be(AddressStatus.Retired.Map()); + expectedLatestItem.OfficiallyAssigned.Should().BeTrue(); + expectedLatestItem.Removed.Should().BeFalse(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressWasRetiredBecauseStreetNameWasRejected.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressWasRetiredBecauseStreetNameWasRejected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRejectedBecauseStreetNameWasRetired() + { + var addressWasRejectedBecauseStreetNameWasRetired = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create(); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRejectedBecauseStreetNameWasRetired, + metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressWasRejectedBecauseStreetNameWasRetired.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should() + .Be(addressWasRejectedBecauseStreetNameWasRetired.StreetNamePersistentLocalId); + expectedLatestItem.Status.Should().Be(AddressStatus.Rejected); + expectedLatestItem.OsloStatus.Should().Be(AddressStatus.Rejected.Map()); + expectedLatestItem.OfficiallyAssigned.Should().BeTrue(); + expectedLatestItem.Removed.Should().BeFalse(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressWasRejectedBecauseStreetNameWasRetired.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressWasRejectedBecauseStreetNameWasRetired.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasDeregulated() + { + var addressWasDeregulated = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create(); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasDeregulated, + metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressWasDeregulated.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should() + .Be(addressWasDeregulated.StreetNamePersistentLocalId); + expectedLatestItem.Status.Should().Be(AddressStatus.Current); + expectedLatestItem.OsloStatus.Should().Be(AddressStatus.Current.Map()); + expectedLatestItem.OfficiallyAssigned.Should().BeFalse(); + expectedLatestItem.Removed.Should().BeFalse(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressWasDeregulated.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressWasDeregulated.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRegularized() + { + var addressWasRegularized = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create(); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRegularized, + metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressWasRegularized.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should() + .Be(addressWasRegularized.StreetNamePersistentLocalId); + expectedLatestItem.Status.Should().Be(AddressStatus.Proposed); + expectedLatestItem.OsloStatus.Should().Be(AddressStatus.Proposed.Map()); + expectedLatestItem.OfficiallyAssigned.Should().BeTrue(); + expectedLatestItem.Removed.Should().BeFalse(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressWasRegularized.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressWasRegularized.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRetiredV2() + { + var addressWasRetiredV2 = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create(); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRetiredV2, + metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressWasRetiredV2.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should() + .Be(addressWasRetiredV2.StreetNamePersistentLocalId); + expectedLatestItem.Status.Should().Be(AddressStatus.Retired); + expectedLatestItem.OsloStatus.Should().Be(AddressStatus.Retired.Map()); + expectedLatestItem.OfficiallyAssigned.Should().BeTrue(); + expectedLatestItem.Removed.Should().BeFalse(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressWasRetiredV2.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressWasRetiredV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRetiredBecauseHouseNumberWasRetired() + { + var addressWasRetiredBecauseHouseNumberWasRetired = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create(); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRetiredBecauseHouseNumberWasRetired, + metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressWasRetiredBecauseHouseNumberWasRetired.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should() + .Be(addressWasRetiredBecauseHouseNumberWasRetired.StreetNamePersistentLocalId); + expectedLatestItem.Status.Should().Be(AddressStatus.Retired); + expectedLatestItem.OsloStatus.Should().Be(AddressStatus.Retired.Map()); + expectedLatestItem.OfficiallyAssigned.Should().BeTrue(); + expectedLatestItem.Removed.Should().BeFalse(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressWasRetiredBecauseHouseNumberWasRetired.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressWasRetiredBecauseHouseNumberWasRetired.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRetiredBecauseStreetNameWasRetired() + { + var addressWasRetiredBecauseStreetNameWasRetired = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create(); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRetiredBecauseStreetNameWasRetired, + metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressWasRetiredBecauseStreetNameWasRetired.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should() + .Be(addressWasRetiredBecauseStreetNameWasRetired.StreetNamePersistentLocalId); + expectedLatestItem.Status.Should().Be(AddressStatus.Retired); + expectedLatestItem.OsloStatus.Should().Be(AddressStatus.Retired.Map()); + expectedLatestItem.OfficiallyAssigned.Should().BeTrue(); + expectedLatestItem.Removed.Should().BeFalse(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressWasRetiredBecauseStreetNameWasRetired.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressWasRetiredBecauseStreetNameWasRetired.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasCorrectedFromRetiredToCurrent() + { + var addressWasCorrectedFromRetiredToCurrent = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create(); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasCorrectedFromRetiredToCurrent, + metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressWasCorrectedFromRetiredToCurrent.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should() + .Be(addressWasCorrectedFromRetiredToCurrent.StreetNamePersistentLocalId); + expectedLatestItem.Status.Should().Be(AddressStatus.Current); + expectedLatestItem.OsloStatus.Should().Be(AddressStatus.Current.Map()); + expectedLatestItem.OfficiallyAssigned.Should().BeTrue(); + expectedLatestItem.Removed.Should().BeFalse(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressWasCorrectedFromRetiredToCurrent.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressWasCorrectedFromRetiredToCurrent.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressPostalCodeWasChangedV2() + { + var addressPostalCodeWasChangedV2 = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create(); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressPostalCodeWasChangedV2, + metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressPostalCodeWasChangedV2.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should() + .Be(addressPostalCodeWasChangedV2.StreetNamePersistentLocalId); + expectedLatestItem.Removed.Should().BeFalse(); + expectedLatestItem.PostalCode.Should().Be(addressPostalCodeWasChangedV2.PostalCode); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressPostalCodeWasChangedV2.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressPostalCodeWasChangedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressPostalCodeWasCorrectedV2() + { + var addressPostalCodeWasCorrectedV2 = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create(); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressPostalCodeWasCorrectedV2, + metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressPostalCodeWasCorrectedV2.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should() + .Be(addressPostalCodeWasCorrectedV2.StreetNamePersistentLocalId); + expectedLatestItem.Removed.Should().BeFalse(); + expectedLatestItem.PostalCode.Should().Be(addressPostalCodeWasCorrectedV2.PostalCode); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressPostalCodeWasCorrectedV2.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressPostalCodeWasCorrectedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressHouseNumberWasCorrectedV2() + { + var addressHouseNumberWasCorrectedV2 = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create(); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressHouseNumberWasCorrectedV2, + metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressHouseNumberWasCorrectedV2.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should() + .Be(addressHouseNumberWasCorrectedV2.StreetNamePersistentLocalId); + expectedLatestItem.Removed.Should().BeFalse(); + expectedLatestItem.HouseNumber.Should().Be(addressHouseNumberWasCorrectedV2.HouseNumber); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressHouseNumberWasCorrectedV2.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressHouseNumberWasCorrectedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressBoxNumberWasCorrectedV2() + { + var addressBoxNumberWasCorrectedV2 = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create(); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressBoxNumberWasCorrectedV2, + metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressBoxNumberWasCorrectedV2.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should() + .Be(addressBoxNumberWasCorrectedV2.StreetNamePersistentLocalId); + expectedLatestItem.Removed.Should().BeFalse(); + expectedLatestItem.BoxNumber.Should().Be(addressBoxNumberWasCorrectedV2.BoxNumber); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressBoxNumberWasCorrectedV2.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressBoxNumberWasCorrectedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressPositionWasChanged() + { + var addressPositionWasChanged = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithExtendedWkbGeometry(GeometryHelpers.GmlPointGeometry.ToExtendedWkbGeometry()) + .WithGeometryMethod(GeometryMethod.AppointedByAdministrator) + .WithGeometrySpecification(GeometrySpecification.Entry); + + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressPositionWasChanged, + metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressPositionWasChanged.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should() + .Be(addressPositionWasChanged.StreetNamePersistentLocalId); + expectedLatestItem.Removed.Should().BeFalse(); + expectedLatestItem.PositionMethod.Should().Be(addressPositionWasChanged.GeometryMethod); + expectedLatestItem.OsloPositionMethod.Should().Be(addressPositionWasChanged.GeometryMethod.ToPositieGeometrieMethode()); + expectedLatestItem.PositionSpecification.Should() + .Be(addressPositionWasChanged.GeometrySpecification); + expectedLatestItem.OsloPositionSpecification.Should() + .Be(addressPositionWasChanged.GeometrySpecification.ToPositieSpecificatie()); + var geometry = WKBReaderFactory.CreateForLegacy().Read(addressPositionWasChanged.ExtendedWkbGeometry.ToByteArray()); + expectedLatestItem.Geometry.Should().BeEquivalentTo(geometry); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressPositionWasChanged.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressPositionWasChanged.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressPositionWasCorrectedV2() + { + var addressPositionWasCorrectedV2 = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithExtendedWkbGeometry(GeometryHelpers.GmlPointGeometry.ToExtendedWkbGeometry()) + .WithGeometryMethod(GeometryMethod.AppointedByAdministrator) + .WithGeometrySpecification(GeometrySpecification.Entry); + + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressPositionWasCorrectedV2, + metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressPositionWasCorrectedV2.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should() + .Be(addressPositionWasCorrectedV2.StreetNamePersistentLocalId); + expectedLatestItem.Removed.Should().BeFalse(); + expectedLatestItem.PositionMethod.Should().Be(addressPositionWasCorrectedV2.GeometryMethod); + expectedLatestItem.OsloPositionMethod.Should().Be(addressPositionWasCorrectedV2.GeometryMethod.ToPositieGeometrieMethode()); + expectedLatestItem.PositionSpecification.Should() + .Be(addressPositionWasCorrectedV2.GeometrySpecification); + expectedLatestItem.OsloPositionSpecification.Should() + .Be(addressPositionWasCorrectedV2.GeometrySpecification.ToPositieSpecificatie()); + var geometry = WKBReaderFactory.CreateForLegacy().Read(addressPositionWasCorrectedV2.ExtendedWkbGeometry.ToByteArray()); + expectedLatestItem.Geometry.Should().BeEquivalentTo(geometry); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressPositionWasCorrectedV2.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressPositionWasCorrectedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressHouseNumberWasReaddressed() + { + var addressPersistentLocalId = _fixture.Create(); + var boxNumberAddressPersistentLocalId = new AddressPersistentLocalId(addressPersistentLocalId + 1); + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithBoxNumber(null); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + + var addressBoxNumberWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(boxNumberAddressPersistentLocalId); + var proposedBoxNumberMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressBoxNumberWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + var readdressedHouseNumber = new ReaddressedAddressData( + new AddressPersistentLocalId(addressPersistentLocalId + 10), + addressPersistentLocalId, + isDestinationNewlyProposed: true, + AddressStatus.Current, + new HouseNumber("3"), + boxNumber: null, + new PostalCode("9000"), + new AddressGeometry( + GeometryMethod.AppointedByAdministrator, + GeometrySpecification.Entry, + GeometryHelpers.GmlPointGeometry.ToExtendedWkbGeometry()), + sourceIsOfficiallyAssigned: false); + + var readdressedBoxNumber = new ReaddressedAddressData( + new AddressPersistentLocalId(addressPersistentLocalId + 11), + boxNumberAddressPersistentLocalId, + isDestinationNewlyProposed: true, + AddressStatus.Current, + new HouseNumber("3"), + new BoxNumber("A"), + new PostalCode("9000"), + new AddressGeometry( + GeometryMethod.AppointedByAdministrator, + GeometrySpecification.Entry, + GeometryHelpers.GmlPointGeometry.ToExtendedWkbGeometry()), + sourceIsOfficiallyAssigned: false); + + var addressHouseNumberWasReaddressed = new AddressHouseNumberWasReaddressed( + _fixture.Create(), + addressPersistentLocalId, + readdressedHouseNumber, + new List { readdressedBoxNumber }); + ((ISetProvenance)addressHouseNumberWasReaddressed).SetProvenance(_fixture.Create()); + + var addressHouseNumberWasReaddressedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressHouseNumberWasReaddressed.GetHash() }, + { Envelope.PositionMetadataKey, position + 2 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressBoxNumberWasProposedV2, proposedBoxNumberMetadata)), + new Envelope(new Envelope(addressHouseNumberWasReaddressed, + addressHouseNumberWasReaddressedMetadata))) + .Then(async ct => + { + var houseNumberItem = await ct.AddressLatestItems.FindAsync(addressWasProposedV2.AddressPersistentLocalId); + houseNumberItem.Should().NotBeNull(); + + houseNumberItem!.Status.Should().Be(readdressedHouseNumber.SourceStatus); + houseNumberItem.OsloStatus.Should().Be(readdressedHouseNumber.SourceStatus.Map()); + houseNumberItem.HouseNumber.Should().Be(readdressedHouseNumber.DestinationHouseNumber); + houseNumberItem.BoxNumber.Should().Be(null); + houseNumberItem.PostalCode.Should().Be(readdressedHouseNumber.SourcePostalCode); + houseNumberItem.OfficiallyAssigned.Should().Be(readdressedHouseNumber.SourceIsOfficiallyAssigned); + var houseNumberItemGeometry = + WKBReaderFactory.CreateForLegacy().Read(readdressedHouseNumber.SourceExtendedWkbGeometry.ToByteArray()); + houseNumberItem.Geometry.Should().BeEquivalentTo(houseNumberItemGeometry); + houseNumberItem.PositionMethod.Should().Be(readdressedHouseNumber.SourceGeometryMethod); + houseNumberItem.OsloPositionMethod.Should().Be(readdressedHouseNumber.SourceGeometryMethod.ToPositieGeometrieMethode()); + houseNumberItem.PositionSpecification.Should().Be(readdressedHouseNumber.SourceGeometrySpecification); + houseNumberItem.OsloPositionSpecification.Should().Be(readdressedHouseNumber.SourceGeometrySpecification.ToPositieSpecificatie()); + houseNumberItem.VersionTimestamp.Should().Be(addressHouseNumberWasReaddressed.Provenance.Timestamp); + + houseNumberItem.Namespace.Should().Be(Namespace); + houseNumberItem.PuriId.Should().Be($"{Namespace}/{addressHouseNumberWasReaddressed.AddressPersistentLocalId}"); + houseNumberItem.VersionTimestamp.Should().Be(addressHouseNumberWasReaddressed.Provenance.Timestamp); + + + var boxNumberItem = await ct.AddressLatestItems.FindAsync(addressBoxNumberWasProposedV2.AddressPersistentLocalId); + houseNumberItem.Should().NotBeNull(); + boxNumberItem!.Status.Should().Be(readdressedBoxNumber.SourceStatus); + boxNumberItem.OsloStatus.Should().Be(readdressedBoxNumber.SourceStatus.Map()); + boxNumberItem.HouseNumber.Should().Be(readdressedBoxNumber.DestinationHouseNumber); + boxNumberItem.BoxNumber.Should().Be(readdressedBoxNumber.SourceBoxNumber); + boxNumberItem.PostalCode.Should().Be(readdressedBoxNumber.SourcePostalCode); + boxNumberItem.OfficiallyAssigned.Should().Be(readdressedBoxNumber.SourceIsOfficiallyAssigned); + var boxNumberItemGeometry = WKBReaderFactory.CreateForLegacy().Read(readdressedBoxNumber.SourceExtendedWkbGeometry.ToByteArray()); + boxNumberItem.Geometry.Should().BeEquivalentTo(boxNumberItemGeometry); + boxNumberItem.PositionMethod.Should().Be(readdressedBoxNumber.SourceGeometryMethod); + boxNumberItem.OsloPositionMethod.Should().Be(readdressedBoxNumber.SourceGeometryMethod.ToPositieGeometrieMethode()); + boxNumberItem.PositionSpecification.Should().Be(readdressedBoxNumber.SourceGeometrySpecification); + boxNumberItem.OsloPositionSpecification.Should().Be(readdressedBoxNumber.SourceGeometrySpecification.ToPositieSpecificatie()); + boxNumberItem.VersionTimestamp.Should().Be(addressHouseNumberWasReaddressed.Provenance.Timestamp); + + boxNumberItem.Namespace.Should().Be(Namespace); + boxNumberItem.PuriId.Should().Be($"{Namespace}/{readdressedBoxNumber.DestinationAddressPersistentLocalId}"); + boxNumberItem.VersionTimestamp.Should().Be(addressHouseNumberWasReaddressed.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasProposedBecauseOfReaddress() + { + var addressWasProposedBecauseOfReaddress = _fixture.Create(); + + var position = _fixture.Create(); + + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + await Sut + .Given(new Envelope(new Envelope(addressWasProposedBecauseOfReaddress, metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressWasProposedBecauseOfReaddress.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should().Be(addressWasProposedBecauseOfReaddress.StreetNamePersistentLocalId); + expectedLatestItem.HouseNumber.Should().Be(addressWasProposedBecauseOfReaddress.HouseNumber); + expectedLatestItem.BoxNumber.Should().Be(addressWasProposedBecauseOfReaddress.BoxNumber); + expectedLatestItem.PostalCode.Should().Be(addressWasProposedBecauseOfReaddress.PostalCode); + expectedLatestItem.Status.Should().Be(AddressStatus.Proposed); + expectedLatestItem.OsloStatus.Should().Be(AddressStatus.Proposed.Map()); + expectedLatestItem.OfficiallyAssigned.Should().BeTrue(); + expectedLatestItem.PositionMethod.Should().Be(addressWasProposedBecauseOfReaddress.GeometryMethod); + expectedLatestItem.OsloPositionMethod.Should().Be(addressWasProposedBecauseOfReaddress.GeometryMethod.ToPositieGeometrieMethode()); + expectedLatestItem.PositionSpecification.Should() + .Be(addressWasProposedBecauseOfReaddress.GeometrySpecification); + expectedLatestItem.OsloPositionSpecification.Should() + .Be(addressWasProposedBecauseOfReaddress.GeometrySpecification.ToPositieSpecificatie()); + expectedLatestItem.Removed.Should().BeFalse(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressWasProposedBecauseOfReaddress.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressWasProposedBecauseOfReaddress.Provenance.Timestamp); + + var geometry = WKBReaderFactory.CreateForLegacy().Read(addressWasProposedBecauseOfReaddress.ExtendedWkbGeometry.ToByteArray()); + expectedLatestItem.Geometry.Should().BeEquivalentTo(geometry); + }); + } + + [Fact] + public async Task WhenAddressWasRejectedBecauseOfReaddress() + { + var addressWasRejectedBecauseOfReaddress = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create(); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRejectedBecauseOfReaddress, metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressWasRejectedBecauseOfReaddress.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should().Be(addressWasRejectedBecauseOfReaddress.StreetNamePersistentLocalId); + expectedLatestItem.Status.Should().Be(AddressStatus.Rejected); + expectedLatestItem.OsloStatus.Should().Be(AddressStatus.Rejected.Map()); + expectedLatestItem.OfficiallyAssigned.Should().BeTrue(); + expectedLatestItem.Removed.Should().BeFalse(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressWasRejectedBecauseOfReaddress.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressWasRejectedBecauseOfReaddress.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRetiredBecauseOfReaddress() + { + var addressWasRetiredBecauseOfReaddress = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create(); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRetiredBecauseOfReaddress, metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressWasRetiredBecauseOfReaddress.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should().Be(addressWasRetiredBecauseOfReaddress.StreetNamePersistentLocalId); + expectedLatestItem.Status.Should().Be(AddressStatus.Retired); + expectedLatestItem.OsloStatus.Should().Be(AddressStatus.Retired.Map()); + expectedLatestItem.OfficiallyAssigned.Should().BeTrue(); + expectedLatestItem.Removed.Should().BeFalse(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressWasRetiredBecauseOfReaddress.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressWasRetiredBecauseOfReaddress.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRemovedV2() + { + var addressWasRemovedV2 = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create(); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRemovedV2, metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressWasRemovedV2.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should().Be(addressWasRemovedV2.StreetNamePersistentLocalId); + expectedLatestItem.Removed.Should().BeTrue(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressWasRemovedV2.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressWasRemovedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRemovedBecauseStreetNameWasRemoved() + { + var addressWasRemovedBecauseStreetNameWasRemoved = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create(); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRemovedBecauseStreetNameWasRemoved, metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressWasRemovedBecauseStreetNameWasRemoved.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should() + .Be(addressWasRemovedBecauseStreetNameWasRemoved.StreetNamePersistentLocalId); + expectedLatestItem.Removed.Should().BeTrue(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressWasRemovedBecauseStreetNameWasRemoved.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressWasRemovedBecauseStreetNameWasRemoved.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRemovedBecauseHouseNumberWasRemoved() + { + var addressWasRemovedBecauseHouseNumberWasRemoved = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create(); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRemovedBecauseHouseNumberWasRemoved, + metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressWasRemovedBecauseHouseNumberWasRemoved.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should() + .Be(addressWasRemovedBecauseHouseNumberWasRemoved.StreetNamePersistentLocalId); + expectedLatestItem.Removed.Should().BeTrue(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressWasRemovedBecauseHouseNumberWasRemoved.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressWasRemovedBecauseHouseNumberWasRemoved.Provenance.Timestamp); + }); + } + + + [Fact] + public async Task WhenAddressWasCorrectedFromRejectedToProposed() + { + var addressWasCorrectedFromRejectedToProposed = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create(); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasCorrectedFromRejectedToProposed, metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressWasCorrectedFromRejectedToProposed.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should() + .Be(addressWasCorrectedFromRejectedToProposed.StreetNamePersistentLocalId); + expectedLatestItem.Status.Should().Be(AddressStatus.Proposed); + expectedLatestItem.OsloStatus.Should().Be(AddressStatus.Proposed.Map()); + expectedLatestItem.Removed.Should().BeFalse(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressWasCorrectedFromRejectedToProposed.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressWasCorrectedFromRejectedToProposed.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressRegularizationWasCorrected() + { + var addressRegularizationWasCorrected = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasMigratedToStreetName = _fixture.Create() + .WithStatus(AddressStatus.Proposed) + .WithOfficiallyAssigned(true); + + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasMigratedToStreetName.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasMigratedToStreetName, proposedMetadata)), + new Envelope(new Envelope(addressRegularizationWasCorrected, metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressRegularizationWasCorrected.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should() + .Be(addressRegularizationWasCorrected.StreetNamePersistentLocalId); + expectedLatestItem.OfficiallyAssigned.Should().BeFalse(); + expectedLatestItem.Status.Should().Be(AddressStatus.Current); + expectedLatestItem.OsloStatus.Should().Be(AddressStatus.Current.Map()); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressRegularizationWasCorrected.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressRegularizationWasCorrected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressDeregulationWasCorrected() + { + var addressDeregulationWasCorrected = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasMigratedToStreetName = _fixture.Create() + .WithStatus(AddressStatus.Proposed) + .WithOfficiallyAssigned(false); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasMigratedToStreetName.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasMigratedToStreetName, proposedMetadata)), + new Envelope(new Envelope(addressDeregulationWasCorrected, metadata))) + .Then(async ct => + { + var expectedLatestItem = + await ct.AddressLatestItems.FindAsync(addressDeregulationWasCorrected.AddressPersistentLocalId); + expectedLatestItem.Should().NotBeNull(); + expectedLatestItem!.StreetNamePersistentLocalId.Should() + .Be(addressDeregulationWasCorrected.StreetNamePersistentLocalId); + expectedLatestItem.OfficiallyAssigned.Should().BeTrue(); + + expectedLatestItem.Namespace.Should().Be(Namespace); + expectedLatestItem.PuriId.Should().Be($"{Namespace}/{addressDeregulationWasCorrected.AddressPersistentLocalId}"); + expectedLatestItem.VersionTimestamp.Should().Be(addressDeregulationWasCorrected.Provenance.Timestamp); + }); + } + + protected override AddressLatestItemProjections CreateProjection() + => new AddressLatestItemProjections( + new OptionsWrapper(new IntegrationOptions { Namespace = Namespace })); + } +} diff --git a/test/AddressRegistry.Tests/Integration/AddressVersionTests.cs b/test/AddressRegistry.Tests/Integration/AddressVersionTests.cs new file mode 100644 index 000000000..f37a9f070 --- /dev/null +++ b/test/AddressRegistry.Tests/Integration/AddressVersionTests.cs @@ -0,0 +1,2745 @@ +namespace AddressRegistry.Tests.Integration +{ + using System.Collections.Generic; + using System.Threading.Tasks; + using Address.Events; + using Api.BackOffice.Abstractions; + using AutoFixture; + using Be.Vlaanderen.Basisregisters.GrAr.Common.Pipes; + using Be.Vlaanderen.Basisregisters.GrAr.Provenance; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore; + using Be.Vlaanderen.Basisregisters.Utilities.HexByteConvertor; + using EventExtensions; + using FluentAssertions; + using global::AutoFixture; + using Microsoft.EntityFrameworkCore; + using Microsoft.Extensions.Options; + using Moq; + using Projections.Integration; + using Projections.Integration.Convertors; + using Projections.Integration.Infrastructure; + using StreetName; + using StreetName.DataStructures; + using StreetName.Events; + using Xunit; + + public sealed class AddressVersionTests : IntegrationProjectionTest + { + private const string Namespace = "https://data.vlaanderen.be/id/adres"; + private readonly Fixture _fixture; + private readonly Mock _eventsRepositoryMock; + + public AddressVersionTests() + { + _fixture = new Fixture(); + _fixture.Customize(new InfrastructureCustomization()); + _fixture.Customize(new WithValidHouseNumber()); + _fixture.Customize(new WithFixedAddressId()); + _fixture.Customize(new WithExtendedWkbGeometry()); + _fixture.Customize(new WithFixedStreetNamePersistentLocalId()); + _eventsRepositoryMock = new Mock(); + } + + [Fact] + public async Task WhenAddressWasMigratedToStreetName() + { + var addressWasMigratedToStreetName = _fixture.Create() + .WithStatus(AddressStatus.Proposed); + var geometry = WKBReaderFactory.CreateForLegacy().Read(addressWasMigratedToStreetName.ExtendedWkbGeometry.ToByteArray()); + + var position = _fixture.Create(); + + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + await Sut + .Given(new Envelope(new Envelope(addressWasMigratedToStreetName, metadata))) + .Then(async ct => + { + var addressVersion = + await ct.AddressVersions.FindAsync(position, addressWasMigratedToStreetName.AddressPersistentLocalId); + addressVersion.Should().NotBeNull(); + addressVersion!.StreetNamePersistentLocalId.Should().Be(addressWasMigratedToStreetName.StreetNamePersistentLocalId); + addressVersion.HouseNumber.Should().Be(addressWasMigratedToStreetName.HouseNumber); + addressVersion.BoxNumber.Should().Be(addressWasMigratedToStreetName.BoxNumber); + addressVersion.PostalCode.Should().Be(addressWasMigratedToStreetName.PostalCode); + addressVersion.Status.Should().Be(addressWasMigratedToStreetName.Status); + addressVersion.OsloStatus.Should().Be(addressWasMigratedToStreetName.Status.Map()); + addressVersion.OfficiallyAssigned.Should().Be(addressWasMigratedToStreetName.OfficiallyAssigned); + addressVersion.PositionMethod.Should().Be(addressWasMigratedToStreetName.GeometryMethod); + addressVersion.OsloPositionMethod.Should().Be(addressWasMigratedToStreetName.GeometryMethod.ToPositieGeometrieMethode()); + addressVersion.PositionSpecification.Should().Be(addressWasMigratedToStreetName.GeometrySpecification); + addressVersion.OsloPositionSpecification.Should() + .Be(addressWasMigratedToStreetName.GeometrySpecification.ToPositieSpecificatie()); + addressVersion.Removed.Should().Be(addressWasMigratedToStreetName.IsRemoved); + addressVersion.Namespace.Should().Be(Namespace); + addressVersion.PuriId.Should().Be($"{Namespace}/{addressWasMigratedToStreetName.AddressPersistentLocalId}"); + addressVersion.VersionTimestamp.Should().Be(addressWasMigratedToStreetName.Provenance.Timestamp); + addressVersion.CreatedOnTimestamp.Should().Be(addressWasMigratedToStreetName.Provenance.Timestamp); + addressVersion.Geometry.Should().BeEquivalentTo(geometry); + }); + } + + [Fact] + public async Task WhenAddressWasProposedV2() + { + var addressWasProposedV2 = _fixture.Create(); + + var position = _fixture.Create(); + + var geometry = WKBReaderFactory.CreateForLegacy().Read(addressWasProposedV2.ExtendedWkbGeometry.ToByteArray()); + + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + await Sut + .Given(new Envelope(new Envelope(addressWasProposedV2, metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position, addressWasProposedV2.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should().Be(addressWasProposedV2.StreetNamePersistentLocalId); + expectedVersion.HouseNumber.Should().Be(addressWasProposedV2.HouseNumber); + expectedVersion.BoxNumber.Should().Be(addressWasProposedV2.BoxNumber); + expectedVersion.PostalCode.Should().Be(addressWasProposedV2.PostalCode); + expectedVersion.Status.Should().Be(AddressStatus.Proposed); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Proposed.Map()); + expectedVersion.OfficiallyAssigned.Should().Be(true); + expectedVersion.PositionMethod.Should().Be(addressWasProposedV2.GeometryMethod); + expectedVersion.OsloPositionMethod.Should().Be(addressWasProposedV2.GeometryMethod.ToPositieGeometrieMethode()); + expectedVersion.PositionSpecification.Should().Be(addressWasProposedV2.GeometrySpecification); + expectedVersion.OsloPositionSpecification.Should().Be(addressWasProposedV2.GeometrySpecification.ToPositieSpecificatie()); + expectedVersion.Removed.Should().Be(false); + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressWasProposedV2.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressWasProposedV2.Provenance.Timestamp); + expectedVersion.CreatedOnTimestamp.Should().Be(addressWasProposedV2.Provenance.Timestamp); + expectedVersion.Geometry.Should().BeEquivalentTo(geometry); + }); + } + + [Fact] + public async Task WhenAddressWasApproved() + { + var addressWasApproved = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressWasApproved.AddressPersistentLocalId); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasApproved, metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressWasApproved.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should().Be(addressWasApproved.StreetNamePersistentLocalId); + expectedVersion.Status.Should().Be(AddressStatus.Current); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Current.Map()); + expectedVersion.OfficiallyAssigned.Should().BeTrue(); + expectedVersion.Removed.Should().BeFalse(); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressWasApproved.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressWasApproved.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasCorrectedFromApprovedToProposed() + { + var addressWasCorrectedFromApprovedToProposed = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressWasCorrectedFromApprovedToProposed.AddressPersistentLocalId); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasCorrectedFromApprovedToProposed, metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressWasCorrectedFromApprovedToProposed.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should() + .Be(addressWasCorrectedFromApprovedToProposed.StreetNamePersistentLocalId); + expectedVersion.Status.Should().Be(AddressStatus.Proposed); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Proposed.Map()); + expectedVersion.OfficiallyAssigned.Should().BeTrue(); + expectedVersion.Removed.Should().BeFalse(); + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressWasCorrectedFromApprovedToProposed.AddressPersistentLocalId}"); + + expectedVersion.VersionTimestamp.Should().Be(addressWasCorrectedFromApprovedToProposed.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasCorrectedFromApprovedToProposedBecauseHouseNumberWasCorrected() + { + var addressWasCorrectedFromApprovedToProposedBecauseHouseNumberWasCorrected = + _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressWasCorrectedFromApprovedToProposedBecauseHouseNumberWasCorrected.AddressPersistentLocalId); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope( + new Envelope(addressWasCorrectedFromApprovedToProposedBecauseHouseNumberWasCorrected, metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressWasCorrectedFromApprovedToProposedBecauseHouseNumberWasCorrected + .AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should() + .Be(addressWasCorrectedFromApprovedToProposedBecauseHouseNumberWasCorrected.StreetNamePersistentLocalId); + expectedVersion.Status.Should().Be(AddressStatus.Proposed); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Proposed.Map()); + expectedVersion.OfficiallyAssigned.Should().BeTrue(); + expectedVersion.Removed.Should().BeFalse(); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should() + .Be($"{Namespace}/{addressWasCorrectedFromApprovedToProposedBecauseHouseNumberWasCorrected.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should() + .Be(addressWasCorrectedFromApprovedToProposedBecauseHouseNumberWasCorrected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRejected() + { + var addressWasRejected = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressWasRejected.AddressPersistentLocalId); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRejected, metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressWasRejected.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should().Be(addressWasRejected.StreetNamePersistentLocalId); + expectedVersion.Status.Should().Be(AddressStatus.Rejected); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Rejected.Map()); + expectedVersion.OfficiallyAssigned.Should().BeTrue(); + expectedVersion.Removed.Should().BeFalse(); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressWasRejected.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressWasRejected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRejectedBecauseHouseNumberWasRejected() + { + var addressWasRejectedBecauseHouseNumberWasRejected = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressWasRejectedBecauseHouseNumberWasRejected.AddressPersistentLocalId); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRejectedBecauseHouseNumberWasRejected, + metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressWasRejectedBecauseHouseNumberWasRejected.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should() + .Be(addressWasRejectedBecauseHouseNumberWasRejected.StreetNamePersistentLocalId); + expectedVersion.Status.Should().Be(AddressStatus.Rejected); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Rejected.Map()); + expectedVersion.OfficiallyAssigned.Should().BeTrue(); + expectedVersion.Removed.Should().BeFalse(); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressWasRejectedBecauseHouseNumberWasRejected.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressWasRejectedBecauseHouseNumberWasRejected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRejectedBecauseHouseNumberWasRetired() + { + var addressWasRejectedBecauseHouseNumberWasRetired = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressWasRejectedBecauseHouseNumberWasRetired.AddressPersistentLocalId); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRejectedBecauseHouseNumberWasRetired, + metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressWasRejectedBecauseHouseNumberWasRetired.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should() + .Be(addressWasRejectedBecauseHouseNumberWasRetired.StreetNamePersistentLocalId); + expectedVersion.Status.Should().Be(AddressStatus.Rejected); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Rejected.Map()); + expectedVersion.OfficiallyAssigned.Should().BeTrue(); + expectedVersion.Removed.Should().BeFalse(); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressWasRejectedBecauseHouseNumberWasRetired.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressWasRejectedBecauseHouseNumberWasRetired.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRejectedBecauseStreetNameWasRejected() + { + var addressWasRejectedBecauseStreetNameWasRejected = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressWasRejectedBecauseStreetNameWasRejected.AddressPersistentLocalId); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRejectedBecauseStreetNameWasRejected, + metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressWasRejectedBecauseStreetNameWasRejected.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should() + .Be(addressWasRejectedBecauseStreetNameWasRejected.StreetNamePersistentLocalId); + expectedVersion.Status.Should().Be(AddressStatus.Rejected); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Rejected.Map()); + expectedVersion.OfficiallyAssigned.Should().BeTrue(); + expectedVersion.Removed.Should().BeFalse(); + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressWasRejectedBecauseStreetNameWasRejected.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressWasRejectedBecauseStreetNameWasRejected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRetiredBecauseStreetNameWasRejected() + { + var addressWasRetiredBecauseStreetNameWasRejected = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressWasRetiredBecauseStreetNameWasRejected.AddressPersistentLocalId); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRetiredBecauseStreetNameWasRejected, + metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressWasRetiredBecauseStreetNameWasRejected.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should() + .Be(addressWasRetiredBecauseStreetNameWasRejected.StreetNamePersistentLocalId); + expectedVersion.Status.Should().Be(AddressStatus.Retired); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Retired.Map()); + expectedVersion.OfficiallyAssigned.Should().BeTrue(); + expectedVersion.Removed.Should().BeFalse(); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressWasRetiredBecauseStreetNameWasRejected.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressWasRetiredBecauseStreetNameWasRejected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRejectedBecauseStreetNameWasRetired() + { + var addressWasRejectedBecauseStreetNameWasRetired = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressWasRejectedBecauseStreetNameWasRetired.AddressPersistentLocalId); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRejectedBecauseStreetNameWasRetired, + metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressWasRejectedBecauseStreetNameWasRetired.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should() + .Be(addressWasRejectedBecauseStreetNameWasRetired.StreetNamePersistentLocalId); + expectedVersion.Status.Should().Be(AddressStatus.Rejected); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Rejected.Map()); + expectedVersion.OfficiallyAssigned.Should().BeTrue(); + expectedVersion.Removed.Should().BeFalse(); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressWasRejectedBecauseStreetNameWasRetired.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressWasRejectedBecauseStreetNameWasRetired.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasDeregulated() + { + var addressWasDeregulated = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressWasDeregulated.AddressPersistentLocalId); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasDeregulated, + metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressWasDeregulated.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should() + .Be(addressWasDeregulated.StreetNamePersistentLocalId); + expectedVersion.Status.Should().Be(AddressStatus.Current); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Current.Map()); + expectedVersion.OfficiallyAssigned.Should().BeFalse(); + expectedVersion.Removed.Should().BeFalse(); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressWasDeregulated.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressWasDeregulated.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRegularized() + { + var addressWasRegularized = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressWasRegularized.AddressPersistentLocalId); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRegularized, + metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressWasRegularized.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should() + .Be(addressWasRegularized.StreetNamePersistentLocalId); + expectedVersion.Status.Should().Be(AddressStatus.Proposed); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Proposed.Map()); + expectedVersion.OfficiallyAssigned.Should().BeTrue(); + expectedVersion.Removed.Should().BeFalse(); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressWasRegularized.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressWasRegularized.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRetiredV2() + { + var addressWasRetiredV2 = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressWasRetiredV2.AddressPersistentLocalId); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRetiredV2, + metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressWasRetiredV2.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should() + .Be(addressWasRetiredV2.StreetNamePersistentLocalId); + expectedVersion.Status.Should().Be(AddressStatus.Retired); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Retired.Map()); + expectedVersion.OfficiallyAssigned.Should().BeTrue(); + expectedVersion.Removed.Should().BeFalse(); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressWasRetiredV2.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressWasRetiredV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRetiredBecauseHouseNumberWasRetired() + { + var addressWasRetiredBecauseHouseNumberWasRetired = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressWasRetiredBecauseHouseNumberWasRetired.AddressPersistentLocalId); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRetiredBecauseHouseNumberWasRetired, + metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressWasRetiredBecauseHouseNumberWasRetired.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should() + .Be(addressWasRetiredBecauseHouseNumberWasRetired.StreetNamePersistentLocalId); + expectedVersion.Status.Should().Be(AddressStatus.Retired); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Retired.Map()); + expectedVersion.OfficiallyAssigned.Should().BeTrue(); + expectedVersion.Removed.Should().BeFalse(); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressWasRetiredBecauseHouseNumberWasRetired.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressWasRetiredBecauseHouseNumberWasRetired.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRetiredBecauseStreetNameWasRetired() + { + var addressWasRetiredBecauseStreetNameWasRetired = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressWasRetiredBecauseStreetNameWasRetired.AddressPersistentLocalId); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRetiredBecauseStreetNameWasRetired, + metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressWasRetiredBecauseStreetNameWasRetired.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should() + .Be(addressWasRetiredBecauseStreetNameWasRetired.StreetNamePersistentLocalId); + expectedVersion.Status.Should().Be(AddressStatus.Retired); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Retired.Map()); + expectedVersion.OfficiallyAssigned.Should().BeTrue(); + expectedVersion.Removed.Should().BeFalse(); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressWasRetiredBecauseStreetNameWasRetired.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressWasRetiredBecauseStreetNameWasRetired.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasCorrectedFromRetiredToCurrent() + { + var addressWasCorrectedFromRetiredToCurrent = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressWasCorrectedFromRetiredToCurrent.AddressPersistentLocalId); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasCorrectedFromRetiredToCurrent, + metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressWasCorrectedFromRetiredToCurrent.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should() + .Be(addressWasCorrectedFromRetiredToCurrent.StreetNamePersistentLocalId); + expectedVersion.Status.Should().Be(AddressStatus.Current); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Current.Map()); + expectedVersion.OfficiallyAssigned.Should().BeTrue(); + expectedVersion.Removed.Should().BeFalse(); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressWasCorrectedFromRetiredToCurrent.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressWasCorrectedFromRetiredToCurrent.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressPostalCodeWasChangedV2() + { + var boxNumberPersistentLocalId = new AddressPersistentLocalId(1); + var addressPostalCodeWasChangedV2 = _fixture.Create() + .WithBoxNumberPersistentLocalIds( + new List + { + boxNumberPersistentLocalId + }); + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressPostalCodeWasChangedV2.AddressPersistentLocalId); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + var boxNumberWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(boxNumberPersistentLocalId); + var boxNumberMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(boxNumberWasProposedV2, boxNumberMetadata)), + new Envelope(new Envelope(addressPostalCodeWasChangedV2, + metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressPostalCodeWasChangedV2.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should() + .Be(addressPostalCodeWasChangedV2.StreetNamePersistentLocalId); + expectedVersion.Removed.Should().BeFalse(); + expectedVersion.PostalCode.Should().Be(addressPostalCodeWasChangedV2.PostalCode); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressPostalCodeWasChangedV2.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressPostalCodeWasChangedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressPostalCodeWasCorrectedV2() + { + var boxNumberPersistentLocalId = new AddressPersistentLocalId(1); + var addressPostalCodeWasCorrectedV2 = _fixture.Create() + .WithBoxNumberPersistentLocalIds(new List() + { + boxNumberPersistentLocalId + }); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressPostalCodeWasCorrectedV2.AddressPersistentLocalId); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + var boxNumberWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(boxNumberPersistentLocalId); + var boxNumberMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(boxNumberWasProposedV2, boxNumberMetadata)), + new Envelope(new Envelope(addressPostalCodeWasCorrectedV2, + metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressPostalCodeWasCorrectedV2.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should() + .Be(addressPostalCodeWasCorrectedV2.StreetNamePersistentLocalId); + expectedVersion.Removed.Should().BeFalse(); + expectedVersion.PostalCode.Should().Be(addressPostalCodeWasCorrectedV2.PostalCode); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressPostalCodeWasCorrectedV2.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressPostalCodeWasCorrectedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressHouseNumberWasCorrectedV2() + { + var houseNumberPersistentLocalId = _fixture.Create(); + var boxNumberPersistentLocalId = houseNumberPersistentLocalId + 1; + var addressHouseNumberWasCorrectedV2 = _fixture.Create() + .WithBoxNumberPersistentLocalIds(new List() + { + new(boxNumberPersistentLocalId) + }); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressHouseNumberWasCorrectedV2.AddressPersistentLocalId); + + var boxNumberWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(boxNumberPersistentLocalId); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var proposedBoxNumberMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, boxNumberWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 2 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(boxNumberWasProposedV2, proposedBoxNumberMetadata)), + new Envelope(new Envelope(addressHouseNumberWasCorrectedV2, + metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 2, addressHouseNumberWasCorrectedV2.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should() + .Be(addressHouseNumberWasCorrectedV2.StreetNamePersistentLocalId); + expectedVersion.Removed.Should().BeFalse(); + expectedVersion.HouseNumber.Should().Be(addressHouseNumberWasCorrectedV2.HouseNumber); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressHouseNumberWasCorrectedV2.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressHouseNumberWasCorrectedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressBoxNumberWasCorrectedV2() + { + var addressBoxNumberWasCorrectedV2 = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressBoxNumberWasCorrectedV2.AddressPersistentLocalId); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressBoxNumberWasCorrectedV2, + metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressBoxNumberWasCorrectedV2.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should() + .Be(addressBoxNumberWasCorrectedV2.StreetNamePersistentLocalId); + expectedVersion.Removed.Should().BeFalse(); + expectedVersion.BoxNumber.Should().Be(addressBoxNumberWasCorrectedV2.BoxNumber); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressBoxNumberWasCorrectedV2.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressBoxNumberWasCorrectedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressPositionWasChanged() + { + var addressPositionWasChanged = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressPositionWasChanged.AddressPersistentLocalId) + .WithExtendedWkbGeometry(GeometryHelpers.GmlPointGeometry.ToExtendedWkbGeometry()) + .WithGeometryMethod(GeometryMethod.AppointedByAdministrator) + .WithGeometrySpecification(GeometrySpecification.Entry); + + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressPositionWasChanged, + metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressPositionWasChanged.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should() + .Be(addressPositionWasChanged.StreetNamePersistentLocalId); + expectedVersion.Removed.Should().BeFalse(); + expectedVersion.PositionMethod.Should().Be(addressPositionWasChanged.GeometryMethod); + expectedVersion.OsloPositionMethod.Should().Be(addressPositionWasChanged.GeometryMethod.ToPositieGeometrieMethode()); + expectedVersion.PositionSpecification.Should() + .Be(addressPositionWasChanged.GeometrySpecification); + expectedVersion.OsloPositionSpecification.Should() + .Be(addressPositionWasChanged.GeometrySpecification.ToPositieSpecificatie()); + var geometry = WKBReaderFactory.CreateForLegacy().Read(addressPositionWasChanged.ExtendedWkbGeometry.ToByteArray()); + expectedVersion.Geometry.Should().BeEquivalentTo(geometry); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressPositionWasChanged.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressPositionWasChanged.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressPositionWasCorrectedV2() + { + var addressPositionWasCorrectedV2 = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressPositionWasCorrectedV2.AddressPersistentLocalId) + .WithExtendedWkbGeometry(GeometryHelpers.GmlPointGeometry.ToExtendedWkbGeometry()) + .WithGeometryMethod(GeometryMethod.AppointedByAdministrator) + .WithGeometrySpecification(GeometrySpecification.Entry); + + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressPositionWasCorrectedV2, + metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressPositionWasCorrectedV2.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should() + .Be(addressPositionWasCorrectedV2.StreetNamePersistentLocalId); + expectedVersion.Removed.Should().BeFalse(); + expectedVersion.PositionMethod.Should().Be(addressPositionWasCorrectedV2.GeometryMethod); + expectedVersion.OsloPositionMethod.Should().Be(addressPositionWasCorrectedV2.GeometryMethod.ToPositieGeometrieMethode()); + expectedVersion.PositionSpecification.Should() + .Be(addressPositionWasCorrectedV2.GeometrySpecification); + expectedVersion.OsloPositionSpecification.Should() + .Be(addressPositionWasCorrectedV2.GeometrySpecification.ToPositieSpecificatie()); + var geometry = WKBReaderFactory.CreateForLegacy().Read(addressPositionWasCorrectedV2.ExtendedWkbGeometry.ToByteArray()); + expectedVersion.Geometry.Should().BeEquivalentTo(geometry); + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressPositionWasCorrectedV2.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressPositionWasCorrectedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressHouseNumberWasReaddressed() + { + var addressPersistentLocalId = _fixture.Create(); + var boxNumberAddressPersistentLocalId = new AddressPersistentLocalId(addressPersistentLocalId + 1); + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressPersistentLocalId) + .WithBoxNumber(null); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + + var addressBoxNumberWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(boxNumberAddressPersistentLocalId); + var proposedBoxNumberMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressBoxNumberWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + + var readdressedHouseNumber = new ReaddressedAddressData( + new AddressPersistentLocalId(addressPersistentLocalId + 10), + addressPersistentLocalId, + isDestinationNewlyProposed: true, + AddressStatus.Current, + new HouseNumber("3"), + boxNumber: null, + new PostalCode("9000"), + new AddressGeometry( + GeometryMethod.AppointedByAdministrator, + GeometrySpecification.Entry, + GeometryHelpers.GmlPointGeometry.ToExtendedWkbGeometry()), + sourceIsOfficiallyAssigned: false); + + var readdressedBoxNumber = new ReaddressedAddressData( + new AddressPersistentLocalId(addressPersistentLocalId + 11), + boxNumberAddressPersistentLocalId, + isDestinationNewlyProposed: true, + AddressStatus.Current, + new HouseNumber("3"), + new BoxNumber("A"), + new PostalCode("9000"), + new AddressGeometry( + GeometryMethod.AppointedByAdministrator, + GeometrySpecification.Entry, + GeometryHelpers.GmlPointGeometry.ToExtendedWkbGeometry()), + sourceIsOfficiallyAssigned: false); + + var addressHouseNumberWasReaddressed = new AddressHouseNumberWasReaddressed( + _fixture.Create(), + addressPersistentLocalId, + readdressedHouseNumber, + new List { readdressedBoxNumber }); + ((ISetProvenance)addressHouseNumberWasReaddressed).SetProvenance(_fixture.Create()); + + var addressHouseNumberWasReaddressedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressHouseNumberWasReaddressed.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressBoxNumberWasProposedV2, proposedBoxNumberMetadata)), + new Envelope(new Envelope(addressHouseNumberWasReaddressed, + addressHouseNumberWasReaddressedMetadata))) + .Then(async ct => + { + var houseNumberItem = await ct.AddressVersions.FindAsync(position + 1, addressWasProposedV2.AddressPersistentLocalId); + houseNumberItem.Should().NotBeNull(); + + houseNumberItem!.Status.Should().Be(readdressedHouseNumber.SourceStatus); + houseNumberItem.OsloStatus.Should().Be(readdressedHouseNumber.SourceStatus.Map()); + houseNumberItem.HouseNumber.Should().Be(readdressedHouseNumber.DestinationHouseNumber); + houseNumberItem.BoxNumber.Should().Be(null); + houseNumberItem.PostalCode.Should().Be(readdressedHouseNumber.SourcePostalCode); + houseNumberItem.OfficiallyAssigned.Should().Be(readdressedHouseNumber.SourceIsOfficiallyAssigned); + var houseNumberItemGeometry = + WKBReaderFactory.CreateForLegacy().Read(readdressedHouseNumber.SourceExtendedWkbGeometry.ToByteArray()); + houseNumberItem.Geometry.Should().BeEquivalentTo(houseNumberItemGeometry); + houseNumberItem.PositionMethod.Should().Be(readdressedHouseNumber.SourceGeometryMethod); + houseNumberItem.OsloPositionMethod.Should().Be(readdressedHouseNumber.SourceGeometryMethod.ToPositieGeometrieMethode()); + houseNumberItem.PositionSpecification.Should().Be(readdressedHouseNumber.SourceGeometrySpecification); + houseNumberItem.OsloPositionSpecification.Should().Be(readdressedHouseNumber.SourceGeometrySpecification.ToPositieSpecificatie()); + houseNumberItem.VersionTimestamp.Should().Be(addressHouseNumberWasReaddressed.Provenance.Timestamp); + + houseNumberItem.Namespace.Should().Be(Namespace); + houseNumberItem.PuriId.Should().Be($"{Namespace}/{addressHouseNumberWasReaddressed.AddressPersistentLocalId}"); + houseNumberItem.VersionTimestamp.Should().Be(addressHouseNumberWasReaddressed.Provenance.Timestamp); + + + var boxNumberItem = await ct.AddressVersions.FindAsync(position + 1, addressBoxNumberWasProposedV2.AddressPersistentLocalId); + houseNumberItem.Should().NotBeNull(); + boxNumberItem!.Status.Should().Be(readdressedBoxNumber.SourceStatus); + boxNumberItem.OsloStatus.Should().Be(readdressedBoxNumber.SourceStatus.Map()); + boxNumberItem.HouseNumber.Should().Be(readdressedBoxNumber.DestinationHouseNumber); + boxNumberItem.BoxNumber.Should().Be(readdressedBoxNumber.SourceBoxNumber); + boxNumberItem.PostalCode.Should().Be(readdressedBoxNumber.SourcePostalCode); + boxNumberItem.OfficiallyAssigned.Should().Be(readdressedBoxNumber.SourceIsOfficiallyAssigned); + var boxNumberItemGeometry = WKBReaderFactory.CreateForLegacy().Read(readdressedBoxNumber.SourceExtendedWkbGeometry.ToByteArray()); + boxNumberItem.Geometry.Should().BeEquivalentTo(boxNumberItemGeometry); + boxNumberItem.PositionMethod.Should().Be(readdressedBoxNumber.SourceGeometryMethod); + boxNumberItem.OsloPositionMethod.Should().Be(readdressedBoxNumber.SourceGeometryMethod.ToPositieGeometrieMethode()); + boxNumberItem.PositionSpecification.Should().Be(readdressedBoxNumber.SourceGeometrySpecification); + boxNumberItem.OsloPositionSpecification.Should().Be(readdressedBoxNumber.SourceGeometrySpecification.ToPositieSpecificatie()); + boxNumberItem.VersionTimestamp.Should().Be(addressHouseNumberWasReaddressed.Provenance.Timestamp); + + boxNumberItem.Namespace.Should().Be(Namespace); + boxNumberItem.PuriId.Should().Be($"{Namespace}/{readdressedBoxNumber.DestinationAddressPersistentLocalId}"); + boxNumberItem.VersionTimestamp.Should().Be(addressHouseNumberWasReaddressed.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasProposedBecauseOfReaddress() + { + var addressWasProposedBecauseOfReaddress = _fixture.Create(); + + var position = _fixture.Create(); + + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + await Sut + .Given(new Envelope(new Envelope(addressWasProposedBecauseOfReaddress, metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position, addressWasProposedBecauseOfReaddress.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should().Be(addressWasProposedBecauseOfReaddress.StreetNamePersistentLocalId); + expectedVersion.HouseNumber.Should().Be(addressWasProposedBecauseOfReaddress.HouseNumber); + expectedVersion.BoxNumber.Should().Be(addressWasProposedBecauseOfReaddress.BoxNumber); + expectedVersion.PostalCode.Should().Be(addressWasProposedBecauseOfReaddress.PostalCode); + expectedVersion.Status.Should().Be(AddressStatus.Proposed); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Proposed.Map()); + expectedVersion.OfficiallyAssigned.Should().BeTrue(); + expectedVersion.PositionMethod.Should().Be(addressWasProposedBecauseOfReaddress.GeometryMethod); + expectedVersion.OsloPositionMethod.Should().Be(addressWasProposedBecauseOfReaddress.GeometryMethod.ToPositieGeometrieMethode()); + expectedVersion.PositionSpecification.Should() + .Be(addressWasProposedBecauseOfReaddress.GeometrySpecification); + expectedVersion.OsloPositionSpecification.Should() + .Be(addressWasProposedBecauseOfReaddress.GeometrySpecification.ToPositieSpecificatie()); + expectedVersion.Removed.Should().BeFalse(); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressWasProposedBecauseOfReaddress.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressWasProposedBecauseOfReaddress.Provenance.Timestamp); + + var geometry = WKBReaderFactory.CreateForLegacy().Read(addressWasProposedBecauseOfReaddress.ExtendedWkbGeometry.ToByteArray()); + expectedVersion.Geometry.Should().BeEquivalentTo(geometry); + }); + } + + [Fact] + public async Task WhenAddressWasRejectedBecauseOfReaddress() + { + var addressWasRejectedBecauseOfReaddress = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressWasRejectedBecauseOfReaddress.AddressPersistentLocalId); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRejectedBecauseOfReaddress, metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressWasRejectedBecauseOfReaddress.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should().Be(addressWasRejectedBecauseOfReaddress.StreetNamePersistentLocalId); + expectedVersion.Status.Should().Be(AddressStatus.Rejected); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Rejected.Map()); + expectedVersion.OfficiallyAssigned.Should().BeTrue(); + expectedVersion.Removed.Should().BeFalse(); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressWasRejectedBecauseOfReaddress.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressWasRejectedBecauseOfReaddress.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRetiredBecauseOfReaddress() + { + var addressWasRetiredBecauseOfReaddress = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressWasRetiredBecauseOfReaddress.AddressPersistentLocalId); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRetiredBecauseOfReaddress, metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressWasRetiredBecauseOfReaddress.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should().Be(addressWasRetiredBecauseOfReaddress.StreetNamePersistentLocalId); + expectedVersion.Status.Should().Be(AddressStatus.Retired); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Retired.Map()); + expectedVersion.OfficiallyAssigned.Should().BeTrue(); + expectedVersion.Removed.Should().BeFalse(); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressWasRetiredBecauseOfReaddress.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressWasRetiredBecauseOfReaddress.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRemovedV2() + { + var addressWasRemovedV2 = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressWasRemovedV2.AddressPersistentLocalId); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRemovedV2, metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressWasRemovedV2.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should().Be(addressWasRemovedV2.StreetNamePersistentLocalId); + expectedVersion.Removed.Should().BeTrue(); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressWasRemovedV2.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressWasRemovedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRemovedBecauseStreetNameWasRemoved() + { + var addressWasRemovedBecauseStreetNameWasRemoved = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressWasRemovedBecauseStreetNameWasRemoved.AddressPersistentLocalId); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRemovedBecauseStreetNameWasRemoved, metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressWasRemovedBecauseStreetNameWasRemoved.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should() + .Be(addressWasRemovedBecauseStreetNameWasRemoved.StreetNamePersistentLocalId); + expectedVersion.Removed.Should().BeTrue(); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressWasRemovedBecauseStreetNameWasRemoved.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressWasRemovedBecauseStreetNameWasRemoved.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressWasRemovedBecauseHouseNumberWasRemoved() + { + var addressWasRemovedBecauseHouseNumberWasRemoved = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressWasRemovedBecauseHouseNumberWasRemoved.AddressPersistentLocalId); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasRemovedBecauseHouseNumberWasRemoved, + metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressWasRemovedBecauseHouseNumberWasRemoved.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should() + .Be(addressWasRemovedBecauseHouseNumberWasRemoved.StreetNamePersistentLocalId); + expectedVersion.Removed.Should().BeTrue(); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressWasRemovedBecauseHouseNumberWasRemoved.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressWasRemovedBecauseHouseNumberWasRemoved.Provenance.Timestamp); + }); + } + + + [Fact] + public async Task WhenAddressWasCorrectedFromRejectedToProposed() + { + var addressWasCorrectedFromRejectedToProposed = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasProposedV2 = _fixture.Create() + .WithAddressPersistentLocalId(addressWasCorrectedFromRejectedToProposed.AddressPersistentLocalId); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasProposedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasProposedV2, proposedMetadata)), + new Envelope(new Envelope(addressWasCorrectedFromRejectedToProposed, metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressWasCorrectedFromRejectedToProposed.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should() + .Be(addressWasCorrectedFromRejectedToProposed.StreetNamePersistentLocalId); + expectedVersion.Status.Should().Be(AddressStatus.Proposed); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Proposed.Map()); + expectedVersion.Removed.Should().BeFalse(); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressWasCorrectedFromRejectedToProposed.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressWasCorrectedFromRejectedToProposed.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressRegularizationWasCorrected() + { + var addressRegularizationWasCorrected = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasMigratedToStreetName = _fixture.Create() + .WithAddressPersistentLocalId(new AddressPersistentLocalId(addressRegularizationWasCorrected.AddressPersistentLocalId)) + .WithStatus(AddressStatus.Proposed) + .WithOfficiallyAssigned(true); + + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasMigratedToStreetName.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasMigratedToStreetName, proposedMetadata)), + new Envelope(new Envelope(addressRegularizationWasCorrected, metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressRegularizationWasCorrected.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should() + .Be(addressRegularizationWasCorrected.StreetNamePersistentLocalId); + expectedVersion.OfficiallyAssigned.Should().BeFalse(); + expectedVersion.Status.Should().Be(AddressStatus.Current); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Current.Map()); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressRegularizationWasCorrected.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressRegularizationWasCorrected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressDeregulationWasCorrected() + { + var addressDeregulationWasCorrected = _fixture.Create(); + + var position = _fixture.Create(); + + var addressWasMigratedToStreetName = _fixture.Create() + .WithAddressPersistentLocalId(new AddressPersistentLocalId(addressDeregulationWasCorrected.AddressPersistentLocalId)) + .WithStatus(AddressStatus.Proposed) + .WithOfficiallyAssigned(false); + var proposedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, addressWasMigratedToStreetName.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasMigratedToStreetName, proposedMetadata)), + new Envelope(new Envelope(addressDeregulationWasCorrected, metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FindAsync(position + 1, addressDeregulationWasCorrected.AddressPersistentLocalId); + expectedVersion.Should().NotBeNull(); + expectedVersion!.StreetNamePersistentLocalId.Should() + .Be(addressDeregulationWasCorrected.StreetNamePersistentLocalId); + expectedVersion.OfficiallyAssigned.Should().BeTrue(); + + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressDeregulationWasCorrected.AddressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressDeregulationWasCorrected.Provenance.Timestamp); + }); + } + + #region Legacy + + [Fact] + public async Task WhenAddressWasRegistered() + { + var addressWasRegistered = _fixture.Create(); + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + + var position = _fixture.Create(); + + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + await Sut + .Given(new Envelope(new Envelope(addressWasRegistered, metadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId); + expectedVersion.Should().NotBeNull(); + expectedVersion.PersistentLocalId.Should().Be(addressPersistentLocalId); + expectedVersion.StreetNameId.Should().Be(addressWasRegistered.StreetNameId); + expectedVersion.HouseNumber.Should().Be(addressWasRegistered.HouseNumber); + expectedVersion.Namespace.Should().Be(Namespace); + expectedVersion.PuriId.Should().Be($"{Namespace}/{addressPersistentLocalId}"); + expectedVersion.VersionTimestamp.Should().Be(addressWasRegistered.Provenance.Timestamp); + expectedVersion.CreatedOnTimestamp.Should().Be(addressWasRegistered.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenAddressBecameComplete() + { + var addressWasRegistered = _fixture.Create(); + var addressBecameComplete = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position } + }; + + var addressBecameCompleteMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, _fixture.Create() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(addressWasRegistered, metadata)), + new Envelope(new Envelope(addressBecameComplete, addressBecameCompleteMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + }); + } + + [Fact] + public async Task WhenAddressBecameCurrent() + { + var addressWasRegistered = _fixture.Create(); + var addressBecameCurrent = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressBecameCurrent, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.Status.Should().Be(AddressStatus.Current); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Current.Map()); + }); + } + + [Fact] + public async Task WhenAddressBecameIncomplete() + { + var addressWasRegistered = _fixture.Create(); + var addressBecameIncomplete = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressBecameIncomplete, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + }); + } + + [Fact] + public async Task WhenAddressBecameNotOfficiallyAssigned() + { + var addressWasRegistered = _fixture.Create(); + var addressBecameNotOfficiallyAssigned = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressBecameNotOfficiallyAssigned, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.OfficiallyAssigned.Should().BeFalse(); + }); + } + + [Fact] + public async Task WhenAddressHouseNumberWasChanged() + { + var addressWasRegistered = _fixture.Create(); + var addressHouseNumberWasChanged = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressHouseNumberWasChanged, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.HouseNumber.Should().Be(addressHouseNumberWasChanged.HouseNumber); + }); + } + + [Fact] + public async Task WhenAddressHouseNumberWasCorrected() + { + var addressWasRegistered = _fixture.Create(); + var addressHouseNumberWasCorrected = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressHouseNumberWasCorrected, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.HouseNumber.Should().Be(addressHouseNumberWasCorrected.HouseNumber); + }); + } + + [Fact] + public async Task WhenAddressOfficialAssignmentWasRemoved() + { + var addressWasRegistered = _fixture.Create(); + var addressOfficialAssignmentWasRemoved = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressOfficialAssignmentWasRemoved, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.OfficiallyAssigned.Should().BeNull(); + }); + } + + [Fact] + public async Task WhenAddressPersistentLocalIdWasAssigned() + { + var addressWasRegistered = _fixture.Create(); + var addressPersistentLocalIdWasAssigned = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressPersistentLocalIdWasAssigned, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.PersistentLocalId.Should().Be(addressPersistentLocalIdWasAssigned.PersistentLocalId); + }); + } + + [Fact] + public async Task WhenAddressPositionWasCorrected() + { + var extendedWkbGeometry = GeometryHelpers.CreateEwkbFrom( + GeometryHelpers.CreateFromWkt($"POINT ({_fixture.Create()} {_fixture.Create()})")); + var addressWasRegistered = _fixture.Create(); + var addressPositionWasCorrected = _fixture.Create() + .WithExtendedWkbGeometry(extendedWkbGeometry) + .WithAddressId(addressWasRegistered.AddressId); + + var position = _fixture.Create(); + var geometry = WKBReaderFactory.CreateForLegacy().Read(addressPositionWasCorrected.ExtendedWkbGeometry.ToByteArray()); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressPositionWasCorrected, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.PositionMethod.Should().Be(addressPositionWasCorrected.GeometryMethod.ToGeometryMethod()); + expectedVersion.OsloPositionMethod.Should().Be(addressPositionWasCorrected.GeometryMethod.ToPositieGeometrieMethode()); + expectedVersion.PositionSpecification.Should().Be(addressPositionWasCorrected.GeometrySpecification.ToGeometrySpecification()); + expectedVersion.OsloPositionSpecification.Should().Be(addressPositionWasCorrected.GeometrySpecification.ToPositieSpecificatie()); + expectedVersion.Geometry.Should().Be(geometry); + }); + } + + [Fact] + public async Task WhenAddressPositionWasRemoved() + { + var addressWasRegistered = _fixture.Create(); + var addressPositionWasRemoved = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressPositionWasRemoved, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.PositionMethod.Should().BeNull(); + expectedVersion.OsloPositionMethod.Should().BeNull(); + expectedVersion.PositionSpecification.Should().BeNull(); + expectedVersion.OsloPositionSpecification.Should().BeNull(); + }); + } + + [Fact] + public async Task WhenAddressPostalCodeWasChanged() + { + var addressWasRegistered = _fixture.Create(); + var addressPostalCodeWasChanged = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressPostalCodeWasChanged, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.PostalCode.Should().Be(addressPostalCodeWasChanged.PostalCode); + }); + } + + [Fact] + public async Task WhenAddressPostalCodeWasCorrected() + { + var addressWasRegistered = _fixture.Create(); + var addressPostalCodeWasCorrected = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressPostalCodeWasCorrected, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.PostalCode.Should().Be(addressPostalCodeWasCorrected.PostalCode); + }); + } + + [Fact] + public async Task WhenAddressPostalCodeWasRemoved() + { + var addressWasRegistered = _fixture.Create(); + var addressPostalCodeWasRemoved = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressPostalCodeWasRemoved, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.PostalCode.Should().BeNull(); + }); + } + + [Fact] + public async Task WheAddressStatusWasCorrectedToRemoved() + { + var addressWasRegistered = _fixture.Create(); + var addressStatusWasCorrectedToRemoved = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressStatusWasCorrectedToRemoved, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.Status.Should().BeNull(); + expectedVersion.OsloStatus.Should().BeNull(); + }); + } + + [Fact] + public async Task WhenAddressStatusWasRemoved() + { + var addressWasRegistered = _fixture.Create(); + var addressStatusWasRemoved = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressStatusWasRemoved, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.Status.Should().BeNull(); + expectedVersion.OsloStatus.Should().BeNull(); + }); + } + + [Fact] + public async Task WhenAddressStreetNameWasChanged() + { + var addressWasRegistered = _fixture.Create(); + var addressStreetNameWasChanged = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressStreetNameWasChanged, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + }); + } + + [Fact] + public async Task WhenAddressStreetNameWasCorrected() + { + var addressWasRegistered = _fixture.Create(); + var addressStreetNameWasCorrected = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressStreetNameWasCorrected, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + }); + } + + [Fact] + public async Task WhenAddressWasCorrectedToCurrent() + { + var addressWasRegistered = _fixture.Create(); + var addressWasCorrectedToCurrent = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressWasCorrectedToCurrent, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.Status.Should().Be(AddressStatus.Current); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Current.Map()); + }); + } + + [Fact] + public async Task WhenAddressWasCorrectedToNotOfficiallyAssigned() + { + var addressWasRegistered = _fixture.Create(); + var addressWasCorrectedToNotOfficiallyAssigned = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressWasCorrectedToNotOfficiallyAssigned, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.OfficiallyAssigned.Should().BeFalse(); + }); + } + + [Fact] + public async Task WhenAddressWasCorrectedToOfficiallyAssigned() + { + var addressWasRegistered = _fixture.Create(); + var addressWasCorrectedToOfficiallyAssigned = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressWasCorrectedToOfficiallyAssigned, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.OfficiallyAssigned.Should().BeTrue(); + }); + } + + [Fact] + public async Task WhenAddressWasCorrectedToProposed() + { + var addressWasRegistered = _fixture.Create(); + var addressWasCorrectedToProposed = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressWasCorrectedToProposed, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.Status.Should().Be(AddressStatus.Proposed); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Proposed.Map()); + }); + } + + [Fact] + public async Task WhenAddressWasCorrectedToRetired() + { + var addressWasRegistered = _fixture.Create(); + var addressWasCorrectedToRetired = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressWasCorrectedToRetired, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.Status.Should().Be(AddressStatus.Retired); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Retired.Map()); + }); + } + + [Fact] + public async Task WhenAddressWasOfficiallyAssigned() + { + var addressWasRegistered = _fixture.Create(); + var addressWasOfficiallyAssigned = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressWasOfficiallyAssigned, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.OfficiallyAssigned.Should().BeTrue(); + }); + } + + + [Fact] + public async Task WhenAddressWasPositioned() + { + var extendedWkbGeometry = GeometryHelpers.CreateEwkbFrom( + GeometryHelpers.CreateFromWkt($"POINT ({_fixture.Create()} {_fixture.Create()})")); + var addressWasRegistered = _fixture.Create(); + var addressPositionWasCorrected = _fixture.Create() + .WithExtendedWkbGeometry(extendedWkbGeometry) + .WithAddressId(addressWasRegistered.AddressId); + + var position = _fixture.Create(); + var geometry = WKBReaderFactory.CreateForLegacy().Read(addressPositionWasCorrected.ExtendedWkbGeometry.ToByteArray()); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressPositionWasCorrected, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.PositionMethod.Should().Be(addressPositionWasCorrected.GeometryMethod.ToGeometryMethod()); + expectedVersion.OsloPositionMethod.Should().Be(addressPositionWasCorrected.GeometryMethod.ToPositieGeometrieMethode()); + expectedVersion.PositionSpecification.Should().Be(addressPositionWasCorrected.GeometrySpecification.ToGeometrySpecification()); + expectedVersion.OsloPositionSpecification.Should().Be(addressPositionWasCorrected.GeometrySpecification.ToPositieSpecificatie()); + expectedVersion.Geometry.Should().Be(geometry); + }); + } + + [Fact] + public async Task WhenAddressWasProposed() + { + var addressWasRegistered = _fixture.Create(); + var addressWasProposed = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressWasProposed, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.Status.Should().Be(AddressStatus.Proposed); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Proposed.Map()); + }); + } + + [Fact] + public async Task WhenAddressWasRemoved() + { + var addressWasRegistered = _fixture.Create(); + var addressWasRemoved = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressWasRemoved, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.Removed.Should().BeTrue(); + }); + } + + [Fact] + public async Task WhenAddressWasRetired() + { + var addressWasRegistered = _fixture.Create(); + var addressWasRetired = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressWasRetired, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.Status.Should().Be(AddressStatus.Retired); + expectedVersion.OsloStatus.Should().Be(AddressStatus.Retired.Map()); + }); + } + + [Fact] + public async Task WhenAddressBoxNumberWasChanged() + { + var addressWasRegistered = _fixture.Create(); + var addressBoxNumberWasChanged = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressBoxNumberWasChanged, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.BoxNumber.Should().Be(addressBoxNumberWasChanged.BoxNumber); + }); + } + + [Fact] + public async Task WhenAddressBoxNumberWasCorrected() + { + var addressWasRegistered = _fixture.Create(); + var addressBoxNumberWasCorrected = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressBoxNumberWasCorrected, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.BoxNumber.Should().Be(addressBoxNumberWasCorrected.BoxNumber); + }); + } + + [Fact] + public async Task WhenAddressBoxNumberWasRemoved() + { + var addressWasRegistered = _fixture.Create(); + var addressBoxNumberWasRemoved = _fixture.Create(); + + var position = _fixture.Create(); + + var addressPersistentLocalId = _fixture.Create(); + _eventsRepositoryMock.Setup(x => x.GetAddressPersistentLocalId(addressWasRegistered.AddressId)) + .ReturnsAsync(addressPersistentLocalId); + 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(addressWasRegistered, firstEventMetadata)), + new Envelope(new Envelope(addressBoxNumberWasRemoved, secondEventMetadata))) + .Then(async ct => + { + var expectedVersion = + await ct.AddressVersions.FirstAsync(x => x.AddressId == addressWasRegistered.AddressId & x.Position == position +1); + expectedVersion.Should().NotBeNull(); + expectedVersion.Position.Should().Be(position + 1); + expectedVersion.BoxNumber.Should().BeNull(); + }); + } + #endregion + + protected override AddressVersionProjections CreateProjection() + => new AddressVersionProjections( + new OptionsWrapper(new IntegrationOptions { Namespace = Namespace }), _eventsRepositoryMock.Object); + } +} diff --git a/test/AddressRegistry.Tests/Integration/IntegrationTest.cs b/test/AddressRegistry.Tests/Integration/IntegrationTest.cs new file mode 100644 index 000000000..3f1eff73c --- /dev/null +++ b/test/AddressRegistry.Tests/Integration/IntegrationTest.cs @@ -0,0 +1,30 @@ +namespace AddressRegistry.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(); + } +}