public Task <WriteResult> Append(IEnumerable <IDomainEvent> events, Maybe <long> expectedVersion = default) { return(_store.AppendToStreamAsync( Id, expectedVersion.OrElse(ExpectedVersion.NoStream), events.Select(e => _serializer.Serialize(e, Guid.NewGuid(), _metadataContext.GetMetadata())))); }
public static async Task ExecuteAsync <TState>(IEventStore store, ICommand command, Func <TState, IEvent[]> action, Func <IEvent[], Task> pub) where TState : class, new() { if (command.CorrelationId == default(Guid)) { throw new ArgumentException("CorrelationId required"); } var aggregateName = typeof(TState).Name.Replace("State", "Aggregate").ToLower(); var streamName = $"{aggregateName}-{command.AggregateId}"; var happend = await store.LoadEventStreamAsync(streamName, 0); var state = happend.Events.Rehydrate <TState>(); var events = action(state); events .Where(x => x.Meta == null) .ForEach(x => x.Meta = new Dictionary <string, string>()); events .ForEach(x => x .Tap(e => e.Meta.AddMetaData(happend.Version + 1, streamName, aggregateName, command)) .Tap(e => e.Meta.AddTypeInfo(e)) ); if (events.Any()) { await store.AppendToStreamAsync(streamName, events.Last().GetVersion(), events); } await pub(events); //need to always execute due to locks }
public async Task <bool> SaveOrder(EventUserInfo eventUserInfo, Order aggregate, OrderSnapshot snapshot = null) { if (aggregate.Changes.Any()) { var streamId = aggregate.Id.ToString(); // save all events bool savedEvents = await _eventStore.AppendToStreamAsync(eventUserInfo, streamId, aggregate.Version, aggregate.Changes); // save snapshot if (savedEvents && snapshot != null && _snapshotStore != null) { await SaveOrderSnapshot(snapshot); } return(savedEvents); } return(true); }
public async Task <bool> SaveMeterAsync(Meter meter) { if (meter.Changes.Any()) { var streamId = $"meter:{meter.MeterId}"; return(await _eventStore.AppendToStreamAsync( streamId, meter.Version, meter.Changes)); } return(true); }
/// <summary> /// Commits any pending events previously appended with <see cref="Append{T}"/> to the /// <see cref="IEventStore"/> specified by <paramref name="store"/>, and clears the queue of pending events. /// </summary> /// <param name="store">The <see cref="IEventStore"/> to store events in.</param> /// <param name="configuration">The configuration of the aggregate.</param> /// <param name="cancellationToken">Cancellation token.</param> /// <returns>A <see cref="Task{TResult}"/></returns> /// <exception cref="InvalidOperationException"> /// If there are no pending events, previously appended with <see cref="Append{T}"/>, to commit. /// </exception> /// <remarks> /// Intended to be wrapped by a public member on the aggregate, in order to keep the aggregate configuration /// private, like so: /// <code> /// public sealed class Goat : Aggregate<GoatId, Goat> /// { /// private static readonly AggregateConfiguration<GoatId, Goat> Configuration = /// new AggregateConfiguration<GoatId, Goat>("goat"); /// /// public Task CommitAsync(IEventStore store) => CommitAsync(store, Configuration); /// } /// </code> /// </remarks> protected internal async Task CommitAsync( IEventStore store, AggregateConfiguration <TIdentity, TAggregate> configuration, CancellationToken cancellationToken = default ) { if (_pendingEvents.Count == 0) { throw new InvalidOperationException("There are no pending events to commit"); } var pendingEvents = _pendingEvents.ToArray(); await store.AppendToStreamAsync(Id, configuration, _versionNumber, pendingEvents, cancellationToken); _versionNumber += _pendingEvents.Count; _pendingEvents.Clear(); }
public static async Task <long> AppendToStreamAsync(this IEventStore store, string streamName, params IEvent[] events) { var r = await store.LoadEventStreamAsync(streamName, 0); //TODO optimize :) return(await store.AppendToStreamAsync(streamName, r.Version, events)); }