From a763ddf5890780c47d1d4f8f6f5f74b9f4ece99a Mon Sep 17 00:00:00 2001 From: jvandaal Date: Tue, 19 Dec 2023 17:06:16 +0100 Subject: [PATCH 1/2] chore: update projectionhandling --- paket.dependencies | 25 +++-- paket.lock | 97 ++++++++++++++----- .../ConsumerAddressContext.cs | 8 +- .../paket.references | 2 +- .../ConsumerParcelContext.cs | 2 +- .../paket.references | 2 +- .../Projections/MigratorProjectionContext.cs | 3 +- .../ProducerContextMigrationFactory.cs | 6 +- .../ProducerModule.cs | 4 +- .../paket.references | 1 + .../Infrastructure/Modules/ProducerModule.cs | 2 +- .../ProducerContextMigrationFactory.cs | 6 +- .../paket.references | 1 + .../BackOfficeProjectionsContext.cs | 3 +- .../ServiceCollectionExtensions.cs | 2 +- .../paket.references | 2 +- .../ExtractContextMigrationFactory.cs | 4 +- .../ExtractModule.cs | 8 +- .../paket.references | 2 +- .../BuildingUnitLastChangedListModule.cs | 2 +- .../DataMigrationsContext.cs | 3 +- .../BuildingSyndication.cs | 2 +- .../BuildingUnitSyndication.cs | 8 +- .../BuildingUnitSyndicationV2.cs | 8 +- .../LegacyContextMigrationFactory.cs | 4 +- .../LegacyModule.cs | 4 +- .../paket.references | 2 +- .../MigrationHelper.cs | 3 +- .../SyndicationContext.cs | 2 +- .../SyndicationModule.cs | 4 +- .../paket.references | 2 +- .../WfsContextMigrationFactory.cs | 4 +- .../WfsModule.cs | 8 +- .../paket.references | 2 +- .../WmsContextMigrationFactory.cs | 4 +- .../WmsModule.cs | 8 +- .../paket.references | 2 +- 37 files changed, 157 insertions(+), 95 deletions(-) diff --git a/paket.dependencies b/paket.dependencies index 106557032..b3397ffbf 100644 --- a/paket.dependencies +++ b/paket.dependencies @@ -7,6 +7,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 Dapper 2.0.123 nuget AsyncEnumerator 4.0.2 @@ -20,8 +21,12 @@ nuget MediatR.Extensions.Microsoft.DependencyInjection 10.0.1 nuget Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite 6.0.3 nuget NetTopologySuite 2.4.0 +nuget NodaTime 3.1.6 nuget Microsoft.EntityFrameworkCore.Design 6.0.3 +nuget Npgsql.EntityFrameworkCore.PostgreSQL 6.0.3 +nuget Npgsql.EntityFrameworkCore.PostgreSQL.Design 2.0.0-preview1 + nuget AWSSDK.S3 3.7.103.26 nuget AWSSDK.Extensions.NETCore.Setup 3.7.5 nuget AWSSDK.ECS 3.7.108 @@ -58,15 +63,17 @@ nuget Be.Vlaanderen.Basisregisters.MessageHandling.Kafka.Producer 4.8.3 nuget Be.Vlaanderen.Basisregisters.MessageHandling.Kafka.Consumer 4.8.3 nuget Be.Vlaanderen.Basisregisters.MessageHandling.Kafka.Consumer.SqlServer 4.8.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 12.0.1 +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 e02a38093..c5d261621 100644 --- a/paket.lock +++ b/paket.lock @@ -9,6 +9,9 @@ NUGET Amazon.Lambda.SQSEvents (2.1) Amazon.Lambda.TestUtilities (2.0) Amazon.Lambda.Core (>= 2.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) @@ -369,25 +372,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.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 (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 (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) @@ -396,30 +412,44 @@ 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 (12.0.1) + 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.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) - Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner (>= 11.0.1) - 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) + System.Configuration.ConfigurationManager (>= 6.0) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) System.Threading.Tasks.Dataflow (>= 6.0) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Be.Vlaanderen.Basisregisters.Shaperon (9.0.1) Be.Vlaanderen.Basisregisters.Shaperon.Geometries (9.0.1) @@ -729,7 +759,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) @@ -744,9 +774,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) @@ -994,7 +1027,7 @@ NUGET Microsoft.Build.Utilities.Core (>= 16.10) Namotion.Reflection (2.0.10) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Microsoft.CSharp (>= 4.3) - restriction: || (&& (== net472) (< net40)) (== net6.0) - NETStandard.Library (2.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + NETStandard.Library (2.0.3) Microsoft.NETCore.Platforms (>= 1.1) NetTopologySuite (2.4) System.Memory (>= 4.5.3) @@ -1019,11 +1052,27 @@ NUGET Newtonsoft.Json (>= 9.0.1) NJsonSchema (>= 10.6.10) NJsonSchema.CodeGeneration (>= 10.6.10) - NodaTime (3.1.6) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + NodaTime (3.1.6) System.Runtime.CompilerServices.Unsafe (>= 4.7.1) 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) + System.Runtime.CompilerServices.Unsafe (>= 6.0) + Npgsql.EntityFrameworkCore.PostgreSQL (6.0.3) + Microsoft.EntityFrameworkCore (>= 6.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Microsoft.EntityFrameworkCore.Abstractions (>= 6.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Microsoft.EntityFrameworkCore.Relational (>= 6.0.1) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Npgsql (>= 6.0.3) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) + Npgsql.EntityFrameworkCore.PostgreSQL.Design (2.0.0-preview1) + Microsoft.EntityFrameworkCore (>= 2.0.0-preview1-final) + Microsoft.EntityFrameworkCore.Relational (>= 2.0.0-preview1-final) + Microsoft.EntityFrameworkCore.Relational.Design (>= 2.0.0-preview1-final) + Microsoft.Extensions.DependencyInjection (>= 2.0.0-preview1-final) + Microsoft.Extensions.DependencyInjection.Abstractions (>= 2.0.0-preview1-final) + NETStandard.Library (>= 1.6.1) - restriction: || (&& (== net472) (< net46)) (== net6.0) + Npgsql (>= 3.2.2) + Npgsql.EntityFrameworkCore.PostgreSQL (>= 2.0.0-preview1) NSwag.CodeGeneration (13.15.10) - restriction: || (&& (== net472) (>= net6.0)) (== net6.0) Newtonsoft.Json (>= 9.0.1) NJsonSchema (>= 10.6.10) diff --git a/src/BuildingRegistry.Consumer.Address/ConsumerAddressContext.cs b/src/BuildingRegistry.Consumer.Address/ConsumerAddressContext.cs index 08ef70b46..8ed92a1ee 100644 --- a/src/BuildingRegistry.Consumer.Address/ConsumerAddressContext.cs +++ b/src/BuildingRegistry.Consumer.Address/ConsumerAddressContext.cs @@ -4,15 +4,15 @@ namespace BuildingRegistry.Consumer.Address using System.IO; using System.Linq; using System.Reflection; - using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; - using Building.Datastructures; + using Be.Vlaanderen.Basisregisters.EntityFrameworkCore.EntityTypeConfiguration; + using Be.Vlaanderen.Basisregisters.MessageHandling.Kafka.Consumer.SqlServer; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using Building; + using Building.Datastructures; using BuildingRegistry.Infrastructure; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; using Microsoft.Extensions.Configuration; - using Be.Vlaanderen.Basisregisters.EntityFrameworkCore.EntityTypeConfiguration; - using Be.Vlaanderen.Basisregisters.MessageHandling.Kafka.Consumer.SqlServer; public class ConsumerAddressContext : SqlServerConsumerDbContext, IAddresses { diff --git a/src/BuildingRegistry.Consumer.Address/paket.references b/src/BuildingRegistry.Consumer.Address/paket.references index ca4f79f77..35880c8fe 100644 --- a/src/BuildingRegistry.Consumer.Address/paket.references +++ b/src/BuildingRegistry.Consumer.Address/paket.references @@ -10,7 +10,7 @@ Be.Vlaanderen.Basisregisters.MessageHandling.Kafka.Producer Be.Vlaanderen.Basisregisters.MessageHandling.Kafka.Consumer.SqlServer Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector -Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner +Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore.Autofac Serilog diff --git a/src/BuildingRegistry.Consumer.Read.Parcel/ConsumerParcelContext.cs b/src/BuildingRegistry.Consumer.Read.Parcel/ConsumerParcelContext.cs index 291457c07..98a682bab 100644 --- a/src/BuildingRegistry.Consumer.Read.Parcel/ConsumerParcelContext.cs +++ b/src/BuildingRegistry.Consumer.Read.Parcel/ConsumerParcelContext.cs @@ -5,7 +5,7 @@ namespace BuildingRegistry.Consumer.Read.Parcel using System.Threading; using System.Threading.Tasks; using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; - using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using BuildingRegistry.Infrastructure; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; diff --git a/src/BuildingRegistry.Consumer.Read.Parcel/paket.references b/src/BuildingRegistry.Consumer.Read.Parcel/paket.references index d606f0a62..399ef6812 100644 --- a/src/BuildingRegistry.Consumer.Read.Parcel/paket.references +++ b/src/BuildingRegistry.Consumer.Read.Parcel/paket.references @@ -9,7 +9,7 @@ Be.Vlaanderen.Basisregisters.GrAr.Contracts Be.Vlaanderen.Basisregisters.MessageHandling.Kafka.Consumer Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector -Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner +Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer Serilog Serilog.Settings.Configuration diff --git a/src/BuildingRegistry.Migrator.Building/Projections/MigratorProjectionContext.cs b/src/BuildingRegistry.Migrator.Building/Projections/MigratorProjectionContext.cs index 385cb3bdd..73a4ee541 100644 --- a/src/BuildingRegistry.Migrator.Building/Projections/MigratorProjectionContext.cs +++ b/src/BuildingRegistry.Migrator.Building/Projections/MigratorProjectionContext.cs @@ -1,6 +1,7 @@ namespace BuildingRegistry.Migrator.Building.Projections { using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer; using BuildingRegistry.Infrastructure; using Microsoft.EntityFrameworkCore; @@ -17,7 +18,7 @@ public MigratorProjectionContext(DbContextOptions opt public override string ProjectionStateSchema => Schema.MigrateBuilding; } - public class MigratorProjectionContextFactory : RunnerDbContextMigrationFactory + public class MigratorProjectionContextFactory : SqlServerRunnerDbContextMigrationFactory { public MigratorProjectionContextFactory() : this("Events") diff --git a/src/BuildingRegistry.Producer.Snapshot.Oslo/ProducerContextMigrationFactory.cs b/src/BuildingRegistry.Producer.Snapshot.Oslo/ProducerContextMigrationFactory.cs index 7402c7cf6..eddcdf717 100644 --- a/src/BuildingRegistry.Producer.Snapshot.Oslo/ProducerContextMigrationFactory.cs +++ b/src/BuildingRegistry.Producer.Snapshot.Oslo/ProducerContextMigrationFactory.cs @@ -1,10 +1,10 @@ namespace BuildingRegistry.Producer.Snapshot.Oslo { - using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; - using Microsoft.EntityFrameworkCore; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer; using BuildingRegistry.Infrastructure; + using Microsoft.EntityFrameworkCore; - public class ProducerContextMigrationFactory : RunnerDbContextMigrationFactory + public class ProducerContextMigrationFactory : SqlServerRunnerDbContextMigrationFactory { public ProducerContextMigrationFactory() : base("ProducerSnapshotProjectionsAdmin", HistoryConfiguration) { } diff --git a/src/BuildingRegistry.Producer.Snapshot.Oslo/ProducerModule.cs b/src/BuildingRegistry.Producer.Snapshot.Oslo/ProducerModule.cs index 1fb49f6a7..799e2019a 100644 --- a/src/BuildingRegistry.Producer.Snapshot.Oslo/ProducerModule.cs +++ b/src/BuildingRegistry.Producer.Snapshot.Oslo/ProducerModule.cs @@ -3,13 +3,13 @@ namespace BuildingRegistry.Producer.Snapshot.Oslo using System; 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 BuildingRegistry.Infrastructure; using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; - using BuildingRegistry.Infrastructure; public class ProducerModule : Module { diff --git a/src/BuildingRegistry.Producer.Snapshot.Oslo/paket.references b/src/BuildingRegistry.Producer.Snapshot.Oslo/paket.references index c33433df4..7efba64d4 100644 --- a/src/BuildingRegistry.Producer.Snapshot.Oslo/paket.references +++ b/src/BuildingRegistry.Producer.Snapshot.Oslo/paket.references @@ -4,6 +4,7 @@ Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql Be.Vlaanderen.Basisregisters.GrAr.Legacy Be.Vlaanderen.Basisregisters.GrAr.Oslo Be.Vlaanderen.BasisRegisters.MessageHandling.Kafka.Producer +Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore.Autofac Be.Vlaanderen.Basisregisters.Projector diff --git a/src/BuildingRegistry.Producer/Infrastructure/Modules/ProducerModule.cs b/src/BuildingRegistry.Producer/Infrastructure/Modules/ProducerModule.cs index f33919c37..d60ff68cc 100644 --- a/src/BuildingRegistry.Producer/Infrastructure/Modules/ProducerModule.cs +++ b/src/BuildingRegistry.Producer/Infrastructure/Modules/ProducerModule.cs @@ -11,7 +11,7 @@ namespace BuildingRegistry.Producer.Infrastructure.Modules using Be.Vlaanderen.Basisregisters.EventHandling.Autofac; using Be.Vlaanderen.Basisregisters.MessageHandling.Kafka; using Be.Vlaanderen.Basisregisters.MessageHandling.Kafka.Producer; - using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore.Autofac; using Be.Vlaanderen.Basisregisters.Projector; using Be.Vlaanderen.Basisregisters.Projector.ConnectedProjections; diff --git a/src/BuildingRegistry.Producer/ProducerContextMigrationFactory.cs b/src/BuildingRegistry.Producer/ProducerContextMigrationFactory.cs index 61c78b148..cb8876095 100644 --- a/src/BuildingRegistry.Producer/ProducerContextMigrationFactory.cs +++ b/src/BuildingRegistry.Producer/ProducerContextMigrationFactory.cs @@ -1,10 +1,10 @@ namespace BuildingRegistry.Producer { - using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; - using Microsoft.EntityFrameworkCore; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer; using BuildingRegistry.Infrastructure; + using Microsoft.EntityFrameworkCore; - public class ProducerContextMigrationFactory : RunnerDbContextMigrationFactory + public class ProducerContextMigrationFactory : SqlServerRunnerDbContextMigrationFactory { public ProducerContextMigrationFactory() : base("ProducerProjectionsAdmin", HistoryConfiguration) { } diff --git a/src/BuildingRegistry.Producer/paket.references b/src/BuildingRegistry.Producer/paket.references index 997d7ccbf..cf5acca17 100644 --- a/src/BuildingRegistry.Producer/paket.references +++ b/src/BuildingRegistry.Producer/paket.references @@ -3,6 +3,7 @@ Be.Vlaanderen.Basisregisters.EventHandling.Autofac Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql Be.Vlaanderen.Basisregisters.GrAr.Contracts Be.Vlaanderen.BasisRegisters.MessageHandling.Kafka.Producer +Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore.Autofac Be.Vlaanderen.Basisregisters.Projector diff --git a/src/BuildingRegistry.Projections.BackOffice/BackOfficeProjectionsContext.cs b/src/BuildingRegistry.Projections.BackOffice/BackOfficeProjectionsContext.cs index 757a406fa..926031f82 100644 --- a/src/BuildingRegistry.Projections.BackOffice/BackOfficeProjectionsContext.cs +++ b/src/BuildingRegistry.Projections.BackOffice/BackOfficeProjectionsContext.cs @@ -1,6 +1,7 @@ namespace BuildingRegistry.Projections.BackOffice { using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer; using BuildingRegistry.Infrastructure; using Microsoft.EntityFrameworkCore; @@ -17,7 +18,7 @@ public BackOfficeProjectionsContext(DbContextOptions + public sealed class BackOfficeProjectionsContextMigrationFactory : SqlServerRunnerDbContextMigrationFactory { public BackOfficeProjectionsContextMigrationFactory() : base("BackOfficeProjectionsAdmin", HistoryConfiguration) { } diff --git a/src/BuildingRegistry.Projections.BackOffice/Infrastructure/ServiceCollectionExtensions.cs b/src/BuildingRegistry.Projections.BackOffice/Infrastructure/ServiceCollectionExtensions.cs index de76f20b8..d14c34542 100644 --- a/src/BuildingRegistry.Projections.BackOffice/Infrastructure/ServiceCollectionExtensions.cs +++ b/src/BuildingRegistry.Projections.BackOffice/Infrastructure/ServiceCollectionExtensions.cs @@ -2,7 +2,7 @@ { using System; using Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql.EntityFrameworkCore; - using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using BuildingRegistry.Infrastructure; using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; diff --git a/src/BuildingRegistry.Projections.BackOffice/paket.references b/src/BuildingRegistry.Projections.BackOffice/paket.references index 8414e5c47..0611525a3 100644 --- a/src/BuildingRegistry.Projections.BackOffice/paket.references +++ b/src/BuildingRegistry.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/BuildingRegistry.Projections.Extract/ExtractContextMigrationFactory.cs b/src/BuildingRegistry.Projections.Extract/ExtractContextMigrationFactory.cs index 78ef8e667..4dd55091c 100644 --- a/src/BuildingRegistry.Projections.Extract/ExtractContextMigrationFactory.cs +++ b/src/BuildingRegistry.Projections.Extract/ExtractContextMigrationFactory.cs @@ -1,10 +1,10 @@ namespace BuildingRegistry.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/BuildingRegistry.Projections.Extract/ExtractModule.cs b/src/BuildingRegistry.Projections.Extract/ExtractModule.cs index 2332dd1ec..105f25276 100755 --- a/src/BuildingRegistry.Projections.Extract/ExtractModule.cs +++ b/src/BuildingRegistry.Projections.Extract/ExtractModule.cs @@ -1,11 +1,11 @@ namespace BuildingRegistry.Projections.Extract { using System; - using Microsoft.Data.SqlClient; - using Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql.EntityFrameworkCore; using Autofac; - using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; + using Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql.EntityFrameworkCore; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using Infrastructure; + using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -54,7 +54,7 @@ private static void RunOnSqlServer( { if (enableRetry) sqlServerOptions.EnableRetryOnFailure(); - + sqlServerOptions.MigrationsHistoryTable(MigrationTables.Extract, Schema.Extract); }) .UseExtendedSqlServerMigrations()); diff --git a/src/BuildingRegistry.Projections.Extract/paket.references b/src/BuildingRegistry.Projections.Extract/paket.references index 67b389eaf..7e6109e1d 100644 --- a/src/BuildingRegistry.Projections.Extract/paket.references +++ b/src/BuildingRegistry.Projections.Extract/paket.references @@ -1,6 +1,6 @@ Be.Vlaanderen.Basisregisters.EventHandling.Autofac Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql -Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner +Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore.Autofac Be.Vlaanderen.Basisregisters.Shaperon Be.Vlaanderen.Basisregisters.Shaperon.Geometries diff --git a/src/BuildingRegistry.Projections.LastChangedList/BuildingUnitLastChangedListModule.cs b/src/BuildingRegistry.Projections.LastChangedList/BuildingUnitLastChangedListModule.cs index 20a271dd7..e58c00504 100644 --- a/src/BuildingRegistry.Projections.LastChangedList/BuildingUnitLastChangedListModule.cs +++ b/src/BuildingRegistry.Projections.LastChangedList/BuildingUnitLastChangedListModule.cs @@ -3,7 +3,7 @@ namespace BuildingRegistry.Projections.LastChangedList using System; 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/BuildingRegistry.Projections.LastChangedList/DataMigrationsContext.cs b/src/BuildingRegistry.Projections.LastChangedList/DataMigrationsContext.cs index b2f46284b..57e7bd226 100644 --- a/src/BuildingRegistry.Projections.LastChangedList/DataMigrationsContext.cs +++ b/src/BuildingRegistry.Projections.LastChangedList/DataMigrationsContext.cs @@ -5,6 +5,7 @@ namespace BuildingRegistry.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/BuildingRegistry.Projections.Legacy/BuildingSyndication/BuildingSyndication.cs b/src/BuildingRegistry.Projections.Legacy/BuildingSyndication/BuildingSyndication.cs index 9052ecdaa..ff4c81203 100755 --- a/src/BuildingRegistry.Projections.Legacy/BuildingSyndication/BuildingSyndication.cs +++ b/src/BuildingRegistry.Projections.Legacy/BuildingSyndication/BuildingSyndication.cs @@ -4,7 +4,7 @@ namespace BuildingRegistry.Projections.Legacy.BuildingSyndication using System.Collections.ObjectModel; using System.Linq; using Be.Vlaanderen.Basisregisters.GrAr.Provenance; - using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using BuildingRegistry.Legacy; using Infrastructure; using Microsoft.EntityFrameworkCore; diff --git a/src/BuildingRegistry.Projections.Legacy/BuildingSyndication/BuildingUnitSyndication.cs b/src/BuildingRegistry.Projections.Legacy/BuildingSyndication/BuildingUnitSyndication.cs index 1171ea2d7..2ecc8348e 100755 --- a/src/BuildingRegistry.Projections.Legacy/BuildingSyndication/BuildingUnitSyndication.cs +++ b/src/BuildingRegistry.Projections.Legacy/BuildingSyndication/BuildingUnitSyndication.cs @@ -1,13 +1,13 @@ namespace BuildingRegistry.Projections.Legacy.BuildingSyndication { - using Infrastructure; - using Microsoft.EntityFrameworkCore; - using Microsoft.EntityFrameworkCore.Metadata.Builders; using System; using System.Collections.ObjectModel; using System.Linq; - using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using BuildingRegistry.Legacy; + using Infrastructure; + using Microsoft.EntityFrameworkCore; + using Microsoft.EntityFrameworkCore.Metadata.Builders; using NodaTime; public class BuildingUnitSyndicationItem diff --git a/src/BuildingRegistry.Projections.Legacy/BuildingSyndication/BuildingUnitSyndicationV2.cs b/src/BuildingRegistry.Projections.Legacy/BuildingSyndication/BuildingUnitSyndicationV2.cs index a13177965..4af00318b 100644 --- a/src/BuildingRegistry.Projections.Legacy/BuildingSyndication/BuildingUnitSyndicationV2.cs +++ b/src/BuildingRegistry.Projections.Legacy/BuildingSyndication/BuildingUnitSyndicationV2.cs @@ -1,13 +1,13 @@ namespace BuildingRegistry.Projections.Legacy.BuildingSyndication { - using Infrastructure; - using Microsoft.EntityFrameworkCore; - using Microsoft.EntityFrameworkCore.Metadata.Builders; using System; using System.Collections.ObjectModel; using System.Linq; - using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using Building; + using Infrastructure; + using Microsoft.EntityFrameworkCore; + using Microsoft.EntityFrameworkCore.Metadata.Builders; using NodaTime; public class BuildingUnitSyndicationItemV2 diff --git a/src/BuildingRegistry.Projections.Legacy/LegacyContextMigrationFactory.cs b/src/BuildingRegistry.Projections.Legacy/LegacyContextMigrationFactory.cs index be13bd275..8dc1801ec 100644 --- a/src/BuildingRegistry.Projections.Legacy/LegacyContextMigrationFactory.cs +++ b/src/BuildingRegistry.Projections.Legacy/LegacyContextMigrationFactory.cs @@ -1,11 +1,11 @@ namespace BuildingRegistry.Projections.Legacy { - using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer; using Infrastructure; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; - public class LegacyContextMigrationFactory : RunnerDbContextMigrationFactory + public class LegacyContextMigrationFactory : SqlServerRunnerDbContextMigrationFactory { public LegacyContextMigrationFactory() : base("LegacyProjectionsAdmin", HistoryConfiguration) diff --git a/src/BuildingRegistry.Projections.Legacy/LegacyModule.cs b/src/BuildingRegistry.Projections.Legacy/LegacyModule.cs index 824c69075..98faac488 100755 --- a/src/BuildingRegistry.Projections.Legacy/LegacyModule.cs +++ b/src/BuildingRegistry.Projections.Legacy/LegacyModule.cs @@ -1,11 +1,11 @@ namespace BuildingRegistry.Projections.Legacy { using System; - using Microsoft.Data.SqlClient; using Autofac; using Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql.EntityFrameworkCore; - using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using Infrastructure; + using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; diff --git a/src/BuildingRegistry.Projections.Legacy/paket.references b/src/BuildingRegistry.Projections.Legacy/paket.references index 71d865428..fa0e03abf 100644 --- a/src/BuildingRegistry.Projections.Legacy/paket.references +++ b/src/BuildingRegistry.Projections.Legacy/paket.references @@ -1,6 +1,6 @@ Be.Vlaanderen.Basisregisters.EventHandling.Autofac Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql -Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner +Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore.Autofac Be.Vlaanderen.Basisregisters.GrAr.Common diff --git a/src/BuildingRegistry.Projections.Syndication/MigrationHelper.cs b/src/BuildingRegistry.Projections.Syndication/MigrationHelper.cs index b2dfc4805..f28a617e5 100755 --- a/src/BuildingRegistry.Projections.Syndication/MigrationHelper.cs +++ b/src/BuildingRegistry.Projections.Syndication/MigrationHelper.cs @@ -1,11 +1,12 @@ namespace BuildingRegistry.Projections.Syndication { using System; - using Microsoft.Data.SqlClient; 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.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Polly; diff --git a/src/BuildingRegistry.Projections.Syndication/SyndicationContext.cs b/src/BuildingRegistry.Projections.Syndication/SyndicationContext.cs index 7b64c71c6..ac3131a70 100755 --- a/src/BuildingRegistry.Projections.Syndication/SyndicationContext.cs +++ b/src/BuildingRegistry.Projections.Syndication/SyndicationContext.cs @@ -4,7 +4,7 @@ namespace BuildingRegistry.Projections.Syndication using System.IO; using Address; 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 Microsoft.EntityFrameworkCore.Design; diff --git a/src/BuildingRegistry.Projections.Syndication/SyndicationModule.cs b/src/BuildingRegistry.Projections.Syndication/SyndicationModule.cs index affaa3877..e0b0ef772 100755 --- a/src/BuildingRegistry.Projections.Syndication/SyndicationModule.cs +++ b/src/BuildingRegistry.Projections.Syndication/SyndicationModule.cs @@ -1,14 +1,14 @@ namespace BuildingRegistry.Projections.Syndication { using System; - using Microsoft.Data.SqlClient; using System.Net.Http; using Autofac; 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.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; diff --git a/src/BuildingRegistry.Projections.Syndication/paket.references b/src/BuildingRegistry.Projections.Syndication/paket.references index e5a637461..26d82ec18 100644 --- a/src/BuildingRegistry.Projections.Syndication/paket.references +++ b/src/BuildingRegistry.Projections.Syndication/paket.references @@ -22,7 +22,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/BuildingRegistry.Projections.Wfs/WfsContextMigrationFactory.cs b/src/BuildingRegistry.Projections.Wfs/WfsContextMigrationFactory.cs index 05bcafc69..531ab4493 100644 --- a/src/BuildingRegistry.Projections.Wfs/WfsContextMigrationFactory.cs +++ b/src/BuildingRegistry.Projections.Wfs/WfsContextMigrationFactory.cs @@ -1,11 +1,11 @@ namespace BuildingRegistry.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/BuildingRegistry.Projections.Wfs/WfsModule.cs b/src/BuildingRegistry.Projections.Wfs/WfsModule.cs index 30503a033..d09a41af8 100644 --- a/src/BuildingRegistry.Projections.Wfs/WfsModule.cs +++ b/src/BuildingRegistry.Projections.Wfs/WfsModule.cs @@ -1,15 +1,15 @@ namespace BuildingRegistry.Projections.Wfs { + using System; using Autofac; + using Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql.EntityFrameworkCore; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using Infrastructure; + using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; - using System; - using Microsoft.Data.SqlClient; - using Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql.EntityFrameworkCore; - using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; public class WfsModule : Module { diff --git a/src/BuildingRegistry.Projections.Wfs/paket.references b/src/BuildingRegistry.Projections.Wfs/paket.references index 3eae31fb0..84dc5aad7 100644 --- a/src/BuildingRegistry.Projections.Wfs/paket.references +++ b/src/BuildingRegistry.Projections.Wfs/paket.references @@ -1,6 +1,6 @@ Be.Vlaanderen.Basisregisters.EventHandling.Autofac Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql -Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner +Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore.Autofac Be.Vlaanderen.Basisregisters.GrAr.Common diff --git a/src/BuildingRegistry.Projections.Wms/WmsContextMigrationFactory.cs b/src/BuildingRegistry.Projections.Wms/WmsContextMigrationFactory.cs index 0f7cbee11..29104f321 100644 --- a/src/BuildingRegistry.Projections.Wms/WmsContextMigrationFactory.cs +++ b/src/BuildingRegistry.Projections.Wms/WmsContextMigrationFactory.cs @@ -1,10 +1,10 @@ namespace BuildingRegistry.Projections.Wms { - using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer; using Infrastructure; using Microsoft.EntityFrameworkCore; - public class WmsContextMigrationFactory : RunnerDbContextMigrationFactory + public class WmsContextMigrationFactory : SqlServerRunnerDbContextMigrationFactory { public WmsContextMigrationFactory() : base("WmsProjectionsAdmin", HistoryConfiguration) diff --git a/src/BuildingRegistry.Projections.Wms/WmsModule.cs b/src/BuildingRegistry.Projections.Wms/WmsModule.cs index 1f3f8f609..5fc2f0992 100755 --- a/src/BuildingRegistry.Projections.Wms/WmsModule.cs +++ b/src/BuildingRegistry.Projections.Wms/WmsModule.cs @@ -1,15 +1,15 @@ namespace BuildingRegistry.Projections.Wms { + using System; using Autofac; + using Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql.EntityFrameworkCore; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer.MigrationExtensions; using Infrastructure; + using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; - using System; - using Microsoft.Data.SqlClient; - using Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql.EntityFrameworkCore; - using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.MigrationExtensions; public class WmsModule : Module { diff --git a/src/BuildingRegistry.Projections.Wms/paket.references b/src/BuildingRegistry.Projections.Wms/paket.references index ed1028f7e..f7e8069ee 100644 --- a/src/BuildingRegistry.Projections.Wms/paket.references +++ b/src/BuildingRegistry.Projections.Wms/paket.references @@ -1,6 +1,6 @@ Be.Vlaanderen.Basisregisters.EventHandling.Autofac Be.Vlaanderen.Basisregisters.DataDog.Tracing.Sql -Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner +Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.SqlServer Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore.Autofac Be.Vlaanderen.Basisregisters.GrAr.Common From 1ae54b17eff58558ad24e7ade15447aeb259bbb6 Mon Sep 17 00:00:00 2001 From: jvandaal Date: Fri, 12 Jan 2024 17:13:33 +0100 Subject: [PATCH 2/2] feat: add integration database latest item projections --- BuildingRegistry.sln | 7 + paket.dependencies | 1 + paket.lock | 8 + src/BuildingRegistry.Infrastructure/Schema.cs | 2 + .../Building/LatestItem/BuildingLatestItem.cs | 76 + .../BuildingLatestItemExtensions.cs | 30 + .../BuildingLatestItemProjections.cs | 380 +++++ .../LatestItem/MunicipalityGeometry.cs | 33 + ...ingRegistry.Projections.Integration.csproj | 13 + .../LatestItem/BuildingUnitAddress.cs | 33 + .../LatestItem/BuildingUnitLatestItem.cs | 82 + .../BuildingUnitLatestItemExtensions.cs | 62 + .../BuildingUnitLatestItemProjections.cs | 613 +++++++ .../Converters/BuildingExtensions.cs | 57 + .../Converters/BuildingUnitExtensions.cs | 71 + .../Infrastructure/IntegrationModule.cs | 62 + .../Infrastructure/IntegrationOptions.cs | 9 + .../IntegrationContext.cs | 54 + .../IntegrationContextMigrationFactory.cs | 29 + .../20240115145624_Initial.Designer.cs | 258 +++ .../Migrations/20240115145624_Initial.cs | 191 +++ .../IntegrationContextModelSnapshot.cs | 256 +++ .../Properties/AssemblyInfo.cs | 7 + .../paket.references | 16 + .../BuildingRegistry.Projector.csproj | 1 + .../Infrastructure/Modules/ApiModule.cs | 46 +- .../Infrastructure/Startup.cs | 26 +- .../Projections/ProjectionsController.cs | 1 + .../appsettings.json | 10 +- .../paket.references | 5 + .../EF.MigrationHelper.csproj | 1 + src/EF.MigrationsHelper/appsettings.json | 3 +- src/EF.MigrationsHelper/paket.references | 3 + .../BuildingRegistry.Tests.csproj | 1 + .../BuildingLatestItemProjectionsTests.cs | 894 ++++++++++ .../BuildingUnitLatestItemProjectionsTests.cs | 1491 +++++++++++++++++ .../Integration/IntegrationProjectionTest.cs | 30 + 37 files changed, 4849 insertions(+), 13 deletions(-) create mode 100644 src/BuildingRegistry.Projections.Integration/Building/LatestItem/BuildingLatestItem.cs create mode 100644 src/BuildingRegistry.Projections.Integration/Building/LatestItem/BuildingLatestItemExtensions.cs create mode 100644 src/BuildingRegistry.Projections.Integration/Building/LatestItem/BuildingLatestItemProjections.cs create mode 100644 src/BuildingRegistry.Projections.Integration/Building/LatestItem/MunicipalityGeometry.cs create mode 100644 src/BuildingRegistry.Projections.Integration/BuildingRegistry.Projections.Integration.csproj create mode 100644 src/BuildingRegistry.Projections.Integration/BuildingUnit/LatestItem/BuildingUnitAddress.cs create mode 100644 src/BuildingRegistry.Projections.Integration/BuildingUnit/LatestItem/BuildingUnitLatestItem.cs create mode 100644 src/BuildingRegistry.Projections.Integration/BuildingUnit/LatestItem/BuildingUnitLatestItemExtensions.cs create mode 100644 src/BuildingRegistry.Projections.Integration/BuildingUnit/LatestItem/BuildingUnitLatestItemProjections.cs create mode 100644 src/BuildingRegistry.Projections.Integration/Converters/BuildingExtensions.cs create mode 100644 src/BuildingRegistry.Projections.Integration/Converters/BuildingUnitExtensions.cs create mode 100644 src/BuildingRegistry.Projections.Integration/Infrastructure/IntegrationModule.cs create mode 100644 src/BuildingRegistry.Projections.Integration/Infrastructure/IntegrationOptions.cs create mode 100644 src/BuildingRegistry.Projections.Integration/IntegrationContext.cs create mode 100644 src/BuildingRegistry.Projections.Integration/IntegrationContextMigrationFactory.cs create mode 100644 src/BuildingRegistry.Projections.Integration/Migrations/20240115145624_Initial.Designer.cs create mode 100644 src/BuildingRegistry.Projections.Integration/Migrations/20240115145624_Initial.cs create mode 100644 src/BuildingRegistry.Projections.Integration/Migrations/IntegrationContextModelSnapshot.cs create mode 100644 src/BuildingRegistry.Projections.Integration/Properties/AssemblyInfo.cs create mode 100644 src/BuildingRegistry.Projections.Integration/paket.references create mode 100644 test/BuildingRegistry.Tests/ProjectionTests/Integration/BuildingLatestItemProjectionsTests.cs create mode 100644 test/BuildingRegistry.Tests/ProjectionTests/Integration/BuildingUnitLatestItemProjectionsTests.cs create mode 100644 test/BuildingRegistry.Tests/ProjectionTests/Integration/IntegrationProjectionTest.cs diff --git a/BuildingRegistry.sln b/BuildingRegistry.sln index ae38447e1..0264949b5 100755 --- a/BuildingRegistry.sln +++ b/BuildingRegistry.sln @@ -78,6 +78,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildingRegistry.Consumer.R EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildingRegistry.Snapshot.Verifier", "src\BuildingRegistry.Snapshot.Verifier\BuildingRegistry.Snapshot.Verifier.csproj", "{6F18B5C9-0E57-4352-B320-7976094B0738}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildingRegistry.Projections.Integration", "src\BuildingRegistry.Projections.Integration\BuildingRegistry.Projections.Integration.csproj", "{2CD597C6-43AB-4AB8-AF3A-5AC186AB92A3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -184,6 +186,10 @@ Global {6F18B5C9-0E57-4352-B320-7976094B0738}.Debug|Any CPU.Build.0 = Debug|Any CPU {6F18B5C9-0E57-4352-B320-7976094B0738}.Release|Any CPU.ActiveCfg = Release|Any CPU {6F18B5C9-0E57-4352-B320-7976094B0738}.Release|Any CPU.Build.0 = Release|Any CPU + {2CD597C6-43AB-4AB8-AF3A-5AC186AB92A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2CD597C6-43AB-4AB8-AF3A-5AC186AB92A3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2CD597C6-43AB-4AB8-AF3A-5AC186AB92A3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2CD597C6-43AB-4AB8-AF3A-5AC186AB92A3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -214,6 +220,7 @@ Global {72C98F9C-C576-4DFC-BAD6-4249E2AB64F1} = {1A034126-30E6-416B-BB2E-F5786E07B178} {7ADEA3CC-89A7-40B2-936A-3DC0BBF755B5} = {24B47154-C5F0-4356-B059-49A1E72C38A6} {6F18B5C9-0E57-4352-B320-7976094B0738} = {24B47154-C5F0-4356-B059-49A1E72C38A6} + {2CD597C6-43AB-4AB8-AF3A-5AC186AB92A3} = {24B47154-C5F0-4356-B059-49A1E72C38A6} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {65FA30D5-DDFC-40EC-9BC9-3BF93D1B430F} diff --git a/paket.dependencies b/paket.dependencies index b3397ffbf..f3f84a267 100644 --- a/paket.dependencies +++ b/paket.dependencies @@ -19,6 +19,7 @@ nuget MediatR.Contracts 2.0.1 nuget MediatR.Extensions.Microsoft.DependencyInjection 10.0.1 nuget Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite 6.0.3 +nuget Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite 6.0.3 nuget NetTopologySuite 2.4.0 nuget NodaTime 3.1.6 diff --git a/paket.lock b/paket.lock index c5d261621..7ba6de81e 100644 --- a/paket.lock +++ b/paket.lock @@ -1031,6 +1031,8 @@ NUGET 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) @@ -1073,6 +1075,12 @@ NUGET 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) diff --git a/src/BuildingRegistry.Infrastructure/Schema.cs b/src/BuildingRegistry.Infrastructure/Schema.cs index a10d97890..b99cbf7d8 100644 --- a/src/BuildingRegistry.Infrastructure/Schema.cs +++ b/src/BuildingRegistry.Infrastructure/Schema.cs @@ -17,6 +17,7 @@ public static class Schema public const string BackOfficeProjections = "BuildingRegistryBackOfficeProjections"; public const string Producer = "BuildingRegistryProducer"; public const string ProducerSnapshotOslo = "BuildingRegistryProducerSnapshotOslo"; + public const string Integration = "integration_building"; } public static class MigrationTables @@ -35,5 +36,6 @@ public static class MigrationTables public const string MigratorProjection = "__EFMigrationsHistoryMigrationProjection"; public const string Producer = "__EFMigrationsHistoryProducer"; public const string ProducerSnapshotOslo = "__EFMigrationsHistoryProducerSnapshotOslo"; + public const string Integration = "__EFMigrationsHistory"; } } diff --git a/src/BuildingRegistry.Projections.Integration/Building/LatestItem/BuildingLatestItem.cs b/src/BuildingRegistry.Projections.Integration/Building/LatestItem/BuildingLatestItem.cs new file mode 100644 index 000000000..bc949f00a --- /dev/null +++ b/src/BuildingRegistry.Projections.Integration/Building/LatestItem/BuildingLatestItem.cs @@ -0,0 +1,76 @@ +namespace BuildingRegistry.Projections.Integration.Building.LatestItem +{ + using System; + using Be.Vlaanderen.Basisregisters.GrAr.Common; + using Be.Vlaanderen.Basisregisters.Utilities; + using BuildingRegistry.Infrastructure; + using Microsoft.EntityFrameworkCore; + using Microsoft.EntityFrameworkCore.Metadata.Builders; + using NetTopologySuite.Geometries; + using NodaTime; + + public sealed class BuildingLatestItem + { + public const string VersionTimestampBackingPropertyName = nameof(VersionTimestampAsDateTimeOffset); + + public int BuildingPersistentLocalId { get; set; } + public string Status { get; set; } + public string OsloStatus { get; set; } + public string GeometryMethod { get; set; } + public string OsloGeometryMethod { get; set; } + public Geometry Geometry { get; set; } + public string? NisCode { get; set; } + public bool IsRemoved { 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 BuildingLatestItem() + { } + } + + public sealed class BuildingLatestItemConfiguration : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + const string tableName = "building_latest_items"; + + builder + .ToTable(tableName, Schema.Integration) // to schema per type + .HasKey(x => x.BuildingPersistentLocalId); + + builder.Property(x => x.BuildingPersistentLocalId).HasColumnName("building_persistent_local_id"); + builder.Property(x => x.Status).HasColumnName("status"); + builder.Property(x => x.OsloStatus).HasColumnName("oslo_status"); + builder.Property(x => x.GeometryMethod).HasColumnName("geometry_method"); + builder.Property(x => x.OsloGeometryMethod).HasColumnName("oslo_geometry_method"); + builder.Property(x => x.Geometry).HasColumnName("geometry"); + builder.Property(x => x.NisCode).HasColumnName("nis_code"); + builder.Property(x => x.IsRemoved).HasColumnName("is_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(BuildingLatestItem.VersionTimestampBackingPropertyName).HasColumnName("version_timestamp"); + + builder.Ignore(x => x.VersionTimestamp); + + builder.HasIndex(x => x.Status); + builder.HasIndex(x => x.OsloStatus); + builder.HasIndex(x => x.IsRemoved); + builder.HasIndex(x => x.NisCode); + builder.HasIndex(x => x.Geometry).HasMethod("GIST"); + } + } +} diff --git a/src/BuildingRegistry.Projections.Integration/Building/LatestItem/BuildingLatestItemExtensions.cs b/src/BuildingRegistry.Projections.Integration/Building/LatestItem/BuildingLatestItemExtensions.cs new file mode 100644 index 000000000..c5c086609 --- /dev/null +++ b/src/BuildingRegistry.Projections.Integration/Building/LatestItem/BuildingLatestItemExtensions.cs @@ -0,0 +1,30 @@ +namespace BuildingRegistry.Projections.Integration.Building.LatestItem +{ + using System; + using System.Threading; + using System.Threading.Tasks; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector; + + public static class BuildingLatestItemExtensions + { + public static async Task FindAndUpdateBuilding(this IntegrationContext context, + int buildingPersistentLocalId, + Action updateFunc, + CancellationToken ct) + { + var building = await context + .BuildingLatestItems + .FindAsync(buildingPersistentLocalId, cancellationToken: ct); + + if (building == null) + throw DatabaseItemNotFound(buildingPersistentLocalId); + + updateFunc(building); + + return building; + } + + private static ProjectionItemNotFoundException DatabaseItemNotFound(int buildingPersistentLocalId) + => new ProjectionItemNotFoundException(buildingPersistentLocalId.ToString()); + } +} diff --git a/src/BuildingRegistry.Projections.Integration/Building/LatestItem/BuildingLatestItemProjections.cs b/src/BuildingRegistry.Projections.Integration/Building/LatestItem/BuildingLatestItemProjections.cs new file mode 100644 index 000000000..661019042 --- /dev/null +++ b/src/BuildingRegistry.Projections.Integration/Building/LatestItem/BuildingLatestItemProjections.cs @@ -0,0 +1,380 @@ +namespace BuildingRegistry.Projections.Integration.Building.LatestItem +{ + using Be.Vlaanderen.Basisregisters.GrAr.Provenance; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore; + using Be.Vlaanderen.Basisregisters.Utilities.HexByteConvertor; + using BuildingRegistry.Building; + using BuildingRegistry.Building.Events; + using Converters; + using Infrastructure; + using Microsoft.Extensions.Options; + + [ConnectedProjectionName("Integratie gebouw latest item")] + [ConnectedProjectionDescription("Projectie die de laatste gebouw data voor de integratie database bijhoudt.")] + public sealed class BuildingLatestItemProjections : ConnectedProjection + { + public BuildingLatestItemProjections(IOptions options) + { + var wkbReader = WKBReaderFactory.Create(); + + When>(async (context, message, ct) => + { + var geometryAsBinary = message.Message.ExtendedWkbGeometry.ToByteArray(); + var sysGeometry = wkbReader.Read(geometryAsBinary); + + var nisCode = await context.FindMostIntersectingNisCodeBy(sysGeometry, ct); + + var building = new BuildingLatestItem + { + BuildingPersistentLocalId = message.Message.BuildingPersistentLocalId, + Status = BuildingStatus.Parse(message.Message.BuildingStatus).Map(), + OsloStatus = message.Message.BuildingStatus, + GeometryMethod = BuildingGeometryMethod.Parse(message.Message.GeometryMethod).Map(), + OsloGeometryMethod = message.Message.GeometryMethod, + Geometry = sysGeometry, + NisCode = nisCode, + IsRemoved = message.Message.IsRemoved, + VersionTimestamp = message.Message.Provenance.Timestamp, + Namespace = options.Value.BuildingNamespace, + PuriId = $"{options.Value.BuildingNamespace}/{message.Message.BuildingPersistentLocalId}" + }; + + await context + .BuildingLatestItems + .AddAsync(building, ct); + }); + + When>(async (context, message, ct) => + { + var geometryAsBinary = message.Message.ExtendedWkbGeometry.ToByteArray(); + var sysGeometry = wkbReader.Read(geometryAsBinary); + + var nisCode = await context.FindMostIntersectingNisCodeBy(sysGeometry, ct); + + var building = new BuildingLatestItem + { + BuildingPersistentLocalId = message.Message.BuildingPersistentLocalId, + Status = BuildingStatus.Planned.Map(), + OsloStatus = BuildingStatus.Planned.Value, + GeometryMethod = BuildingGeometryMethod.Outlined.Map(), + OsloGeometryMethod = BuildingGeometryMethod.Outlined.Value, + Geometry = sysGeometry, + NisCode = nisCode, + IsRemoved = false, + VersionTimestamp = message.Message.Provenance.Timestamp, + Namespace = options.Value.BuildingNamespace, + PuriId = $"{options.Value.BuildingNamespace}/{message.Message.BuildingPersistentLocalId}" + }; + + await context + .BuildingLatestItems + .AddAsync(building, ct); + }); + + When>(async (context, message, ct) => + { + var geometryAsBinary = message.Message.ExtendedWkbGeometry.ToByteArray(); + var sysGeometry = wkbReader.Read(geometryAsBinary); + + var nisCode = await context.FindMostIntersectingNisCodeBy(sysGeometry, ct); + + var building = new BuildingLatestItem + { + BuildingPersistentLocalId = message.Message.BuildingPersistentLocalId, + Status = BuildingStatus.Realized.Map(), + OsloStatus = BuildingStatus.Realized.Value, + GeometryMethod = BuildingGeometryMethod.MeasuredByGrb.Map(), + OsloGeometryMethod = BuildingGeometryMethod.MeasuredByGrb.Value, + Geometry = sysGeometry, + NisCode = nisCode, + IsRemoved = false, + VersionTimestamp = message.Message.Provenance.Timestamp, + Namespace = options.Value.BuildingNamespace, + PuriId = $"{options.Value.BuildingNamespace}/{message.Message.BuildingPersistentLocalId}" + }; + + await context + .BuildingLatestItems + .AddAsync(building, ct); + }); + + When>(async (context, message, ct) => + { + var geometryAsBinary = message.Message.ExtendedWkbGeometryBuilding.ToByteArray(); + var sysGeometry = wkbReader.Read(geometryAsBinary); + + var nisCode = await context.FindMostIntersectingNisCodeBy(sysGeometry, ct); + + await context.FindAndUpdateBuilding( + message.Message.BuildingPersistentLocalId, + building => + { + building.Geometry = sysGeometry; + building.GeometryMethod = BuildingGeometryMethod.Outlined.Map(); + building.OsloGeometryMethod = BuildingGeometryMethod.Outlined.Value; + building.NisCode = nisCode; + UpdateVersionTimestamp(building, message.Message); + }, + ct); + }); + + When>(async (context, message, ct) => + { + var geometryAsBinary = message.Message.ExtendedWkbGeometryBuilding.ToByteArray(); + var sysGeometry = wkbReader.Read(geometryAsBinary); + + var nisCode = await context.FindMostIntersectingNisCodeBy(sysGeometry, ct); + + await context.FindAndUpdateBuilding( + message.Message.BuildingPersistentLocalId, + building => + { + building.Geometry = sysGeometry; + building.GeometryMethod = BuildingGeometryMethod.MeasuredByGrb.Map(); + building.OsloGeometryMethod = BuildingGeometryMethod.MeasuredByGrb.Value; + building.NisCode = nisCode; + UpdateVersionTimestamp(building, message.Message); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuilding( + message.Message.BuildingPersistentLocalId, + building => + { + building.Status = BuildingStatus.UnderConstruction.Map(); + building.OsloStatus = BuildingStatus.UnderConstruction.Value; + UpdateVersionTimestamp(building, message.Message); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuilding( + message.Message.BuildingPersistentLocalId, + building => + { + building.Status = BuildingStatus.Planned.Map(); + building.OsloStatus = BuildingStatus.Planned.Value; + UpdateVersionTimestamp(building, message.Message); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuilding( + message.Message.BuildingPersistentLocalId, + building => + { + building.Status = BuildingStatus.Realized.Map(); + building.OsloStatus = BuildingStatus.Realized.Value; + UpdateVersionTimestamp(building, message.Message); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuilding( + message.Message.BuildingPersistentLocalId, + building => + { + building.Status = BuildingStatus.UnderConstruction.Map(); + building.OsloStatus = BuildingStatus.UnderConstruction.Value; + UpdateVersionTimestamp(building, message.Message); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuilding( + message.Message.BuildingPersistentLocalId, + building => + { + building.Status = BuildingStatus.NotRealized.Map(); + building.OsloStatus = BuildingStatus.NotRealized.Value; + UpdateVersionTimestamp(building, message.Message); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuilding( + message.Message.BuildingPersistentLocalId, + building => + { + building.Status = BuildingStatus.Planned.Map(); + building.OsloStatus = BuildingStatus.Planned.Value; + UpdateVersionTimestamp(building, message.Message); + }, + ct); + }); + + When>(async (context, message, ct) => + { + var geometryAsBinary = message.Message.ExtendedWkbGeometryBuilding.ToByteArray(); + var sysGeometry = wkbReader.Read(geometryAsBinary); + + var nisCode = await context.FindMostIntersectingNisCodeBy(sysGeometry, ct); + + await context.FindAndUpdateBuilding( + message.Message.BuildingPersistentLocalId, + building => + { + building.Geometry = sysGeometry; + building.GeometryMethod = BuildingGeometryMethod.MeasuredByGrb.Map(); + building.OsloGeometryMethod = BuildingGeometryMethod.MeasuredByGrb.Value; + building.NisCode = nisCode; + UpdateVersionTimestamp(building, message.Message); + }, + ct); + }); + + When>(async (context, message, ct) => + { + var geometryAsBinary = message.Message.ExtendedWkbGeometryBuilding.ToByteArray(); + var sysGeometry = wkbReader.Read(geometryAsBinary); + + var nisCode = await context.FindMostIntersectingNisCodeBy(sysGeometry, ct); + + await context.FindAndUpdateBuilding( + message.Message.BuildingPersistentLocalId, + building => + { + building.Geometry = sysGeometry; + building.GeometryMethod = BuildingGeometryMethod.MeasuredByGrb.Map(); + building.OsloGeometryMethod = BuildingGeometryMethod.MeasuredByGrb.Value; + building.NisCode = nisCode; + UpdateVersionTimestamp(building, message.Message); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuilding( + message.Message.BuildingPersistentLocalId, + building => + { + building.Status = BuildingStatus.Retired.Map(); + building.OsloStatus = BuildingStatus.Retired.Value; + UpdateVersionTimestamp(building, message.Message); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuilding( + message.Message.BuildingPersistentLocalId, + building => + { + building.IsRemoved = true; + UpdateVersionTimestamp(building, message.Message); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuilding( + message.Message.BuildingPersistentLocalId, + building => { UpdateVersionTimestamp(building, message.Message); }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuilding( + message.Message.BuildingPersistentLocalId, + building => { UpdateVersionTimestamp(building, message.Message); }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuilding( + message.Message.BuildingPersistentLocalId, + building => + { + UpdateVersionTimestamp(building, message.Message); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuilding( + message.Message.BuildingPersistentLocalId, + building => { UpdateVersionTimestamp(building, message.Message); }, + ct); + }); + + When>(async (context, message, ct) => + { + var geometryAsBinary = message.Message.ExtendedWkbGeometry.ToByteArray(); + var sysGeometry = wkbReader.Read(geometryAsBinary); + + var nisCode = await context.FindMostIntersectingNisCodeBy(sysGeometry, ct); + + var building = new BuildingLatestItem + { + BuildingPersistentLocalId = message.Message.BuildingPersistentLocalId, + Status = BuildingStatus.Realized.Map(), + OsloStatus = BuildingStatus.Realized.Value, + GeometryMethod = BuildingGeometryMethod.MeasuredByGrb.Map(), + OsloGeometryMethod = BuildingGeometryMethod.MeasuredByGrb.Value, + Geometry = sysGeometry, + NisCode = nisCode, + IsRemoved = false, + VersionTimestamp = message.Message.Provenance.Timestamp, + Namespace = options.Value.BuildingNamespace, + PuriId = $"{options.Value.BuildingNamespace}/{message.Message.BuildingPersistentLocalId}" + }; + + await context + .BuildingLatestItems + .AddAsync(building, ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuilding( + message.Message.BuildingPersistentLocalId, + building => { UpdateVersionTimestamp(building, message.Message); }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuilding( + message.Message.BuildingPersistentLocalId, + building => { UpdateVersionTimestamp(building, message.Message); }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuilding( + message.Message.BuildingPersistentLocalId, + building => + { + building.Status = BuildingStatus.Retired.Map(); + building.OsloStatus = BuildingStatus.Retired.Value; + UpdateVersionTimestamp(building, message.Message); + }, + ct); + }); + } + + private static void UpdateVersionTimestamp(BuildingLatestItem building, IHasProvenance message) + => building.VersionTimestamp = message.Provenance.Timestamp; + } +} diff --git a/src/BuildingRegistry.Projections.Integration/Building/LatestItem/MunicipalityGeometry.cs b/src/BuildingRegistry.Projections.Integration/Building/LatestItem/MunicipalityGeometry.cs new file mode 100644 index 000000000..c9a6d57fc --- /dev/null +++ b/src/BuildingRegistry.Projections.Integration/Building/LatestItem/MunicipalityGeometry.cs @@ -0,0 +1,33 @@ +namespace BuildingRegistry.Projections.Integration.Building.LatestItem +{ + using BuildingRegistry.Infrastructure; + using Microsoft.EntityFrameworkCore; + using Microsoft.EntityFrameworkCore.Metadata.Builders; + using NetTopologySuite.Geometries; + + public sealed class MunicipalityGeometry + { + public string NisCode { get; set; } + public Geometry Geometry { get; set; } + + public MunicipalityGeometry() + { } + } + + public sealed class MunicipalityGeometryConfiguration : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + const string schema = "integration_municipality"; + const string viewName = "municipality_geometries"; + + builder.Property(x => x.NisCode).HasColumnName("nis_code"); + builder.Property(x => x.Geometry).HasColumnName("geometry"); + + builder + .ToView(viewName, schema) // It's actually a table, but to not create EF migrations, we configure it as a view without a key. + .HasNoKey() + .ToSqlQuery($"SELECT nis_code, geometry FROM {schema}.{viewName}"); + } + } +} diff --git a/src/BuildingRegistry.Projections.Integration/BuildingRegistry.Projections.Integration.csproj b/src/BuildingRegistry.Projections.Integration/BuildingRegistry.Projections.Integration.csproj new file mode 100644 index 000000000..4d52b65a9 --- /dev/null +++ b/src/BuildingRegistry.Projections.Integration/BuildingRegistry.Projections.Integration.csproj @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/BuildingRegistry.Projections.Integration/BuildingUnit/LatestItem/BuildingUnitAddress.cs b/src/BuildingRegistry.Projections.Integration/BuildingUnit/LatestItem/BuildingUnitAddress.cs new file mode 100644 index 000000000..6c9542141 --- /dev/null +++ b/src/BuildingRegistry.Projections.Integration/BuildingUnit/LatestItem/BuildingUnitAddress.cs @@ -0,0 +1,33 @@ +namespace BuildingRegistry.Projections.Integration.BuildingUnit.LatestItem +{ + using BuildingRegistry.Infrastructure; + using Microsoft.EntityFrameworkCore; + using Microsoft.EntityFrameworkCore.Metadata.Builders; + + public sealed class BuildingUnitAddress + { + public int BuildingUnitPersistentLocalId { get; set; } + public int AddressPersistentLocalId { get; set; } + + public BuildingUnitAddress() + { } + } + + public sealed class BuildingUnitAddressConfiguration : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + const string tableName = "building_unit_addresses"; + + builder + .ToTable(tableName, Schema.Integration) // to schema per type + .HasKey(x => new { x.BuildingUnitPersistentLocalId, x.AddressPersistentLocalId }); + + builder.Property(x => x.BuildingUnitPersistentLocalId).HasColumnName("building_unit_persistent_local_id"); + builder.Property(x => x.AddressPersistentLocalId).HasColumnName("address_persistent_local_id"); + + builder.HasIndex(x => x.BuildingUnitPersistentLocalId); + builder.HasIndex(x => x.AddressPersistentLocalId); + } + } +} diff --git a/src/BuildingRegistry.Projections.Integration/BuildingUnit/LatestItem/BuildingUnitLatestItem.cs b/src/BuildingRegistry.Projections.Integration/BuildingUnit/LatestItem/BuildingUnitLatestItem.cs new file mode 100644 index 000000000..46deeb6b4 --- /dev/null +++ b/src/BuildingRegistry.Projections.Integration/BuildingUnit/LatestItem/BuildingUnitLatestItem.cs @@ -0,0 +1,82 @@ +namespace BuildingRegistry.Projections.Integration.BuildingUnit.LatestItem +{ + using System; + using Be.Vlaanderen.Basisregisters.GrAr.Common; + using Be.Vlaanderen.Basisregisters.Utilities; + using BuildingRegistry.Infrastructure; + using Microsoft.EntityFrameworkCore; + using Microsoft.EntityFrameworkCore.Metadata.Builders; + using NetTopologySuite.Geometries; + using NodaTime; + + public sealed class BuildingUnitLatestItem + { + public const string VersionTimestampBackingPropertyName = nameof(VersionTimestampAsDateTimeOffset); + + public int BuildingUnitPersistentLocalId { get; set; } + public int BuildingPersistentLocalId { get; set; } + public string Status { get; set; } + public string OsloStatus { get; set; } + public string Function { get; set; } + public string OsloFunction { get; set; } + public string GeometryMethod { get; set; } + public string OsloGeometryMethod { get; set; } + public Geometry Geometry { get; set; } + public bool HasDeviation { get; set; } + public bool IsRemoved { 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 BuildingUnitLatestItem() + { } + } + + public sealed class BuildingUnitLatestItemConfiguration : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + const string tableName = "building_unit_latest_items"; + + builder + .ToTable(tableName, Schema.Integration) // to schema per type + .HasKey(x => x.BuildingUnitPersistentLocalId); + + builder.Property(x => x.BuildingUnitPersistentLocalId).HasColumnName("building_unit_persistent_local_id"); + builder.Property(x => x.BuildingPersistentLocalId).HasColumnName("building_persistent_local_id"); + builder.Property(x => x.Status).HasColumnName("status"); + builder.Property(x => x.OsloStatus).HasColumnName("oslo_status"); + builder.Property(x => x.Function).HasColumnName("function"); + builder.Property(x => x.OsloFunction).HasColumnName("oslo_function"); + builder.Property(x => x.GeometryMethod).HasColumnName("geometry_method"); + builder.Property(x => x.OsloGeometryMethod).HasColumnName("oslo_geometry_method"); + builder.Property(x => x.Geometry).HasColumnName("geometry"); + builder.Property(x => x.HasDeviation).HasColumnName("has_deviation"); + builder.Property(x => x.IsRemoved).HasColumnName("is_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(BuildingUnitLatestItem.VersionTimestampBackingPropertyName).HasColumnName("version_timestamp"); + + builder.Ignore(x => x.VersionTimestamp); + + builder.HasIndex(x => x.BuildingPersistentLocalId); + builder.HasIndex(x => x.Status); + builder.HasIndex(x => x.OsloStatus); + builder.HasIndex(x => x.IsRemoved); + builder.HasIndex(x => x.Geometry).HasMethod("GIST"); + } + } +} diff --git a/src/BuildingRegistry.Projections.Integration/BuildingUnit/LatestItem/BuildingUnitLatestItemExtensions.cs b/src/BuildingRegistry.Projections.Integration/BuildingUnit/LatestItem/BuildingUnitLatestItemExtensions.cs new file mode 100644 index 000000000..58a84a06f --- /dev/null +++ b/src/BuildingRegistry.Projections.Integration/BuildingUnit/LatestItem/BuildingUnitLatestItemExtensions.cs @@ -0,0 +1,62 @@ +namespace BuildingRegistry.Projections.Integration.BuildingUnit.LatestItem +{ + using System; + using System.Threading; + using System.Threading.Tasks; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector; + + public static class BuildingUnitLatestItemExtensions + { + public static async Task FindAndUpdateBuildingUnit(this IntegrationContext context, + int buildingUnitPersistentLocalId, + Func updateFunc, + CancellationToken ct) + { + var buildingUnit = await context + .BuildingUnitLatestItems + .FindAsync(buildingUnitPersistentLocalId, cancellationToken: ct); + + if (buildingUnit == null) + throw DatabaseItemNotFound(buildingUnitPersistentLocalId); + + await updateFunc(buildingUnit); + + return buildingUnit; + } + + public static async Task AddIdempotentBuildingUnitAddress(this IntegrationContext context, + BuildingUnitLatestItem buildingUnit, + int addressPersistentLocalId, + CancellationToken ct) + { + var buildingUnitAddress = await context.BuildingUnitAddresses.FindAsync( + new object[] { buildingUnit.BuildingUnitPersistentLocalId, addressPersistentLocalId }, ct); + + if (buildingUnitAddress is null) + { + context.BuildingUnitAddresses.Add(new BuildingUnitAddress + { + BuildingUnitPersistentLocalId = buildingUnit.BuildingUnitPersistentLocalId, + AddressPersistentLocalId = addressPersistentLocalId + }); + } + } + + public static async Task RemoveIdempotentBuildingUnitAddress(this IntegrationContext context, + BuildingUnitLatestItem buildingUnit, + int addressPersistentLocalId, + CancellationToken ct) + { + var buildingUnitAddress = await context.BuildingUnitAddresses.FindAsync( + new object[] { buildingUnit.BuildingUnitPersistentLocalId, addressPersistentLocalId }, ct); + + if (buildingUnitAddress is not null) + { + context.BuildingUnitAddresses.Remove(buildingUnitAddress); + } + } + + private static ProjectionItemNotFoundException DatabaseItemNotFound(int buildingUnitPersistentLocalId) + => new ProjectionItemNotFoundException(buildingUnitPersistentLocalId.ToString()); + } +} diff --git a/src/BuildingRegistry.Projections.Integration/BuildingUnit/LatestItem/BuildingUnitLatestItemProjections.cs b/src/BuildingRegistry.Projections.Integration/BuildingUnit/LatestItem/BuildingUnitLatestItemProjections.cs new file mode 100644 index 000000000..68217ecf7 --- /dev/null +++ b/src/BuildingRegistry.Projections.Integration/BuildingUnit/LatestItem/BuildingUnitLatestItemProjections.cs @@ -0,0 +1,613 @@ +namespace BuildingRegistry.Projections.Integration.BuildingUnit.LatestItem +{ + using System.Linq; + using System.Threading.Tasks; + using Be.Vlaanderen.Basisregisters.GrAr.Provenance; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Connector; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore; + using Be.Vlaanderen.Basisregisters.Utilities.HexByteConvertor; + using BuildingRegistry.Building; + using BuildingRegistry.Building.Events; + using Converters; + using Infrastructure; + using Microsoft.Extensions.Options; + + [ConnectedProjectionName("Integratie gebouweenheid latest item")] + [ConnectedProjectionDescription("Projectie die de laatste gebouweenheid data voor de integratie database bijhoudt.")] + public sealed class BuildingUnitLatestItemProjections : ConnectedProjection + { + public BuildingUnitLatestItemProjections(IOptions options) + { + var wkbReader = WKBReaderFactory.Create(); + + #region Building + + When>(async (context, message, ct) => + { + foreach (var buildingUnit in message.Message.BuildingUnits) + { + var geometryAsBinary = buildingUnit.ExtendedWkbGeometry.ToByteArray(); + var sysGeometry = wkbReader.Read(geometryAsBinary); + + var buildingUnitLatestItem = new BuildingUnitLatestItem + { + BuildingUnitPersistentLocalId = buildingUnit.BuildingUnitPersistentLocalId, + BuildingPersistentLocalId = message.Message.BuildingPersistentLocalId, + Status = BuildingUnitStatus.Parse(buildingUnit.Status).Map(), + OsloStatus = buildingUnit.Status, + Function = BuildingUnitFunction.Parse(buildingUnit.Function).Map(), + OsloFunction = buildingUnit.Function, + GeometryMethod = BuildingUnitPositionGeometryMethod.Parse(buildingUnit.GeometryMethod).Map(), + OsloGeometryMethod = buildingUnit.GeometryMethod, + Geometry = sysGeometry, + HasDeviation = false, + IsRemoved = buildingUnit.IsRemoved, + VersionTimestamp = message.Message.Provenance.Timestamp, + Namespace = options.Value.BuildingUnitNamespace, + PuriId = $"{options.Value.BuildingUnitNamespace}/{buildingUnit.BuildingUnitPersistentLocalId}" + }; + + await context + .BuildingUnitLatestItems + .AddAsync(buildingUnitLatestItem, ct); + + var addressPersistentLocalIds = buildingUnit.AddressPersistentLocalIds.Distinct(); + foreach (var addressPersistentLocalId in addressPersistentLocalIds) + { + await context.AddIdempotentBuildingUnitAddress(buildingUnitLatestItem, addressPersistentLocalId, ct); + } + } + }); + + When>(async (context, message, ct) => + { + if (!message.Message.BuildingUnitPersistentLocalIds.Any()) + { + return; + } + + var geometryAsBinary = message.Message.ExtendedWkbGeometryBuildingUnits!.ToByteArray(); + var sysGeometry = wkbReader.Read(geometryAsBinary); + + foreach (var buildingUnitPersistentLocalId in message.Message.BuildingUnitPersistentLocalIds) + { + await context.FindAndUpdateBuildingUnit( + buildingUnitPersistentLocalId, + buildingUnit => + { + buildingUnit.Geometry = sysGeometry; + buildingUnit.GeometryMethod = BuildingUnitPositionGeometryMethod.DerivedFromObject.Map(); + buildingUnit.OsloGeometryMethod = BuildingUnitPositionGeometryMethod.DerivedFromObject.GeometryMethod; + UpdateVersionTimestamp(buildingUnit, message.Message); + return Task.CompletedTask; + }, + ct); + } + }); + + When>(async (context, message, ct) => + { + if (!message.Message.BuildingUnitPersistentLocalIds.Any() + && !message.Message.BuildingUnitPersistentLocalIdsWhichBecameDerived.Any()) + { + return; + } + + var geometryAsBinary = message.Message.ExtendedWkbGeometryBuildingUnits!.ToByteArray(); + var sysGeometry = wkbReader.Read(geometryAsBinary); + + foreach (var buildingUnitPersistentLocalId in message.Message.BuildingUnitPersistentLocalIds + .Concat(message.Message.BuildingUnitPersistentLocalIdsWhichBecameDerived)) + { + await context.FindAndUpdateBuildingUnit( + buildingUnitPersistentLocalId, + buildingUnit => + { + buildingUnit.Geometry = sysGeometry; + buildingUnit.GeometryMethod = BuildingUnitPositionGeometryMethod.DerivedFromObject.Map(); + buildingUnit.OsloGeometryMethod = BuildingUnitPositionGeometryMethod.DerivedFromObject.GeometryMethod; + UpdateVersionTimestamp(buildingUnit, message.Message); + return Task.CompletedTask; + }, + ct); + } + }); + + When>(async (context, message, ct) => + { + if (!message.Message.BuildingUnitPersistentLocalIds.Any() + && !message.Message.BuildingUnitPersistentLocalIdsWhichBecameDerived.Any()) + { + return; + } + + var geometryAsBinary = message.Message.ExtendedWkbGeometryBuildingUnits!.ToByteArray(); + var sysGeometry = wkbReader.Read(geometryAsBinary); + + foreach (var buildingUnitPersistentLocalId in message.Message.BuildingUnitPersistentLocalIds + .Concat(message.Message.BuildingUnitPersistentLocalIdsWhichBecameDerived)) + { + await context.FindAndUpdateBuildingUnit( + buildingUnitPersistentLocalId, + buildingUnit => + { + buildingUnit.Geometry = sysGeometry; + buildingUnit.GeometryMethod = BuildingUnitPositionGeometryMethod.DerivedFromObject.Map(); + buildingUnit.OsloGeometryMethod = BuildingUnitPositionGeometryMethod.DerivedFromObject.GeometryMethod; + UpdateVersionTimestamp(buildingUnit, message.Message); + return Task.CompletedTask; + }, + ct); + } + }); + + When>(async (context, message, ct) => + { + if (!message.Message.BuildingUnitPersistentLocalIds.Any() + && !message.Message.BuildingUnitPersistentLocalIdsWhichBecameDerived.Any()) + { + return; + } + + var geometryAsBinary = message.Message.ExtendedWkbGeometryBuildingUnits!.ToByteArray(); + var sysGeometry = wkbReader.Read(geometryAsBinary); + + foreach (var buildingUnitPersistentLocalId in message.Message.BuildingUnitPersistentLocalIds + .Concat(message.Message.BuildingUnitPersistentLocalIdsWhichBecameDerived)) + { + await context.FindAndUpdateBuildingUnit( + buildingUnitPersistentLocalId, + buildingUnit => + { + buildingUnit.Geometry = sysGeometry; + buildingUnit.GeometryMethod = BuildingUnitPositionGeometryMethod.DerivedFromObject.Map(); + buildingUnit.OsloGeometryMethod = BuildingUnitPositionGeometryMethod.DerivedFromObject.GeometryMethod; + UpdateVersionTimestamp(buildingUnit, message.Message); + return Task.CompletedTask; + }, + ct); + } + }); + + #endregion + + When>(async (context, message, ct) => + { + var geometryAsBinary = message.Message.ExtendedWkbGeometry.ToByteArray(); + var sysGeometry = wkbReader.Read(geometryAsBinary); + + var buildingUnitLatestItem = new BuildingUnitLatestItem + { + BuildingUnitPersistentLocalId = message.Message.BuildingUnitPersistentLocalId, + BuildingPersistentLocalId = message.Message.BuildingPersistentLocalId, + Status = BuildingUnitStatus.Planned.Map(), + OsloStatus = BuildingUnitStatus.Planned.Status, + Function = BuildingUnitFunction.Parse(message.Message.Function).Map(), + OsloFunction = message.Message.Function, + GeometryMethod = BuildingUnitPositionGeometryMethod.Parse(message.Message.GeometryMethod).Map(), + OsloGeometryMethod = message.Message.GeometryMethod, + Geometry = sysGeometry, + HasDeviation = message.Message.HasDeviation, + IsRemoved = false, + VersionTimestamp = message.Message.Provenance.Timestamp, + Namespace = options.Value.BuildingUnitNamespace, + PuriId = $"{options.Value.BuildingUnitNamespace}/{message.Message.BuildingUnitPersistentLocalId}" + }; + + await context + .BuildingUnitLatestItems + .AddAsync(buildingUnitLatestItem, ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + buildingUnit => + { + buildingUnit.Status = BuildingUnitStatus.Realized.Map(); + buildingUnit.OsloStatus = BuildingUnitStatus.Realized.Status; + UpdateVersionTimestamp(buildingUnit, message.Message); + return Task.CompletedTask; + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + buildingUnit => + { + buildingUnit.Status = BuildingUnitStatus.Realized.Map(); + buildingUnit.OsloStatus = BuildingUnitStatus.Realized.Status; + UpdateVersionTimestamp(buildingUnit, message.Message); + return Task.CompletedTask; + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + buildingUnit => + { + buildingUnit.Status = BuildingUnitStatus.Planned.Map(); + buildingUnit.OsloStatus = BuildingUnitStatus.Planned.Status; + UpdateVersionTimestamp(buildingUnit, message.Message); + return Task.CompletedTask; + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + buildingUnit => + { + buildingUnit.Status = BuildingUnitStatus.Planned.Map(); + buildingUnit.OsloStatus = BuildingUnitStatus.Planned.Status; + UpdateVersionTimestamp(buildingUnit, message.Message); + return Task.CompletedTask; + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + buildingUnit => + { + buildingUnit.Status = BuildingUnitStatus.NotRealized.Map(); + buildingUnit.OsloStatus = BuildingUnitStatus.NotRealized.Status; + UpdateVersionTimestamp(buildingUnit, message.Message); + return Task.CompletedTask; + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + buildingUnit => + { + buildingUnit.Status = BuildingUnitStatus.NotRealized.Map(); + buildingUnit.OsloStatus = BuildingUnitStatus.NotRealized.Status; + UpdateVersionTimestamp(buildingUnit, message.Message); + return Task.CompletedTask; + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + buildingUnit => + { + buildingUnit.Status = BuildingUnitStatus.Planned.Map(); + buildingUnit.OsloStatus = BuildingUnitStatus.Planned.Status; + UpdateVersionTimestamp(buildingUnit, message.Message); + return Task.CompletedTask; + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + buildingUnit => + { + buildingUnit.Status = BuildingUnitStatus.Retired.Map(); + buildingUnit.OsloStatus = BuildingUnitStatus.Retired.Status; + UpdateVersionTimestamp(buildingUnit, message.Message); + return Task.CompletedTask; + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + buildingUnit => + { + buildingUnit.Status = BuildingUnitStatus.Realized.Map(); + buildingUnit.OsloStatus = BuildingUnitStatus.Realized.Status; + UpdateVersionTimestamp(buildingUnit, message.Message); + return Task.CompletedTask; + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + buildingUnit => + { + buildingUnit.IsRemoved = true; + UpdateVersionTimestamp(buildingUnit, message.Message); + return Task.CompletedTask; + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + buildingUnit => + { + buildingUnit.IsRemoved = true; + UpdateVersionTimestamp(buildingUnit, message.Message); + return Task.CompletedTask; + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + buildingUnit => + { + var geometryAsBinary = message.Message.ExtendedWkbGeometry.ToByteArray(); + var sysGeometry = wkbReader.Read(geometryAsBinary); + + buildingUnit.Status = BuildingUnitStatus.Parse(message.Message.BuildingUnitStatus).Map(); + buildingUnit.OsloStatus = message.Message.BuildingUnitStatus; + buildingUnit.Function = BuildingUnitFunction.Parse(message.Message.Function).Map(); + buildingUnit.OsloFunction = message.Message.Function; + buildingUnit.Geometry = sysGeometry; + buildingUnit.GeometryMethod = BuildingUnitPositionGeometryMethod.Parse(message.Message.GeometryMethod).Map(); + buildingUnit.OsloGeometryMethod = message.Message.GeometryMethod; + buildingUnit.HasDeviation = message.Message.HasDeviation; + buildingUnit.IsRemoved = false; + UpdateVersionTimestamp(buildingUnit, message.Message); + return Task.CompletedTask; + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + buildingUnit => + { + buildingUnit.HasDeviation = false; + UpdateVersionTimestamp(buildingUnit, message.Message); + return Task.CompletedTask; + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + buildingUnit => + { + buildingUnit.HasDeviation = true; + UpdateVersionTimestamp(buildingUnit, message.Message); + return Task.CompletedTask; + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + buildingUnit => + { + buildingUnit.HasDeviation = true; + UpdateVersionTimestamp(buildingUnit, message.Message); + return Task.CompletedTask; + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + buildingUnit => + { + buildingUnit.HasDeviation = false; + UpdateVersionTimestamp(buildingUnit, message.Message); + return Task.CompletedTask; + }, + ct); + }); + + When>(async (context, message, ct) => + { + var geometryAsBinary = message.Message.ExtendedWkbGeometry.ToByteArray(); + var sysGeometry = wkbReader.Read(geometryAsBinary); + + var buildingUnitLatestItem = new BuildingUnitLatestItem + { + BuildingUnitPersistentLocalId = message.Message.BuildingUnitPersistentLocalId, + BuildingPersistentLocalId = message.Message.BuildingPersistentLocalId, + Status = BuildingUnitStatus.Parse(message.Message.BuildingUnitStatus).Map(), + OsloStatus = message.Message.BuildingUnitStatus, + Function = BuildingUnitFunction.Common.Map(), + OsloFunction = BuildingUnitFunction.Common.Function, + GeometryMethod = BuildingUnitPositionGeometryMethod.Parse(message.Message.GeometryMethod).Map(), + OsloGeometryMethod = message.Message.GeometryMethod, + Geometry = sysGeometry, + HasDeviation = message.Message.HasDeviation, + IsRemoved = false, + VersionTimestamp = message.Message.Provenance.Timestamp, + Namespace = options.Value.BuildingUnitNamespace, + PuriId = $"{options.Value.BuildingUnitNamespace}/{message.Message.BuildingUnitPersistentLocalId}" + }; + + await context + .BuildingUnitLatestItems + .AddAsync(buildingUnitLatestItem, ct); + }); + + When>(async (context, message, ct) => + { + var geometryAsBinary = message.Message.ExtendedWkbGeometry.ToByteArray(); + var sysGeometry = wkbReader.Read(geometryAsBinary); + + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + buildingUnit => + { + buildingUnit.Geometry = sysGeometry; + buildingUnit.GeometryMethod = BuildingUnitPositionGeometryMethod.Parse(message.Message.GeometryMethod).Map(); + buildingUnit.OsloGeometryMethod = message.Message.GeometryMethod; + UpdateVersionTimestamp(buildingUnit, message.Message); + return Task.CompletedTask; + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + async buildingUnit => + { + await context.AddIdempotentBuildingUnitAddress(buildingUnit, message.Message.AddressPersistentLocalId, ct); + UpdateVersionTimestamp(buildingUnit, message.Message); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + async buildingUnit => + { + await context.RemoveIdempotentBuildingUnitAddress(buildingUnit, message.Message.AddressPersistentLocalId, ct); + UpdateVersionTimestamp(buildingUnit, message.Message); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + async buildingUnit => + { + await context.RemoveIdempotentBuildingUnitAddress(buildingUnit, message.Message.AddressPersistentLocalId, ct); + UpdateVersionTimestamp(buildingUnit, message.Message); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + async buildingUnit => + { + await context.RemoveIdempotentBuildingUnitAddress(buildingUnit, message.Message.AddressPersistentLocalId, ct); + UpdateVersionTimestamp(buildingUnit, message.Message); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + async buildingUnit => + { + await context.RemoveIdempotentBuildingUnitAddress(buildingUnit, message.Message.AddressPersistentLocalId, ct); + UpdateVersionTimestamp(buildingUnit, message.Message); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + async buildingUnit => + { + await context.RemoveIdempotentBuildingUnitAddress(buildingUnit, message.Message.PreviousAddressPersistentLocalId, ct); + await context.AddIdempotentBuildingUnitAddress(buildingUnit, message.Message.NewAddressPersistentLocalId, ct); + UpdateVersionTimestamp(buildingUnit, message.Message); + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + buildingUnit => + { + buildingUnit.Status = BuildingUnitStatus.Retired.Map(); + buildingUnit.OsloStatus = BuildingUnitStatus.Retired.Status; + UpdateVersionTimestamp(buildingUnit, message.Message); + return Task.CompletedTask; + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + buildingUnit => + { + buildingUnit.Status = BuildingUnitStatus.NotRealized.Map(); + buildingUnit.OsloStatus = BuildingUnitStatus.NotRealized.Status; + UpdateVersionTimestamp(buildingUnit, message.Message); + return Task.CompletedTask; + }, + ct); + }); + + When>(async (context, message, ct) => + { + await context.FindAndUpdateBuildingUnit( + message.Message.BuildingUnitPersistentLocalId, + async buildingUnit => + { + var geometryAsBinary = message.Message.ExtendedWkbGeometry.ToByteArray(); + var sysGeometry = wkbReader.Read(geometryAsBinary); + + buildingUnit.BuildingPersistentLocalId = message.Message.BuildingPersistentLocalId; + buildingUnit.Status = BuildingUnitStatus.Parse(message.Message.Status).Map(); + buildingUnit.OsloStatus = message.Message.Status; + buildingUnit.Function = BuildingUnitFunction.Parse(message.Message.Function).Map(); + buildingUnit.OsloFunction = message.Message.Function; + buildingUnit.Geometry = sysGeometry; + buildingUnit.GeometryMethod = BuildingUnitPositionGeometryMethod.Parse(message.Message.GeometryMethod).Map(); + buildingUnit.OsloGeometryMethod = message.Message.GeometryMethod; + buildingUnit.HasDeviation = message.Message.HasDeviation; + UpdateVersionTimestamp(buildingUnit, message.Message); + + var addressPersistentLocalIds = message.Message.AddressPersistentLocalIds.Distinct(); + foreach (var addressPersistentLocalId in addressPersistentLocalIds) + { + await context.AddIdempotentBuildingUnitAddress(buildingUnit, addressPersistentLocalId, ct); + } + }, + ct); + }); + + // BuildingUnitWasTransferred couples the unit to another building and BuildingUnitMoved is an event applicable on the old building. + When>((_, _, _) => Task.CompletedTask); + } + + private static void UpdateVersionTimestamp(BuildingUnitLatestItem building, IHasProvenance message) + => building.VersionTimestamp = message.Provenance.Timestamp; + } +} diff --git a/src/BuildingRegistry.Projections.Integration/Converters/BuildingExtensions.cs b/src/BuildingRegistry.Projections.Integration/Converters/BuildingExtensions.cs new file mode 100644 index 000000000..f700081df --- /dev/null +++ b/src/BuildingRegistry.Projections.Integration/Converters/BuildingExtensions.cs @@ -0,0 +1,57 @@ +namespace BuildingRegistry.Projections.Integration.Converters +{ + using System; + using Be.Vlaanderen.Basisregisters.GrAr.Legacy.Gebouw; + using BuildingRegistry.Building; + + public static class BuildingStatusExtensions + { + public static string Map(this BuildingStatus status) + { + if (status == BuildingStatus.Planned) + { + return GebouwStatus.Gepland.ToString(); + } + + if (status == BuildingStatus.UnderConstruction) + { + return GebouwStatus.InAanbouw.ToString(); + } + + if (status == BuildingStatus.NotRealized) + { + return GebouwStatus.NietGerealiseerd.ToString(); + } + + if (status == BuildingStatus.Realized) + { + return GebouwStatus.Gerealiseerd.ToString(); + } + + if (status == BuildingStatus.Retired) + { + return GebouwStatus.Gehistoreerd.ToString(); + } + + throw new ArgumentOutOfRangeException(nameof(status), status, null); + } + } + + public static class BuildingGeometryMethodExtensions + { + public static string Map(this BuildingGeometryMethod geometryMethod) + { + if (geometryMethod == BuildingGeometryMethod.Outlined) + { + return GeometrieMethode.Ingeschetst.ToString(); + } + + if (geometryMethod == BuildingGeometryMethod.MeasuredByGrb) + { + return GeometrieMethode.IngemetenGRB.ToString(); + } + + throw new ArgumentOutOfRangeException(nameof(geometryMethod), geometryMethod, null); + } + } +} diff --git a/src/BuildingRegistry.Projections.Integration/Converters/BuildingUnitExtensions.cs b/src/BuildingRegistry.Projections.Integration/Converters/BuildingUnitExtensions.cs new file mode 100644 index 000000000..680ea2e1e --- /dev/null +++ b/src/BuildingRegistry.Projections.Integration/Converters/BuildingUnitExtensions.cs @@ -0,0 +1,71 @@ +namespace BuildingRegistry.Projections.Integration.Converters +{ + using System; + using Be.Vlaanderen.Basisregisters.GrAr.Legacy; + using Be.Vlaanderen.Basisregisters.GrAr.Legacy.Gebouweenheid; + using BuildingRegistry.Building; + + public static class BuildingUnitStatusExtensions + { + public static string Map(this BuildingUnitStatus status) + { + if (BuildingUnitStatus.Planned == status) + { + return GebouweenheidStatus.Gepland.ToString(); + } + + if (BuildingUnitStatus.NotRealized == status) + { + return GebouweenheidStatus.NietGerealiseerd.ToString(); + } + + if (BuildingUnitStatus.Realized == status) + { + return GebouweenheidStatus.Gerealiseerd.ToString(); + } + + if (BuildingUnitStatus.Retired == status) + { + return GebouweenheidStatus.Gehistoreerd.ToString(); + } + + throw new ArgumentOutOfRangeException(nameof(status), status, null); + } + } + + public static class BuildingUnitPositionGeometryMethodExtensions + { + public static string Map(this BuildingUnitPositionGeometryMethod geometryMethod) + { + if (BuildingUnitPositionGeometryMethod.DerivedFromObject == geometryMethod) + { + return PositieGeometrieMethode.AfgeleidVanObject.ToString(); + } + + if (BuildingUnitPositionGeometryMethod.AppointedByAdministrator == geometryMethod) + { + return PositieGeometrieMethode.AangeduidDoorBeheerder.ToString(); + } + + throw new ArgumentOutOfRangeException(nameof(geometryMethod), geometryMethod, null); + } + } + + public static class BuildingUnitFunctionExtensions + { + public static string Map(this BuildingUnitFunction function) + { + if (function == BuildingUnitFunction.Unknown) + { + return GebouweenheidFunctie.NietGekend.ToString(); + } + + if (function == BuildingUnitFunction.Common) + { + return GebouweenheidFunctie.GemeenschappelijkDeel.ToString(); + } + + throw new ArgumentOutOfRangeException(nameof(function), function, null); + } + } +} diff --git a/src/BuildingRegistry.Projections.Integration/Infrastructure/IntegrationModule.cs b/src/BuildingRegistry.Projections.Integration/Infrastructure/IntegrationModule.cs new file mode 100644 index 000000000..51f3081b3 --- /dev/null +++ b/src/BuildingRegistry.Projections.Integration/Infrastructure/IntegrationModule.cs @@ -0,0 +1,62 @@ +namespace BuildingRegistry.Projections.Integration.Infrastructure +{ + using System; + using Autofac; + using BuildingRegistry.Infrastructure; + 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(); + 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 connectionString) + { + services + .AddNpgsql(connectionString, 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/BuildingRegistry.Projections.Integration/Infrastructure/IntegrationOptions.cs b/src/BuildingRegistry.Projections.Integration/Infrastructure/IntegrationOptions.cs new file mode 100644 index 000000000..44e82d62d --- /dev/null +++ b/src/BuildingRegistry.Projections.Integration/Infrastructure/IntegrationOptions.cs @@ -0,0 +1,9 @@ +namespace BuildingRegistry.Projections.Integration.Infrastructure +{ + public class IntegrationOptions + { + public string BuildingNamespace { get; set; } + public string BuildingUnitNamespace { get; set; } + public bool Enabled { get; set; } + } +} diff --git a/src/BuildingRegistry.Projections.Integration/IntegrationContext.cs b/src/BuildingRegistry.Projections.Integration/IntegrationContext.cs new file mode 100644 index 000000000..cfd264d18 --- /dev/null +++ b/src/BuildingRegistry.Projections.Integration/IntegrationContext.cs @@ -0,0 +1,54 @@ +namespace BuildingRegistry.Projections.Integration +{ + using System.Linq; + using System.Threading; + using System.Threading.Tasks; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner; + using Building.LatestItem; + using BuildingRegistry.Infrastructure; + using BuildingUnit.LatestItem; + using Microsoft.EntityFrameworkCore; + using NetTopologySuite.Geometries; + + public class IntegrationContext : RunnerDbContext + { + public override string ProjectionStateSchema => Schema.Integration; + + public DbSet BuildingLatestItems => Set(); + + public DbSet BuildingUnitLatestItems => Set(); + public DbSet BuildingUnitAddresses => Set(); + + private DbSet MunicipalityGeometries => Set(); + + public async Task FindMostIntersectingNisCodeBy(Geometry sysGeometry, CancellationToken ct) + { + var municipalityGeometries = await MunicipalityGeometries + .Where(x => sysGeometry.Intersects(x.Geometry)) + .ToListAsync(ct); + + if (municipalityGeometries.Count > 1) + { + return municipalityGeometries + .Select(x => new + { + MunicipalityGeometry = x, + Intersection = sysGeometry.Intersection(x.Geometry) + }).MaxBy(x => x.Intersection)! + .MunicipalityGeometry + .NisCode; + } + + return municipalityGeometries.Count == 1 + ? municipalityGeometries.Single().NisCode + : null; + } + + // 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/BuildingRegistry.Projections.Integration/IntegrationContextMigrationFactory.cs b/src/BuildingRegistry.Projections.Integration/IntegrationContextMigrationFactory.cs new file mode 100644 index 000000000..1865aa2c3 --- /dev/null +++ b/src/BuildingRegistry.Projections.Integration/IntegrationContextMigrationFactory.cs @@ -0,0 +1,29 @@ +namespace BuildingRegistry.Projections.Integration +{ + using Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.Npgsql; + using Microsoft.EntityFrameworkCore; + using BuildingRegistry.Infrastructure; + 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/BuildingRegistry.Projections.Integration/Migrations/20240115145624_Initial.Designer.cs b/src/BuildingRegistry.Projections.Integration/Migrations/20240115145624_Initial.Designer.cs new file mode 100644 index 000000000..5825afb4a --- /dev/null +++ b/src/BuildingRegistry.Projections.Integration/Migrations/20240115145624_Initial.Designer.cs @@ -0,0 +1,258 @@ +// +using System; +using BuildingRegistry.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 BuildingRegistry.Projections.Integration.Migrations +{ + [DbContext(typeof(IntegrationContext))] + [Migration("20240115145624_Initial")] + partial class Initial + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.ProjectionStates.ProjectionStateItem", b => + { + b.Property("Name") + .HasColumnType("text"); + + b.Property("DesiredState") + .HasColumnType("text"); + + b.Property("DesiredStateChangedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ErrorMessage") + .HasColumnType("text"); + + b.Property("Position") + .HasColumnType("bigint"); + + b.HasKey("Name"); + + b.ToTable("ProjectionStates", "integration_building"); + }); + + modelBuilder.Entity("BuildingRegistry.Projections.Integration.Building.LatestItem.BuildingLatestItem", b => + { + b.Property("BuildingPersistentLocalId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("building_persistent_local_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("BuildingPersistentLocalId")); + + b.Property("Geometry") + .IsRequired() + .HasColumnType("geometry") + .HasColumnName("geometry"); + + b.Property("GeometryMethod") + .IsRequired() + .HasColumnType("text") + .HasColumnName("geometry_method"); + + b.Property("IsRemoved") + .HasColumnType("boolean") + .HasColumnName("is_removed"); + + b.Property("Namespace") + .IsRequired() + .HasColumnType("text") + .HasColumnName("namespace"); + + b.Property("NisCode") + .HasColumnType("text") + .HasColumnName("nis_code"); + + b.Property("OsloGeometryMethod") + .IsRequired() + .HasColumnType("text") + .HasColumnName("oslo_geometry_method"); + + b.Property("OsloStatus") + .IsRequired() + .HasColumnType("text") + .HasColumnName("oslo_status"); + + b.Property("PuriId") + .IsRequired() + .HasColumnType("text") + .HasColumnName("puri_id"); + + b.Property("Status") + .IsRequired() + .HasColumnType("text") + .HasColumnName("status"); + + b.Property("VersionAsString") + .IsRequired() + .HasColumnType("text") + .HasColumnName("version_as_string"); + + b.Property("VersionTimestampAsDateTimeOffset") + .HasColumnType("timestamp with time zone") + .HasColumnName("version_timestamp"); + + b.HasKey("BuildingPersistentLocalId"); + + b.HasIndex("Geometry"); + + NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex("Geometry"), "GIST"); + + b.HasIndex("IsRemoved"); + + b.HasIndex("NisCode"); + + b.HasIndex("OsloStatus"); + + b.HasIndex("Status"); + + b.ToTable("building_latest_items", "integration_building"); + }); + + modelBuilder.Entity("BuildingRegistry.Projections.Integration.Building.LatestItem.MunicipalityGeometry", b => + { + b.Property("Geometry") + .IsRequired() + .HasColumnType("geometry") + .HasColumnName("geometry"); + + b.Property("NisCode") + .IsRequired() + .HasColumnType("text") + .HasColumnName("nis_code"); + + b.ToView("municipality_geometries", "integration_municipality"); + + b.ToSqlQuery("SELECT nis_code, geometry FROM integration_municipality.municipality_geometries"); + }); + + modelBuilder.Entity("BuildingRegistry.Projections.Integration.BuildingUnit.LatestItem.BuildingUnitAddress", b => + { + b.Property("BuildingUnitPersistentLocalId") + .HasColumnType("integer") + .HasColumnName("building_unit_persistent_local_id"); + + b.Property("AddressPersistentLocalId") + .HasColumnType("integer") + .HasColumnName("address_persistent_local_id"); + + b.HasKey("BuildingUnitPersistentLocalId", "AddressPersistentLocalId"); + + b.HasIndex("AddressPersistentLocalId"); + + b.HasIndex("BuildingUnitPersistentLocalId"); + + b.ToTable("building_unit_addresses", "integration_building"); + }); + + modelBuilder.Entity("BuildingRegistry.Projections.Integration.BuildingUnit.LatestItem.BuildingUnitLatestItem", b => + { + b.Property("BuildingUnitPersistentLocalId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("building_unit_persistent_local_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("BuildingUnitPersistentLocalId")); + + b.Property("BuildingPersistentLocalId") + .HasColumnType("integer") + .HasColumnName("building_persistent_local_id"); + + b.Property("Function") + .IsRequired() + .HasColumnType("text") + .HasColumnName("function"); + + b.Property("Geometry") + .IsRequired() + .HasColumnType("geometry") + .HasColumnName("geometry"); + + b.Property("GeometryMethod") + .IsRequired() + .HasColumnType("text") + .HasColumnName("geometry_method"); + + b.Property("HasDeviation") + .HasColumnType("boolean") + .HasColumnName("has_deviation"); + + b.Property("IsRemoved") + .HasColumnType("boolean") + .HasColumnName("is_removed"); + + b.Property("Namespace") + .IsRequired() + .HasColumnType("text") + .HasColumnName("namespace"); + + b.Property("OsloFunction") + .IsRequired() + .HasColumnType("text") + .HasColumnName("oslo_function"); + + b.Property("OsloGeometryMethod") + .IsRequired() + .HasColumnType("text") + .HasColumnName("oslo_geometry_method"); + + b.Property("OsloStatus") + .IsRequired() + .HasColumnType("text") + .HasColumnName("oslo_status"); + + b.Property("PuriId") + .IsRequired() + .HasColumnType("text") + .HasColumnName("puri_id"); + + b.Property("Status") + .IsRequired() + .HasColumnType("text") + .HasColumnName("status"); + + b.Property("VersionAsString") + .IsRequired() + .HasColumnType("text") + .HasColumnName("version_as_string"); + + b.Property("VersionTimestampAsDateTimeOffset") + .HasColumnType("timestamp with time zone") + .HasColumnName("version_timestamp"); + + b.HasKey("BuildingUnitPersistentLocalId"); + + b.HasIndex("BuildingPersistentLocalId"); + + b.HasIndex("Geometry"); + + NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex("Geometry"), "GIST"); + + b.HasIndex("IsRemoved"); + + b.HasIndex("OsloStatus"); + + b.HasIndex("Status"); + + b.ToTable("building_unit_latest_items", "integration_building"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/BuildingRegistry.Projections.Integration/Migrations/20240115145624_Initial.cs b/src/BuildingRegistry.Projections.Integration/Migrations/20240115145624_Initial.cs new file mode 100644 index 000000000..ba3e40606 --- /dev/null +++ b/src/BuildingRegistry.Projections.Integration/Migrations/20240115145624_Initial.cs @@ -0,0 +1,191 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using NetTopologySuite.Geometries; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace BuildingRegistry.Projections.Integration.Migrations +{ + public partial class Initial : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.EnsureSchema( + name: "integration_building"); + + migrationBuilder.CreateTable( + name: "building_latest_items", + schema: "integration_building", + columns: table => new + { + building_persistent_local_id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + status = table.Column(type: "text", nullable: false), + oslo_status = table.Column(type: "text", nullable: false), + geometry_method = table.Column(type: "text", nullable: false), + oslo_geometry_method = table.Column(type: "text", nullable: false), + geometry = table.Column(type: "geometry", nullable: false), + nis_code = table.Column(type: "text", nullable: true), + is_removed = table.Column(type: "boolean", nullable: false), + puri_id = table.Column(type: "text", nullable: false), + @namespace = table.Column(name: "namespace", type: "text", nullable: false), + version_as_string = table.Column(type: "text", nullable: false), + version_timestamp = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_building_latest_items", x => x.building_persistent_local_id); + }); + + migrationBuilder.CreateTable( + name: "building_unit_addresses", + schema: "integration_building", + columns: table => new + { + building_unit_persistent_local_id = table.Column(type: "integer", nullable: false), + address_persistent_local_id = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_building_unit_addresses", x => new { x.building_unit_persistent_local_id, x.address_persistent_local_id }); + }); + + migrationBuilder.CreateTable( + name: "building_unit_latest_items", + schema: "integration_building", + columns: table => new + { + building_unit_persistent_local_id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + building_persistent_local_id = table.Column(type: "integer", nullable: false), + status = table.Column(type: "text", nullable: false), + oslo_status = table.Column(type: "text", nullable: false), + function = table.Column(type: "text", nullable: false), + oslo_function = table.Column(type: "text", nullable: false), + geometry_method = table.Column(type: "text", nullable: false), + oslo_geometry_method = table.Column(type: "text", nullable: false), + geometry = table.Column(type: "geometry", nullable: false), + has_deviation = table.Column(type: "boolean", nullable: false), + is_removed = table.Column(type: "boolean", nullable: false), + puri_id = table.Column(type: "text", nullable: false), + @namespace = table.Column(name: "namespace", type: "text", nullable: false), + version_as_string = table.Column(type: "text", nullable: false), + version_timestamp = table.Column(type: "timestamp with time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_building_unit_latest_items", x => x.building_unit_persistent_local_id); + }); + + migrationBuilder.CreateTable( + name: "ProjectionStates", + schema: "integration_building", + 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_building_latest_items_geometry", + schema: "integration_building", + table: "building_latest_items", + column: "geometry") + .Annotation("Npgsql:IndexMethod", "GIST"); + + migrationBuilder.CreateIndex( + name: "IX_building_latest_items_is_removed", + schema: "integration_building", + table: "building_latest_items", + column: "is_removed"); + + migrationBuilder.CreateIndex( + name: "IX_building_latest_items_nis_code", + schema: "integration_building", + table: "building_latest_items", + column: "nis_code"); + + migrationBuilder.CreateIndex( + name: "IX_building_latest_items_oslo_status", + schema: "integration_building", + table: "building_latest_items", + column: "oslo_status"); + + migrationBuilder.CreateIndex( + name: "IX_building_latest_items_status", + schema: "integration_building", + table: "building_latest_items", + column: "status"); + + migrationBuilder.CreateIndex( + name: "IX_building_unit_addresses_address_persistent_local_id", + schema: "integration_building", + table: "building_unit_addresses", + column: "address_persistent_local_id"); + + migrationBuilder.CreateIndex( + name: "IX_building_unit_addresses_building_unit_persistent_local_id", + schema: "integration_building", + table: "building_unit_addresses", + column: "building_unit_persistent_local_id"); + + migrationBuilder.CreateIndex( + name: "IX_building_unit_latest_items_building_persistent_local_id", + schema: "integration_building", + table: "building_unit_latest_items", + column: "building_persistent_local_id"); + + migrationBuilder.CreateIndex( + name: "IX_building_unit_latest_items_geometry", + schema: "integration_building", + table: "building_unit_latest_items", + column: "geometry") + .Annotation("Npgsql:IndexMethod", "GIST"); + + migrationBuilder.CreateIndex( + name: "IX_building_unit_latest_items_is_removed", + schema: "integration_building", + table: "building_unit_latest_items", + column: "is_removed"); + + migrationBuilder.CreateIndex( + name: "IX_building_unit_latest_items_oslo_status", + schema: "integration_building", + table: "building_unit_latest_items", + column: "oslo_status"); + + migrationBuilder.CreateIndex( + name: "IX_building_unit_latest_items_status", + schema: "integration_building", + table: "building_unit_latest_items", + column: "status"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "building_latest_items", + schema: "integration_building"); + + migrationBuilder.DropTable( + name: "building_unit_addresses", + schema: "integration_building"); + + migrationBuilder.DropTable( + name: "building_unit_latest_items", + schema: "integration_building"); + + migrationBuilder.DropTable( + name: "ProjectionStates", + schema: "integration_building"); + } + } +} diff --git a/src/BuildingRegistry.Projections.Integration/Migrations/IntegrationContextModelSnapshot.cs b/src/BuildingRegistry.Projections.Integration/Migrations/IntegrationContextModelSnapshot.cs new file mode 100644 index 000000000..19738953f --- /dev/null +++ b/src/BuildingRegistry.Projections.Integration/Migrations/IntegrationContextModelSnapshot.cs @@ -0,0 +1,256 @@ +// +using System; +using BuildingRegistry.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 BuildingRegistry.Projections.Integration.Migrations +{ + [DbContext(typeof(IntegrationContext))] + partial class IntegrationContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Be.Vlaanderen.Basisregisters.ProjectionHandling.Runner.ProjectionStates.ProjectionStateItem", b => + { + b.Property("Name") + .HasColumnType("text"); + + b.Property("DesiredState") + .HasColumnType("text"); + + b.Property("DesiredStateChangedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ErrorMessage") + .HasColumnType("text"); + + b.Property("Position") + .HasColumnType("bigint"); + + b.HasKey("Name"); + + b.ToTable("ProjectionStates", "integration_building"); + }); + + modelBuilder.Entity("BuildingRegistry.Projections.Integration.Building.LatestItem.BuildingLatestItem", b => + { + b.Property("BuildingPersistentLocalId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("building_persistent_local_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("BuildingPersistentLocalId")); + + b.Property("Geometry") + .IsRequired() + .HasColumnType("geometry") + .HasColumnName("geometry"); + + b.Property("GeometryMethod") + .IsRequired() + .HasColumnType("text") + .HasColumnName("geometry_method"); + + b.Property("IsRemoved") + .HasColumnType("boolean") + .HasColumnName("is_removed"); + + b.Property("Namespace") + .IsRequired() + .HasColumnType("text") + .HasColumnName("namespace"); + + b.Property("NisCode") + .HasColumnType("text") + .HasColumnName("nis_code"); + + b.Property("OsloGeometryMethod") + .IsRequired() + .HasColumnType("text") + .HasColumnName("oslo_geometry_method"); + + b.Property("OsloStatus") + .IsRequired() + .HasColumnType("text") + .HasColumnName("oslo_status"); + + b.Property("PuriId") + .IsRequired() + .HasColumnType("text") + .HasColumnName("puri_id"); + + b.Property("Status") + .IsRequired() + .HasColumnType("text") + .HasColumnName("status"); + + b.Property("VersionAsString") + .IsRequired() + .HasColumnType("text") + .HasColumnName("version_as_string"); + + b.Property("VersionTimestampAsDateTimeOffset") + .HasColumnType("timestamp with time zone") + .HasColumnName("version_timestamp"); + + b.HasKey("BuildingPersistentLocalId"); + + b.HasIndex("Geometry"); + + NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex("Geometry"), "GIST"); + + b.HasIndex("IsRemoved"); + + b.HasIndex("NisCode"); + + b.HasIndex("OsloStatus"); + + b.HasIndex("Status"); + + b.ToTable("building_latest_items", "integration_building"); + }); + + modelBuilder.Entity("BuildingRegistry.Projections.Integration.Building.LatestItem.MunicipalityGeometry", b => + { + b.Property("Geometry") + .IsRequired() + .HasColumnType("geometry") + .HasColumnName("geometry"); + + b.Property("NisCode") + .IsRequired() + .HasColumnType("text") + .HasColumnName("nis_code"); + + b.ToView("municipality_geometries", "integration_municipality"); + + b.ToSqlQuery("SELECT nis_code, geometry FROM integration_municipality.municipality_geometries"); + }); + + modelBuilder.Entity("BuildingRegistry.Projections.Integration.BuildingUnit.LatestItem.BuildingUnitAddress", b => + { + b.Property("BuildingUnitPersistentLocalId") + .HasColumnType("integer") + .HasColumnName("building_unit_persistent_local_id"); + + b.Property("AddressPersistentLocalId") + .HasColumnType("integer") + .HasColumnName("address_persistent_local_id"); + + b.HasKey("BuildingUnitPersistentLocalId", "AddressPersistentLocalId"); + + b.HasIndex("AddressPersistentLocalId"); + + b.HasIndex("BuildingUnitPersistentLocalId"); + + b.ToTable("building_unit_addresses", "integration_building"); + }); + + modelBuilder.Entity("BuildingRegistry.Projections.Integration.BuildingUnit.LatestItem.BuildingUnitLatestItem", b => + { + b.Property("BuildingUnitPersistentLocalId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("building_unit_persistent_local_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("BuildingUnitPersistentLocalId")); + + b.Property("BuildingPersistentLocalId") + .HasColumnType("integer") + .HasColumnName("building_persistent_local_id"); + + b.Property("Function") + .IsRequired() + .HasColumnType("text") + .HasColumnName("function"); + + b.Property("Geometry") + .IsRequired() + .HasColumnType("geometry") + .HasColumnName("geometry"); + + b.Property("GeometryMethod") + .IsRequired() + .HasColumnType("text") + .HasColumnName("geometry_method"); + + b.Property("HasDeviation") + .HasColumnType("boolean") + .HasColumnName("has_deviation"); + + b.Property("IsRemoved") + .HasColumnType("boolean") + .HasColumnName("is_removed"); + + b.Property("Namespace") + .IsRequired() + .HasColumnType("text") + .HasColumnName("namespace"); + + b.Property("OsloFunction") + .IsRequired() + .HasColumnType("text") + .HasColumnName("oslo_function"); + + b.Property("OsloGeometryMethod") + .IsRequired() + .HasColumnType("text") + .HasColumnName("oslo_geometry_method"); + + b.Property("OsloStatus") + .IsRequired() + .HasColumnType("text") + .HasColumnName("oslo_status"); + + b.Property("PuriId") + .IsRequired() + .HasColumnType("text") + .HasColumnName("puri_id"); + + b.Property("Status") + .IsRequired() + .HasColumnType("text") + .HasColumnName("status"); + + b.Property("VersionAsString") + .IsRequired() + .HasColumnType("text") + .HasColumnName("version_as_string"); + + b.Property("VersionTimestampAsDateTimeOffset") + .HasColumnType("timestamp with time zone") + .HasColumnName("version_timestamp"); + + b.HasKey("BuildingUnitPersistentLocalId"); + + b.HasIndex("BuildingPersistentLocalId"); + + b.HasIndex("Geometry"); + + NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex("Geometry"), "GIST"); + + b.HasIndex("IsRemoved"); + + b.HasIndex("OsloStatus"); + + b.HasIndex("Status"); + + b.ToTable("building_unit_latest_items", "integration_building"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/BuildingRegistry.Projections.Integration/Properties/AssemblyInfo.cs b/src/BuildingRegistry.Projections.Integration/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..d0f36f40e --- /dev/null +++ b/src/BuildingRegistry.Projections.Integration/Properties/AssemblyInfo.cs @@ -0,0 +1,7 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyDescription("BuildingRegistry Integration Projections")] + +[assembly: ComVisible(false)] +[assembly: Guid("9dd11e3e-74fd-4fc9-b86a-59741579e787")] diff --git a/src/BuildingRegistry.Projections.Integration/paket.references b/src/BuildingRegistry.Projections.Integration/paket.references new file mode 100644 index 000000000..32209b3e1 --- /dev/null +++ b/src/BuildingRegistry.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 + +Npgsql.EntityFrameworkCore.PostgreSQL.Design +Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite + +Be.Vlaanderen.Basisregisters.GrAr.Common +Be.Vlaanderen.Basisregisters.GrAr.Legacy + +Dapper + +SourceLink.Embed.AllSourceFiles +SourceLink.Copy.PdbFiles diff --git a/src/BuildingRegistry.Projector/BuildingRegistry.Projector.csproj b/src/BuildingRegistry.Projector/BuildingRegistry.Projector.csproj index e9b3e2a4d..ac900392d 100644 --- a/src/BuildingRegistry.Projector/BuildingRegistry.Projector.csproj +++ b/src/BuildingRegistry.Projector/BuildingRegistry.Projector.csproj @@ -32,6 +32,7 @@ + diff --git a/src/BuildingRegistry.Projector/Infrastructure/Modules/ApiModule.cs b/src/BuildingRegistry.Projector/Infrastructure/Modules/ApiModule.cs index 1552be538..2c3548aca 100755 --- a/src/BuildingRegistry.Projector/Infrastructure/Modules/ApiModule.cs +++ b/src/BuildingRegistry.Projector/Infrastructure/Modules/ApiModule.cs @@ -1,6 +1,5 @@ namespace BuildingRegistry.Projector.Infrastructure.Modules { - using System; using Autofac; using Autofac.Extensions.DependencyInjection; using Be.Vlaanderen.Basisregisters.Api.Exceptions; @@ -19,21 +18,25 @@ namespace BuildingRegistry.Projector.Infrastructure.Modules using BuildingRegistry.Projections.Extract.BuildingExtract; using BuildingRegistry.Projections.Extract.BuildingUnitAddressLinkExtract; using BuildingRegistry.Projections.Extract.BuildingUnitExtract; + using BuildingRegistry.Projections.Integration; + using BuildingRegistry.Projections.Integration.Building.LatestItem; + using BuildingRegistry.Projections.Integration.BuildingUnit.LatestItem; + using BuildingRegistry.Projections.Integration.Infrastructure; using BuildingRegistry.Projections.LastChangedList; using BuildingRegistry.Projections.Legacy; - using BuildingRegistry.Projections.Legacy.BuildingDetail; using BuildingRegistry.Projections.Legacy.BuildingDetailV2; - using BuildingRegistry.Projections.Legacy.BuildingPersistentIdCrabIdMapping; using BuildingRegistry.Projections.Legacy.BuildingSyndication; - using BuildingRegistry.Projections.Legacy.BuildingUnitDetail; using BuildingRegistry.Projections.Legacy.BuildingUnitDetailV2; using BuildingRegistry.Projections.Wfs; using BuildingRegistry.Projections.Wms; + using BuildingRegistry.Projections.Wms.BuildingUnitV2; + using BuildingRegistry.Projections.Wms.BuildingV2; using Microsoft.Data.SqlClient; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; + using LastChangedListContextMigrationFactory = BuildingRegistry.Projections.LastChangedList.LastChangedListContextMigrationFactory; public class ApiModule : Module { @@ -83,6 +86,11 @@ private void RegisterProjectionSetup(ContainerBuilder builder) RegisterLegacyProjectionsV2(builder); RegisterWmsProjectionsV2(builder); RegisterWfsProjectionsV2(builder); + + if (_configuration.GetSection("Integration").GetValue("Enabled", false)) + { + RegisterIntegrationProjections(builder); + } } private void RegisterExtractProjectionsV2(ContainerBuilder builder) @@ -130,7 +138,7 @@ private void RegisterLastChangedProjections(ContainerBuilder builder) _loggerFactory)); builder - .RegisterProjectionMigrator( + .RegisterProjectionMigrator( _configuration, _loggerFactory) .RegisterProjectionMigrator( @@ -184,11 +192,11 @@ private void RegisterWmsProjectionsV2(ContainerBuilder builder) .RegisterProjectionMigrator( _configuration, _loggerFactory) - .RegisterProjections(() => - new BuildingRegistry.Projections.Wms.BuildingV2.BuildingV2Projections(WKBReaderFactory.Create()), + .RegisterProjections(() => + new BuildingV2Projections(WKBReaderFactory.Create()), wmsProjectionSettings) - .RegisterProjections(() => - new BuildingRegistry.Projections.Wms.BuildingUnitV2.BuildingUnitV2Projections(WKBReaderFactory.Create()), + .RegisterProjections(() => + new BuildingUnitV2Projections(WKBReaderFactory.Create()), wmsProjectionSettings); } @@ -216,5 +224,25 @@ private void RegisterWfsProjectionsV2(ContainerBuilder builder) new BuildingRegistry.Projections.Wfs.BuildingUnitV2.BuildingUnitV2Projections(WKBReaderFactory.Create()), wfsProjectionSettings); } + + private void RegisterIntegrationProjections(ContainerBuilder builder) + { + builder + .RegisterModule( + new IntegrationModule( + _configuration, + _services, + _loggerFactory)); + builder + .RegisterProjectionMigrator( + _configuration, + _loggerFactory) + .RegisterProjections( + context => new BuildingLatestItemProjections(context.Resolve>()), + ConnectedProjectionSettings.Default) + .RegisterProjections( + context => new BuildingUnitLatestItemProjections(context.Resolve>()), + ConnectedProjectionSettings.Default); + } } } diff --git a/src/BuildingRegistry.Projector/Infrastructure/Startup.cs b/src/BuildingRegistry.Projector/Infrastructure/Startup.cs index f653be6f4..2add9884f 100755 --- a/src/BuildingRegistry.Projector/Infrastructure/Startup.cs +++ b/src/BuildingRegistry.Projector/Infrastructure/Startup.cs @@ -11,6 +11,7 @@ namespace BuildingRegistry.Projector.Infrastructure using Be.Vlaanderen.Basisregisters.ProjectionHandling.LastChangedList; using Be.Vlaanderen.Basisregisters.Projector.ConnectedProjections; using BuildingRegistry.Projections.Extract; + using BuildingRegistry.Projections.Integration.Infrastructure; using BuildingRegistry.Projections.Legacy; using BuildingRegistry.Projections.Wfs; using BuildingRegistry.Projections.Wms; @@ -94,13 +95,33 @@ public IServiceProvider ConfigureServices(IServiceCollection services) { var connectionStrings = _configuration .GetSection("ConnectionStrings") - .GetChildren(); + .GetChildren() + .ToList(); - foreach (var connectionString in connectionStrings) + if (!_configuration.GetSection("Integration").GetValue("Enabled", false)) + { + connectionStrings = connectionStrings + .Where(x => !x.Key.StartsWith("Integration", StringComparison.OrdinalIgnoreCase)) + .ToList(); + } + + foreach (var connectionString in connectionStrings + .Where(x => !x.Value.Contains("host", StringComparison.OrdinalIgnoreCase))) + { health.AddSqlServer( connectionString.Value, name: $"sqlserver-{connectionString.Key.ToLowerInvariant()}", tags: new[] {DatabaseTag, "sql", "sqlserver"}); + } + + foreach (var connectionString in connectionStrings + .Where(x => x.Value.Contains("host", StringComparison.OrdinalIgnoreCase))) + { + health.AddNpgSql( + connectionString.Value, + name: $"npgsql-{connectionString.Key.ToLowerInvariant()}", + tags: new[] {DatabaseTag, "sql", "npgsql"}); + } health.AddDbContextCheck( $"dbcontext-{nameof(ExtractContext).ToLowerInvariant()}", @@ -125,6 +146,7 @@ public IServiceProvider ConfigureServices(IServiceCollection services) } }) .Configure(_configuration.GetSection("Extract")) + .Configure(_configuration.GetSection("Integration")) .Configure(_configuration.GetSection(FeatureToggleOptions.ConfigurationKey)) .AddSingleton(c => new UseProjectionsV2Toggle(c.GetRequiredService>().Value.UseProjectionsV2)); diff --git a/src/BuildingRegistry.Projector/Projections/ProjectionsController.cs b/src/BuildingRegistry.Projector/Projections/ProjectionsController.cs index 4aea6a9cd..34d89f566 100644 --- a/src/BuildingRegistry.Projector/Projections/ProjectionsController.cs +++ b/src/BuildingRegistry.Projector/Projections/ProjectionsController.cs @@ -21,6 +21,7 @@ public ProjectionsController( RegisterConnectionString(Schema.Legacy, configuration.GetConnectionString("LegacyProjections")); RegisterConnectionString(Schema.Extract, configuration.GetConnectionString("ExtractProjections")); RegisterConnectionString(Schema.Wms, configuration.GetConnectionString("WmsProjections")); + RegisterConnectionString(Schema.Integration, configuration.GetConnectionString("IntegrationProjections")); } } } diff --git a/src/BuildingRegistry.Projector/appsettings.json b/src/BuildingRegistry.Projector/appsettings.json index 6e69d0cff..16cf00837 100755 --- a/src/BuildingRegistry.Projector/appsettings.json +++ b/src/BuildingRegistry.Projector/appsettings.json @@ -12,7 +12,9 @@ "WfsProjections": "Server=(localdb)\\mssqllocaldb;Database=EFProviders.InMemory.BuildingRegistry;Trusted_Connection=True;TrustServerCertificate=True;", "WfsProjectionsAdmin": "Server=(localdb)\\mssqllocaldb;Database=EFProviders.InMemory.BuildingRegistry;Trusted_Connection=True;TrustServerCertificate=True;", "Syndication": "Server=(localdb)\\mssqllocaldb;Database=EFProviders.InMemory.BuildingRegistry;Trusted_Connection=True;TrustServerCertificate=True;", - "ConsumerAddress": "Server=(localdb)\\mssqllocaldb;Database=EFProviders.InMemory.BuildingRegistry;Trusted_Connection=True;TrustServerCertificate=True;" + "ConsumerAddress": "Server=(localdb)\\mssqllocaldb;Database=EFProviders.InMemory.BuildingRegistry;Trusted_Connection=True;TrustServerCertificate=True;", + "IntegrationProjections": ".", + "IntegrationProjectionsAdmin": "." }, "DataDog": { @@ -50,6 +52,12 @@ "DataVlaanderenNamespaceBuildingUnit": "https://data.vlaanderen.be/id/gebouweenheid" }, + "Integration": { + "BuildingNamespace": "https://data.vlaanderen.be/id/gebouw", + "BuildingUnitNamespace": "https://data.vlaanderen.be/id/gebouweenheid", + "Enabled": false + }, + "DistributedLock": { "Region": "eu-west-1", "TableName": "__DistributedLocks__", diff --git a/src/BuildingRegistry.Projector/paket.references b/src/BuildingRegistry.Projector/paket.references index b348639d6..f75974aad 100644 --- a/src/BuildingRegistry.Projector/paket.references +++ b/src/BuildingRegistry.Projector/paket.references @@ -4,7 +4,12 @@ Be.Vlaanderen.Basisregisters.EventHandling.Autofac Be.Vlaanderen.Basisregisters.DataDog.Tracing.Autofac Be.Vlaanderen.Basisregisters.Projector +Npgsql +Npgsql.EntityFrameworkCore.PostgreSQL +Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite + AspNetCore.HealthChecks.SqlServer +AspNetCore.HealthChecks.NpgSql SourceLink.Embed.AllSourceFiles SourceLink.Copy.PdbFiles diff --git a/src/EF.MigrationsHelper/EF.MigrationHelper.csproj b/src/EF.MigrationsHelper/EF.MigrationHelper.csproj index b6f202157..6bb64c316 100644 --- a/src/EF.MigrationsHelper/EF.MigrationHelper.csproj +++ b/src/EF.MigrationsHelper/EF.MigrationHelper.csproj @@ -29,6 +29,7 @@ + diff --git a/src/EF.MigrationsHelper/appsettings.json b/src/EF.MigrationsHelper/appsettings.json index 7d5194ed9..2c8faae1a 100644 --- a/src/EF.MigrationsHelper/appsettings.json +++ b/src/EF.MigrationsHelper/appsettings.json @@ -12,7 +12,8 @@ "BackOffice": "Server=(localdb)\\mssqllocaldb;Database=EFProviders.InMemory.BuildingRegistry;Trusted_Connection=True;", "ProducerProjectionsAdmin": "Server=(localdb)\\mssqllocaldb;Database=EFProviders.InMemory.BuildingRegistry;Trusted_Connection=True;", "BackOfficeProjectionsAdmin": "Server=(localdb)\\mssqllocaldb;Database=EFProviders.InMemory.BuildingRegistry;Trusted_Connection=True;", - "BuildingGrbAdmin": "Server=(localdb)\\mssqllocaldb;Database=EFProviders.InMemory.BuildingRegistry;Trusted_Connection=True;" + "BuildingGrbAdmin": "Server=(localdb)\\mssqllocaldb;Database=EFProviders.InMemory.BuildingRegistry;Trusted_Connection=True;", + "IntegrationProjectionsAdmin": "Host=vbr-integrationdb-test.postgres.database.azure.com;Database=postgres;Username=basisregisters;Password=Rj7Hnudk02zie4eA2N2jkSeIAEflbQe7e6DwN7Dhe9gDAFR7akvfvLVx2KOXo5Pkjd3BFiALyUkcbjoxI29R1zGT3dWhdJDhu0A" }, "Logging": { diff --git a/src/EF.MigrationsHelper/paket.references b/src/EF.MigrationsHelper/paket.references index 2ccd1f4fb..2751ec9c3 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 diff --git a/test/BuildingRegistry.Tests/BuildingRegistry.Tests.csproj b/test/BuildingRegistry.Tests/BuildingRegistry.Tests.csproj index e06103498..001a77ab1 100644 --- a/test/BuildingRegistry.Tests/BuildingRegistry.Tests.csproj +++ b/test/BuildingRegistry.Tests/BuildingRegistry.Tests.csproj @@ -9,6 +9,7 @@ + diff --git a/test/BuildingRegistry.Tests/ProjectionTests/Integration/BuildingLatestItemProjectionsTests.cs b/test/BuildingRegistry.Tests/ProjectionTests/Integration/BuildingLatestItemProjectionsTests.cs new file mode 100644 index 000000000..67301db82 --- /dev/null +++ b/test/BuildingRegistry.Tests/ProjectionTests/Integration/BuildingLatestItemProjectionsTests.cs @@ -0,0 +1,894 @@ +namespace BuildingRegistry.Tests.ProjectionTests.Integration +{ + using System.Collections.Generic; + using System.Threading.Tasks; + using AutoFixture; + using Be.Vlaanderen.Basisregisters.GrAr.Common.Pipes; + using Be.Vlaanderen.Basisregisters.ProjectionHandling.SqlStreamStore; + using Be.Vlaanderen.Basisregisters.Utilities.HexByteConvertor; + using Building; + using Building.Events; + using Fixtures; + using FluentAssertions; + using Microsoft.Extensions.Options; + using NetTopologySuite.IO; + using Projections.Integration.Building.LatestItem; + using Projections.Integration.Converters; + using Projections.Integration.Infrastructure; + using Tests.Legacy.Autofixture; + using Xunit; + + public class BuildingLatestItemProjectionsTests : IntegrationProjectionTest + { + private const string BuildingNamespace = "https://data.vlaanderen.be/id/gebouw"; + private const string BuildingUnitNamespace = "https://data.vlaanderen.be/id/gebouweenheid"; + + private readonly Fixture _fixture; + private readonly WKBReader _wkbReader = WKBReaderFactory.Create(); + + public BuildingLatestItemProjectionsTests() + { + _fixture = new Fixture(); + _fixture.Customize(new InfrastructureCustomization()); + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithBuildingStatus()); + _fixture.Customize(new WithBuildingGeometryMethod()); + _fixture.Customize(new WithValidExtendedWkbPolygon()); + _fixture.Customize(new WithBuildingUnitStatus()); + _fixture.Customize(new WithBuildingUnitFunction()); + _fixture.Customize(new WithBuildingUnitPositionGeometryMethod()); + } + + [Fact] + public async Task WhenBuildingWasMigrated() + { + var buildingWasMigrated = _fixture.Create(); + + var position = _fixture.Create(); + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasMigrated.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + + await Sut + .Given(new Envelope(new Envelope(buildingWasMigrated, metadata))) + .Then(async ct => + { + var buildingLatestItem = await ct.BuildingLatestItems.FindAsync(buildingWasMigrated.BuildingPersistentLocalId); + buildingLatestItem.Should().NotBeNull(); + + buildingLatestItem!.Status.Should().Be(BuildingStatus.Parse(buildingWasMigrated.BuildingStatus).Map()); + buildingLatestItem.OsloStatus.Should().Be(buildingWasMigrated.BuildingStatus); + buildingLatestItem.Geometry.Should().BeEquivalentTo(_wkbReader.Read(buildingWasMigrated.ExtendedWkbGeometry.ToByteArray())); + buildingLatestItem.GeometryMethod.Should().Be(BuildingGeometryMethod.Parse(buildingWasMigrated.GeometryMethod).Map()); + buildingLatestItem.OsloGeometryMethod.Should().Be(buildingWasMigrated.GeometryMethod); + buildingLatestItem.IsRemoved.Should().Be(buildingWasMigrated.IsRemoved); + buildingLatestItem.Namespace.Should().Be(BuildingNamespace); + buildingLatestItem.PuriId.Should().Be($"{BuildingNamespace}/{buildingWasMigrated.BuildingPersistentLocalId}"); + buildingLatestItem.VersionTimestamp.Should().Be(buildingWasMigrated.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingWasPlannedV2() + { + var buildingWasPlannedV2 = _fixture.Create(); + + var position = _fixture.Create(); + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + + await Sut + .Given(new Envelope(new Envelope(buildingWasPlannedV2, metadata))) + .Then(async ct => + { + var buildingLatestItem = await ct.BuildingLatestItems.FindAsync(buildingWasPlannedV2.BuildingPersistentLocalId); + buildingLatestItem.Should().NotBeNull(); + + buildingLatestItem!.Status.Should().Be(BuildingStatus.Planned.Map()); + buildingLatestItem.OsloStatus.Should().Be("Planned"); + buildingLatestItem.Geometry.Should().BeEquivalentTo(_wkbReader.Read(buildingWasPlannedV2.ExtendedWkbGeometry.ToByteArray())); + buildingLatestItem.GeometryMethod.Should().Be(BuildingGeometryMethod.Outlined.Map()); + buildingLatestItem.OsloGeometryMethod.Should().Be("Outlined"); + buildingLatestItem.IsRemoved.Should().BeFalse(); + buildingLatestItem.Namespace.Should().Be(BuildingNamespace); + buildingLatestItem.PuriId.Should().Be($"{BuildingNamespace}/{buildingWasPlannedV2.BuildingPersistentLocalId}"); + buildingLatestItem.VersionTimestamp.Should().Be(buildingWasPlannedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenUnplannedBuildingWasRealizedAndMeasured() + { + var unplannedBuildingWasRealizedAndMeasured = _fixture.Create(); + + var position = _fixture.Create(); + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, unplannedBuildingWasRealizedAndMeasured.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + + await Sut + .Given(new Envelope(new Envelope(unplannedBuildingWasRealizedAndMeasured, metadata))) + .Then(async ct => + { + var buildingLatestItem = + await ct.BuildingLatestItems.FindAsync(unplannedBuildingWasRealizedAndMeasured.BuildingPersistentLocalId); + buildingLatestItem.Should().NotBeNull(); + + buildingLatestItem!.Status.Should().Be(BuildingStatus.Realized.Map()); + buildingLatestItem.OsloStatus.Should().Be("Realized"); + buildingLatestItem.GeometryMethod.Should().Be(BuildingGeometryMethod.MeasuredByGrb.Map()); + buildingLatestItem.OsloGeometryMethod.Should().Be("MeasuredByGrb"); + buildingLatestItem.Geometry.Should() + .BeEquivalentTo(_wkbReader.Read(unplannedBuildingWasRealizedAndMeasured.ExtendedWkbGeometry.ToByteArray())); + buildingLatestItem.IsRemoved.Should().BeFalse(); + buildingLatestItem.Namespace.Should().Be(BuildingNamespace); + buildingLatestItem.PuriId.Should().Be($"{BuildingNamespace}/{unplannedBuildingWasRealizedAndMeasured.BuildingPersistentLocalId}"); + buildingLatestItem.VersionTimestamp.Should().Be(unplannedBuildingWasRealizedAndMeasured.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingUnitWasPlanned() + { + var buildingWasPlannedV2 = _fixture.Create(); + var buildingUnitWasPlannedV2 = _fixture.Create(); + + var position = _fixture.Create(); + var buildingWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given(new Envelope(new Envelope(buildingWasPlannedV2, buildingWasPlannedMetadata)), + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata))) + .Then(async ct => + { + var buildingLatestItem = await ct.BuildingLatestItems.FindAsync(buildingUnitWasPlannedV2.BuildingPersistentLocalId); + buildingLatestItem.Should().NotBeNull(); + + buildingLatestItem!.VersionTimestamp.Should().Be(buildingUnitWasPlannedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenCommonBuildingUnitWasAdded() + { + var buildingWasPlannedV2 = _fixture.Create(); + var commonBuildingUnitWasAddedV2 = _fixture.Create(); + + var position = _fixture.Create(); + var buildingWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var commonBuildingUnitWasAddedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, commonBuildingUnitWasAddedV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given(new Envelope(new Envelope(buildingWasPlannedV2, buildingWasPlannedMetadata)), + new Envelope(new Envelope(commonBuildingUnitWasAddedV2, commonBuildingUnitWasAddedMetadata))) + .Then(async ct => + { + var buildingLatestItem = await ct.BuildingLatestItems.FindAsync(commonBuildingUnitWasAddedV2.BuildingPersistentLocalId); + buildingLatestItem.Should().NotBeNull(); + + buildingLatestItem!.VersionTimestamp.Should().Be(commonBuildingUnitWasAddedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingUnitWasRemovedV2() + { + var position = _fixture.Create(); + + var buildingWasPlannedV2 = _fixture.Create(); + var buildingWasPlannedV2Metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingUnitWasPlannedV2Metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + var buildingUnitWasRemovedV2 = _fixture.Create(); + var buildingUnitWasRemovedV2Metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasRemovedV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 2 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingWasPlannedV2, buildingWasPlannedV2Metadata)), + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedV2Metadata)), + new Envelope(new Envelope(buildingUnitWasRemovedV2, buildingUnitWasRemovedV2Metadata))) + .Then(async ct => + { + var buildingLatestItem = await ct.BuildingLatestItems.FindAsync(buildingUnitWasRemovedV2.BuildingPersistentLocalId); + buildingLatestItem.Should().NotBeNull(); + + buildingLatestItem!.VersionTimestamp.Should().Be(buildingUnitWasRemovedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingUnitRemovalWasCorrected() + { + var position = _fixture.Create(); + + var buildingWasPlannedV2 = _fixture.Create(); + var buildingWasPlannedV2Metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingUnitWasPlannedV2Metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + var buildingUnitWasRemovedV2 = _fixture.Create(); + var buildingUnitWasRemovedV2Metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasRemovedV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 2 } + }; + + var buildingUnitRemovalWasCorrected = _fixture.Create(); + var buildingUnitRemovalWasCorrectedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitRemovalWasCorrected.GetHash() }, + { Envelope.PositionMetadataKey, position + 3 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingWasPlannedV2, buildingWasPlannedV2Metadata)), + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedV2Metadata)), + new Envelope(new Envelope(buildingUnitWasRemovedV2, buildingUnitWasRemovedV2Metadata)), + new Envelope(new Envelope(buildingUnitRemovalWasCorrected, buildingUnitRemovalWasCorrectedMetadata)) + ) + .Then(async ct => + { + var buildingLatestItem = await ct.BuildingLatestItems.FindAsync(buildingUnitRemovalWasCorrected.BuildingPersistentLocalId); + buildingLatestItem.Should().NotBeNull(); + + buildingLatestItem!.IsRemoved.Should().BeFalse(); + buildingLatestItem.VersionTimestamp.Should().Be(buildingUnitRemovalWasCorrected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingOutlineWasChanged() + { + var position = _fixture.Create(); + + var buildingWasPlannedV2 = _fixture.Create(); + var buildingOutlineWasChanged = _fixture.Create(); + + var buildingWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + + var buildingOutlineWasChangedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingOutlineWasChanged.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingWasPlannedV2, buildingWasPlannedMetadata)), + new Envelope(new Envelope(buildingOutlineWasChanged, buildingOutlineWasChangedMetadata))) + .Then(async ct => + { + var buildingLatestItem = await ct.BuildingLatestItems.FindAsync(buildingOutlineWasChanged.BuildingPersistentLocalId); + buildingLatestItem.Should().NotBeNull(); + + buildingLatestItem!.Geometry.Should() + .BeEquivalentTo(_wkbReader.Read(buildingOutlineWasChanged.ExtendedWkbGeometryBuilding.ToByteArray())); + buildingLatestItem.GeometryMethod.Should().Be(BuildingGeometryMethod.Outlined.Map()); + buildingLatestItem.OsloGeometryMethod.Should().Be("Outlined"); + buildingLatestItem.VersionTimestamp.Should().Be(buildingOutlineWasChanged.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingMeasurementWasChanged() + { + var position = _fixture.Create(); + + var buildingWasPlannedV2 = _fixture.Create(); + var buildingOMeasurementWasChanged = _fixture.Create(); + + var buildingWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + + var buildingMeasurementWasChangedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingOMeasurementWasChanged.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingWasPlannedV2, buildingWasPlannedMetadata)), + new Envelope(new Envelope(buildingOMeasurementWasChanged, buildingMeasurementWasChangedMetadata))) + .Then(async ct => + { + var buildingLatestItem = await ct.BuildingLatestItems.FindAsync(buildingOMeasurementWasChanged.BuildingPersistentLocalId); + buildingLatestItem.Should().NotBeNull(); + + buildingLatestItem!.Geometry.Should() + .BeEquivalentTo(_wkbReader.Read(buildingOMeasurementWasChanged.ExtendedWkbGeometryBuilding.ToByteArray())); + buildingLatestItem.GeometryMethod.Should().Be(BuildingGeometryMethod.MeasuredByGrb.Map()); + buildingLatestItem.OsloGeometryMethod.Should().Be("MeasuredByGrb"); + buildingLatestItem.VersionTimestamp.Should().Be(buildingOMeasurementWasChanged.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingBecameUnderConstructionV2() + { + var position = _fixture.Create(); + + var buildingWasPlannedV2 = _fixture.Create(); + var buildingBecameUnderConstructionV2 = _fixture.Create(); + + var buildingWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + + var buildingBecameUnderConstructionMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingBecameUnderConstructionV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingWasPlannedV2, buildingWasPlannedMetadata)), + new Envelope(new Envelope(buildingBecameUnderConstructionV2, + buildingBecameUnderConstructionMetadata))) + .Then(async ct => + { + var buildingLatestItem = await ct.BuildingLatestItems.FindAsync(buildingBecameUnderConstructionV2.BuildingPersistentLocalId); + buildingLatestItem.Should().NotBeNull(); + + buildingLatestItem!.Status.Should().Be(BuildingStatus.UnderConstruction.Map()); + buildingLatestItem.OsloStatus.Should().Be("UnderConstruction"); + buildingLatestItem.VersionTimestamp.Should().Be(buildingBecameUnderConstructionV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingWasCorrectedFromUnderConstructionToPlanned() + { + var buildingWasPlannedV2 = _fixture.Create(); + var buildingWasCorrectedFromUnderConstructionToPlanned = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + + var buildingWasCorrectedToPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasCorrectedFromUnderConstructionToPlanned.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingWasPlannedV2, buildingWasPlannedMetadata)), + new Envelope( + new Envelope(buildingWasCorrectedFromUnderConstructionToPlanned, buildingWasCorrectedToPlannedMetadata))) + .Then(async ct => + { + var buildingLatestItem = + await ct.BuildingLatestItems.FindAsync(buildingWasCorrectedFromUnderConstructionToPlanned.BuildingPersistentLocalId); + buildingLatestItem.Should().NotBeNull(); + + buildingLatestItem!.Status.Should().Be(BuildingStatus.Planned.Map()); + buildingLatestItem.OsloStatus.Should().Be("Planned"); + buildingLatestItem.VersionTimestamp.Should().Be(buildingWasCorrectedFromUnderConstructionToPlanned.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingWasRealizedV2() + { + var buildingWasPlannedV2 = _fixture.Create(); + var buildingWasRealizedV2 = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + + var buildingWasRealizedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasRealizedV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingWasPlannedV2, buildingWasPlannedMetadata)), + new Envelope(new Envelope(buildingWasRealizedV2, buildingWasRealizedMetadata))) + .Then(async ct => + { + var buildingLatestItem = await ct.BuildingLatestItems.FindAsync(buildingWasRealizedV2.BuildingPersistentLocalId); + buildingLatestItem.Should().NotBeNull(); + + buildingLatestItem!.Status.Should().Be(BuildingStatus.Realized.Map()); + buildingLatestItem.OsloStatus.Should().Be("Realized"); + buildingLatestItem.VersionTimestamp.Should().Be(buildingWasRealizedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingWasCorrectedFromRealizedToUnderConstruction() + { + var buildingWasPlannedV2 = _fixture.Create(); + var buildingWasRealizedV2 = _fixture.Create(); + var buildingWasCorrectedFromRealizedToUnderConstruction = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingWasRealizedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasRealizedV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + var buildingWasCorrectedToUnderConstructionMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasCorrectedFromRealizedToUnderConstruction.GetHash() }, + { Envelope.PositionMetadataKey, position + 2 } + }; + + await Sut + .Given( + new Envelope( + new Envelope( + buildingWasPlannedV2, + buildingWasPlannedMetadata)), + new Envelope( + new Envelope( + buildingWasRealizedV2, + buildingWasRealizedMetadata)), + new Envelope( + new Envelope( + buildingWasCorrectedFromRealizedToUnderConstruction, + buildingWasCorrectedToUnderConstructionMetadata))) + .Then(async ct => + { + var buildingLatestItem = await ct.BuildingLatestItems.FindAsync(buildingWasRealizedV2.BuildingPersistentLocalId); + buildingLatestItem.Should().NotBeNull(); + + buildingLatestItem!.Status.Should().Be(BuildingStatus.UnderConstruction.Map()); + buildingLatestItem.OsloStatus.Should().Be("UnderConstruction"); + buildingLatestItem.VersionTimestamp.Should().Be(buildingWasCorrectedFromRealizedToUnderConstruction.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingWasNotRealizedV2() + { + var buildingWasPlannedV2 = _fixture.Create(); + var buildingWasNotRealizedV2 = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingWasNotRealizedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasNotRealizedV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + await Sut + .Given(new Envelope(new Envelope(buildingWasPlannedV2, buildingWasPlannedMetadata)), + new Envelope(new Envelope(buildingWasNotRealizedV2, buildingWasNotRealizedMetadata))) + .Then(async ct => + { + var buildingLatestItem = await ct.BuildingLatestItems.FindAsync(buildingWasNotRealizedV2.BuildingPersistentLocalId); + buildingLatestItem.Should().NotBeNull(); + + buildingLatestItem!.Status.Should().Be(BuildingStatus.NotRealized.Map()); + buildingLatestItem.OsloStatus.Should().Be("NotRealized"); + buildingLatestItem.VersionTimestamp.Should().Be(buildingWasNotRealizedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingWasCorrectedFromNotRealizedToPlanned() + { + var buildingWasPlannedV2 = _fixture.Create(); + var buildingWasNotRealizedV2 = _fixture.Create(); + var buildingWasCorrectedFromNotRealizedToPlanned = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingWasNotRealizedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasNotRealizedV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + var buildingWasCorrectedToPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasCorrectedFromNotRealizedToPlanned.GetHash() }, + { Envelope.PositionMetadataKey, position + 2 } + }; + + await Sut + .Given( + new Envelope( + new Envelope( + buildingWasPlannedV2, + buildingWasPlannedMetadata)), + new Envelope( + new Envelope( + buildingWasNotRealizedV2, + buildingWasNotRealizedMetadata)), + new Envelope( + new Envelope( + buildingWasCorrectedFromNotRealizedToPlanned, + buildingWasCorrectedToPlannedMetadata))) + .Then(async ct => + { + var buildingLatestItem = await ct.BuildingLatestItems.FindAsync(buildingWasNotRealizedV2.BuildingPersistentLocalId); + buildingLatestItem.Should().NotBeNull(); + + buildingLatestItem!.Status.Should().Be(BuildingStatus.Planned.Map()); + buildingLatestItem.OsloStatus.Should().Be("Planned"); + buildingLatestItem.VersionTimestamp.Should().Be(buildingWasCorrectedFromNotRealizedToPlanned.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingWasRemovedV2() + { + var buildingWasPlannedV2 = _fixture.Create(); + var buildingWasRemovedV2 = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingWasRemovedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasRemovedV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope( + new Envelope( + buildingWasPlannedV2, + buildingWasPlannedMetadata)), + new Envelope( + new Envelope( + buildingWasRemovedV2, + buildingWasRemovedMetadata))) + .Then(async ct => + { + var buildingLatestItem = await ct.BuildingLatestItems.FindAsync(buildingWasRemovedV2.BuildingPersistentLocalId); + buildingLatestItem.Should().NotBeNull(); + + buildingLatestItem!.IsRemoved.Should().BeTrue(); + buildingLatestItem.VersionTimestamp.Should().Be(buildingWasRemovedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingWasMeasured() + { + var buildingWasPlannedV2 = _fixture.Create(); + var buildingWasMeasured = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingWasMeasuredMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasMeasured.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given(new Envelope( + new Envelope( + buildingWasPlannedV2, + buildingWasPlannedMetadata)), + new Envelope( + new Envelope( + buildingWasMeasured, + buildingWasMeasuredMetadata))) + .Then(async ct => + { + var buildingLatestItem = await ct.BuildingLatestItems.FindAsync(buildingWasMeasured.BuildingPersistentLocalId); + buildingLatestItem.Should().NotBeNull(); + + buildingLatestItem!.Geometry.Should().BeEquivalentTo(_wkbReader.Read(buildingWasMeasured.ExtendedWkbGeometryBuilding.ToByteArray())); + buildingLatestItem.GeometryMethod.Should().Be(BuildingGeometryMethod.MeasuredByGrb.Map()); + buildingLatestItem.OsloGeometryMethod.Should().Be("MeasuredByGrb"); + buildingLatestItem.VersionTimestamp.Should().Be(buildingWasMeasured.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingMeasurementWasCorrected() + { + var buildingWasPlannedV2 = _fixture.Create(); + var buildingWasMeasured = _fixture.Create(); + var buildingMeasurementWasCorrected = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + await Sut + .Given( + new Envelope( + new Envelope( + buildingWasPlannedV2, + buildingWasPlannedMetadata)), + new Envelope( + new Envelope( + buildingWasMeasured, + new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingMeasurementWasCorrected.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + })), + new Envelope( + new Envelope( + buildingMeasurementWasCorrected, + new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingMeasurementWasCorrected.GetHash() }, + { Envelope.PositionMetadataKey, position + 2 } + }))) + .Then(async ct => + { + var buildingLatestItem = await ct.BuildingLatestItems.FindAsync(buildingMeasurementWasCorrected.BuildingPersistentLocalId); + buildingLatestItem.Should().NotBeNull(); + + buildingLatestItem!.Geometry.Should().BeEquivalentTo(_wkbReader.Read(buildingMeasurementWasCorrected.ExtendedWkbGeometryBuilding.ToByteArray())); + buildingLatestItem.GeometryMethod.Should().Be(BuildingGeometryMethod.MeasuredByGrb.Map()); + buildingLatestItem.OsloGeometryMethod.Should().Be("MeasuredByGrb"); + buildingLatestItem.VersionTimestamp.Should().Be(buildingMeasurementWasCorrected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingWasDemolished() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingWasPlannedV2 = _fixture.Create(); + var buildingWasDemolished = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingWasDemolishedMetdata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasDemolished.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope( + new Envelope( + buildingWasPlannedV2, + buildingWasPlannedMetadata)), + new Envelope( + new Envelope( + buildingWasDemolished, + buildingWasDemolishedMetdata))) + .Then(async ct => + { + var buildingLatestItem = await ct.BuildingLatestItems.FindAsync(buildingWasDemolished.BuildingPersistentLocalId); + buildingLatestItem.Should().NotBeNull(); + + buildingLatestItem!.Status.Should().Be(BuildingStatus.Retired.Map()); + buildingLatestItem.OsloStatus.Should().Be("Retired"); + buildingLatestItem.VersionTimestamp.Should().Be(buildingWasDemolished.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingMergerWasRealized() + { + var buildingMergerWasRealized = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingMergerWasRealizedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingMergerWasRealized.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + + await Sut + .Given( + new Envelope( + new Envelope( + buildingMergerWasRealized, + buildingMergerWasRealizedMetadata))) + .Then(async ct => + { + var buildingLatestItem = await ct.BuildingLatestItems.FindAsync(buildingMergerWasRealized.BuildingPersistentLocalId); + buildingLatestItem.Should().NotBeNull(); + + buildingLatestItem!.BuildingPersistentLocalId.Should().Be(buildingMergerWasRealized.BuildingPersistentLocalId); + buildingLatestItem.Status.Should().Be(BuildingStatus.Realized.Map()); + buildingLatestItem.OsloStatus.Should().Be("Realized"); + buildingLatestItem.Geometry.Should().BeEquivalentTo(_wkbReader.Read(buildingMergerWasRealized.ExtendedWkbGeometry.ToByteArray())); + buildingLatestItem.GeometryMethod.Should().Be(BuildingGeometryMethod.MeasuredByGrb.Map()); + buildingLatestItem.OsloGeometryMethod.Should().Be("MeasuredByGrb"); + buildingLatestItem.VersionTimestamp.Should().Be(buildingMergerWasRealized.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingUnitWasMoved() + { + var buildingWasPlanned = _fixture.Create(); + var buildingUnitWasPlanned = _fixture.Create(); + var buildingUnitWasMoved = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasPlanned.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlanned.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + var buildingUnitWasMovedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasMoved.GetHash() }, + { Envelope.PositionMetadataKey, position + 2 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingWasPlanned, buildingWasPlannedMetadata)), + new Envelope(new Envelope(buildingUnitWasPlanned, buildingUnitWasPlannedMetadata)), + new Envelope(new Envelope(buildingUnitWasMoved, buildingUnitWasMovedMetadata))) + .Then(async ct => + { + var buildingLatestItem = await ct.BuildingLatestItems.FindAsync(buildingUnitWasMoved.BuildingPersistentLocalId); + buildingLatestItem.Should().NotBeNull(); + + buildingLatestItem!.BuildingPersistentLocalId.Should().Be(buildingUnitWasMoved.BuildingPersistentLocalId); + buildingLatestItem.VersionTimestamp.Should().Be(buildingUnitWasMoved.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingWasMerged() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + + var buildingWasPlanned = _fixture.Create(); + var buildingWasMerged = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasPlanned.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingWasMergedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasMerged.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope( + new Envelope( + buildingWasPlanned, + buildingWasPlannedMetadata)), + new Envelope( + new Envelope( + buildingWasMerged, + buildingWasMergedMetadata))) + .Then(async ct => + { + var buildingLatestItem = await ct.BuildingLatestItems.FindAsync(buildingWasMerged.BuildingPersistentLocalId); + buildingLatestItem.Should().NotBeNull(); + + buildingLatestItem!.Status.Should().Be(BuildingStatus.Retired.Map()); + buildingLatestItem.OsloStatus.Should().Be("Retired"); + buildingLatestItem.VersionTimestamp.Should().Be(buildingWasMerged.Provenance.Timestamp); + }); + } + + protected override BuildingLatestItemProjections CreateProjection() => + new BuildingLatestItemProjections(new OptionsWrapper(new IntegrationOptions + { + BuildingNamespace = BuildingNamespace, + BuildingUnitNamespace = BuildingUnitNamespace + })); + } +} diff --git a/test/BuildingRegistry.Tests/ProjectionTests/Integration/BuildingUnitLatestItemProjectionsTests.cs b/test/BuildingRegistry.Tests/ProjectionTests/Integration/BuildingUnitLatestItemProjectionsTests.cs new file mode 100644 index 000000000..01117ea34 --- /dev/null +++ b/test/BuildingRegistry.Tests/ProjectionTests/Integration/BuildingUnitLatestItemProjectionsTests.cs @@ -0,0 +1,1491 @@ +namespace BuildingRegistry.Tests.ProjectionTests.Integration +{ + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + 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 Building; + using Building.Events; + using Extensions; + using Fixtures; + using FluentAssertions; + using Microsoft.Extensions.Options; + using NetTopologySuite.IO; + using Projections.Integration.BuildingUnit.LatestItem; + using Projections.Integration.Converters; + using Projections.Integration.Infrastructure; + using Tests.Legacy.Autofixture; + using Xunit; + + public class BuildingUnitLatestItemProjectionsTests : IntegrationProjectionTest + { + private const string BuildingNamespace = "https://data.vlaanderen.be/id/gebouw"; + private const string BuildingUnitNamespace = "https://data.vlaanderen.be/id/gebouweenheid"; + + private readonly Fixture _fixture; + private readonly WKBReader _wkbReader = WKBReaderFactory.Create(); + + public BuildingUnitLatestItemProjectionsTests() + { + _fixture = new Fixture(); + _fixture.Customizations.Add(new WithUniqueInteger()); + _fixture.Customize(new InfrastructureCustomization()); + _fixture.Customize(new WithBuildingStatus()); + _fixture.Customize(new WithBuildingGeometryMethod()); + _fixture.Customize(new WithValidExtendedWkbPolygon()); + _fixture.Customize(new WithBuildingUnitStatus()); + _fixture.Customize(new WithBuildingUnitFunction()); + _fixture.Customize(new WithBuildingUnitPositionGeometryMethod()); + } + + [Theory] + [InlineData("Planned")] + [InlineData("UnderConstruction")] + [InlineData("Realized")] + [InlineData("Retired")] + [InlineData("NotRealized")] + public async Task WhenBuildingWasMigrated(string buildingStatus) + { + _fixture.Register(() => BuildingStatus.Parse(buildingStatus)); + + var buildingWasMigrated = _fixture.Create(); + + var position = _fixture.Create(); + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasMigrated.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + + await Sut + .Given(new Envelope(new Envelope(buildingWasMigrated, metadata))) + .Then(context => + { + var buildingUnits = context.BuildingUnitLatestItems + .Where(x => x.BuildingPersistentLocalId == buildingWasMigrated.BuildingPersistentLocalId) + .ToList(); + + foreach (var buildingUnit in buildingWasMigrated.BuildingUnits) + { + var buildingUnitLatestItem = buildingUnits + .Single(x => x.BuildingUnitPersistentLocalId == buildingUnit.BuildingUnitPersistentLocalId); + + buildingUnitLatestItem.BuildingPersistentLocalId.Should().Be(buildingWasMigrated.BuildingPersistentLocalId); + buildingUnitLatestItem.Status.Should().Be(BuildingUnitStatus.Parse(buildingUnit.Status).Map()); + buildingUnitLatestItem.OsloStatus.Should().Be(buildingUnit.Status); + buildingUnitLatestItem.Function.Should().Be(BuildingUnitFunction.Parse(buildingUnit.Function).Map()); + buildingUnitLatestItem.OsloFunction.Should().Be(buildingUnit.Function); + buildingUnitLatestItem.GeometryMethod.Should() + .Be(BuildingUnitPositionGeometryMethod.Parse(buildingUnit.GeometryMethod).Map()); + buildingUnitLatestItem.Geometry.Should().BeEquivalentTo(_wkbReader.Read(buildingUnit.ExtendedWkbGeometry.ToByteArray())); + buildingUnitLatestItem.HasDeviation.Should().BeFalse(); + buildingUnitLatestItem.IsRemoved.Should().Be(buildingUnit.IsRemoved); + buildingUnitLatestItem.Namespace.Should().Be(BuildingUnitNamespace); + buildingUnitLatestItem.PuriId.Should().Be($"{BuildingUnitNamespace}/{buildingUnitLatestItem.BuildingUnitPersistentLocalId}"); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingWasMigrated.Provenance.Timestamp); + + var buildingUnitAddresses = context.BuildingUnitAddresses + .Where(x => x.BuildingUnitPersistentLocalId == buildingUnitLatestItem.BuildingUnitPersistentLocalId) + .ToList(); + + buildingUnitAddresses.Should().HaveCount(buildingUnit.AddressPersistentLocalIds.Count); + foreach (var addressPersistentLocalId in buildingUnit.AddressPersistentLocalIds) + { + buildingUnitAddresses.SingleOrDefault(x => x.AddressPersistentLocalId == addressPersistentLocalId) + .Should().NotBeNull(); + } + } + + return Task.CompletedTask; + }); + } + + [Fact] + public async Task WhenBuildingOutlineWasChanged() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingOutlineWasChanged = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingOutLineWasChangedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingOutlineWasChanged.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope(new Envelope(buildingOutlineWasChanged, buildingOutLineWasChangedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitWasPlannedV2.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.GeometryMethod.Should().Be(BuildingUnitPositionGeometryMethod.DerivedFromObject.Map()); + buildingUnitLatestItem.Geometry.Should().BeEquivalentTo( + _wkbReader.Read(buildingOutlineWasChanged.ExtendedWkbGeometryBuildingUnits!.ToByteArray())); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingOutlineWasChanged.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingWasMeasured() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingWasMeasured = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingWasMeasuredMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingWasMeasured.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope(new Envelope(buildingWasMeasured, buildingWasMeasuredMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitWasPlannedV2.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.GeometryMethod.Should().Be(BuildingUnitPositionGeometryMethod.DerivedFromObject.Map()); + buildingUnitLatestItem.Geometry.Should().BeEquivalentTo( + _wkbReader.Read(buildingWasMeasured.ExtendedWkbGeometryBuildingUnits!.ToByteArray())); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingWasMeasured.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingMeasurementWasCorrected() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingMeasurementWasCorrected = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingMeasurementWasCorrectedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingMeasurementWasCorrected.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope(new Envelope(buildingMeasurementWasCorrected, buildingMeasurementWasCorrectedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitWasPlannedV2.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.GeometryMethod.Should().Be(BuildingUnitPositionGeometryMethod.DerivedFromObject.Map()); + buildingUnitLatestItem.Geometry.Should() + .BeEquivalentTo(_wkbReader.Read(buildingMeasurementWasCorrected.ExtendedWkbGeometryBuildingUnits!.ToByteArray())); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingMeasurementWasCorrected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingMeasurementWasChanged() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingMeasurementWasChanged = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingMeasurementWasChangedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingMeasurementWasChanged.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope(new Envelope(buildingMeasurementWasChanged, buildingMeasurementWasChangedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = await context.BuildingUnitLatestItems.FindAsync(buildingUnitWasPlannedV2 + .BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.GeometryMethod.Should().Be(BuildingUnitPositionGeometryMethod.DerivedFromObject.Map()); + buildingUnitLatestItem.Geometry.Should().BeEquivalentTo( + _wkbReader.Read(buildingMeasurementWasChanged.ExtendedWkbGeometryBuildingUnits!.ToByteArray())); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingMeasurementWasChanged.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingUnitWasPlannedV2() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + + var position = _fixture.Create(); + var metadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + + await Sut + .Given(new Envelope(new Envelope(buildingUnitWasPlannedV2, metadata))) + .Then(async context => + { + var buildingUnitLatestItem = await context.BuildingUnitLatestItems.FindAsync(buildingUnitWasPlannedV2.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.BuildingPersistentLocalId.Should().Be(buildingUnitWasPlannedV2.BuildingPersistentLocalId); + buildingUnitLatestItem.Geometry.Should().BeEquivalentTo( + _wkbReader.Read(buildingUnitWasPlannedV2.ExtendedWkbGeometry.ToByteArray())); + buildingUnitLatestItem.GeometryMethod.Should() + .Be(BuildingUnitPositionGeometryMethod.Parse(buildingUnitWasPlannedV2.GeometryMethod).Map()); + buildingUnitLatestItem.Function.Should().Be(BuildingUnitFunction.Parse(buildingUnitWasPlannedV2.Function).Map()); + buildingUnitLatestItem.OsloFunction.Should().Be(buildingUnitWasPlannedV2.Function); + buildingUnitLatestItem.Status.Should().Be(BuildingUnitStatus.Planned.Map()); + buildingUnitLatestItem.OsloStatus.Should().Be("Planned"); + buildingUnitLatestItem.HasDeviation.Should().Be(buildingUnitWasPlannedV2.HasDeviation); + buildingUnitLatestItem.IsRemoved.Should().BeFalse(); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingUnitWasPlannedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingUnitWasRealizedV2() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingUnitWasRealizedV2 = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitWasRealizedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasRealizedV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope(new Envelope(buildingUnitWasRealizedV2, buildingUnitWasRealizedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitWasRealizedV2.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.Status.Should().Be(BuildingUnitStatus.Realized.Map()); + buildingUnitLatestItem.OsloStatus.Should().Be("Realized"); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingUnitWasRealizedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingUnitWasRealizedBecauseBuildingWasRealized() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingUnitWasRealized = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitWasRealizedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasRealized.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope(new Envelope(buildingUnitWasRealized, buildingUnitWasRealizedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitWasRealized.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.Status.Should().Be(BuildingUnitStatus.Realized.Map()); + buildingUnitLatestItem.OsloStatus.Should().Be("Realized"); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingUnitWasRealized.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingUnitWasCorrectedFromRealizedToPlanned() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingUnitWasRealizedV2 = _fixture.Create(); + var buildingUnitWasCorrectedFromRealizedToPlanned = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitWasRealizedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasRealizedV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + var buildingUnitWasCorrectedToPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasCorrectedFromRealizedToPlanned.GetHash() }, + { Envelope.PositionMetadataKey, position + 2 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope(new Envelope(buildingUnitWasRealizedV2, buildingUnitWasRealizedMetadata)), + new Envelope( + new Envelope(buildingUnitWasCorrectedFromRealizedToPlanned, buildingUnitWasCorrectedToPlannedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitWasCorrectedFromRealizedToPlanned.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.Status.Should().Be(BuildingUnitStatus.Planned.Map()); + buildingUnitLatestItem.OsloStatus.Should().Be("Planned"); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingUnitWasCorrectedFromRealizedToPlanned.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingUnitWasCorrectedFromRealizedToPlannedBecauseBuildingWasCorrected() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingUnitWasRealizedV2 = _fixture.Create(); + var buildingUnitWasCorrectedToPlanned = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitWasRealizedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasRealizedV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + var buildingUnitWasCorrectedToPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasCorrectedToPlanned.GetHash() }, + { Envelope.PositionMetadataKey, position + 2 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope(new Envelope(buildingUnitWasRealizedV2, buildingUnitWasRealizedMetadata)), + new Envelope( + new Envelope(buildingUnitWasCorrectedToPlanned, buildingUnitWasCorrectedToPlannedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitWasCorrectedToPlanned.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.Status.Should().Be(BuildingUnitStatus.Planned.Map()); + buildingUnitLatestItem.OsloStatus.Should().Be("Planned"); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingUnitWasCorrectedToPlanned.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingUnitWasNotRealizedV2() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingUnitWasNotRealizedV2 = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitWasNotRealizedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasNotRealizedV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope(new Envelope(buildingUnitWasNotRealizedV2, buildingUnitWasNotRealizedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitWasNotRealizedV2.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.Status.Should().Be(BuildingUnitStatus.NotRealized.Map()); + buildingUnitLatestItem.OsloStatus.Should().Be("NotRealized"); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingUnitWasNotRealizedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingUnitWasNotRealizedBecauseBuildingWasNotRealized() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingUnitWasNotRealized = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitWasNotRealizedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasNotRealized.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope( + new Envelope(buildingUnitWasNotRealized, buildingUnitWasNotRealizedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitWasNotRealized.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.Status.Should().Be(BuildingUnitStatus.NotRealized.Map()); + buildingUnitLatestItem.OsloStatus.Should().Be("NotRealized"); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingUnitWasNotRealized.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingUnitWasCorrectedFromNotRealizedToPlanned() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingUnitWasNotRealizedV2 = _fixture.Create(); + var buildingUnitWasCorrectedToPlanned = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitWasNotRealizedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasNotRealizedV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + var buildingUnitWasCorrectedToPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasCorrectedToPlanned.GetHash() }, + { Envelope.PositionMetadataKey, position + 2 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope(new Envelope(buildingUnitWasNotRealizedV2, buildingUnitWasNotRealizedMetadata)), + new Envelope( + new Envelope(buildingUnitWasCorrectedToPlanned, buildingUnitWasCorrectedToPlannedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitWasCorrectedToPlanned.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.Status.Should().Be(BuildingUnitStatus.Planned.Map()); + buildingUnitLatestItem.OsloStatus.Should().Be("Planned"); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingUnitWasCorrectedToPlanned.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingUnitWasRetiredV2() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingUnitWasRealizedV2 = _fixture.Create(); + var buildingUnitWasRetiredV2 = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitWasRealizedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasRealizedV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + var buildingUnitWasRetiredMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasRetiredV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 2 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope(new Envelope(buildingUnitWasRealizedV2, buildingUnitWasRealizedMetadata)), + new Envelope(new Envelope(buildingUnitWasRetiredV2, buildingUnitWasRetiredMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitWasRetiredV2.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.Status.Should().Be(BuildingUnitStatus.Retired.Map()); + buildingUnitLatestItem.OsloStatus.Should().Be("Retired"); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingUnitWasRetiredV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingUnitWasCorrectedFromRetiredToRealized() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingUnitWasRetiredV2 = _fixture.Create(); + var buildingUnitWasCorrectedToRealized = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitWasRetiredMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasRetiredV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + var buildingUnitWasCorrectedToRealizedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasCorrectedToRealized.GetHash() }, + { Envelope.PositionMetadataKey, position + 2 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope(new Envelope(buildingUnitWasRetiredV2, buildingUnitWasRetiredMetadata)), + new Envelope( + new Envelope(buildingUnitWasCorrectedToRealized, buildingUnitWasCorrectedToRealizedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitWasCorrectedToRealized.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.Status.Should().Be(BuildingUnitStatus.Realized.Map()); + buildingUnitLatestItem.OsloStatus.Should().Be("Realized"); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingUnitWasCorrectedToRealized.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingUnitPositionWasCorrected() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingUnitPositionWasCorrected = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitPositionWasCorrectedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitPositionWasCorrected.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope(new Envelope(buildingUnitPositionWasCorrected, buildingUnitPositionWasCorrectedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitPositionWasCorrected.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.BuildingPersistentLocalId.Should().Be(buildingUnitPositionWasCorrected.BuildingPersistentLocalId); + buildingUnitLatestItem.Geometry.Should().BeEquivalentTo( + _wkbReader.Read(buildingUnitPositionWasCorrected.ExtendedWkbGeometry.ToByteArray())); + buildingUnitLatestItem.GeometryMethod.Should() + .Be(BuildingUnitPositionGeometryMethod.Parse(buildingUnitPositionWasCorrected.GeometryMethod).Map()); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingUnitPositionWasCorrected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingUnitWasRemovedV2() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingUnitWasRemovedV2 = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitWasRemovedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasRemovedV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope(new Envelope(buildingUnitWasRemovedV2, buildingUnitWasRemovedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitWasRemovedV2.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.IsRemoved.Should().BeTrue(); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingUnitWasRemovedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingUnitWasRemovedBecauseBuildingWasRemoved() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingUnitWasRemoved = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitWasRemovedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasRemoved.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope(new Envelope(buildingUnitWasRemoved, buildingUnitWasRemovedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitWasRemoved.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.IsRemoved.Should().BeTrue(); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingUnitWasRemoved.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingUnitRemovalWasCorrected() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingUnitWasRemovedV2 = _fixture.Create(); + var buildingUnitRemovalWasCorrected = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitWasRemovedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasRemovedV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + var buildingUnitRemovalWasCorrectedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitRemovalWasCorrected.GetHash() }, + { Envelope.PositionMetadataKey, position + 2 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope(new Envelope(buildingUnitWasRemovedV2, buildingUnitWasRemovedMetadata)), + new Envelope(new Envelope(buildingUnitRemovalWasCorrected, buildingUnitRemovalWasCorrectedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitRemovalWasCorrected.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.Status.Should().Be(BuildingUnitStatus.Parse(buildingUnitRemovalWasCorrected.BuildingUnitStatus).Map()); + buildingUnitLatestItem.OsloStatus.Should().Be(buildingUnitRemovalWasCorrected.BuildingUnitStatus); + buildingUnitLatestItem.Function.Should().Be(BuildingUnitFunction.Parse(buildingUnitRemovalWasCorrected.Function).Map()); + buildingUnitLatestItem.OsloFunction.Should().Be(buildingUnitRemovalWasCorrected.Function); + buildingUnitLatestItem.Geometry.Should().BeEquivalentTo( + _wkbReader.Read(buildingUnitRemovalWasCorrected.ExtendedWkbGeometry.ToByteArray())); + buildingUnitLatestItem.GeometryMethod.Should() + .Be(BuildingUnitPositionGeometryMethod.Parse(buildingUnitRemovalWasCorrected.GeometryMethod).Map()); + buildingUnitLatestItem.HasDeviation.Should().Be(buildingUnitRemovalWasCorrected.HasDeviation); + buildingUnitLatestItem.IsRemoved.Should().BeFalse(); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingUnitRemovalWasCorrected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingUnitWasRegularized() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create().WithDeviation(true); + var buildingUnitWasRegularized = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitWasRegularizedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasRegularized.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope(new Envelope(buildingUnitWasRegularized, buildingUnitWasRegularizedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitWasRegularized.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.HasDeviation.Should().BeFalse(); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingUnitWasRegularized.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingUnitRegularizationWasCorrected() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create().WithDeviation(false); + var buildingUnitRegularizationWasCorrected = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitRegularizationWasCorrectedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitRegularizationWasCorrected.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope( + new Envelope(buildingUnitRegularizationWasCorrected, buildingUnitRegularizationWasCorrectedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitRegularizationWasCorrected.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.HasDeviation.Should().BeTrue(); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingUnitRegularizationWasCorrected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingUnitWasDeregulated() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create().WithDeviation(false); + var buildingUnitWasDeregulated = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitWasDeregulatedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasDeregulated.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope(new Envelope(buildingUnitWasDeregulated, buildingUnitWasDeregulatedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitWasDeregulated.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.HasDeviation.Should().BeTrue(); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingUnitWasDeregulated.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingUnitDeregulationWasCorrected() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create().WithDeviation(true); + var buildingUnitDeregulationWasCorrected = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitDeregulationWasCorrectedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitDeregulationWasCorrected.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope( + new Envelope(buildingUnitDeregulationWasCorrected, buildingUnitDeregulationWasCorrectedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitDeregulationWasCorrected.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.HasDeviation.Should().BeFalse(); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingUnitDeregulationWasCorrected.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenCommonBuildingUnitWasAddedV2() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var commonBuildingUnitWasAddedV2 = new CommonBuildingUnitWasAddedV2( + _fixture.Create(), + _fixture.Create(), + BuildingUnitStatus.Planned, + BuildingUnitPositionGeometryMethod.DerivedFromObject, + _fixture.Create(), + false); + ((ISetProvenance)commonBuildingUnitWasAddedV2).SetProvenance(_fixture.Create()); + + var position = _fixture.Create(); + + var commonBuildingUnitWasAddedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, commonBuildingUnitWasAddedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + + await Sut + .Given(new Envelope(new Envelope(commonBuildingUnitWasAddedV2, commonBuildingUnitWasAddedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = await context.BuildingUnitLatestItems.FindAsync(commonBuildingUnitWasAddedV2 + .BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.BuildingPersistentLocalId.Should().Be(commonBuildingUnitWasAddedV2.BuildingPersistentLocalId); + buildingUnitLatestItem.Geometry.Should().BeEquivalentTo( + _wkbReader.Read(commonBuildingUnitWasAddedV2.ExtendedWkbGeometry.ToByteArray())); + buildingUnitLatestItem.GeometryMethod.Should() + .Be(BuildingUnitPositionGeometryMethod.Parse(commonBuildingUnitWasAddedV2.GeometryMethod).Map()); + buildingUnitLatestItem.Function.Should().Be(BuildingUnitFunction.Common.Map()); + buildingUnitLatestItem.OsloFunction.Should().Be(BuildingUnitFunction.Common.Function); + buildingUnitLatestItem.Status.Should().Be(BuildingUnitStatus.Parse(commonBuildingUnitWasAddedV2.BuildingUnitStatus).Map()); + buildingUnitLatestItem.OsloStatus.Should().Be(commonBuildingUnitWasAddedV2.BuildingUnitStatus); + buildingUnitLatestItem.HasDeviation.Should().Be(commonBuildingUnitWasAddedV2.HasDeviation); + buildingUnitLatestItem.IsRemoved.Should().BeFalse(); + buildingUnitLatestItem.VersionTimestamp.Should().Be(commonBuildingUnitWasAddedV2.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingUnitAddressWasAttachedV2() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingUnitAddressWasAttachedV2 = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitAddressWasAttachedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitAddressWasAttachedV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope(new Envelope(buildingUnitAddressWasAttachedV2, buildingUnitAddressWasAttachedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitAddressWasAttachedV2.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.VersionTimestamp.Should().Be(buildingUnitAddressWasAttachedV2.Provenance.Timestamp); + + var buildingUnitAddresses = context.BuildingUnitAddresses + .Where(x => x.BuildingUnitPersistentLocalId == buildingUnitLatestItem.BuildingUnitPersistentLocalId) + .ToList(); + buildingUnitAddresses.Should().HaveCount(1); + buildingUnitAddresses.Single().AddressPersistentLocalId.Should().Be(buildingUnitAddressWasAttachedV2.AddressPersistentLocalId); + }); + } + + [Fact] + public async Task WhenBuildingUnitAddressWasDetachedV2() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + _fixture.Customize(new WithFixedAddressPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingUnitAddressWasAttached = _fixture.Create(); + var buildingUnitAddressWasDetachedV2 = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitAddressWasAttachedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitAddressWasAttached.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + var buildingUnitAddressWasDetachedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitAddressWasDetachedV2.GetHash() }, + { Envelope.PositionMetadataKey, position + 2 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope(new Envelope(buildingUnitAddressWasAttached, buildingUnitAddressWasAttachedMetadata)), + new Envelope(new Envelope(buildingUnitAddressWasDetachedV2, buildingUnitAddressWasDetachedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitAddressWasDetachedV2.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.VersionTimestamp.Should().Be(buildingUnitAddressWasDetachedV2.Provenance.Timestamp); + + var buildingUnitAddresses = context.BuildingUnitAddresses + .Where(x => x.BuildingUnitPersistentLocalId == buildingUnitLatestItem.BuildingUnitPersistentLocalId) + .ToList(); + buildingUnitAddresses.Should().BeEmpty(); + }); + } + + [Fact] + public async Task WhenBuildingUnitAddressWasDetachedBecauseAddressWasRetired() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + _fixture.Customize(new WithFixedAddressPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingUnitAddressWasAttached = _fixture.Create(); + var buildingUnitAddressWasDetached = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitAddressWasAttachedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitAddressWasAttached.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + var buildingUnitAddressWasDetachedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitAddressWasDetached.GetHash() }, + { Envelope.PositionMetadataKey, position + 2 } + }; + + await Sut + .Given( + new Envelope( + new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope( + new Envelope(buildingUnitAddressWasAttached, buildingUnitAddressWasAttachedMetadata)), + new Envelope( + new Envelope(buildingUnitAddressWasDetached, buildingUnitAddressWasDetachedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitAddressWasDetached.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.VersionTimestamp.Should().Be(buildingUnitAddressWasDetached.Provenance.Timestamp); + + var buildingUnitAddresses = context.BuildingUnitAddresses + .Where(x => x.BuildingUnitPersistentLocalId == buildingUnitLatestItem.BuildingUnitPersistentLocalId) + .ToList(); + buildingUnitAddresses.Should().BeEmpty(); + }); + } + + [Fact] + public async Task WhenBuildingUnitAddressWasDetachedBecauseAddressWasRejected() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + _fixture.Customize(new WithFixedAddressPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingUnitAddressWasAttached = _fixture.Create(); + var buildingUnitAddressWasDetached = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitAddressWasAttachedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitAddressWasAttached.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + var buildingUnitAddressWasDetachedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitAddressWasDetached.GetHash() }, + { Envelope.PositionMetadataKey, position + 2 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope( + new Envelope(buildingUnitAddressWasAttached, buildingUnitAddressWasAttachedMetadata)), + new Envelope( + new Envelope(buildingUnitAddressWasDetached, buildingUnitAddressWasDetachedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitAddressWasDetached.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.VersionTimestamp.Should().Be(buildingUnitAddressWasDetached.Provenance.Timestamp); + + var buildingUnitAddresses = context.BuildingUnitAddresses + .Where(x => x.BuildingUnitPersistentLocalId == buildingUnitLatestItem.BuildingUnitPersistentLocalId) + .ToList(); + buildingUnitAddresses.Should().BeEmpty(); + }); + } + + [Fact] + public async Task WhenBuildingUnitAddressWasDetachedBecauseAddressWasRemoved() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + _fixture.Customize(new WithFixedAddressPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingUnitAddressWasAttached = _fixture.Create(); + var buildingUnitAddressWasDetached = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitAddressWasAttachedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitAddressWasAttached.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + var buildingUnitAddressWasDetachedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitAddressWasDetached.GetHash() }, + { Envelope.PositionMetadataKey, position + 2 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope( + new Envelope(buildingUnitAddressWasAttached, buildingUnitAddressWasAttachedMetadata)), + new Envelope( + new Envelope(buildingUnitAddressWasDetached, buildingUnitAddressWasDetachedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitAddressWasDetached.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.VersionTimestamp.Should().Be(buildingUnitAddressWasDetached.Provenance.Timestamp); + + var buildingUnitAddresses = context.BuildingUnitAddresses + .Where(x => x.BuildingUnitPersistentLocalId == buildingUnitLatestItem.BuildingUnitPersistentLocalId) + .ToList(); + buildingUnitAddresses.Should().BeEmpty(); + }); + } + + [Fact] + public async Task WhenBuildingUnitAddressWasReplacedBecauseAddressWasReaddressed() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + _fixture.Customize(new WithFixedAddressPersistentLocalId()); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingUnitAddressWasAttached = _fixture.Create(); + var buildingUnitAddressWasReplacedBecauseAddressWasReaddressed = new BuildingUnitAddressWasReplacedBecauseAddressWasReaddressed( + _fixture.Create(), + _fixture.Create(), + new AddressPersistentLocalId(buildingUnitAddressWasAttached.AddressPersistentLocalId), + new AddressPersistentLocalId(buildingUnitAddressWasAttached.AddressPersistentLocalId + 1)); + ((ISetProvenance)buildingUnitAddressWasReplacedBecauseAddressWasReaddressed).SetProvenance(_fixture.Create()); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitAddressWasAttachedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitAddressWasAttached.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + var buildingUnitAddressWasReplacedBecauseAddressWasReaddressedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitAddressWasReplacedBecauseAddressWasReaddressed.GetHash() }, + { Envelope.PositionMetadataKey, position + 2 } + }; + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope(new Envelope(buildingUnitAddressWasAttached, buildingUnitAddressWasAttachedMetadata)), + new Envelope( + new Envelope( + buildingUnitAddressWasReplacedBecauseAddressWasReaddressed, + buildingUnitAddressWasReplacedBecauseAddressWasReaddressedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitAddressWasReplacedBecauseAddressWasReaddressed.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.VersionTimestamp.Should().Be(buildingUnitAddressWasReplacedBecauseAddressWasReaddressed.Provenance.Timestamp); + + var newAddress = context.BuildingUnitAddresses.SingleOrDefault(x => + x.AddressPersistentLocalId == buildingUnitAddressWasReplacedBecauseAddressWasReaddressed.NewAddressPersistentLocalId); + newAddress.Should().NotBeNull(); + + var oldAddress = context.BuildingUnitAddresses.SingleOrDefault(x => + x.AddressPersistentLocalId == buildingUnitAddressWasReplacedBecauseAddressWasReaddressed.PreviousAddressPersistentLocalId); + oldAddress.Should().BeNull(); + }); + } + + [Fact] + public async Task WhenBuildingUnitWasRetiredBecauseBuildingWasDemolished() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingUnitWasRetired = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitWasRetiredMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasRetired.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope(new Envelope(buildingUnitWasRetired, buildingUnitWasRetiredMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitWasRetired.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.Status.Should().Be(BuildingUnitStatus.Retired.Map()); + buildingUnitLatestItem.OsloStatus.Should().Be("Retired"); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingUnitWasRetired.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingUnitWasNotRealizedBecauseBuildingWasDemolished() + { + _fixture.Customize(new WithFixedBuildingPersistentLocalId()); + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingUnitWasNotRealized = _fixture.Create(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitWasNotRealizedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasNotRealized.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope(new Envelope(buildingUnitWasNotRealized, buildingUnitWasNotRealizedMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitWasNotRealized.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.Status.Should().Be(BuildingUnitStatus.NotRealized.Map()); + buildingUnitLatestItem.OsloStatus.Should().Be("NotRealized"); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingUnitWasNotRealized.Provenance.Timestamp); + }); + } + + [Fact] + public async Task WhenBuildingUnitWasTransferred() + { + _fixture.Customize(new WithFixedBuildingUnitPersistentLocalId()); + + var buildingUnitWasPlannedV2 = _fixture.Create(); + var buildingUnitWasTransferred = new BuildingUnitWasTransferredBuilder(_fixture) + .WithBuildingUnitPersistentLocalId(buildingUnitWasPlannedV2.BuildingUnitPersistentLocalId) + .WithSourceBuildingPersistentLocalId(buildingUnitWasPlannedV2.BuildingPersistentLocalId) + .Build(); + + var position = _fixture.Create(); + + var buildingUnitWasPlannedMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasPlannedV2.GetHash() }, + { Envelope.PositionMetadataKey, position } + }; + var buildingUnitWasTransferredMetadata = new Dictionary + { + { AddEventHashPipe.HashMetadataKey, buildingUnitWasTransferred.GetHash() }, + { Envelope.PositionMetadataKey, position + 1 } + }; + + await Sut + .Given( + new Envelope(new Envelope(buildingUnitWasPlannedV2, buildingUnitWasPlannedMetadata)), + new Envelope(new Envelope(buildingUnitWasTransferred, buildingUnitWasTransferredMetadata))) + .Then(async context => + { + var buildingUnitLatestItem = + await context.BuildingUnitLatestItems.FindAsync(buildingUnitWasTransferred.BuildingUnitPersistentLocalId); + buildingUnitLatestItem.Should().NotBeNull(); + + buildingUnitLatestItem!.BuildingPersistentLocalId.Should().Be(buildingUnitWasTransferred.BuildingPersistentLocalId); + buildingUnitLatestItem.Status.Should().Be( + BuildingUnitStatus.Parse(buildingUnitWasTransferred.Status).Map()); + buildingUnitLatestItem.OsloStatus.Should().Be(buildingUnitWasTransferred.Status); + buildingUnitLatestItem.Function.Should().Be( + BuildingUnitFunction.Parse(buildingUnitWasTransferred.Function).Map()); + buildingUnitLatestItem.OsloFunction.Should().Be(buildingUnitWasTransferred.Function); + buildingUnitLatestItem.GeometryMethod.Should().Be( + BuildingUnitPositionGeometryMethod.Parse(buildingUnitWasTransferred.GeometryMethod).Map()); + buildingUnitLatestItem.Geometry.Should().BeEquivalentTo( + _wkbReader.Read(buildingUnitWasTransferred.ExtendedWkbGeometry.ToByteArray())); + buildingUnitLatestItem.HasDeviation.Should().BeFalse(); + buildingUnitLatestItem.VersionTimestamp.Should().Be(buildingUnitWasTransferred.Provenance.Timestamp); + + var buildingUnitAddresses = context.BuildingUnitAddresses + .Where(x => x.BuildingUnitPersistentLocalId == buildingUnitLatestItem.BuildingUnitPersistentLocalId) + .ToList(); + + buildingUnitAddresses.Should().HaveCount(buildingUnitWasTransferred.AddressPersistentLocalIds.Count); + foreach (var addressPersistentLocalId in buildingUnitWasTransferred.AddressPersistentLocalIds) + { + buildingUnitAddresses.SingleOrDefault(x => x.AddressPersistentLocalId == addressPersistentLocalId) + .Should().NotBeNull(); + } + }); + } + + protected override BuildingUnitLatestItemProjections CreateProjection() => + new BuildingUnitLatestItemProjections(new OptionsWrapper(new IntegrationOptions + { + BuildingNamespace = BuildingNamespace, + BuildingUnitNamespace = BuildingUnitNamespace + })); + } +} diff --git a/test/BuildingRegistry.Tests/ProjectionTests/Integration/IntegrationProjectionTest.cs b/test/BuildingRegistry.Tests/ProjectionTests/Integration/IntegrationProjectionTest.cs new file mode 100644 index 000000000..8da760613 --- /dev/null +++ b/test/BuildingRegistry.Tests/ProjectionTests/Integration/IntegrationProjectionTest.cs @@ -0,0 +1,30 @@ +namespace BuildingRegistry.Tests.ProjectionTests.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(); + } +}