Skip to content

Commit c999b94

Browse files
NH-4030 - Refactoring future extension methods.
1 parent ad4c2ef commit c999b94

File tree

1 file changed

+73
-33
lines changed

1 file changed

+73
-33
lines changed

src/NHibernate/Linq/LinqExtensionMethods.cs

Lines changed: 73 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,15 @@
66
using NHibernate.Impl;
77
using NHibernate.Type;
88
using NHibernate.Util;
9-
using Remotion.Linq;
109
using Remotion.Linq.Parsing.ExpressionTreeVisitors;
1110

1211
namespace NHibernate.Linq
1312
{
13+
/// <summary>
14+
/// NHibernate LINQ extension methods. They are meant to work with <see cref="NhQueryable{T}"/>. Supplied <see cref="IQueryable{T}"/> parameters
15+
/// should at least have an <see cref="INhQueryProvider"/> <see cref="IQueryable.Provider"/>. <see cref="LinqExtensionMethods.Query{T}(ISession)"/> and
16+
/// its overloads supply such queryables.
17+
/// </summary>
1418
public static class LinqExtensionMethods
1519
{
1620
public static IQueryable<T> Query<T>(this ISession session)
@@ -77,51 +81,87 @@ public static IQueryable<T> Timeout<T>(this IQueryable<T> query, int timeout)
7781
return new NhQueryable<T>(query.Provider, callExpression);
7882
}
7983

80-
public static IEnumerable<T> ToFuture<T>(this IQueryable<T> query)
84+
/// <summary>
85+
/// Wraps the query in a deferred <see cref="IEnumerable{T}"/> which enumeration will trigger a batch of all pending future queries.
86+
/// </summary>
87+
/// <param name="source">An <see cref="T:System.Linq.IQueryable`1" /> to convert to a future query.</param>
88+
/// <typeparam name="TSource">The type of the elements of <paramref name="source" />.</typeparam>
89+
/// <returns>A <see cref="IEnumerable{T}"/>.</returns>
90+
/// <exception cref="T:System.ArgumentNullException"><paramref name="source" /> is <see langword="null"/>.</exception>
91+
/// <exception cref="T:System.NotSupportedException"><paramref name="source" /> <see cref="IQueryable.Provider"/> is not a <see cref="INhQueryProvider"/>.</exception>
92+
public static IEnumerable<TSource> ToFuture<TSource>(this IQueryable<TSource> source)
8193
{
82-
var nhQueryable = query as QueryableBase<T>;
83-
if (nhQueryable == null)
84-
throw new NotSupportedException("Query needs to be of type QueryableBase<T>");
85-
86-
var provider = (INhQueryProvider) nhQueryable.Provider;
87-
var future = provider.ExecuteFuture(nhQueryable.Expression);
88-
return (IEnumerable<T>) future;
94+
if (source == null)
95+
{
96+
throw new ArgumentNullException(nameof(source));
97+
}
98+
if (!(source.Provider is INhQueryProvider provider))
99+
{
100+
throw new NotSupportedException($"Source {nameof(source.Provider)} must be a {nameof(INhQueryProvider)}");
101+
}
102+
var future = provider.ExecuteFuture(source.Expression);
103+
return (IEnumerable<TSource>)future;
89104
}
90105

91-
public static IFutureValue<T> ToFutureValue<T>(this IQueryable<T> query)
106+
/// <summary>
107+
/// Wraps the query in a deferred <see cref="IFutureValue{T}"/> which will trigger a batch of all pending future queries
108+
/// when its <see cref="IFutureValue{T}.Value"/> is read.
109+
/// </summary>
110+
/// <param name="source">An <see cref="T:System.Linq.IQueryable`1" /> to convert to a future query.</param>
111+
/// <typeparam name="TSource">The type of the elements of <paramref name="source" />.</typeparam>
112+
/// <returns>A <see cref="IFutureValue{T}"/>.</returns>
113+
/// <exception cref="T:System.ArgumentNullException"><paramref name="source" /> is <see langword="null"/>.</exception>
114+
/// <exception cref="T:System.NotSupportedException"><paramref name="source" /> <see cref="IQueryable.Provider"/> is not a <see cref="INhQueryProvider"/>.</exception>
115+
public static IFutureValue<TSource> ToFutureValue<TSource>(this IQueryable<TSource> source)
92116
{
93-
var nhQueryable = query as QueryableBase<T>;
94-
if (nhQueryable == null)
95-
throw new NotSupportedException("Query needs to be of type QueryableBase<T>");
96-
97-
var provider = (INhQueryProvider) nhQueryable.Provider;
98-
var future = provider.ExecuteFuture(nhQueryable.Expression);
99-
if (future is IEnumerable<T>)
117+
if (source == null)
100118
{
101-
return new FutureValue<T>(() => ((IEnumerable<T>) future));
119+
throw new ArgumentNullException(nameof(source));
120+
}
121+
if (!(source.Provider is INhQueryProvider provider))
122+
{
123+
throw new NotSupportedException($"Source {nameof(source.Provider)} must be a {nameof(INhQueryProvider)}");
124+
}
125+
var future = provider.ExecuteFuture(source.Expression);
126+
if (future is IEnumerable<TSource> enumerable)
127+
{
128+
return new FutureValue<TSource>(() => enumerable);
102129
}
103130

104-
return (IFutureValue<T>) future;
131+
return (IFutureValue<TSource>)future;
105132
}
106133

107-
public static T MappedAs<T>(this T parameter, IType type)
134+
/// <summary>
135+
/// Wraps the query in a deferred <see cref="IFutureValue{T}"/> which will trigger a batch of all pending future queries
136+
/// when its <see cref="IFutureValue{T}.Value"/> is read.
137+
/// </summary>
138+
/// <param name="source">An <see cref="T:System.Linq.IQueryable`1" /> to convert to a future query.</param>
139+
/// <param name="selector">An aggregation function to apply to <paramref name="source"/>.</param>
140+
/// <typeparam name="TSource">The type of the elements of <paramref name="source" />.</typeparam>
141+
/// <typeparam name="TResult">The type of the value returned by the function represented by <paramref name="selector"/>.</typeparam>
142+
/// <returns>A <see cref="IFutureValue{T}"/>.</returns>
143+
/// <exception cref="T:System.ArgumentNullException"><paramref name="source" /> is <see langword="null"/>.</exception>
144+
/// <exception cref="T:System.NotSupportedException"><paramref name="source" /> <see cref="IQueryable.Provider"/> is not a <see cref="INhQueryProvider"/>.</exception>
145+
public static IFutureValue<TResult> ToFutureValue<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<IQueryable<TSource>, TResult>> selector)
108146
{
109-
throw new InvalidOperationException("The method should be used inside Linq to indicate a type of a parameter");
110-
}
111-
112-
public static IFutureValue<TResult> ToFutureValue<T, TResult>(this IQueryable<T> query, Expression<Func<IQueryable<T>, TResult>> selector)
113-
{
114-
var nhQueryable = query as QueryableBase<T>;
115-
if (nhQueryable == null)
116-
throw new NotSupportedException("Query needs to be of type QueryableBase<T>");
147+
if (source == null)
148+
{
149+
throw new ArgumentNullException(nameof(source));
150+
}
151+
if (!(source.Provider is INhQueryProvider provider))
152+
{
153+
throw new NotSupportedException($"Source {nameof(source.Provider)} must be a {nameof(INhQueryProvider)}");
154+
}
117155

118-
var provider = (INhQueryProvider) query.Provider;
156+
var expression = ReplacingExpressionTreeVisitor
157+
.Replace(selector.Parameters.Single(), source.Expression, selector.Body);
119158

120-
var expression = ReplacingExpressionTreeVisitor.Replace(selector.Parameters.Single(),
121-
query.Expression,
122-
selector.Body);
159+
return (IFutureValue<TResult>)provider.ExecuteFuture(expression);
160+
}
123161

124-
return (IFutureValue<TResult>) provider.ExecuteFuture(expression);
162+
public static T MappedAs<T>(this T parameter, IType type)
163+
{
164+
throw new InvalidOperationException("The method should be used inside Linq to indicate a type of a parameter");
125165
}
126166
}
127167
}

0 commit comments

Comments
 (0)