/// <inheritdoc/> public Task <Try <UncommittedAggregateEvents> > TryConverge(EmbeddingCurrentState current, ProjectionState desired, ExecutionContext executionContext, CancellationToken cancellationToken) => DoWork( current, newCurrent => _stateComparer.TryCheckEquality(newCurrent.State, desired), (newCurrent, token) => _embedding.TryCompare(newCurrent, desired, executionContext, token), executionContext, cancellationToken);
/// <inheritdoc/> public Task <Try <UncommittedAggregateEvents> > TryDelete(EmbeddingCurrentState current, ExecutionContext executionContext, CancellationToken cancellationToken) => DoWork( current, newCurrent => Try <bool> .Do(() => newCurrent.Type is EmbeddingCurrentStateType.Deleted), (newCurrent, token) => _embedding.TryDelete(newCurrent, executionContext, token), executionContext, cancellationToken);
Task <Try> TryUpdateOrDeleteState(EmbeddingCurrentState state, CancellationToken cancellationToken) => state.Type == EmbeddingCurrentStateType.Deleted ? _embeddingStore.TryRemove( _embedding, state.Key, state.Version, cancellationToken) : _embeddingStore.TryReplace( _embedding, state.Key, state.Version, state.State, cancellationToken);
async Task <Try <UncommittedEvents> > TryGetAndAddNewTransitionEventsInto( IList <UncommittedEvents> allTransitionEvents, EmbeddingCurrentState current, Func <EmbeddingCurrentState, CancellationToken, Task <Try <UncommittedEvents> > > getTransitionEvents, CancellationToken cancellationToken) { var newTransitionEvents = await getTransitionEvents(current, cancellationToken).ConfigureAwait(false); if (!newTransitionEvents.Success) { return(newTransitionEvents.Exception); } allTransitionEvents.Add(newTransitionEvents.Result); return(newTransitionEvents); }
async Task <Try <EmbeddingCurrentState> > TryProjectOne(EmbeddingCurrentState currentState, UncommittedEvent @event, ExecutionContext executionContext, CancellationToken cancellationToken) { try { var result = await _embedding.Project(currentState, @event, executionContext, cancellationToken).ConfigureAwait(false); var nextAggregateRootVersion = currentState.Version.Value + 1; return(result switch { ProjectionFailedResult failedResult => failedResult.Exception, ProjectionReplaceResult replaceResult => new EmbeddingCurrentState(nextAggregateRootVersion, EmbeddingCurrentStateType.Persisted, replaceResult.State, currentState.Key), ProjectionDeleteResult => new EmbeddingCurrentState(nextAggregateRootVersion, EmbeddingCurrentStateType.Deleted, _initialState, currentState.Key), _ => new UnknownProjectionResultType(result) }); }
/// <inheritdoc/> public async Task <Partial <EmbeddingCurrentState> > TryProject(EmbeddingCurrentState currentState, UncommittedEvents events, ExecutionContext executionContext, CancellationToken cancellationToken) { _logger.ProjectingEventsOnEmbedding(_identifier, currentState.Key, events); for (var i = 0; i < events.Count; i++) { var tryProject = await TryProjectOne(currentState, events[i], executionContext, cancellationToken).ConfigureAwait(false); if (!tryProject.Success) { return(i == 0 ? tryProject.Exception : Partial <EmbeddingCurrentState> .PartialSuccess(currentState, tryProject.Exception)); } currentState = tryProject.Result; } return(currentState); }
async Task <Try <EmbeddingCurrentState> > TryProjectNewState( EmbeddingCurrentState current, Try <UncommittedEvents> newTransitionEvents, IEnumerable <ProjectionState> previousStates, ExecutionContext executionContext, CancellationToken cancellationToken) { var intermediateState = await _projector.TryProject(current, newTransitionEvents.Result, executionContext, cancellationToken).ConfigureAwait(false); if (!intermediateState.Success) { return(intermediateState.IsPartialResult ? new CouldNotProjectAllEvents(_embeddingId, intermediateState.Exception) : new FailedProjectingEvents(_embeddingId, intermediateState.Exception)); } var loopDetected = _loopDetector.TryCheckForProjectionStateLoop(intermediateState.Result.State, previousStates); return(loopDetected switch { { Success : false } => loopDetected.Exception,
Try <bool> TryCheckIfDesiredState( EmbeddingCurrentState current, IEnumerable <UncommittedEvents> allTransitionEvents, Func <EmbeddingCurrentState, Try <bool> > isDesiredState, out UncommittedAggregateEvents eventsToCommit) { eventsToCommit = null; var isDesired = isDesiredState(current); if (!isDesired.Success) { return(isDesired.Exception); } if (!isDesired.Result) { return(false); } var flattenedTransitionEvents = from uncommittedEvents in allTransitionEvents from @event in uncommittedEvents select @event; eventsToCommit = CreateUncommittedAggregateEvents(new UncommittedEvents(flattenedTransitionEvents.ToArray()), current); return(true); }
/// <summary> /// Convert to a protobuf representation of <see cref="EmbeddingCurrentState"/>. /// </summary> /// <param name="state"><see cref="EmbeddingCurrentState"/> to convert.</param> /// <returns>Converted <see cref="ContractsProjectionCurrentState"/>.</returns> public static ContractsProjectionCurrentState ToProtobuf(this EmbeddingCurrentState state) => new()
async Task <Try <UncommittedAggregateEvents> > DoWork( EmbeddingCurrentState current, Func <EmbeddingCurrentState, Try <bool> > isDesiredState, Func <EmbeddingCurrentState, CancellationToken, Task <Try <UncommittedEvents> > > getTransitionEvents, ExecutionContext executionContext, CancellationToken cancellationToken) { try { _logger.CalculatingStateTransitionEvents(_embeddingId, current.Key, current.Version); var allTransitionEvents = new List <UncommittedEvents>(); var previousStates = new List <ProjectionState> { current.State }; while (true) { if (cancellationToken.IsCancellationRequested) { _logger.CalculatingStateTransitionEventsCancelled(_embeddingId, current.Key, current.Version); return(new CalculateStateTransitionEventsCancelled(_embeddingId)); } var getEventsToCommit = TryCheckIfDesiredState(current, allTransitionEvents, isDesiredState, out var eventsToCommit); if (!getEventsToCommit.Success || getEventsToCommit.Result) { if (getEventsToCommit.Exception != default) { _logger.CalculatingStateTransitionEventsFailedCheckingIfDesiredState( _embeddingId, current.Key, current.Version, getEventsToCommit.Exception); return(getEventsToCommit.Exception); } return(eventsToCommit); } var addNewTransitionEvents = await TryGetAndAddNewTransitionEventsInto( allTransitionEvents, current, getTransitionEvents, cancellationToken).ConfigureAwait(false); if (!addNewTransitionEvents.Success) { _logger.CalculatingStateTransitionEventsFailedGettingNextTransitionEvents( _embeddingId, current.Key, current.Version, addNewTransitionEvents.Exception); return(addNewTransitionEvents.Exception); } var projectIntermediateState = await TryProjectNewState(current, addNewTransitionEvents, previousStates, executionContext, cancellationToken).ConfigureAwait(false); if (!projectIntermediateState.Success) { _logger.CalculatingStateTransitionEventsFailedProjectingNewState( _embeddingId, current.Key, current.Version, addNewTransitionEvents.Exception); return(projectIntermediateState.Exception); } previousStates.Add(projectIntermediateState.Result.State); current = projectIntermediateState; } } catch (Exception ex) { return(ex); } }
/// <inheritdoc/> public Task <Partial <EmbeddingCurrentState> > TryProject(EmbeddingCurrentState currentState, CommittedAggregateEvents events, ExecutionContext executionContext, CancellationToken cancellationToken) => TryProject( currentState, new UncommittedEvents(events.Select(_ => new UncommittedEvent(_.EventSource, _.Type, _.Public, _.Content)).ToList()), executionContext, cancellationToken);