/// <summary>Helper async method to get the first element of an async sequence</summary>
        /// <typeparam name="TSource">Type of elements of the async sequence</typeparam>
        /// <param name="source">Source async sequence</param>
        /// <param name="single">If true, the sequence must contain at most one element</param>
        /// <param name="orDefault">When the sequence is empty: If true then returns the default value for the type. Otherwise, throws an exception</param>
        /// <param name="ct">Cancellation token that can be used to cancel the operation</param>
        /// <returns>Value of the first element of the <param ref="source"/> sequence, or the default value, or an exception (depending on <paramref name="single"/> and <paramref name="orDefault"/></returns>
        internal static async Task <TSource> Head <TSource>(
            [NotNull] IFdbAsyncEnumerable <TSource> source,
            bool single,
            bool orDefault,
            CancellationToken ct)
        {
            ct.ThrowIfCancellationRequested();

            //note: we should not use "ConfigureAwait(false)" here because we would like to execute the action in the original synchronization context if possible...

            using (var iterator = source.GetEnumerator(FdbAsyncMode.Head))
            {
                Contract.Assert(iterator != null, "The underlying sequence returned a null async iterator");

                if (await iterator.MoveNext(ct))
                {
                    TSource first = iterator.Current;
                    if (single)
                    {
                        if (await iterator.MoveNext(ct))
                        {
                            throw new InvalidOperationException("The sequence contained more than one element");
                        }
                    }
                    return(first);
                }
                if (!orDefault)
                {
                    throw new InvalidOperationException("The sequence was empty");
                }
                return(default(TSource));
            }
        }
        /// <summary>Immediately execute an async action on each element of an async sequence</summary>
        /// <typeparam name="TSource">Type of elements of the async sequence</typeparam>
        /// <param name="source">Source async sequence</param>
        /// <param name="mode">Expected execution mode of the query</param>
        /// <param name="action">Asynchronous action to perform on each element as it arrives</param>
        /// <param name="ct">Cancellation token that can be used to cancel the operation</param>
        /// <returns>Number of items that have been processed</returns>
        internal static async Task <long> Run <TSource>(
            [NotNull] IFdbAsyncEnumerable <TSource> source,
            FdbAsyncMode mode,
            [NotNull] Func <TSource, Task> action,
            CancellationToken ct)
        {
            ct.ThrowIfCancellationRequested();

            //note: we should not use "ConfigureAwait(false)" here because we would like to execute the action in the original synchronization context if possible...

            long count = 0;

            using (var iterator = source.GetEnumerator(mode))
            {
                Contract.Assert(iterator != null, "The underlying sequence returned a null async iterator");

                while (await iterator.MoveNext(ct))
                {
                    ct.ThrowIfCancellationRequested();
                    await action(iterator.Current);

                    ++count;
                }
            }
            return(count);
        }
Esempio n. 3
0
        /// <summary>Start the inner iterator</summary>
        protected virtual IFdbAsyncEnumerator <TSource> StartInner()
        {
            // filtering changes the number of items, so that means that, even if the underlying caller wants one item, we may need to read more.
            // => change all "Head" requests into "Iterator" to prevent any wrong optimizations by the underlying source (ex: using a too small batch size)
            var mode = m_mode;

            if (mode == FdbAsyncMode.Head)
            {
                mode = FdbAsyncMode.Iterator;
            }

            return(m_source.GetEnumerator(mode));
        }
Esempio n. 4
0
            public IFdbAsyncEnumerator <TSource> GetEnumerator(FdbAsyncMode mode = FdbAsyncMode.Default)
            {
                var sorter     = GetEnumerableSorter(null);
                var enumerator = default(IFdbAsyncEnumerator <TSource>);

                try
                {
                    enumerator = m_source.GetEnumerator(mode);
                    return(new OrderedEnumerator <TSource>(enumerator, sorter));
                }
                catch (Exception)
                {
                    if (enumerator != null)
                    {
                        enumerator.Dispose();
                    }
                    throw;
                }
            }