Esempio n. 1
0
 /// <summary>
 /// Subscribes the specified aggregator to a catchup.
 /// </summary>
 /// <typeparam name="TProjection">The type of the projection.</typeparam>
 /// <typeparam name="TData">The type of the stream's data.</typeparam>
 /// <typeparam name="TCursor">The type of the cursor.</typeparam>
 /// <param name="catchup">The catchup.</param>
 /// <param name="aggregator">The aggregator.</param>
 /// <returns>A disposable that, when disposed, unsubscribes the aggregator.</returns>
 public static IDisposable Subscribe <TProjection, TData, TCursor>(
     this IStreamCatchup <TData, TCursor> catchup,
     IStreamAggregator <TProjection, TData> aggregator,
     FetchAndSaveProjection <TProjection> manageProjection,
     HandleAggregatorError <TProjection> onError = null)
 {
     return(catchup.SubscribeAggregator(aggregator, manageProjection, onError));
 }
Esempio n. 2
0
 /// <summary>
 /// Wraps a stream aggregator in a decorator function having the same signature.
 /// </summary>
 /// <typeparam name="TProjection">The type of the projection.</typeparam>
 /// <typeparam name="TData">The type of the data.</typeparam>
 /// <param name="aggregator">The aggregator.</param>
 /// <param name="initial">The prior state of the projection.</param>
 /// <returns>A new aggregator that wraps calls to the specified aggregator.</returns>
 public static IStreamAggregator <TProjection, TData> Pipeline <TProjection, TData>(
     this IStreamAggregator <TProjection, TData> aggregator,
     Func <TProjection, IStreamBatch <TData>, AggregateAsync <TProjection, TData>, Task> initial)
 {
     return(Create <TProjection, TData>((projection, batch) => initial(projection,
                                                                       batch,
                                                                       aggregator.Aggregate)));
 }
Esempio n. 3
0
 /// <summary>
 /// Subscribes the specified aggregator to a catchup.
 /// </summary>
 /// <typeparam name="TProjection">The type of the projection.</typeparam>
 /// <typeparam name="TData">The type of the stream's data.</typeparam>
 /// <typeparam name="TCursor">The type of the cursor.</typeparam>
 /// <param name="catchup">The catchup.</param>
 /// <param name="aggregator">The aggregator.</param>
 /// <param name="projectionStore">The projection store.</param>
 /// <returns>A disposable that, when disposed, unsubscribes the aggregator.</returns>
 public static IDisposable Subscribe <TProjection, TData, TCursor>(
     this IStreamCatchup <TData, TCursor> catchup,
     IStreamAggregator <TProjection, TData> aggregator,
     IProjectionStore <string, TProjection> projectionStore = null)
 {
     return(catchup.Subscribe(aggregator,
                              projectionStore.AsHandler()));
 }
Esempio n. 4
0
        /// <summary>
        /// Traces calls to the specified aggregator.
        /// </summary>
        /// <typeparam name="TProjection">The type of the projection.</typeparam>
        /// <typeparam name="TData">The type of the data.</typeparam>
        /// <param name="aggregator">The aggregator.</param>
        /// <param name="write">A delegate that can be used to specify how the arguments should be traced. If this is not provided, output is sent to <see cref="System.Diagnostics.Trace" />.</param>
        /// <returns>The original aggregator wrapped in a tracing decorator.</returns>
        public static IStreamAggregator <TProjection, TData> Trace <TProjection, TData>(
            this IStreamAggregator <TProjection, TData> aggregator,
            Action <TProjection, IStreamBatch <TData> > write = null)
        {
            write = write ?? TraceDefault;

            return(aggregator.Pipeline(async(projection, batch, next) =>
            {
                try
                {
                    write(projection, batch);
                    return await next(projection, batch);
                }
                catch (Exception exception)
                {
                    System.Diagnostics.Trace.WriteLine("[Aggregate] Exception: " + exception);
                    throw;
                }
            }));
        }
Esempio n. 5
0
        /// <summary>
        /// Aggregates a single batch of data from a stream using the specified aggregator and projection.
        /// </summary>
        /// <typeparam name="TProjection">The type of the projection.</typeparam>
        /// <typeparam name="TData">The type of the data.</typeparam>
        /// <typeparam name="TCursor">The type of the cursor.</typeparam>
        /// <param name="stream">The stream.</param>
        /// <param name="aggregator">The aggregator.</param>
        /// <param name="projection">The projection.</param>
        /// <returns>The updated state of the projection.</returns>
        /// <remarks>This method can be used to create on-demand projections. It does not do any projection persistence.</remarks>
        public static async Task <TProjection> Aggregate <TProjection, TData, TCursor>(
            this IStream <TData, TCursor> stream,
            IStreamAggregator <TProjection, TData> aggregator,
            TProjection projection = null)
            where TProjection : class
        {
            var cursor = (projection as ICursor <TCursor>) ??
                         stream.NewCursor();

            var query = stream.CreateQuery(cursor);

            var data = await query.NextBatch();

            if (data.Any())
            {
                projection = await aggregator.Aggregate(projection, data);
            }

            return(projection);
        }
        public IDisposable SubscribeAggregator <TProjection>(
            IStreamAggregator <TProjection, TData> aggregator,
            FetchAndSaveProjection <TProjection> fetchAndSaveProjection,
            HandleAggregatorError <TProjection> onError)
        {
            var added = aggregatorSubscriptions.TryAdd(typeof(TProjection),
                                                       new AggregatorSubscription <TProjection, TData>(aggregator,
                                                                                                       fetchAndSaveProjection,
                                                                                                       onError));

            if (!added)
            {
                throw new InvalidOperationException(string.Format("Aggregator for projection of type {0} is already subscribed.", typeof(TProjection)));
            }

            return(Disposable.Create(() =>
            {
                IAggregatorSubscription _;
                aggregatorSubscriptions.TryRemove(typeof(TProjection), out _);
            }));
        }
Esempio n. 7
0
        public AggregatorSubscription(
            IStreamAggregator <TProjection, TData> aggregator,
            FetchAndSaveProjection <TProjection> fetchAndSaveProjection = null,
            HandleAggregatorError <TProjection> onError = null)
        {
            if (aggregator == null)
            {
                throw new ArgumentNullException("aggregator");
            }

            OnError = onError ?? (error => { });

            if (onError != null)
            {
                fetchAndSaveProjection = fetchAndSaveProjection.Catch(onError);
            }

            FetchAndSaveProjection = fetchAndSaveProjection ??
                                     (async(streamId, aggregate) =>
            {
                await aggregate(Activator.CreateInstance <TProjection>());
            });
            Aggregator = aggregator;
        }