Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions src/System.Linq.Dynamic.Core/DefaultQueryableAnalyzer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using System.Linq.Dynamic.Core.Validation;
using System.Reflection;

namespace System.Linq.Dynamic.Core
{
/// <summary>
/// Default implementation.
/// </summary>
/// <seealso cref="IQueryableAnalyzer" />
public class DefaultQueryableAnalyzer : IQueryableAnalyzer
{
/// <inheritdoc cref="IQueryableAnalyzer.SupportsLinqToObjects"/>
public bool SupportsLinqToObjects(IQueryable query, IQueryProvider provider = null)
{
Check.NotNull(query, nameof(query));
provider = provider ?? query.Provider;

Type baseType = provider.GetType().GetTypeInfo().BaseType;
#if NET35
bool isLinqToObjects = baseType.FullName.Contains("EnumerableQuery");
#else
bool isLinqToObjects = baseType == typeof(EnumerableQuery);
#endif
if (!isLinqToObjects)
{
// Support for https://github.com/StefH/QueryInterceptor.Core, version 1.0.1 and up
if (baseType.Name == "QueryTranslatorProvider")
{
try
{
PropertyInfo property = baseType.GetProperty("OriginalProvider");
IQueryProvider originalProvider = property.GetValue(provider, null) as IQueryProvider;
return originalProvider != null && SupportsLinqToObjects(query, originalProvider);
}
catch
{
return false;
}
}

// Support for https://github.com/scottksmith95/LINQKit ExpandableQuery
if (provider.GetType().GetTypeInfo().Name.StartsWith("ExpandableQuery"))
{
try
{
PropertyInfo property = query.GetType().GetProperty("InnerQuery", BindingFlags.NonPublic | BindingFlags.Instance);
if (property != null)
{
IQueryable innerQuery = property.GetValue(query, null) as IQueryable;
return innerQuery != null && SupportsLinqToObjects(innerQuery, provider);
}

return SupportsLinqToObjects(query);
}
catch
{
return false;
}
}
}

return isLinqToObjects;
}
}
}
49 changes: 27 additions & 22 deletions src/System.Linq.Dynamic.Core/DynamicQueryableExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#if !(WINDOWS_APP45x || SILVERLIGHT)
using System.Diagnostics;
#endif
using System.Linq.Dynamic.Core.Extensions;
using System.Linq.Dynamic.Core.Validation;
using System.Linq.Expressions;
using System.Reflection;
Expand Down Expand Up @@ -146,7 +145,7 @@ public static bool Any([NotNull] this IQueryable source, [CanBeNull] ParsingConf
Check.NotNull(source, nameof(source));
Check.NotEmpty(predicate, nameof(predicate));

bool createParameterCtor = source.IsLinqToObjects();
bool createParameterCtor = SupportsLinqToObjects(config, source);
LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args);

return Execute<bool>(_anyPredicate, source, lambda);
Expand Down Expand Up @@ -242,7 +241,7 @@ public static int Count([NotNull] this IQueryable source, [CanBeNull] ParsingCon
Check.NotNull(source, nameof(source));
Check.NotEmpty(predicate, nameof(predicate));

bool createParameterCtor = source.IsLinqToObjects();
bool createParameterCtor = SupportsLinqToObjects(config, source);
LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args);

return Execute<int>(_countPredicate, source, lambda);
Expand Down Expand Up @@ -371,7 +370,7 @@ public static dynamic First([NotNull] this IQueryable source, [CanBeNull] Parsin
Check.NotNull(source, nameof(source));
Check.NotEmpty(predicate, nameof(predicate));

bool createParameterCtor = source.IsLinqToObjects();
bool createParameterCtor = SupportsLinqToObjects(config, source);
LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args);

return Execute(_firstPredicate, source, lambda);
Expand Down Expand Up @@ -441,7 +440,7 @@ public static dynamic FirstOrDefault([NotNull] this IQueryable source, [CanBeNul
Check.NotNull(source, nameof(source));
Check.NotEmpty(predicate, nameof(predicate));

bool createParameterCtor = source.IsLinqToObjects();
bool createParameterCtor = SupportsLinqToObjects(config, source);
LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args);

return Execute(_firstOrDefaultPredicate, source, lambda);
Expand Down Expand Up @@ -500,7 +499,7 @@ public static IQueryable GroupBy([NotNull] this IQueryable source, [CanBeNull] P
Check.NotEmpty(keySelector, nameof(keySelector));
Check.NotEmpty(resultSelector, nameof(resultSelector));

bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? source.IsLinqToObjects();
bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, source);
LambdaExpression keyLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, keySelector, args);
LambdaExpression elementLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, resultSelector, args);

Expand Down Expand Up @@ -570,7 +569,7 @@ public static IQueryable GroupBy([NotNull] this IQueryable source, [CanBeNull] P
Check.NotNull(source, nameof(source));
Check.NotEmpty(keySelector, nameof(keySelector));

bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? source.IsLinqToObjects();
bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, source);
LambdaExpression keyLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, keySelector, args);

var optimized = OptimizeExpression(Expression.Call(
Expand Down Expand Up @@ -679,7 +678,7 @@ public static IQueryable GroupJoin([NotNull] this IQueryable outer, [CanBeNull]
Type outerType = outer.ElementType;
Type innerType = inner.AsQueryable().ElementType;

bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? outer.IsLinqToObjects();
bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, outer);
LambdaExpression outerSelectorLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, outerType, null, outerKeySelector, args);
LambdaExpression innerSelectorLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, innerType, null, innerKeySelector, args);

Expand Down Expand Up @@ -735,7 +734,7 @@ public static IQueryable Join([NotNull] this IQueryable outer, [CanBeNull] Parsi
Type outerType = outer.ElementType;
Type innerType = inner.AsQueryable().ElementType;

bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? outer.IsLinqToObjects();
bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, outer);
LambdaExpression outerSelectorLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, outerType, null, outerKeySelector, args);
LambdaExpression innerSelectorLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, innerType, null, innerKeySelector, args);

Expand Down Expand Up @@ -830,7 +829,7 @@ public static dynamic Last([NotNull] this IQueryable source, [CanBeNull] Parsing
Check.NotNull(source, nameof(source));
Check.NotEmpty(predicate, nameof(predicate));

bool createParameterCtor = source.IsLinqToObjects();
bool createParameterCtor = SupportsLinqToObjects(config, source);
LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args);

return Execute(_lastPredicate, source, lambda);
Expand Down Expand Up @@ -901,7 +900,7 @@ public static dynamic LastOrDefault([NotNull] this IQueryable source, [CanBeNull
Check.NotNull(source, nameof(source));
Check.NotEmpty(predicate, nameof(predicate));

bool createParameterCtor = source.IsLinqToObjects();
bool createParameterCtor = SupportsLinqToObjects(config, source);
LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args);

return Execute(_lastDefaultPredicate, source, lambda);
Expand Down Expand Up @@ -1132,7 +1131,7 @@ public static IQueryable Select([NotNull] this IQueryable source, [CanBeNull] Pa
Check.NotNull(source, nameof(source));
Check.NotEmpty(selector, nameof(selector));

bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? source.IsLinqToObjects();
bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, source);
LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, selector, args);

var optimized = OptimizeExpression(Expression.Call(
Expand Down Expand Up @@ -1172,7 +1171,7 @@ public static IQueryable<TResult> Select<TResult>([NotNull] this IQueryable sour
Check.NotNull(source, nameof(source));
Check.NotEmpty(selector, nameof(selector));

bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? source.IsLinqToObjects();
bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, source);
LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, typeof(TResult), selector, args);

var optimized = OptimizeExpression(Expression.Call(
Expand Down Expand Up @@ -1210,7 +1209,7 @@ public static IQueryable Select([NotNull] this IQueryable source, [CanBeNull] Pa
Check.NotNull(resultType, nameof(resultType));
Check.NotEmpty(selector, nameof(selector));

bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? source.IsLinqToObjects();
bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, source);
LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, resultType, selector, args);

var optimized = OptimizeExpression(Expression.Call(
Expand Down Expand Up @@ -1288,7 +1287,7 @@ public static IQueryable SelectMany([NotNull] this IQueryable source, [NotNull]

private static IQueryable SelectManyInternal(IQueryable source, ParsingConfig config, Type resultType, string selector, params object[] args)
{
bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? source.IsLinqToObjects();
bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, source);
LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, selector, args);

//Extra help to get SelectMany to work from StackOverflow Answer
Expand Down Expand Up @@ -1345,7 +1344,7 @@ public static IQueryable<TResult> SelectMany<TResult>([NotNull] this IQueryable
Check.NotNull(source, nameof(source));
Check.NotEmpty(selector, nameof(selector));

bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? source.IsLinqToObjects();
bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, source);
LambdaExpression lambda = DynamicExpressionParser.ParseLambda(createParameterCtor, source.ElementType, null, selector, args);

//we have to adjust to lambda to return an IEnumerable<T> instead of whatever the actual property is.
Expand Down Expand Up @@ -1438,7 +1437,7 @@ public static IQueryable SelectMany([NotNull] this IQueryable source, [CanBeNull
Check.NotEmpty(resultSelector, nameof(resultSelector));
Check.NotEmpty(resultParameterName, nameof(resultParameterName));

bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? source.IsLinqToObjects();
bool createParameterCtor = config?.EvaluateGroupByAtDatabase ?? SupportsLinqToObjects(config, source);
LambdaExpression sourceSelectLambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, collectionSelector, collectionSelectorArgs);

//we have to adjust to lambda to return an IEnumerable<T> instead of whatever the actual property is.
Expand Down Expand Up @@ -1512,7 +1511,7 @@ public static dynamic Single([NotNull] this IQueryable source, [CanBeNull] Parsi
Check.NotNull(source, nameof(source));
Check.NotEmpty(predicate, nameof(predicate));

bool createParameterCtor = source.IsLinqToObjects();
bool createParameterCtor = SupportsLinqToObjects(config, source);
LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args);

return Execute(_singlePredicate, source, lambda);
Expand Down Expand Up @@ -1584,7 +1583,7 @@ public static dynamic SingleOrDefault([NotNull] this IQueryable source, [CanBeNu
Check.NotNull(source, nameof(source));
Check.NotEmpty(predicate, nameof(predicate));

bool createParameterCtor = source.IsLinqToObjects();
bool createParameterCtor = SupportsLinqToObjects(config, source);
LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args);

return Execute(_singleDefaultPredicate, source, lambda);
Expand Down Expand Up @@ -1671,7 +1670,7 @@ public static IQueryable SkipWhile([NotNull] this IQueryable source, [CanBeNull]
Check.NotNull(source, nameof(source));
Check.NotNull(predicate, nameof(predicate));

bool createParameterCtor = source.IsLinqToObjects();
bool createParameterCtor = SupportsLinqToObjects(config, source);
LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args);

return CreateQuery(_skipWhilePredicate, source, lambda);
Expand Down Expand Up @@ -1748,7 +1747,7 @@ public static IQueryable TakeWhile([NotNull] this IQueryable source, [CanBeNull]
Check.NotNull(source, nameof(source));
Check.NotNull(predicate, nameof(predicate));

bool createParameterCtor = source.IsLinqToObjects();
bool createParameterCtor = SupportsLinqToObjects(config, source);
LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args);

return CreateQuery(_takeWhilePredicate, source, lambda);
Expand Down Expand Up @@ -1894,7 +1893,7 @@ public static IQueryable Where([NotNull] this IQueryable source, [CanBeNull] Par
Check.NotNull(source, nameof(source));
Check.NotEmpty(predicate, nameof(predicate));

bool createParameterCtor = source.IsLinqToObjects();
bool createParameterCtor = SupportsLinqToObjects(config, source);
LambdaExpression lambda = DynamicExpressionParser.ParseLambda(config, createParameterCtor, source.ElementType, null, predicate, args);

var optimized = OptimizeExpression(Expression.Call(typeof(Queryable), nameof(Queryable.Where), new[] { source.ElementType }, source.Expression, Expression.Quote(lambda)));
Expand Down Expand Up @@ -1924,6 +1923,12 @@ public static IQueryable Where([NotNull] this IQueryable source, [NotNull] Lambd
#endregion

#region Private Helpers

private static bool SupportsLinqToObjects(ParsingConfig config, IQueryable query)
{
return (config ?? ParsingConfig.Default).QueryableAnalyzer.SupportsLinqToObjects(query);
}

private static void CheckOuterAndInnerTypes(ParsingConfig config, bool createParameterCtor, Type outerType, Type innerType, string outerKeySelector, string innerKeySelector, ref LambdaExpression outerSelectorLambda, ref LambdaExpression innerSelectorLambda, params object[] args)
{
Type outerSelectorReturnType = outerSelectorLambda.Body.Type;
Expand Down
51 changes: 0 additions & 51 deletions src/System.Linq.Dynamic.Core/Extensions/LinqProviderExtensions.cs

This file was deleted.

18 changes: 18 additions & 0 deletions src/System.Linq.Dynamic.Core/IQueryableAnalyzer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using JetBrains.Annotations;

namespace System.Linq.Dynamic.Core
{
/// <summary>
/// Interface for QueryableAnalyzer.
/// </summary>
public interface IQueryableAnalyzer
{
/// <summary>
/// Determines whether the specified query (and provider) supports LinqToObjects.
/// </summary>
/// <param name="query">The query to check.</param>
/// <param name="provider">The provider to check (can be null).</param>
/// <returns>true/false</returns>
bool SupportsLinqToObjects([NotNull] IQueryable query, [CanBeNull] IQueryProvider provider = null);
}
}
Loading