Esempio n. 1
0
        /// <summary>
        /// Register a projection to the Marten configuration
        /// </summary>
        /// <param name="projection">Value values are Inline/Async, The default is Inline</param>
        /// <param name="lifecycle"></param>
        /// <param name="projectionName">Overwrite the named identity of this projection. This is valuable if using the projection asynchonously</param>
        /// <param name="asyncConfiguration">Optional configuration including teardown instructions for the usage of this projection within the async projection daempon</param>
        public void Add(IProjection projection, ProjectionLifecycle lifecycle = ProjectionLifecycle.Inline,
                        string projectionName = null, Action <AsyncOptions> asyncConfiguration = null)
        {
            if (lifecycle == ProjectionLifecycle.Live)
            {
                throw new ArgumentOutOfRangeException(nameof(lifecycle),
                                                      $"{nameof(ProjectionLifecycle.Live)} cannot be used for IProjection");
            }

            if (projection is ProjectionBase p)
            {
                p.AssembleAndAssertValidity();
                p.Lifecycle = lifecycle;
            }

            if (projection is IProjectionSource source)
            {
                asyncConfiguration?.Invoke(source.Options);
                All.Add(source);
            }
            else
            {
                var wrapper = new ProjectionWrapper(projection, lifecycle);
                if (projectionName.IsNotEmpty())
                {
                    wrapper.ProjectionName = projectionName;
                }

                asyncConfiguration?.Invoke(wrapper.Options);
                All.Add(wrapper);
            }
        }
Esempio n. 2
0
        public async ValueTask ApplyChangesAsync(DocumentSessionBase session,
                                                 EventSlice <TDoc, TId> slice, CancellationToken cancellation,
                                                 ProjectionLifecycle lifecycle = ProjectionLifecycle.Inline)
        {
            if (Projection.MatchesAnyDeleteType(slice))
            {
                var operation = Storage.DeleteForId(slice.Id, slice.Tenant.TenantId);
                session.QueueOperation(operation);
                return;
            }

            var aggregate = slice.Aggregate;

            if (slice.Aggregate == null && lifecycle == ProjectionLifecycle.Inline)
            {
                aggregate = await Storage.LoadAsync(slice.Id, session, cancellation).ConfigureAwait(false);
            }

            // Does the aggregate already exist before the events are applied?
            var exists = aggregate != null;

            foreach (var @event in slice.Events())
            {
                try
                {
                    aggregate = await ApplyEvent(session, slice, @event, aggregate, cancellation).ConfigureAwait(false);
                }
                catch (MartenCommandException)
                {
                    throw;
                }
                catch (NpgsqlException)
                {
                    throw;
                }
                catch (Exception e)
                {
                    throw new ApplyEventException(@event, e);
                }
            }

            if (aggregate != null)
            {
                Storage.SetIdentity(aggregate, slice.Id);
            }

            // Delete the aggregate *if* it existed prior to these events
            if (aggregate == null)
            {
                if (exists)
                {
                    var operation = Storage.DeleteForId(slice.Id, slice.Tenant.TenantId);
                    session.QueueOperation(operation);
                }

                return;
            }

            session.QueueOperation(Storage.Upsert(aggregate, session, slice.Tenant.TenantId));
        }
Esempio n. 3
0
        public override ValueTask ApplyChangesAsync(DocumentSessionBase session, EventSlice <CustomAggregate, int> slice, CancellationToken cancellation,
                                                    ProjectionLifecycle lifecycle = ProjectionLifecycle.Inline)
        {
            var aggregate = slice.Aggregate ?? new CustomAggregate {
                Id = slice.Id
            };

            foreach (var @event in slice.Events())
            {
                if (@event.Data is CustomEvent e)
                {
                    switch (e.Letter)
                    {
                    case 'a':
                        aggregate.ACount++;
                        break;

                    case 'b':
                        aggregate.BCount++;
                        break;

                    case 'c':
                        aggregate.CCount++;
                        break;

                    case 'd':
                        aggregate.DCount++;
                        break;
                    }
                }
            }

            session.Store(aggregate);
            return(new ValueTask());
        }
Esempio n. 4
0
        /// <summary>
        /// Register a projection to the Marten configuration
        /// </summary>
        /// <param name="projection">Value values are Inline/Async, The default is Inline</param>
        /// <param name="lifecycle"></param>
        /// <param name="projectionName">Overwrite the named identity of this projection. This is valuable if using the projection asynchonously</param>
        /// <param name="asyncConfiguration">Optional configuration including teardown instructions for the usage of this projection within the async projection daempon</param>
        public void Add(IProjection projection, ProjectionLifecycle lifecycle = ProjectionLifecycle.Inline,
                        string projectionName = null, Action <AsyncOptions> asyncConfiguration = null)
        {
            if (lifecycle == ProjectionLifecycle.Live)
            {
                throw new ArgumentOutOfRangeException(nameof(lifecycle),
                                                      $"{nameof(ProjectionLifecycle.Live)} cannot be used for IProjection");
            }


            var wrapper = new ProjectionWrapper(projection, lifecycle);

            if (projectionName.IsNotEmpty())
            {
                wrapper.ProjectionName = projectionName;
            }

            asyncConfiguration?.Invoke(wrapper.Options);
            All.Add(wrapper);
        }
Esempio n. 5
0
        public override ValueTask ApplyChangesAsync(DocumentSessionBase session, EventSlice <StartAndStopAggregate, Guid> slice, CancellationToken cancellation,
                                                    ProjectionLifecycle lifecycle = ProjectionLifecycle.Inline)
        {
            var aggregate = slice.Aggregate;


            foreach (var data in slice.AllData())
            {
                switch (data)
                {
                case Start:
                    aggregate = new StartAndStopAggregate
                    {
                        // Have to assign the identity ourselves
                        Id = slice.Id
                    };
                    break;

                case Increment when aggregate is { Deleted: false } :
                    // Use explicit code to only apply this event
                    // if the aggregate already exists
                    aggregate.Increment();
                    break;
Esempio n. 6
0
 public override ValueTask ApplyChangesAsync(DocumentSessionBase session, EventSlice <CustomAggregate, int> slice, CancellationToken cancellation,
                                             ProjectionLifecycle lifecycle = ProjectionLifecycle.Inline)
 {
     throw new NotImplementedException();
 }
Esempio n. 7
0
        public async Task <IStorageOperation?> DetermineOperation(DocumentSessionBase session,
                                                                  EventSlice <TDoc, TId> slice, CancellationToken cancellation, ProjectionLifecycle lifecycle = ProjectionLifecycle.Inline)
        {
            var aggregate = slice.Aggregate;

            if (slice.Aggregate == null && lifecycle == ProjectionLifecycle.Inline)
            {
                aggregate = await Storage.LoadAsync(slice.Id, session, cancellation).ConfigureAwait(false);
            }

            var exists = aggregate != null;

            foreach (var @event in slice.Events())
            {
                try
                {
                    aggregate = await ApplyEvent(session, slice, @event, aggregate, cancellation).ConfigureAwait(false);
                }
                catch (MartenCommandException)
                {
                    throw;
                }
                catch (NpgsqlException)
                {
                    throw;
                }
                catch (Exception e)
                {
                    throw new ApplyEventException(@event, e);
                }
            }

            if (aggregate != null)
            {
                Storage.SetIdentity(aggregate, slice.Id);
            }

            if (aggregate == null)
            {
                return(exists ? Storage.DeleteForId(slice.Id, slice.Tenant) : null);
            }

            return(Storage.Upsert(aggregate, session, slice.Tenant));
        }
Esempio n. 8
0
 public ProjectionWrapper(IProjection projection, ProjectionLifecycle lifecycle) : base(projection.GetType().FullNameInCode())
 {
     _projection = projection;
     Lifecycle   = lifecycle;
 }
Esempio n. 9
0
 /// <summary>
 /// Apply any document changes based on the incoming slice of events to the underlying aggregate document
 /// </summary>
 /// <param name="session"></param>
 /// <param name="slice"></param>
 /// <param name="cancellation"></param>
 /// <param name="lifecycle"></param>
 /// <returns></returns>
 public abstract ValueTask ApplyChangesAsync(DocumentSessionBase session, EventSlice <TDoc, TId> slice,
                                             CancellationToken cancellation,
                                             ProjectionLifecycle lifecycle = ProjectionLifecycle.Inline);
Esempio n. 10
0
        public async Task <IStorageOperation> DetermineOperation(DocumentSessionBase session,
                                                                 EventSlice <TDoc, TId> slice, CancellationToken cancellation, ProjectionLifecycle lifecycle = ProjectionLifecycle.Inline)
        {
            var aggregate = slice.Aggregate;

            if (slice.Aggregate == null && lifecycle == ProjectionLifecycle.Inline)
            {
                aggregate = await Storage.LoadAsync(slice.Id, session, cancellation);
            }

            var exists = aggregate != null;

            foreach (var @event in slice.Events)
            {
                aggregate = await ApplyEvent(session, slice, @event, aggregate, cancellation);
            }

            if (aggregate != null)
            {
                Storage.SetIdentity(aggregate, slice.Id);
            }

            if (aggregate == null)
            {
                return(exists ? Storage.DeleteForId(slice.Id, slice.Tenant) : null);
            }

            return(Storage.Upsert(aggregate, session, slice.Tenant));
        }