예제 #1
0
    public async Task <AppendEventsResult> AppendEvents(
        StreamName stream,
        ExpectedStreamVersion expectedVersion,
        IReadOnlyCollection <StreamEvent> events,
        CancellationToken cancellationToken
        )
    {
        var streamName = stream.ToString();
        var documents  = events.Select(AsDocument).ToArray();
        var bulk       = new BulkDescriptor(_options.IndexName).CreateMany(documents).Refresh(Refresh.WaitFor);
        var result     = await _client.BulkAsync(bulk, cancellationToken);

        return(result.IsValid
            ? new AppendEventsResult(0, documents.Last().StreamPosition + 1)
            : throw new ApplicationException($"Unable to add events: {result.DebugInformation}"));

        PersistedEvent AsDocument(StreamEvent evt)
        => new(
            evt.Id.ToString(),
            TypeMap.Instance.GetTypeName(evt.Payload !),
            evt.Position + 1,
            evt.ContentType,
            streamName,
            (ulong)evt.Position + 1,
            evt.Payload,
            evt.Metadata.ToHeaders(),
            DateTime.Now
            );
    }
예제 #2
0
    public Task TruncateStream(
        StreamName stream,
        StreamTruncatePosition truncatePosition,
        ExpectedStreamVersion expectedVersion,
        CancellationToken cancellationToken
        )
    {
        var meta = new StreamMetadata(truncateBefore: truncatePosition.AsStreamPosition());

        return(TryExecute(
                   () => AnyOrNot(
                       expectedVersion,
                       () => _client.SetStreamMetadataAsync(
                           stream,
                           StreamState.Any,
                           meta,
                           cancellationToken: cancellationToken
                           ),
                       () => _client.SetStreamMetadataAsync(
                           stream,
                           expectedVersion.AsStreamRevision(),
                           meta,
                           cancellationToken: cancellationToken
                           )
                       ),
                   stream,
                   () => new ErrorInfo(
                       "Unable to truncate stream {Stream} at {Position}",
                       stream,
                       truncatePosition
                       ),
                   (s, ex) => new TruncateStreamException(s, ex)
                   ));
    }
예제 #3
0
        public async Task Store <T>(T aggregate)
            where T : Aggregate
        {
            Ensure.NotNull(aggregate, nameof(aggregate));

            if (aggregate.Changes.Count == 0)
            {
                return;
            }

            var stream          = StreamName.For <T>(aggregate.GetId());
            var expectedVersion = new ExpectedStreamVersion(aggregate.OriginalVersion);

            await _eventStore.AppendEvents(stream, expectedVersion, aggregate.Changes.Select(ToStreamEvent).ToArray());

            StreamEvent ToStreamEvent(object evt)
            => new(TypeMap.GetTypeName(evt), _serializer.Serialize(evt), null, _serializer.ContentType);
        }
예제 #4
0
    public static async Task <AppendEventsResult> Store <T>(
        this IEventWriter eventWriter,
        StreamName streamName,
        T aggregate,
        Func <StreamEvent, StreamEvent> amendEvent,
        CancellationToken cancellationToken
        ) where T : Aggregate
    {
        Ensure.NotNull(aggregate);

        if (aggregate.Changes.Count == 0)
        {
            return(AppendEventsResult.NoOp);
        }

        var originalVersion = aggregate.OriginalVersion;
        var expectedVersion = new ExpectedStreamVersion(originalVersion);

        try {
            var result = await eventWriter.AppendEvents(
                streamName,
                expectedVersion,
                aggregate.Changes.Select((o, i) => ToStreamEvent(o, i + originalVersion)).ToArray(),
                cancellationToken
                )
                         .NoContext();

            return(result);
        }
        catch (Exception e) {
            Log.UnableToStoreAggregate(aggregate, e);

            throw e.InnerException?.Message.Contains("WrongExpectedVersion") == true
                ? new OptimisticConcurrencyException <T>(aggregate, e) : e;
        }

        StreamEvent ToStreamEvent(object evt, int position)
        {
            var streamEvent = new StreamEvent(Guid.NewGuid(), evt, new Metadata(), "", position);

            return(amendEvent(streamEvent));
        }
    }
예제 #5
0
        public async Task Store <T>(T aggregate)
            where T : Aggregate
        {
            if (aggregate == null)
            {
                throw new ArgumentNullException(nameof(aggregate));
            }

            if (aggregate.Changes.Count == 0)
            {
                return;
            }

            var stream          = StreamName.For <T>(aggregate.GetId());
            var expectedVersion = new ExpectedStreamVersion(aggregate.Version);

            await _eventStore.AppendEvents(stream, expectedVersion, aggregate.Changes.Select(ToStreamEvent).ToArray());

            JsonStreamEvent ToStreamEvent(object evt)
            => new(TypeMap.GetTypeName(evt), _serializer.Serialize(evt));
        }
예제 #6
0
 public Task DeleteStream(
     StreamName stream,
     ExpectedStreamVersion expectedVersion,
     CancellationToken cancellationToken
     ) => TryExecute(
     () => AnyOrNot(
         expectedVersion,
         () => _client.DeleteAsync(
             stream,
             StreamState.Any,
             cancellationToken: cancellationToken
             ),
         () => _client.DeleteAsync(
             stream,
             expectedVersion.AsStreamRevision(),
             cancellationToken: cancellationToken
             )
         ),
     stream,
     () => new ErrorInfo("Unable to delete stream {Stream}", stream),
     (s, ex) => new DeleteStreamException(s, ex)
     );
 public static StreamRevision AsStreamRevision(this ExpectedStreamVersion version)
 => StreamRevision.FromInt64(version.Value);
예제 #8
0
    public Task <AppendEventsResult> AppendEvents(
        StreamName stream,
        ExpectedStreamVersion expectedVersion,
        IReadOnlyCollection <StreamEvent> events,
        CancellationToken cancellationToken
        )
    {
        var proposedEvents = events.Select(ToEventData);

        var resultTask = expectedVersion == ExpectedStreamVersion.NoStream
            ? _client.AppendToStreamAsync(
            stream,
            StreamState.NoStream,
            proposedEvents,
            cancellationToken: cancellationToken
            ) : AnyOrNot(
            expectedVersion,
            () => _client.AppendToStreamAsync(
                stream,
                StreamState.Any,
                proposedEvents,
                cancellationToken: cancellationToken
                ),
            () => _client.AppendToStreamAsync(
                stream,
                expectedVersion.AsStreamRevision(),
                proposedEvents,
                cancellationToken: cancellationToken
                )
            );

        return(TryExecute(
                   async() => {
            var result = await resultTask.NoContext();

            return new AppendEventsResult(
                result.LogPosition.CommitPosition,
                result.NextExpectedStreamRevision.ToInt64()
                );
        },
                   stream,
                   () => new ErrorInfo("Unable to appends events to {Stream}", stream),
                   (s, ex) => {
            EventuousEventSource.Log.UnableToAppendEvents(stream, ex);
            return new AppendToStreamException(s, ex);
        }
                   ));

        EventData ToEventData(StreamEvent streamEvent)
        {
            var(eventType, contentType, payload) = _serializer.SerializeEvent(streamEvent.Payload !);

            return(new EventData(
                       Uuid.FromGuid(streamEvent.Id),
                       eventType,
                       payload,
                       _metaSerializer.Serialize(streamEvent.Metadata),
                       contentType
                       ));
        }
    }
예제 #9
0
 static Task <T> AnyOrNot <T>(
     ExpectedStreamVersion version,
     Func <Task <T> > whenAny,
     Func <Task <T> > otherwise
     )
 => version == ExpectedStreamVersion.Any ? whenAny() : otherwise();
예제 #10
0
 public Task <AppendEventsResult> AppendEvents(
     StreamName stream,
     ExpectedStreamVersion expectedVersion,
     IReadOnlyCollection <StreamEvent> events,
     CancellationToken cancellationToken
     ) => default !;
예제 #11
0
 public Task DeleteStream(
     StreamName stream,
     ExpectedStreamVersion expectedVersion,
     CancellationToken cancellationToken
     ) => default !;
예제 #12
0
 public Task TruncateStream(
     StreamName stream,
     StreamTruncatePosition truncatePosition,
     ExpectedStreamVersion expectedVersion,
     CancellationToken cancellationToken
     ) => default !;