Skip to content

Commit

Permalink
Keep original type from subquery (#777)
Browse files Browse the repository at this point in the history
* Fix 775

* ...

* ...

* Issue775a

* InvalidOperationException

* dict
  • Loading branch information
StefH committed Feb 29, 2024
1 parent 13b19d3 commit 8124d8c
Show file tree
Hide file tree
Showing 9 changed files with 336 additions and 443 deletions.
40 changes: 14 additions & 26 deletions src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public class ExpressionParser
private readonly TextParser _textParser;
private readonly NumberParser _numberParser;
private readonly IExpressionHelper _expressionHelper;
private readonly ConstantExpressionHelper _constantExpressionHelper;
private readonly ITypeFinder _typeFinder;
private readonly ITypeConverterFactory _typeConverterFactory;
private readonly Dictionary<string, object> _internals = new();
Expand All @@ -45,7 +46,6 @@ public class ExpressionParser
private ParameterExpression? _root;
private Type? _resultType;
private bool _createParameterCtor;
private ConstantExpressionHelper _constantExpressionHelper;

/// <summary>
/// Gets name for the `it` field. By default this is set to the KeyWord value "it".
Expand Down Expand Up @@ -387,19 +387,11 @@ private Expression ParseIn()
throw ParseError(_textParser.CurrentToken.Pos, Res.IdentifierImplementingInterfaceExpected, typeof(IEnumerable));
}

var args = new[] { left };

Expression? nullExpressionReference = null;
if (_methodFinder.FindMethod(typeof(IEnumerableSignatures), nameof(IEnumerableSignatures.Contains), false, ref nullExpressionReference, ref args, out var containsSignature) != 1)
{
throw ParseError(op.Pos, Res.NoApplicableAggregate, nameof(IEnumerableSignatures.Contains), string.Join(",", args.Select(a => a.Type.Name).ToArray()));
}

var typeArgs = new[] { left.Type };

args = new[] { right, left };
var args = new[] { right, left };

accumulate = Expression.Call(typeof(Enumerable), containsSignature!.Name, typeArgs, args);
accumulate = Expression.Call(typeof(Enumerable), nameof(Enumerable.Contains), typeArgs, args);
}
else
{
Expand Down Expand Up @@ -2014,17 +2006,14 @@ private Expression ParseAsEnum(string id)

private Expression ParseEnumerable(Expression instance, Type elementType, string methodName, int errorPos, Type? type)
{
bool isQueryable = TypeHelper.FindGenericType(typeof(IQueryable<>), type) != null;
bool isDictionary = TypeHelper.IsDictionary(type);

var oldParent = _parent;

ParameterExpression? outerIt = _it;
ParameterExpression innerIt = ParameterExpressionHelper.CreateParameterExpression(elementType, string.Empty, _parsingConfig.RenameEmptyParameterExpressionNames);

_parent = _it;

if (methodName == "Contains" || methodName == "ContainsKey" || methodName == "Skip" || methodName == "Take")
if (new[] { "Contains", "ContainsKey", "Skip", "Take" }.Contains(methodName))
{
// for any method that acts on the parent element type, we need to specify the outerIt as scope.
_it = outerIt;
Expand All @@ -2039,19 +2028,14 @@ private Expression ParseEnumerable(Expression instance, Type elementType, string
_it = outerIt;
_parent = oldParent;

if (isDictionary && _methodFinder.ContainsMethod(typeof(IDictionarySignatures), methodName, false, null, ref args))
{
var method = type!.GetMethod(methodName)!;
return Expression.Call(instance, method, args);
}

if (!_methodFinder.ContainsMethod(typeof(IEnumerableSignatures), methodName, false, null, ref args))
if (type != null && TypeHelper.IsDictionary(type) && _methodFinder.ContainsMethod(type, methodName, false))
{
throw ParseError(errorPos, Res.NoApplicableAggregate, methodName, string.Join(",", args.Select(a => a.Type.Name).ToArray()));
var dictionaryMethod = type.GetMethod(methodName)!;
return Expression.Call(instance, dictionaryMethod, args);
}

Type callType = typeof(Enumerable);
if (isQueryable && _methodFinder.ContainsMethod(typeof(IQueryableSignatures), methodName, false, null, ref args))
var callType = typeof(Enumerable);
if (type != null && TypeHelper.FindGenericType(typeof(IQueryable<>), type) != null && _methodFinder.ContainsMethod(type, methodName))
{
callType = typeof(Queryable);
}
Expand All @@ -2073,10 +2057,14 @@ private Expression ParseEnumerable(Expression instance, Type elementType, string
{
typeArgs = new[] { elementType, args[0].Type, args[1].Type };
}
else
else if (args.Length == 1)
{
typeArgs = new[] { elementType, args[0].Type };
}
else
{
typeArgs = new[] { elementType };
}
}
else if (methodName == "SelectMany")
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@

namespace System.Linq.Dynamic.Core.Parser.SupportedMethods
namespace System.Linq.Dynamic.Core.Parser.SupportedMethods;

internal enum CompareConversionType
{
internal enum CompareConversionType
{
Both = 0,
First = 1,
Second = -1
}
}
Both = 0,
First = 1,
Second = -1
}

This file was deleted.

This file was deleted.

This file was deleted.

Loading

0 comments on commit 8124d8c

Please sign in to comment.