/// <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);
    }
Beispiel #5
0
    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)
            });
        }
Beispiel #6
0
    /// <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);
        }
    }
Beispiel #11
0
 /// <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);