private Result MergeSpanEquipment(CommandContext cmdContext, Guid routeNodeId, SpanEquipmentWithConnectsHolder firstSpanEquipment, SpanEquipmentWithConnectsHolder secondSpanEquipment) { // Merge the first span equipment with the second one var firstSpanEquipmentAR = _eventStore.Aggregates.Load <SpanEquipmentAR>(firstSpanEquipment.SpanEquipment.Id); var firstSpanEquipmentConnectResult = firstSpanEquipmentAR.Merge( cmdContext: cmdContext, routeNodeId: routeNodeId, secondSpanEquipment.SpanEquipment ); if (firstSpanEquipmentConnectResult.IsFailed) { return(firstSpanEquipmentConnectResult); } var firstSpanEquipmentWalk = GetInterestInformation(firstSpanEquipment.SpanEquipment); var secondSpanEquipmentWalk = GetInterestInformation(secondSpanEquipment.SpanEquipment); // Update interest of the first span equipment to cover both span equipments var newSegmentIds = MergeWalks(firstSpanEquipmentWalk, secondSpanEquipmentWalk); var updateWalkOfInterestCommand = new UpdateWalkOfInterest(firstSpanEquipment.SpanEquipment.WalkOfInterestId, newSegmentIds); var updateWalkOfInterestCommandResult = _commandDispatcher.HandleAsync <UpdateWalkOfInterest, Result <RouteNetworkInterest> >(updateWalkOfInterestCommand).Result; if (updateWalkOfInterestCommandResult.IsFailed) { return(updateWalkOfInterestCommandResult); } // Remove the second span equipment var secondSpanEquipmentAR = _eventStore.Aggregates.Load <SpanEquipmentAR>(secondSpanEquipment.SpanEquipment.Id); var removeSpanEquipment = secondSpanEquipmentAR.Remove(cmdContext); if (removeSpanEquipment.IsSuccess) { // Remember to remove the walk of interest as well var unregisterInterestCmd = new UnregisterInterest(secondSpanEquipment.SpanEquipment.WalkOfInterestId); var unregisterInterestCmdResult = _commandDispatcher.HandleAsync <UnregisterInterest, Result>(unregisterInterestCmd).Result; if (unregisterInterestCmdResult.IsFailed) { throw new ApplicationException($"Failed to unregister interest: {secondSpanEquipment.SpanEquipment.WalkOfInterestId} of span equipment: {secondSpanEquipment.SpanEquipment.Id} in RemoveSpanStructureFromSpanEquipmentCommandHandler Error: {unregisterInterestCmdResult.Errors.First().Message}"); } } _eventStore.Aggregates.Store(firstSpanEquipmentAR); _eventStore.Aggregates.Store(secondSpanEquipmentAR); NotifyExternalServicesAboutMerge(firstSpanEquipment.SpanEquipment.Id, updateWalkOfInterestCommandResult.Value.RouteNetworkElementRefs.ToArray()); return(Result.Ok()); }
public Task <Result <RouteNetworkInterest> > HandleAsync(UpdateWalkOfInterest command) { var interestAR = _eventStore.Aggregates.Load <InterestAR>(command.InterestId); var interestProjection = _eventStore.Projections.Get <InterestsProjection>(); var walkOfInterest = new RouteNetworkInterest(command.InterestId, RouteNetworkInterestKindEnum.WalkOfInterest, command.WalkIds); var walkValidator = new WalkValidator(_routeNetworkRepository); var commandContext = new CommandContext(command.CorrelationId, command.CmdId, command.UserContext); var updateInterestResult = interestAR.UpdateRouteNetworkElements(commandContext, walkOfInterest, interestProjection, walkValidator); if (updateInterestResult.IsSuccess) { _eventStore.Aggregates.Store(interestAR); } return(Task.FromResult(updateInterestResult)); }
public Task <Result> HandleAsync(MoveSpanEquipment command) { var utilityNetwork = _eventStore.Projections.Get <UtilityNetworkProjection>(); // Because the client is allowed to provide either a span equipment or segment id, we need look it up via the utility network graph if (!utilityNetwork.TryGetEquipment <SpanEquipment>(command.SpanEquipmentOrSegmentId, out SpanEquipment spanEquipment)) { return(Task.FromResult(Result.Fail(new MoveSpanEquipmentError(MoveSpanEquipmentErrorCodes.SPAN_EQUIPMENT_NOT_FOUND, $"Cannot find any span equipment or segment in the utility graph with id: {command.SpanEquipmentOrSegmentId}")))); } // Get interest information from existing span equipment var existingWalk = GetInterestInformation(spanEquipment); // Validate the new walk var newWalkValidationResult = _commandDispatcher.HandleAsync <ValidateWalkOfInterest, Result <ValidatedRouteNetworkWalk> >(new ValidateWalkOfInterest(command.NewWalkIds)).Result; // If the new walk fails to validate, return the error to the client if (newWalkValidationResult.IsFailed) { return(Task.FromResult(Result.Fail(newWalkValidationResult.Errors.First()))); } var newWalk = newWalkValidationResult.Value; // If the walk has not changed return error as well if (existingWalk.Equals(newWalk)) { return(Task.FromResult(Result.Fail(new MoveSpanEquipmentError(MoveSpanEquipmentErrorCodes.NEW_WALK_EQUALS_EXISTING_WALK, $"The new walk specified is not different from the existing walk of the span equipment.")))); } // Reverse new walk if one of its ends are opposite of existing walk ends if (newWalk.FromNodeId == existingWalk.ToNodeId || newWalk.ToNodeId == existingWalk.FromNodeId) { newWalk = newWalk.Reverse(); } // Try to do the move of the span equipment var spanEquipmentAR = _eventStore.Aggregates.Load <SpanEquipmentAR>(spanEquipment.Id); var commandContext = new CommandContext(command.CorrelationId, command.CmdId, command.UserContext); var moveSpanEquipmentResult = spanEquipmentAR.Move(commandContext, newWalk, existingWalk); if (moveSpanEquipmentResult.IsFailed) { return(Task.FromResult(Result.Fail(moveSpanEquipmentResult.Errors.First()))); } // If we got to here, then the span equipment move was validated fine, so we can update the walk of interest var newSegmentIds = new RouteNetworkElementIdList(); newSegmentIds.AddRange(newWalk.SegmentIds); var updateWalkOfInterestCommand = new UpdateWalkOfInterest(spanEquipment.WalkOfInterestId, newSegmentIds) { UserContext = commandContext.UserContext }; var updateWalkOfInterestCommandResult = _commandDispatcher.HandleAsync <UpdateWalkOfInterest, Result <RouteNetworkInterest> >(updateWalkOfInterestCommand).Result; if (updateWalkOfInterestCommandResult.IsFailed) { throw new ApplicationException($"Got unexpected error result: {updateWalkOfInterestCommandResult.Errors.First().Message} trying to update walk of interest belonging to span equipment with id: {spanEquipment.Id} while processing the MoveSpanEquipment command: " + JsonConvert.SerializeObject(command)); } _eventStore.Aggregates.Store(spanEquipmentAR); NotifyExternalServicesAboutSpanEquipmentChange(spanEquipment.Id, existingWalk, newWalk); return(Task.FromResult(moveSpanEquipmentResult)); }
private void HandleSplitCommand(RouteNetworkEditOperationOccuredEvent request, Events.RouteNetworkCommand command, ITransaction trans) { if (!_networkState.IsLoadMode) { Guid correlationId = Guid.NewGuid(); _logger.LogInformation($"Route network event handler is processing split, event command id: {command.CmdId}, correlation id: {correlationId}, invoked by user: {request.UserName}"); RouteSegmentAdded? firstAddedSegmentEvent = null; RouteSegmentAdded? secondAddedSegmentEvent = null; RouteSegmentRemoved?removedSegmentEvent = null; RouteSegmentAdded?fromAddedSegmentEvent; RouteSegmentAdded?toAddedSegmentEvent; Guid?splitNodeId; foreach (var routeNetworkEvent in command.RouteNetworkEvents) { if (routeNetworkEvent is RouteSegmentAdded && firstAddedSegmentEvent == null) { firstAddedSegmentEvent = routeNetworkEvent as RouteSegmentAdded; } else if (routeNetworkEvent is RouteSegmentAdded && firstAddedSegmentEvent != null && secondAddedSegmentEvent == null) { secondAddedSegmentEvent = routeNetworkEvent as RouteSegmentAdded; } else if (routeNetworkEvent is RouteSegmentRemoved) { removedSegmentEvent = routeNetworkEvent as RouteSegmentRemoved; } } // Only proceed if we manage to get all the needed information from the split command if (firstAddedSegmentEvent != null && secondAddedSegmentEvent != null && removedSegmentEvent != null) { if (firstAddedSegmentEvent.ToNodeId == secondAddedSegmentEvent.FromNodeId) { fromAddedSegmentEvent = firstAddedSegmentEvent; toAddedSegmentEvent = secondAddedSegmentEvent; splitNodeId = firstAddedSegmentEvent.ToNodeId; } else { toAddedSegmentEvent = firstAddedSegmentEvent; fromAddedSegmentEvent = secondAddedSegmentEvent; splitNodeId = firstAddedSegmentEvent.FromNodeId; } // Find all interests of the deleted route segment var interestsProjection = _eventStore.Projections.Get <InterestsProjection>(); var interestRelationsResult = interestsProjection.GetInterestsByRouteNetworkElementId(removedSegmentEvent.SegmentId); if (interestRelationsResult.IsFailed) { _logger.LogError($"Split handler: Failed with error: {interestRelationsResult.Errors.First().Message} trying to get interest related by removed segment with id: {removedSegmentEvent.SegmentId} processing split command: " + JsonConvert.SerializeObject(command)); return; } foreach (var interest in interestRelationsResult.Value) { var firstAddedSegmentInterestRelationsResult = interestsProjection.GetInterestsByRouteNetworkElementId(firstAddedSegmentEvent.SegmentId); if (firstAddedSegmentInterestRelationsResult.IsFailed) { _logger.LogError($"Split handler: Failed with error: {interestRelationsResult.Errors.First().Message} trying to get interest related by added segment with id: {firstAddedSegmentEvent.SegmentId} processing split command: " + JsonConvert.SerializeObject(command)); return; } var newRouteNetworkElementIdList = CreateNewRouteNetworkElementIdListFromSplit(interest.Item1.RouteNetworkElementRefs, removedSegmentEvent.SegmentId, splitNodeId.Value, fromAddedSegmentEvent, toAddedSegmentEvent); var updateWalkOfInterestCommand = new UpdateWalkOfInterest(Guid.NewGuid(), new UserContext(request.UserName, request.WorkTaskMrid ?? Guid.Empty), interest.Item1.Id, newRouteNetworkElementIdList); _logger.LogInformation($"Route network split handler is invoking {updateWalkOfInterestCommand.GetType().Name} command with id: {updateWalkOfInterestCommand.CmdId}, correlation id: {correlationId}"); var updateWalkOfInterestCommandResult = _commandDispatcher.HandleAsync <UpdateWalkOfInterest, Result <RouteNetworkInterest> >(updateWalkOfInterestCommand).Result; if (updateWalkOfInterestCommandResult.IsFailed) { _logger.LogError($"Split handler: Failed error: {updateWalkOfInterestCommandResult.Errors.First().Message} trying to update interest with id: {interest.Item1.Id} processing split command: " + JsonConvert.SerializeObject(command)); } } } else { _logger.LogError("Split handler: Can't find needed information in event. Expected two RouteSegmentAdded and one RouteSegmentRemoved event. Split command being processed: " + JsonConvert.SerializeObject(command)); } } }
public async void UpdateInterestWithInvalidWalk_ShouldFail() { // Route network subset used in this test: // (CO_1) <- (S1) -> (HH_1) var interestId = Guid.NewGuid(); var walk = new RouteNetworkElementIdList() { TestRouteNetwork.S1 }; // Walk with hole var updatedWalk = new RouteNetworkElementIdList() { TestRouteNetwork.S2, TestRouteNetwork.S5 }; var routeNetworkQuery_CO1 = new GetRouteNetworkDetails(new RouteNetworkElementIdList() { TestRouteNetwork.CO_1 }) { RelatedInterestFilter = RelatedInterestFilterOptions.ReferencesFromRouteElementAndInterestObjects }; var routeNetworkQuery_HH2 = new GetRouteNetworkDetails(new RouteNetworkElementIdList() { TestRouteNetwork.HH_2 }) { RelatedInterestFilter = RelatedInterestFilterOptions.ReferencesFromRouteElementAndInterestObjects }; // Act var registerWalkOfInterestCommand = new RegisterWalkOfInterest(Guid.NewGuid(), new UserContext("test", Guid.Empty), interestId, walk); var registerWalkOfInterestCommandResult = await _commandDispatcher.HandleAsync <RegisterWalkOfInterest, Result <RouteNetworkInterest> >(registerWalkOfInterestCommand); Result <GetRouteNetworkDetailsResult> routeNetworkQueryResultBefore = await _queryDispatcher.HandleAsync <GetRouteNetworkDetails, Result <GetRouteNetworkDetailsResult> >(routeNetworkQuery_CO1); var updateWalkOfInterestCommand = new UpdateWalkOfInterest(Guid.NewGuid(), new UserContext("test", Guid.Empty), interestId, updatedWalk); var updateWalkOfInterestCommandResult = await _commandDispatcher.HandleAsync <UpdateWalkOfInterest, Result <RouteNetworkInterest> >(updateWalkOfInterestCommand); Result <GetRouteNetworkDetailsResult> co1_routeNetworkQueryResultAfter = await _queryDispatcher.HandleAsync <GetRouteNetworkDetails, Result <GetRouteNetworkDetailsResult> >(routeNetworkQuery_CO1); Result <GetRouteNetworkDetailsResult> hh2_routeNetworkQueryResultAfter = await _queryDispatcher.HandleAsync <GetRouteNetworkDetails, Result <GetRouteNetworkDetailsResult> >(routeNetworkQuery_HH2); // Assert command result registerWalkOfInterestCommandResult.IsSuccess.Should().BeTrue(); updateWalkOfInterestCommandResult.IsFailed.Should().BeTrue(); routeNetworkQueryResultBefore.IsSuccess.Should().BeTrue(); co1_routeNetworkQueryResultAfter.IsSuccess.Should().BeTrue(); hh2_routeNetworkQueryResultAfter.IsSuccess.Should().BeTrue(); // Assert query result routeNetworkQueryResultBefore.Value.Interests.ContainsKey(interestId).Should().BeTrue(); routeNetworkQueryResultBefore.Value.Interests[interestId].RouteNetworkElementRefs.Count.Should().Be(3); // Make sure index is *not* updated to include new interest at HH 2 hh2_routeNetworkQueryResultAfter.Value.Interests.ContainsKey(interestId).Should().BeFalse(); // Make sure index is still holding interest at CO 1 co1_routeNetworkQueryResultAfter.Value.Interests.ContainsKey(interestId).Should().BeTrue(); }