Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: WR-886 use separate store aggregate for outlined roadsegments #1311

Closed
wants to merge 25 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f43ec70
create separate roadnetwork ID provider/generator
rikdepeuter Nov 21, 2023
0ec3dd0
fix: lambda RoadNetwork usage for parallel processing of outlined roa…
rikdepeuter Nov 22, 2023
a2e29ea
add RoadNetworkDbContext for sequences
rikdepeuter Nov 22, 2023
c5444a0
fix RoadNetworkDbContext initial migration and execute on commandhost…
rikdepeuter Nov 23, 2023
65be325
finalize full flow to create outlined roadsegment
rikdepeuter Nov 23, 2023
7c17434
cleanup
rikdepeuter Nov 23, 2023
049c24a
fix unit tests
rikdepeuter Nov 24, 2023
af02177
Merge branch 'main' of https://github.com/Informatievlaanderen/road-r…
rikdepeuter Nov 24, 2023
c669238
remove temp
rikdepeuter Nov 24, 2023
432ee5b
fix unit tests
rikdepeuter Nov 27, 2023
d4a75ef
fix unit tests
rikdepeuter Nov 27, 2023
91832b2
todos
rikdepeuter Nov 27, 2023
1e16f7a
Merge branch 'main' of https://github.com/Informatievlaanderen/road-r…
rikdepeuter Nov 27, 2023
4bfaa45
TODO
rikdepeuter Nov 27, 2023
c2bacaf
fix order of Entries in EventSourcedEntityMap
rikdepeuter Nov 27, 2023
2dbe5f0
add ConvertedFromOutlined
rikdepeuter Nov 27, 2023
b6676dc
Merge branch 'main' of https://github.com/Informatievlaanderen/road-r…
rikdepeuter Nov 27, 2023
d9b3f62
update FC to explicitly remove outlined roadsegments on conversion to…
rikdepeuter Nov 28, 2023
bce94e9
fix: FC to support outlined roadsegments with identical/overlapping g…
rikdepeuter Nov 29, 2023
56a488f
fix unit test
rikdepeuter Nov 29, 2023
78041db
fix: use streamstore data to check if outlined roadsegment exists for…
rikdepeuter Nov 29, 2023
bd79ce2
cleanup
rikdepeuter Nov 29, 2023
adc1d1c
cleanup
rikdepeuter Nov 29, 2023
e4d4f10
cleanup
rikdepeuter Nov 29, 2023
6744cde
cleanup
rikdepeuter Nov 29, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions RoadRegistry.sln
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RoadRegistry.StreetName", "
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RoadRegistry.BackOffice.Api.IntegrationTests", "test\RoadRegistry.BackOffice.Api.IntegrationTests\RoadRegistry.BackOffice.Api.IntegrationTests.csproj", "{B82B2A5C-BD84-4DD8-B06C-C8C561C70B24}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RoadRegistry.RoadNetwork.Schema", "src\RoadRegistry.RoadNetwork.Schema\RoadRegistry.RoadNetwork.Schema.csproj", "{73D08F55-E44B-49BA-8B2A-7B8F1B9CCC29}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -986,6 +988,18 @@ Global
{B82B2A5C-BD84-4DD8-B06C-C8C561C70B24}.Release|x64.Build.0 = Release|Any CPU
{B82B2A5C-BD84-4DD8-B06C-C8C561C70B24}.Release|x86.ActiveCfg = Release|Any CPU
{B82B2A5C-BD84-4DD8-B06C-C8C561C70B24}.Release|x86.Build.0 = Release|Any CPU
{73D08F55-E44B-49BA-8B2A-7B8F1B9CCC29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{73D08F55-E44B-49BA-8B2A-7B8F1B9CCC29}.Debug|Any CPU.Build.0 = Debug|Any CPU
{73D08F55-E44B-49BA-8B2A-7B8F1B9CCC29}.Debug|x64.ActiveCfg = Debug|Any CPU
{73D08F55-E44B-49BA-8B2A-7B8F1B9CCC29}.Debug|x64.Build.0 = Debug|Any CPU
{73D08F55-E44B-49BA-8B2A-7B8F1B9CCC29}.Debug|x86.ActiveCfg = Debug|Any CPU
{73D08F55-E44B-49BA-8B2A-7B8F1B9CCC29}.Debug|x86.Build.0 = Debug|Any CPU
{73D08F55-E44B-49BA-8B2A-7B8F1B9CCC29}.Release|Any CPU.ActiveCfg = Release|Any CPU
{73D08F55-E44B-49BA-8B2A-7B8F1B9CCC29}.Release|Any CPU.Build.0 = Release|Any CPU
{73D08F55-E44B-49BA-8B2A-7B8F1B9CCC29}.Release|x64.ActiveCfg = Release|Any CPU
{73D08F55-E44B-49BA-8B2A-7B8F1B9CCC29}.Release|x64.Build.0 = Release|Any CPU
{73D08F55-E44B-49BA-8B2A-7B8F1B9CCC29}.Release|x86.ActiveCfg = Release|Any CPU
{73D08F55-E44B-49BA-8B2A-7B8F1B9CCC29}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -1059,6 +1073,7 @@ Global
{ED669395-A0BD-4D59-A679-C79176E38595} = {8EA18457-86E2-4D2D-AC9E-2552FDC9676F}
{1E15EFC6-DD30-4783-A539-5E0D350E4D92} = {C2F8FF63-7A48-4179-A720-86206C42F496}
{B82B2A5C-BD84-4DD8-B06C-C8C561C70B24} = {8EA18457-86E2-4D2D-AC9E-2552FDC9676F}
{73D08F55-E44B-49BA-8B2A-7B8F1B9CCC29} = {C2F8FF63-7A48-4179-A720-86206C42F496}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2EB87445-E263-4E1E-89CC-3839170028E5}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ namespace RoadRegistry.BackOffice.Abstractions;

public interface IHasRoadSegmentId
{
public int RoadSegmentId { get; }
public RoadSegmentId RoadSegmentId { get; }
public RoadSegmentGeometryDrawMethod GeometryDrawMethod { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ namespace RoadRegistry.BackOffice.Abstractions.RoadSegments;
using Be.Vlaanderen.Basisregisters.Sqs.Responses;
using MediatR;

public sealed record LinkStreetNameRequest(int WegsegmentId, string? LinkerstraatnaamId, string? RechterstraatnaamId) : IRequest<ETagResponse>;
public sealed record LinkStreetNameRequest(int WegsegmentId, string Methode, string? LinkerstraatnaamId, string? RechterstraatnaamId) : IRequest<ETagResponse>;
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ namespace RoadRegistry.BackOffice.Abstractions.RoadSegments;
using Be.Vlaanderen.Basisregisters.Sqs.Responses;
using MediatR;

public sealed record UnlinkStreetNameRequest(int WegsegmentId, string? LinkerstraatnaamId, string? RechterstraatnaamId) : IRequest<ETagResponse>;
public sealed record UnlinkStreetNameRequest(int WegsegmentId, string Methode, string? LinkerstraatnaamId, string? RechterstraatnaamId) : IRequest<ETagResponse>;
Original file line number Diff line number Diff line change
@@ -1,33 +1,25 @@
namespace RoadRegistry.BackOffice.Api.Infrastructure;

using System.Threading;
using System.Threading.Tasks;
using Abstractions.Exceptions;
using Be.Vlaanderen.Basisregisters.Api.ETag;
using Editor.Schema;
using RoadSegments;
using System.Threading;
using System.Threading.Tasks;

public interface IIfMatchHeaderValidator
{
public Task<bool> IsValid(string? ifMatchHeaderValue, RoadSegmentId roadSegmentId, CancellationToken ct);
public Task<bool> IsValid(string? ifMatchHeaderValue, RoadSegmentRecord roadSegment, CancellationToken ct);
}

public class IfMatchHeaderValidator : IIfMatchHeaderValidator
{
private readonly EditorContext _editorContext;

public IfMatchHeaderValidator(EditorContext editorContext)
{
_editorContext = editorContext;
}

public async Task<bool> IsValid(string? ifMatchHeaderValue, RoadSegmentId roadSegmentId, CancellationToken ct)
public async Task<bool> IsValid(string? ifMatchHeaderValue, RoadSegmentRecord roadSegment, CancellationToken ct)
{
if (ifMatchHeaderValue is null)
{
return true;
}

var roadSegment = await _editorContext.RoadSegments.FindAsync(roadSegmentId);
if (roadSegment is null)
{
throw new RoadSegmentNotFoundException();
Expand All @@ -40,4 +32,4 @@ public async Task<bool> IsValid(string? ifMatchHeaderValue, RoadSegmentId roadSe

return ifMatchTag == lastHashTag.ToString();
}
}
}
2 changes: 2 additions & 0 deletions src/RoadRegistry.BackOffice.Api/Infrastructure/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ namespace RoadRegistry.BackOffice.Api.Infrastructure;
using NodaTime;
using Options;
using Product.Schema;
using RoadRegistry.BackOffice.Api.RoadSegments;
using Serilog.Extensions.Logging;
using Snapshot.Handlers.Sqs;
using SqlStreamStore;
Expand Down Expand Up @@ -352,6 +353,7 @@ public void ConfigureServices(IServiceCollection services)
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)
.UseSqlServer(
sp.GetRequiredService<TraceDbConnection<ProductContext>>()))
.AddScoped<IRoadSegmentRepository, RoadSegmentRepository>()
.AddValidatorsAsScopedFromAssemblyContaining<Startup>()
.AddValidatorsFromAssemblyContaining<BackOffice.DomainAssemblyMarker>()
.AddValidatorsFromAssemblyContaining<Handlers.DomainAssemblyMarker>()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
namespace RoadRegistry.BackOffice.Api.RoadSegments
{
using BackOffice.Extracts.Dbase.RoadSegments;
using Editor.Schema;
using Editor.Schema.Extensions;
using Microsoft.IO;
using System.Threading;
using System.Threading.Tasks;

public interface IRoadSegmentRepository
{
Task<RoadSegmentRecord> Find(RoadSegmentId id, CancellationToken cancellationToken);
}

public class RoadSegmentRepository: IRoadSegmentRepository
{
private readonly IRoadRegistryContext _roadRegistryContext;
private readonly EditorContext _editorContext;
private readonly RecyclableMemoryStreamManager _manager;
private readonly FileEncoding _fileEncoding;

public RoadSegmentRepository(
IRoadRegistryContext roadRegistryContext,
EditorContext editorContext,
RecyclableMemoryStreamManager manager,
FileEncoding fileEncoding)
{
_roadRegistryContext = roadRegistryContext;
_editorContext = editorContext;
_manager = manager;
_fileEncoding = fileEncoding;
}

public async Task<RoadSegmentRecord> Find(RoadSegmentId id, CancellationToken cancellationToken)
{
{
var roadNetwork = await _roadRegistryContext.RoadNetworks.ForOutlinedRoadSegment(id, cancellationToken);
var roadSegment = roadNetwork.FindRoadSegment(id);
if (roadSegment is not null && roadSegment.AttributeHash.GeometryDrawMethod == RoadSegmentGeometryDrawMethod.Outlined)
{
return new RoadSegmentRecord(id, roadSegment.AttributeHash.GeometryDrawMethod, roadSegment.LastEventHash);
}
}

{
var roadSegment = await _editorContext.RoadSegments.FindAsync(new object[] { id.ToInt32() }, cancellationToken);
if (roadSegment is not null)
{
var roadSegmentDbaseRecord = new RoadSegmentDbaseRecord().FromBytes(roadSegment.DbaseRecord, _manager, _fileEncoding);
return new RoadSegmentRecord(id, RoadSegmentGeometryDrawMethod.ByIdentifier[roadSegmentDbaseRecord.METHODE.Value], roadSegment.LastEventHash);
}
}

return null;
}
}

public sealed record RoadSegmentRecord(RoadSegmentId Id, RoadSegmentGeometryDrawMethod GeometryDrawMethod, string LastEventHash);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
namespace RoadRegistry.BackOffice.Api.RoadSegments;

using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Abstractions.Extensions;
using Abstractions.RoadSegmentsOutline;
using Be.Vlaanderen.Basisregisters.AcmIdm;
Expand All @@ -13,14 +10,19 @@ namespace RoadRegistry.BackOffice.Api.RoadSegments;
using Core.ProblemCodes;
using Extensions;
using FluentValidation;
using FluentValidation.Results;
using Handlers.Sqs.RoadSegments;
using Infrastructure.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using RoadRegistry.BackOffice.Abstractions.Exceptions;
using Swashbuckle.AspNetCore.Annotations;
using Swashbuckle.AspNetCore.Filters;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;

public partial class RoadSegmentsController
{
Expand All @@ -31,6 +33,7 @@ public partial class RoadSegmentsController
/// </summary>
/// <param name="idValidator"></param>
/// <param name="validator"></param>
/// <param name="roadSegmentRepository"></param>
/// <param name="parameters"></param>
/// <param name="id"></param>
/// <param name="cancellationToken"></param>
Expand All @@ -52,15 +55,36 @@ public partial class RoadSegmentsController
[SwaggerRequestExample(typeof(PostChangeOutlineGeometryParameters), typeof(PostChangeOutlineGeometryParametersExamples))]
[SwaggerOperation(OperationId = nameof(ChangeOutlineGeometry), Description = "Wijzig de geometrie van een wegsegment met geometriemethode <ingeschetst>.")]
public async Task<IActionResult> ChangeOutlineGeometry(
[FromServices] RoadSegmentOutlinedIdValidator idValidator,
[FromServices] RoadSegmentIdValidator idValidator,
[FromServices] PostChangeOutlineGeometryParametersValidator validator,
[FromServices] IRoadSegmentRepository roadSegmentRepository,
[FromBody] PostChangeOutlineGeometryParameters parameters,
[FromRoute] int id,
CancellationToken cancellationToken = default)
{
try
{
await idValidator.ValidateRoadSegmentIdAndThrowAsync(id, cancellationToken);

var roadSegment = await roadSegmentRepository.Find(new RoadSegmentId(id), cancellationToken);
if (roadSegment is null)
{
throw new RoadSegmentNotFoundException();
}

if (roadSegment.GeometryDrawMethod != RoadSegmentGeometryDrawMethod.Outlined)
{
var problemTranslation = new RoadSegmentGeometryDrawMethodNotOutlined().TranslateToDutch();
throw new ValidationException(new[] {
new ValidationFailure
{
PropertyName = "objectId",
ErrorCode = problemTranslation.Code,
ErrorMessage = problemTranslation.Message
}
});
}

await validator.ValidateAndThrowAsync(parameters, cancellationToken);

var sqsRequest = new ChangeRoadSegmentOutlineGeometrySqsRequest
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
namespace RoadRegistry.BackOffice.Api.RoadSegments;

using System.Threading;
using System.Threading.Tasks;
using Abstractions.Extensions;
using Abstractions.RoadSegmentsOutline;
using Be.Vlaanderen.Basisregisters.AcmIdm;
using Be.Vlaanderen.Basisregisters.Api.Exceptions;
using Be.Vlaanderen.Basisregisters.Sqs.Exceptions;
using Core;
using Extensions;
using FeatureToggles;
using FluentValidation;
using FluentValidation.Results;
using Handlers.Sqs.RoadSegments;
using Infrastructure.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using RoadRegistry.BackOffice.Abstractions.Exceptions;
using Swashbuckle.AspNetCore.Annotations;
using Swashbuckle.AspNetCore.Filters;
using System.Threading;
using System.Threading.Tasks;

public partial class RoadSegmentsController
{
Expand All @@ -25,6 +30,7 @@ public partial class RoadSegmentsController
/// </summary>
/// <param name="featureToggle"></param>
/// <param name="idValidator"></param>
/// <param name="roadSegmentRepository"></param>
/// <param name="id">Identificator van het ingeschetst wegsegment.</param>
/// <param name="cancellationToken"></param>
/// <response code="202">Als het ingeschetst wegsegment gevonden is.</response>
Expand All @@ -45,7 +51,8 @@ public partial class RoadSegmentsController
[SwaggerOperation(OperationId = nameof(DeleteOutline), Description = "Verwijder een wegsegment met geometriemethode <ingeschetst>.")]
public async Task<IActionResult> DeleteOutline(
[FromServices] UseRoadSegmentOutlineDeleteFeatureToggle featureToggle,
[FromServices] RoadSegmentOutlinedIdValidator idValidator,
[FromServices] RoadSegmentIdValidator idValidator,
[FromServices] IRoadSegmentRepository roadSegmentRepository,
[FromRoute] int id,
CancellationToken cancellationToken)
{
Expand All @@ -58,6 +65,25 @@ public async Task<IActionResult> DeleteOutline(
{
await idValidator.ValidateRoadSegmentIdAndThrowAsync(id, cancellationToken);

var roadSegment = await roadSegmentRepository.Find(new RoadSegmentId(id), cancellationToken);
if (roadSegment is null)
{
throw new RoadSegmentNotFoundException();
}

if (roadSegment.GeometryDrawMethod != RoadSegmentGeometryDrawMethod.Outlined)
{
var problemTranslation = new RoadSegmentGeometryDrawMethodNotOutlined().TranslateToDutch();
throw new ValidationException(new[] {
new ValidationFailure
{
PropertyName = "objectId",
ErrorCode = problemTranslation.Code,
ErrorMessage = problemTranslation.Message
}
});
}

var result = await _mediator.Send(new DeleteRoadSegmentOutlineSqsRequest { Request = new DeleteRoadSegmentOutlineRequest(new RoadSegmentId(id)) }, cancellationToken);

return Accepted(result);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
namespace RoadRegistry.BackOffice.Api.RoadSegments;

using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Abstractions.Extensions;
using Abstractions.RoadSegments;
using Be.Vlaanderen.Basisregisters.AcmIdm;
Expand All @@ -18,8 +15,12 @@ namespace RoadRegistry.BackOffice.Api.RoadSegments;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using RoadRegistry.BackOffice.Abstractions.Exceptions;
using Swashbuckle.AspNetCore.Annotations;
using Swashbuckle.AspNetCore.Filters;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;

public partial class RoadSegmentsController
{
Expand All @@ -32,6 +33,7 @@ public partial class RoadSegmentsController
/// <param name="ifMatchHeaderValidator"></param>
/// <param name="idValidator"></param>
/// <param name="validator"></param>
/// <param name="roadSegmentRepository"></param>
/// <param name="parameters"></param>
/// <param name="id">Identificator van het wegsegment.</param>
/// <param name="ifMatchHeaderValue"></param>
Expand Down Expand Up @@ -60,6 +62,7 @@ public async Task<IActionResult> LinkStreetName(
[FromServices] IIfMatchHeaderValidator ifMatchHeaderValidator,
[FromServices] RoadSegmentIdValidator idValidator,
[FromServices] IValidator<LinkStreetNameRequest> validator,
[FromServices] IRoadSegmentRepository roadSegmentRepository,
[FromBody] PostLinkStreetNameParameters parameters,
[FromRoute] int id,
[FromHeader(Name = "If-Match")] string? ifMatchHeaderValue,
Expand All @@ -74,12 +77,18 @@ public async Task<IActionResult> LinkStreetName(
{
await idValidator.ValidateRoadSegmentIdAndThrowAsync(id, cancellationToken);

if (!await ifMatchHeaderValidator.IsValid(ifMatchHeaderValue, new RoadSegmentId(id), cancellationToken))
var roadSegment = await roadSegmentRepository.Find(new RoadSegmentId(id), cancellationToken);
if (roadSegment is null)
{
throw new RoadSegmentNotFoundException();
}

if (!await ifMatchHeaderValidator.IsValid(ifMatchHeaderValue, roadSegment, cancellationToken))
{
return new PreconditionFailedResult();
}

var request = new LinkStreetNameRequest(id, parameters?.LinkerstraatnaamId, parameters?.RechterstraatnaamId);
var request = new LinkStreetNameRequest(id, roadSegment.GeometryDrawMethod, parameters?.LinkerstraatnaamId, parameters?.RechterstraatnaamId);
await validator.ValidateAndThrowAsync(request, cancellationToken);

var result = await _mediator.Send(new LinkStreetNameSqsRequest { Request = request }, cancellationToken);
Expand Down
Loading
Loading