context: using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Linq.Expressions;
  using NHibernate.Impl;
  using NHibernate.Multi;
  using NHibernate.Type;
  using NHibernate.Util;
  using Remotion.Linq.Parsing.ExpressionVisitors;
  using System.Threading;
  using System.Threading.Tasks;
  using NHibernate.Engine;
  using static NHibernate.Util.ReflectionCache.QueryableMethods;
  
  namespace NHibernate.Linq
  {
  	/// <summary>
  	/// NHibernate LINQ extension methods. They are meant to work with <see cref="NhQueryable{T}"/>. Supplied <see cref="IQueryable{T}"/> parameters
  	/// should at least have an <see cref="INhQueryProvider"/> <see cref="IQueryable.Provider"/>. <see cref="ISession.Query{T}()"/> and
  	/// its overloads supply such queryables.
  	/// </summary>
  	public static class LinqExtensionMethods
  	{
  		#region AnyAsync
  
  		/// <summary>Determines whether a sequence contains any elements.</summary>
  		/// <param name="source">A sequence to check for being empty.</param>
  		/// <param name="cancellationToken">A cancellation token that can be used to cancel the work.</param>
  		/// <typeparam name="TSource">The type of the elements of <paramref name="source" />.</typeparam>
  		/// <returns>true if the source sequence contains any elements; otherwise, false.</returns>
  		/// <exception cref="T:System.ArgumentNullException"><paramref name="source" /> is <see langword="null"/>.</exception>
  		/// <exception cref="T:System.NotSupportedException"><paramref name="source" /> <see cref="IQueryable.Provider"/> is not a <see cref="INhQueryProvider"/>.</exception>
  		public static Task<bool> AnyAsync<TSource>(this IQueryable<TSource> source, CancellationToken cancellationToken = default(CancellationToken))
  		{
  			if (source == null)
  			{
  				throw new ArgumentNullException(nameof(source));
  			}
  			if (!(source.Provider is INhQueryProvider provider))
  			{
  				throw new NotSupportedException($"Source {nameof(source.Provider)} must be a {nameof(INhQueryProvider)}");
  			}
  			if (cancellationToken.IsCancellationRequested)
  			{
  				return Task.FromCanceled<bool>(cancellationToken);
  			}
  			try
  			{
  				var methodInfo = ReflectionCache.QueryableMethods.AnyDefinition.MakeGenericMethod(typeof(TSource));
  				var expression = new[] { source.Expression };
  				return provider.ExecuteAsync<bool>(Expression.Call(null, methodInfo, expression), cancellationToken);
  			}
  			catch (Exception ex)
  			{
  				return Task.FromException<bool>(ex);
  			}
  		}
  
  		/// <summary>Determines whether any element of a sequence satisfies a condition.</summary>
  		/// <param name="source">A sequence whose elements to test for a condition.</param>
  		/// <param name="predicate">A function to test each element for a condition.</param>
  		/// <param name="cancellationToken">A cancellation token that can be used to cancel the work.</param>
  		/// <typeparam name="TSource">The type of the elements of <paramref name="source" />.</typeparam>
  		/// <returns>true if any elements in the source sequence pass the test in the specified predicate; otherwise, false.</returns>
  		/// <exception cref="T:System.ArgumentNullException"><paramref name="source" /> or <paramref name="predicate" /> is <see langword="null"/>.</exception>
  		/// <exception cref="T:System.NotSupportedException"><paramref name="source" /> <see cref="IQueryable.Provider"/> is not a <see cref="INhQueryProvider"/>.</exception>
  		public static Task<bool> AnyAsync<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate, CancellationToken cancellationToken = default(CancellationToken))
  		{
  			if (source == null)
  			{
  				throw new ArgumentNullException(nameof(source));
  			}
  			if (predicate == null)
  			{
  				throw new ArgumentNullException(nameof(predicate));
  			}
  			if (!(source.Provider is INhQueryProvider provider))
  			{
  				throw new NotSupportedException($"Source {nameof(source.Provider)} must be a {nameof(INhQueryProvider)}");
  			}
  			if (cancellationToken.IsCancellationRequested)
  			{
  				return Task.FromCanceled<bool>(cancellationToken);
  			}
  			try
  			{
  				var methodInfo = ReflectionCache.QueryableMethods.AnyWithPredicateDefinition.MakeGenericMethod(typeof(TSource));
  				var expression = new[] { source.Expression, Expression.Quote(predicate) };
  				return provider.ExecuteAsync<bool>(Expression.Call(null, methodInfo, expression), cancellationToken);
  			}
  			catch (Exception ex)
  			{
  				return Task.FromException<bool>(ex);
  			}
  		}
  
  		#endregion
  
  		#region AllAsync
  
  		/// <summary>Determines whether all elements of a sequence satisfies a condition.</summary>
  		/// <param name="source">A sequence whose elements to test for a condition.</param>
  		/// <param name="predicate">A function to test each element for a condition.</param>
  		/// <param name="cancellationToken">A cancellation token that can be used to cancel the work.</param>
  		/// <typeparam name="TSource">The type of the elements of <paramref name="source" />.</typeparam>
  		/// <returns>true if all elements in the source sequence pass the test in the specified predicate; otherwise, false.</returns>
  		/// <exception cref="T:System.ArgumentNullException"><paramref name="source" /> or <paramref name="predicate" /> is <see langword="null"/>.</exception>
  		/// <exception cref="T:System.NotSupportedException"><paramref name="source" /> <see cref="IQueryable.Provider"/> is not a <see cref="INhQueryProvider"/>.</exception>
  		public static Task<bool> AllAsync<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate, CancellationToken cancellationToken = default(CancellationToken))
  		{
  			if (source == null)
  			{
  				throw new ArgumentNullException(nameof(source));
  			}
  			if (predicate == null)
  			{
  				throw new ArgumentNullException(nameof(predicate));
  			}
  			if (!(source.Provider is INhQueryProvider provider))
  			{
  				throw new NotSupportedException($"Source {nameof(source.Provider)} must be a {nameof(INhQueryProvider)}");
  			}
  			if (cancellationToken.IsCancellationRequested)
  			{
  				return Task.FromCanceled<bool>(cancellationToken);
  			}
  			try
  			{
  				var methodInfo = ReflectionCache.QueryableMethods.AllDefinition.MakeGenericMethod(typeof(TSource));
  				var expression = new[] { source.Expression, Expression.Quote(predicate) };
  				return provider.ExecuteAsync<bool>(Expression.Call(null, methodInfo, expression), cancellationToken);
  			}
  			catch (Exception ex)
  			{
  				return Task.FromException<bool>(ex);
  			}
  		}
  
  		#endregion
  
  		#region CountAsync
  
  		/// <summary>Returns the number of elements in a sequence.</summary>
  		/// <param name="source">The <see cref="T:System.Linq.IQueryable`1" /> that contains the elements to be counted.</param>
  		/// <param name="cancellationToken">A cancellation token that can be used to cancel the work.</param>
  		/// <typeparam name="TSource">The type of the elements of <paramref name="source" />.</typeparam>
  		/// <returns>The number of elements in the input sequence.</returns>
  		/// <exception cref="T:System.ArgumentNullException"><paramref name="source" /> is <see langword="null"/>.</exception>
  		/// <exception cref="T:System.NotSupportedException"><paramref name="source" /> <see cref="IQueryable.Provider"/> is not a <see cref="INhQueryProvider"/>.</exception>
  		/// <exception cref="T:System.OverflowException">The number of elements in <paramref name="source" /> is larger than <see cref="F:System.Int32.MaxValue" />.</exception>
  		public static Task<int> CountAsync<TSource>(this IQueryable<TSource> source, CancellationToken cancellationToken = default(CancellationToken))
  		{
  			if (source == null)
  			{
  				throw new ArgumentNullException(nameof(source));
  			}
  			if (!(source.Provider is INhQueryProvider provider))
  			{
  				throw new NotSupportedException($"Source {nameof(source.Provider)} must be a {nameof(INhQueryProvider)}");
  			}
  			if (cancellationToken.IsCancellationRequested)
  			{
  				return Task.FromCanceled<int>(cancellationToken);
  			}
  			try
  			{
  				var methodInfo = ReflectionCache.QueryableMethods.CountDefinition.MakeGenericMethod(typeof(TSource));
  				var expression = new[] { source.Expression };
  				return provider.ExecuteAsync<int>(Expression.Call(null, methodInfo, expression), cancellationToken);
  			}
  			catch (Exception ex)
  			{
  				return Task.FromException<int>(ex);
  			}
  		}
  
  		/// <summary>Returns the number of elements in the specified sequence that satisfies a condition.</summary>
  		/// <param name="source">An <see cref="T:System.Linq.IQueryable`1" /> that contains the elements to be counted.</param>
  		/// <param name="predicate">A function to test each element for a condition.</param>
  		/// <param name="cancellationToken">A cancellation token that can be used to cancel the work.</param>
  		/// <typeparam name="TSource">The type of the elements of <paramref name="source" />.</typeparam>
  		/// <returns>The number of elements in the sequence that satisfies the condition in the predicate function.</returns>
  		/// <exception cref="T:System.ArgumentNullException"><paramref name="source" /> or <paramref name="predicate" /> is <see langword="null"/>.</exception>
  		/// <exception cref="T:System.NotSupportedException"><paramref name="source" /> <see cref="IQueryable.Provider"/> is not a <see cref="INhQueryProvider"/>.</exception>
  		/// <exception cref="T:System.OverflowException">The number of elements in <paramref name="source" /> is larger than <see cref="F:System.Int32.MaxValue" />.</exception>
  		public static Task<int> CountAsync<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate, CancellationToken cancellationToken = default(CancellationToken))
  		{
  			if (source == null)
  			{
  				throw new ArgumentNullException(nameof(source));
  			}
  			if (predicate == null)
  			{
  				throw new ArgumentNullException(nameof(predicate));
  			}
  			if (!(source.Provider is INhQueryProvider provider))
  			{
  				throw new NotSupportedException($"Source {nameof(source.Provider)} must be a {nameof(INhQueryProvider)}");
  			}
  			if (cancellationToken.IsCancellationRequested)
  			{
  				return Task.FromCanceled<int>(cancellationToken);
  			}
  			try
  			{
  				var methodInfo = ReflectionCache.QueryableMethods.CountWithPredicateDefinition.MakeGenericMethod(typeof(TSource));
  				var expression = new[] { source.Expression, Expression.Quote(predicate) };
  				return provider.ExecuteAsync<int>(Expression.Call(null, methodInfo, expression), cancellationToken);
  			}
  			catch (Exception ex)
  			{
  				return Task.FromException<int>(ex);
  			}
  		}
  
  		#endregion
  
  		#region SumAsync
  
  		/// <summary>
  		/// Computes the sum of a sequence of <see cref="T:System.Int32"/> values.
  		/// </summary>
  		/// <param name="source">A sequence of <see cref="T:System.Int32"/> values to calculate the sum of.</param>
  		/// <param name="cancellationToken">A cancellation token that can be used to cancel the work.</param>
  		/// <returns>
  		/// The sum of the values in the sequence.
  		/// </returns>
  		/// <exception cref="T:System.ArgumentNullException"><paramref name="source"/> is <see langword="null"/>.</exception>
  		/// <exception cref="T:System.NotSupportedException"><paramref name="source" /> <see cref="IQueryable.Provider"/> is not a <see cref="INhQueryProvider"/>.</exception>
  		/// <exception cref="T:System.OverflowException">The sum is larger than <see cref="F:System.Int32.MaxValue"/>.</exception>
  		public static Task<int> SumAsync(this IQueryable<int> source, CancellationToken cancellationToken = default(CancellationToken))
  		{
  			if (source == null)
  			{
  				throw new ArgumentNullException(nameof(source));
  			}
  			if (!(source.Provider is INhQueryProvider provider))
  			{
  				throw new NotSupportedException($"Source {nameof(source.Provider)} must be a {nameof(INhQueryProvider)}");
  			}
  			if (cancellationToken.IsCancellationRequested)
  			{
  				return Task.FromCanceled<int>(cancellationToken);
  			}
  			try
  			{
  				var methodInfo = ReflectionCache.QueryableMethods.SumOfInt;
  				var expression = new[] { source.Expression };
  				return provider.ExecuteAsync<int>(Expression.Call(null, methodInfo, expression), cancellationToken);
  			}
  			catch (Exception ex)
  			{
  				return Task.FromException<int>(ex);
  			}
  		}
  
  		/// <summary>
  		/// Computes the sum of a sequence of nullable <see cref="T:System.Int32"/> values.
  		/// </summary>
  		/// <param name="source">A sequence of nullable <see cref="T:System.Int32"/> values to calculate the sum of.</param>
  		/// <param name="cancellationToken">A cancellation token that can be used to cancel the work.</param>
  		/// <returns>
  		/// The sum of the values in the sequence.
  		/// </returns>
  		/// <exception cref="T:System.ArgumentNullException"><paramref name="source"/> is <see langword="null"/>.</exception>
  		/// <exception cref="T:System.NotSupportedException"><paramref name="source" /> <see cref="IQueryable.Provider"/> is not a <see cref="INhQueryProvider"/>.</exception>
  		/// <exception cref="T:System.OverflowException">The sum is larger than <see cref="F:System.Int32.MaxValue"/>.</exception>
  		public static Task<int?> SumAsync(this IQueryable<int?> source, CancellationToken cancellationToken = default(CancellationToken))
  		{
  			if (source == null)
  			{
  				throw new ArgumentNullException(nameof(source));
  			}
  			if (!(source.Provider is INhQueryProvider provider))
  			{
  				throw new NotSupportedException($"Source {nameof(source.Provider)} must be a {nameof(INhQueryProvider)}");
  			}
  			if (cancellationToken.IsCancellationRequested)
  			{
  				return Task.FromCanceled<int?>(cancellationToken);
  			}
  			try
  			{
  				var methodInfo = ReflectionCache.QueryableMethods.SumOfNullableInt;
  				var expression = new[] { source.Expression };
  				return provider.ExecuteAsync<int?>(Expression.Call(null, methodInfo, expression), cancellationToken);
  			}
  			catch (Exception ex)
  			{
  				return Task.FromException<int?>(ex);
  			}
  		}
  
  		/// <summary>
  		/// Computes the sum of a sequence of <see cref="T:System.Int64"/> values.
  		/// </summary>
  		/// <param name="source">A sequence of <see cref="T:System.Int64"/> values to calculate the sum of.</param>
  		/// <param name="cancellationToken">A cancellation token that can be used to cancel the work.</param>
  		/// <returns>
  		/// The sum of the values in the sequence.
  		/// </returns>
  		/// <exception cref="T:System.ArgumentNullException"><paramref name="source"/> is <see langword="null"/>.</exception>
  		/// <exception cref="T:System.NotSupportedException"><paramref name="source" /> <see cref="IQueryable.Provider"/> is not a <see cref="INhQueryProvider"/>.</exception>
  		/// <exception cref="T:System.OverflowException">The sum is larger than <see cref="F:System.Int64.MaxValue"/>.</exception>
  		public static Task<long> SumAsync(this IQueryable<long> source, CancellationToken cancellationToken = default(CancellationToken))
  		{
  			if (source == null)
  			{
  				throw new ArgumentNullException(nameof(source));
  			}
  			if (!(source.Provider is INhQueryProvider provider))
  			{
  				throw new NotSupportedException($"Source {nameof(source.Provider)} must be a {nameof(INhQueryProvider)}");
  			}
  			if (cancellationToken.IsCancellationRequested)
  			{
  				return Task.FromCanceled<long>(cancellationToken);
  			}
  			try
  			{
  				var methodInfo = ReflectionCache.QueryableMethods.SumOfLong;
  				var expression = new[] { source.Expression };
  				return provider.ExecuteAsync<long>(Expression.Call(null, methodInfo, expression), cancellationToken);
  			}
  			catch (Exception ex)
  			{
  				return Task.FromException<long>(ex);
  			}
  		}
  
  		/// <summary>
  		/// Computes the sum of a sequence of nullable <see cref="T:System.Int64"/> values.
  		/// </summary>
  		/// <param name="source">A sequence of nullable <see cref="T:System.Int64"/> values to calculate the sum of.</param>
  		/// <param name="cancellationToken">A cancellation token that can be used to cancel the work.</param>
  		/// <returns>
  		/// The sum of the values in the sequence.
  		/// </returns>
  		/// <exception cref="T:System.ArgumentNullException"><paramref name="source"/> is <see langword="null"/>.</exception>
  		/// <exception cref="T:System.NotSupportedException"><paramref name="source" /> <see cref="IQueryable.Provider"/> is not a <see cref="INhQueryProvider"/>.</exception>
  		/// <exception cref="T:System.OverflowException">The sum is larger than <see cref="F:System.Int64.MaxValue"/>.</exception>
  		public static Task<long?> SumAsync(this IQueryable<long?> source, CancellationToken cancellationToken = default(CancellationToken))
  		{
  			if (source == null)
  			{
  				throw new ArgumentNullException(nameof(source));
  			}
  			if (!(source.Provider is INhQueryProvider provider))
  			{
  				throw new NotSupportedException($"Source {nameof(source.Provider)} must be a {nameof(INhQueryProvider)}");
  			}
  			if (cancellationToken.IsCancellationRequested)
  			{
  				return Task.FromCanceled<long?>(cancellationToken);
  			}
  			try
  			{
  				var methodInfo = ReflectionCache.QueryableMethods.SumOfNullableLong;
  				var expression = new[] { source.Expression };
  				return provider.ExecuteAsync<long?>(Expression.Call(null, methodInfo, expression), cancellationToken);
  			}
  			catch (Exception ex)
  			{
  				return Task.FromException<long?>(ex);
  			}
  		}
  
  		/// <summary>
  		/// Computes the sum of a sequence of <see cref="T:System.Single"/> values.
  		/// </summary>
  		/// <param name="source">A sequence of <see cref="T:System.Single"/> values to calculate the sum of.</param>
  		/// <param name="cancellationToken">A cancellation token that can be used to cancel the work.</param>
  		/// <returns>
  		/// The sum of the values in the sequence.
  		/// </returns>
  		/// <exception cref="T:System.ArgumentNullException"><paramref name="source"/> is <see langword="null"/>.</exception>
  		/// <exception cref="T:System.NotSupportedException"><paramref name="source" /> <see cref="IQueryable.Provider"/> is not a <see cref="INhQueryProvider"/>.</exception>
  		/// <exception cref="T:System.OverflowException">The sum is larger than <see cref="F:System.Single.MaxValue"/>.</exception>
  		public static Task<float> SumAsync(this IQueryable<float> source, CancellationToken cancellationToken = default(CancellationToken))
  		{
  			if (source == null)
  			{
  				throw new ArgumentNullException(nameof(source));
  			}
  			if (!(source.Provider is INhQueryProvider provider))
  			{
  				throw new NotSupportedException($"Source {nameof(source.Provider)} must be a {nameof(INhQueryProvider)}");
  			}
  			if (cancellationToken.IsCancellationRequested)
  			{
  				return Task.FromCanceled<float>(cancellationToken);
  			}
  			try
  			{
  				var methodInfo = ReflectionCache.QueryableMethods.SumOfFloat;
  				var expression = new[] { source.Expression };
  				return provider.ExecuteAsync<float>(Expression.Call(null, methodInfo, expression), cancellationToken);
  			}
  			catch (Exception ex)
  			{
  				return Task.FromException<float>(ex);
  			}
  		}
  
  		/// <summary>
  		/// Computes the sum of a sequence of nullable <see cref="T:System.Single"/> values.
  		/// </summary>
  		/// <param name="source">A sequence of nullable <see cref="T:System.Single"/> values to calculate the sum of.</param>
  		/// <param name="cancellationToken">A cancellation token that can be used to cancel the work.</param>
  		/// <returns>
  		/// The sum of the values in the sequence.
  		/// </returns>
  		/// <exception cref="T:System.ArgumentNullException"><paramref name="source"/> is <see langword="null"/>.</exception>
  		/// <exception cref="T:System.NotSupportedException"><paramref name="source" /> <see cref="IQueryable.Provider"/> is not a <see cref="INhQueryProvider"/>.</exception>
  		/// <exception cref="T:System.OverflowException">The sum is larger than <see cref="F:System.Single.MaxValue"/>.</exception>
  		public static Task<float?> SumAsync(this IQueryable<float?> source, CancellationToken cancellationToken = default(CancellationToken))
  		{
  			if (source == null)
  			{
  				throw new ArgumentNullException(nameof(source));
  			}
  			if (!(source.Provider is INhQueryProvider provider))
  			{
  				throw new NotSupportedException($"Source {nameof(source.Provider)} must be a {nameof(INhQueryProvider)}");
  			}
  			if (cancellationToken.IsCancellationRequested)
  			{
  				return Task.FromCanceled<float?>(cancellationToken);
  			}
  			try
  			{
  				var methodInfo = ReflectionCache.QueryableMethods.SumOfNullableFloat;
  				var expression = new[] { source.Expression };
  				return provider.ExecuteAsync<float?>(Expression.Call(null, methodInfo, expression), cancellationToken);
  			}
  			catch (Exception ex)
  			{
  				return Task.FromException<float?>(ex);
  			}
  		}
  
  		/// <summary>
  		/// Computes the sum of a sequence of <see cref="T:System.Double"/> values.
  		/// </summary>
  		/// <param name="source">A sequence of <see cref="T:System.Double"/> values to calculate the sum of.</param>
  		/// <param name="cancellationToken">A cancellation token that can be used to cancel the work.</param>
  		/// <returns>
  		/// The sum of the values in the sequence.
  		/// </returns>
  		/// <exception cref="T:System.ArgumentNullException"><paramref name="source"/> is <see langword="null"/>.</exception>
  		/// <exception cref="T:System.NotSupportedException"><paramref name="source" /> <see cref="IQueryable.Provider"/> is not a <see cref="INhQueryProvider"/>.</exception>
  		/// <exception cref="T:System.OverflowException">The sum is larger than <see cref="F:System.Double.MaxValue"/>.</exception>
  		public static Task<double> SumAsync(this IQueryable<double> source, CancellationToken cancellationToken = default(CancellationToken))
  		{
  			if (source == null)
  			{
  				throw new ArgumentNullException(nameof(source));
  			}
  			if (!(source.Provider is INhQueryProvider provider))
  			{
  				throw new NotSupportedException($"Source {nameof(source.Provider)} must be a {nameof(INhQueryProvider)}");
  			}
  			if (cancellationToken.IsCancellationRequested)
  			{
  				return Task.FromCanceled<double>(cancellationToken);
  			}
  			try
  			{
  				var methodInfo = ReflectionCache.QueryableMethods.SumOfDouble;
  				var expression = new[] { source.Expression };
  				return provider.ExecuteAsync<double>(Expression.Call(null, methodInfo, expression), cancellationToken);
  			}
  			catch (Exception ex)
  			{
  				return Task.FromException<double>(ex);
  			}
  		}
  
  		/// <summary>
  		/// Computes the sum of a sequence of nullable <see cref="T:System.Double"/> values.
  		/// </summary>
  		/// <param name="source">A sequence of nullable <see cref="T:System.Double"/> values to calculate the sum of.</param>
  		/// <param name="cancellationToken">A cancellation token that can be used to cancel the work.</param>
  		/// <returns>
  		/// The sum of the values in the sequence.
  		/// </returns>
  		/// <exception cref="T:System.ArgumentNullException"><paramref name="source"/> is <see langword="null"/>.</exception>
  		/// <exception cref="T:System.NotSupportedException"><paramref name="source" /> <see cref="IQueryable.Provider"/> is not a <see cref="INhQueryProvider"/>.</exception>
  		/// <exception cref="T:System.OverflowException">The sum is larger than <see cref="F:System.Double.MaxValue"/>.</exception>
  		public static Task<double?> SumAsync(this IQueryable<double?> source, CancellationToken cancellationToken = default(CancellationToken))
  		{
  			if (source == null)
  			{
  				throw new ArgumentNullException(nameof(source));
  			}
  			if (!(source.Provider is INhQueryProvider provider))
  			{
  				throw new NotSupportedException($"Source {nameof(source.Provider)} must be a {nameof(INhQueryProvider)}");
  			}
  			if (cancellationToken.IsCancellationRequested)
  			{
  				return Task.FromCanceled<double?>(cancellationToken);
  			}
  			try
  			{
  				var methodInfo = ReflectionCache.QueryableMethods.SumOfNullableDouble;
  				var expression = new[] { source.Expression };
  				return provider.ExecuteAsync<double?>(Expression.Call(null, methodInfo, expression), cancellationToken);
  			}
  			catch (Exception ex)
  			{
  				return Task.FromException<double?>(ex);
  			}
  		}
  
  		/// <summary>
  		/// Computes the sum of a sequence of <see cref="T:System.Decimal"/> values.
  		/// </summary>
  		/// <param name="source">A sequence of <see cref="T:System.Decimal"/> values to calculate the sum of.</param>
  		/// <param name="cancellationToken">A cancellation token that can be used to cancel the work.</param>
  		/// <returns>
  		/// The sum of the values in the sequence.
  		/// </returns>
  		/// <exception cref="T:System.ArgumentNullException"><paramref name="source"/> is <see langword="null"/>.</exception>
  		/// <exception cref="T:System.NotSupportedException"><paramref name="source" /> <see cref="IQueryable.Provider"/> is not a <see cref="INhQueryProvider"/>.</exception>
  		/// <exception cref="T:System.OverflowException">The sum is larger than <see cref="F:System.Decimal.MaxValue"/>.</exception>
  		public static Task<decimal> SumAsync(this IQueryable<decimal> source, CancellationToken cancellationToken = default(CancellationToken))
  		{
  			if (source == null)
  			{
  				throw new ArgumentNullException(nameof(source));
  			}
  			if (!(source.Provider is INhQueryProvider provider))
  			{
  				throw new NotSupportedException($"Source {nameof(source.Provider)} must be a {nameof(INhQueryProvider)}");
  			}
  			if (cancellationToken.IsCancellationRequested)
  			{
  				return Task.FromCanceled<decimal>(cancellationToken);
  			}
  			try
  			{
  				var methodInfo = ReflectionCache.QueryableMethods.SumOfDecimal;
  				var expression = new[] { source.Expression };
  				return provider.ExecuteAsync<decimal>(Expression.Call(null, methodInfo, expression), cancellationToken);
  			}
  			catch (Exception ex)
  			{
  				return Task.FromException<decimal>(ex);
  			}
  		}
  
  		/// <summary>
  		/// Computes the sum of a sequence of nullable <see cref="T:System.Decimal"/> values.
  		/// </summary>
  		/// <param name="source">A sequence of nullable <see cref="T:System.Decimal"/> values to calculate the sum of.</param>
  		/// <param name="cancellationToken">A cancellation token that can be used to cancel the work.</param>
  		/// <returns>
  		/// The sum of the values in the sequence.
  		/// </returns>
  		/// <exception cref="T:System.ArgumentNullException"><paramref name="source"/> is <see langword="null"/>.</exception>
  		/// <exception cref="T:System.NotSupportedException"><paramref name="source" /> <see cref="IQueryable.Provider"/> is not a <see cref="INhQueryProvider"/>.</exception>
  		/// <exception cref="T:System.OverflowException">The sum is larger than <see cref="F:System.Decimal.MaxValue"/>.</exception>
  		public static Task<decimal?> SumAsync(this IQueryable<decimal?> source, CancellationToken cancellationToken = default(CancellationToken))
  		{
  			if (source == null)
  			{
  				throw new ArgumentNullException(nameof(source));
  			}
  			if (!(source.Provider is INhQueryProvider provider))
  			{
  				throw new NotSupportedException($"Source {nameof(source.Provider)} must be a {nameof(INhQueryProvider)}");
  			}
  			if (cancellationToken.IsCancellationRequested)
  			{
  				return Task.FromCanceled<decimal?>(cancellationToken);
  			}
  			try
  			{
  				var methodInfo = ReflectionCache.QueryableMethods.SumOfNullableDecimal;
  				var expression = new[] { source.Expression };
  				return provider.ExecuteAsync<decimal?>(Expression.Call(null, methodInfo, expression), cancellationToken);
  			}
  			catch (Exception ex)
  			{
  				return Task.FromException<decimal?>(ex);
  			}
  		}
  
  		/// <summary>
  		/// Computes the sum of the sequence of <see cref="T:System.Int32"/> values that is obtained by invoking a projection function on each element of the input sequence.
  		/// </summary>
  		/// <param name="source">A sequence of values of type <paramref name="source"/>.</param>
  		/// <param name="selector">A projection function to apply to each element.</param>
  		/// <param name="cancellationToken">A cancellation token that can be used to cancel the work.</param>
  		/// <typeparam name="TSource">The type of the elements of <paramref name="source"/>.</typeparam>
  		/// <returns>
  		/// The sum of the projected values.
  		/// </returns>
  		/// <exception cref="T:System.ArgumentNullException"><paramref name="source"/> or <paramref name="selector"/> is <see langword="null"/>.</exception>
  		/// <exception cref="T:System.NotSupportedException"><paramref name="source" /> <see cref="IQueryable.Provider"/> is not a <see cref="INhQueryProvider"/>.</exception>
  		/// <exception cref="T:System.OverflowException">The sum is larger than <see cref="F:System.Int32.MaxValue"/>.</exception>
  		public static Task<int> SumAsync<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, int>> selector, CancellationToken cancellationToken = default(CancellationToken))
  		{
  
gt: 			if (source == null)