Skip to content

Commit

Permalink
Refactored Parser (#127)
Browse files Browse the repository at this point in the history
* refactored
* Fixed issue #129
  • Loading branch information
StefH committed Dec 16, 2017
1 parent bd69f2d commit 02fd83b
Show file tree
Hide file tree
Showing 47 changed files with 2,182 additions and 1,655 deletions.
8 changes: 8 additions & 0 deletions src-console/ConsoleAppEF1.1/Program.cs
Expand Up @@ -11,6 +11,14 @@ static void Main(string[] args)
{
using (var db = new MyDbContext())
{
var all = new
{
test1 = new List<int> { 1, 2, 3 }.ToDynamicList(typeof(int)),
test2 = new List<dynamic> { 4, 5, 6 }.ToDynamicList(typeof(int)),
test3 = new List<object> { 7, 8, 9 }.ToDynamicList(typeof(int))
};
Console.WriteLine("all {0}", JsonConvert.SerializeObject(all, Formatting.Indented));

var persons = new List<Person>
{
new Person { Name = "a", Age = 18, Address = new Address { Street = "s1" } },
Expand Down
21 changes: 15 additions & 6 deletions src-console/ConsoleAppEF2.0/Program.cs
Expand Up @@ -27,7 +27,16 @@ public HashSet<Type> GetCustomTypes()

static void Main(string[] args)
{
GlobalConfig.CustomTypeProvider = new C();
var all = new
{
test1 = new List<int> { 1, 2, 3 }.ToDynamicList(typeof(int)),
test2 = new List<dynamic> { 4, 5, 6 }.ToDynamicList(typeof(int)),
test3 = new List<object> { 7, 8, 9 }.ToDynamicList(typeof(int))
};
Console.WriteLine("all {0}", JsonConvert.SerializeObject(all, Formatting.Indented));

var config = new ParsingConfig();
config.CustomTypeProvider = new C();

var context = new TestContext();

Expand All @@ -42,7 +51,7 @@ static void Main(string[] args)
context.SaveChanges();
}

var carFirstOrDefault = context.Cars.Where("Brand == \"Ford\"");
var carFirstOrDefault = context.Cars.Where(config, "Brand == \"Ford\"");
Console.WriteLine("carFirstOrDefault {0}", JsonConvert.SerializeObject(carFirstOrDefault, Formatting.Indented));

var carsLike1 =
Expand All @@ -54,16 +63,16 @@ where EF.Functions.Like(c.Brand, "%a%")
var cars2Like = context.Cars.Where(c => EF.Functions.Like(c.Brand, "%a%"));
Console.WriteLine("cars2Like {0}", JsonConvert.SerializeObject(cars2Like, Formatting.Indented));

var dynamicCarsLike1 = context.Cars.Where("TestContext.Like(Brand, \"%a%\")");
var dynamicCarsLike1 = context.Cars.Where(config, "TestContext.Like(Brand, \"%a%\")");
Console.WriteLine("dynamicCarsLike1 {0}", JsonConvert.SerializeObject(dynamicCarsLike1, Formatting.Indented));

var dynamicCarsLike2 = context.Cars.Where("TestContext.Like(Brand, \"%d%\")");
var dynamicCarsLike2 = context.Cars.Where(config, "TestContext.Like(Brand, \"%d%\")");
Console.WriteLine("dynamicCarsLike2 {0}", JsonConvert.SerializeObject(dynamicCarsLike2, Formatting.Indented));

var dynamicFunctionsLike1 = context.Cars.Where("DynamicFunctions.Like(Brand, \"%a%\")");
var dynamicFunctionsLike1 = context.Cars.Where(config, "DynamicFunctions.Like(Brand, \"%a%\")");
Console.WriteLine("dynamicFunctionsLike1 {0}", JsonConvert.SerializeObject(dynamicFunctionsLike1, Formatting.Indented));

var dynamicFunctionsLike2 = context.Cars.Where("DynamicFunctions.Like(Vin, \"%a.%b%\", \".\")");
var dynamicFunctionsLike2 = context.Cars.Where(config, "DynamicFunctions.Like(Vin, \"%a.%b%\", \".\")");
Console.WriteLine("dynamicFunctionsLike2 {0}", JsonConvert.SerializeObject(dynamicFunctionsLike2, Formatting.Indented));
}
}
Expand Down
Expand Up @@ -62,6 +62,9 @@
<Reference Include="Linq.Expression.Optimizer, Version=1.0.6.0, Culture=neutral, PublicKeyToken=34b6af2337893e15, processorArchitecture=MSIL">
<HintPath>..\..\packages\Linq.Expression.Optimizer.1.0.9\lib\net45\Linq.Expression.Optimizer.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" />
Expand Down
10 changes: 10 additions & 0 deletions src-console/ConsoleApp_net452_EF6/Program.cs
@@ -1,14 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ConsoleApp_net452_EF6.Entities;
using System.Linq.Dynamic.Core;
using Newtonsoft.Json;

namespace ConsoleApp_net452_EF6
{
class Program
{
static void Main(string[] args)
{
var all = new
{
test1 = new List<int> { 1, 2, 3 }.ToDynamicList(typeof(int)),
test2 = new List<dynamic> { 4, 5, 6 }.ToDynamicList(typeof(int)),
test3 = new List<object> { 7, 8, 9 }.ToDynamicList(typeof(int))
};

Console.WriteLine("all {0}", JsonConvert.SerializeObject(all, Formatting.Indented));
using (var context = new KendoGridDbContext())
{
string search = "2";
Expand Down
1 change: 1 addition & 0 deletions src-console/ConsoleApp_net452_EF6/packages.config
Expand Up @@ -3,4 +3,5 @@
<package id="EntityFramework" version="6.2.0" targetFramework="net452" />
<package id="FSharp.Core" version="4.2.3" targetFramework="net452" />
<package id="Linq.Expression.Optimizer" version="1.0.9" targetFramework="net452" />
<package id="Newtonsoft.Json" version="10.0.3" targetFramework="net452" />
</packages>
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<Description>Dynamic Linq extensions for EntityFramework which adds Async support</Description>
<AssemblyTitle>EntityFramework.DynamicLinq</AssemblyTitle>
<VersionPrefix>1.0.4.7</VersionPrefix>
<VersionPrefix>1.0.8.0</VersionPrefix>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net45;net46</TargetFrameworks>
<DefineConstants>EF</DefineConstants>
Expand Down
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<Description>Dynamic Linq extensions for Microsoft.EntityFrameworkCore which adds Async support</Description>
<AssemblyTitle>Microsoft.EntityFrameworkCore.DynamicLinq</AssemblyTitle>
<VersionPrefix>1.0.4.8</VersionPrefix>
<VersionPrefix>1.0.8.0</VersionPrefix>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net451;net46;netstandard1.3;netstandard2.0;uap10.0</TargetFrameworks>
<DefineConstants>$(DefineConstants);EFCORE</DefineConstants>
Expand Down
Expand Up @@ -21,12 +21,14 @@ public class DefaultDynamicLinqCustomTypeProvider : AbstractDynamicLinqCustomTyp
public virtual HashSet<Type> GetCustomTypes()
{
if (_customTypes != null)
{
return _customTypes;
}

IEnumerable<Assembly> assemblies = _assemblyHelper.GetAssemblies();
_customTypes = new HashSet<Type>(FindTypesMarkedWithDynamicLinqTypeAttribute(assemblies));
return _customTypes;
}
}
}
#endif
#endif
8 changes: 4 additions & 4 deletions src/System.Linq.Dynamic.Core/DynamicEnumerableExtensions.cs
Expand Up @@ -65,11 +65,11 @@ public static dynamic[] ToDynamicArray([NotNull] this IEnumerable source, [NotNu
Check.NotNull(source, nameof(source));
Check.NotNull(type, nameof(type));

object result = ToDynamicArrayGenericMethod.MakeGenericMethod(type).Invoke(source, new object[] { source });
IEnumerable result = (IEnumerable)ToDynamicArrayGenericMethod.MakeGenericMethod(type).Invoke(source, new object[] { source });
#if NET35
return (object[])result;
return CastToArray<object>(result);
#else
return (dynamic[])result;
return CastToArray<dynamic>(result);
#endif
}

Expand Down Expand Up @@ -132,4 +132,4 @@ internal static List<T> CastToList<T>(IEnumerable source)
return source.Cast<T>().ToList();
}
}
}
}
60 changes: 34 additions & 26 deletions src/System.Linq.Dynamic.Core/DynamicExpressionParser.cs
@@ -1,4 +1,5 @@
using JetBrains.Annotations;
using System.Linq.Dynamic.Core.Parser;
using JetBrains.Annotations;
using System.Linq.Dynamic.Core.Validation;
using System.Linq.Expressions;

Expand All @@ -14,43 +15,41 @@ public static class DynamicExpressionParser
/// </summary>
/// <param name="resultType">Type of the result. If not specified, it will be generated dynamically.</param>
/// <param name="expression">The expression.</param>
/// <param name="parsingConfig">The Configuration for the parsing.</param>
/// <param name="values">An object array that contains zero or more objects which are used as replacement values.</param>
/// <returns>The generated <see cref="LambdaExpression"/></returns>
[PublicAPI]
public static LambdaExpression ParseLambda([CanBeNull] Type resultType, string expression, params object[] values)
public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values)
{
return ParseLambda(true, resultType, expression, values);
return ParseLambda(parsingConfig, true, resultType, expression, values);
}

/// <summary>
/// Parses an expression into a LambdaExpression.
/// Parses an expression into a LambdaExpression. (Also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.)
/// </summary>
/// <param name="createParameterCtor">if set to <c>true</c> then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.</param>
/// <param name="resultType">Type of the result. If not specified, it will be generated dynamically.</param>
/// <param name="expression">The expression.</param>
/// <param name="values">An object array that contains zero or more objects which are used as replacement values.</param>
/// <returns>The generated <see cref="LambdaExpression"/></returns>
[PublicAPI]
public static LambdaExpression ParseLambda(bool createParameterCtor, [CanBeNull] Type resultType, string expression, params object[] values)
public static LambdaExpression ParseLambda([CanBeNull] Type resultType, [NotNull] string expression, params object[] values)
{
Check.NotEmpty(expression, nameof(expression));

var parser = new ExpressionParser(new ParameterExpression[0], expression, values, null);

return Expression.Lambda(parser.Parse(resultType, true));
return ParseLambda(null, true, resultType, expression, values);
}

/// <summary>
/// Parses an expression into a LambdaExpression.
/// </summary>
/// <param name="parsingConfig">The Configuration for the parsing.</param>
/// <param name="createParameterCtor">if set to <c>true</c> then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.</param>
/// <param name="resultType">Type of the result. If not specified, it will be generated dynamically.</param>
/// <param name="expression">The expression.</param>
/// <param name="parsingConfig">The Configuration for the parsing.</param>
/// <param name="values">An object array that contains zero or more objects which are used as replacement values.</param>
/// <returns>The generated <see cref="LambdaExpression"/></returns>
[PublicAPI]
public static LambdaExpression ParseLambda(bool createParameterCtor, [CanBeNull] Type resultType, string expression, ParsingConfig parsingConfig, params object[] values)
public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [CanBeNull] Type resultType, string expression, params object[] values)
{
Check.NotEmpty(expression, nameof(expression));

Expand Down Expand Up @@ -83,7 +82,7 @@ public static LambdaExpression ParseLambda([NotNull] Type itType, [CanBeNull] Ty
/// <param name="values">An object array that contains zero or more objects which are used as replacement values.</param>
/// <returns>The generated <see cref="LambdaExpression"/></returns>
[PublicAPI]
public static LambdaExpression ParseLambda([NotNull] Type itType, [CanBeNull] Type resultType, string expression, ParsingConfig parsingConfig, params object[] values)
public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, [NotNull] Type itType, [CanBeNull] Type resultType, string expression, params object[] values)
{
return ParseLambda(true, itType, resultType, expression, parsingConfig, values);
}
Expand All @@ -109,20 +108,20 @@ public static LambdaExpression ParseLambda(bool createParameterCtor, [NotNull] T
/// <summary>
/// Parses an expression into a LambdaExpression.
/// </summary>
/// <param name="parsingConfig">The Configuration for the parsing.</param>
/// <param name="createParameterCtor">if set to <c>true</c> then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.</param>
/// <param name="itType">The main type from the dynamic class expression.</param>
/// <param name="resultType">Type of the result. If not specified, it will be generated dynamically.</param>
/// <param name="expression">The expression.</param>
/// <param name="parsingConfig">The Configuration for the parsing.</param>
/// <param name="values">An object array that contains zero or more objects which are used as replacement values.</param>
/// <returns>The generated <see cref="LambdaExpression"/></returns>
[PublicAPI]
public static LambdaExpression ParseLambda(bool createParameterCtor, [NotNull] Type itType, [CanBeNull] Type resultType, string expression, ParsingConfig parsingConfig, params object[] values)
public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] Type itType, [CanBeNull] Type resultType, string expression, params object[] values)
{
Check.NotNull(itType, nameof(itType));
Check.NotEmpty(expression, nameof(expression));

return ParseLambda(createParameterCtor, new[] { Expression.Parameter(itType, "") }, resultType, expression, parsingConfig, values);
return ParseLambda(parsingConfig, createParameterCtor, new[] { Expression.Parameter(itType, "") }, resultType, expression, values);
}

/// <summary>
Expand All @@ -136,7 +135,22 @@ public static LambdaExpression ParseLambda(bool createParameterCtor, [NotNull] T
[PublicAPI]
public static LambdaExpression ParseLambda([NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, string expression, params object[] values)
{
return ParseLambda(true, parameters, resultType, expression, values);
return ParseLambda(null, true, parameters, resultType, expression, values);
}

/// <summary>
/// Parses an expression into a LambdaExpression. (Also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.)
/// </summary>
/// <param name="parsingConfig">The Configuration for the parsing.</param>
/// <param name="parameters">A array from ParameterExpressions.</param>
/// <param name="resultType">Type of the result. If not specified, it will be generated dynamically.</param>
/// <param name="expression">The expression.</param>
/// <param name="values">An object array that contains zero or more objects which are used as replacement values.</param>
/// <returns>The generated <see cref="LambdaExpression"/></returns>
[PublicAPI]
public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, string expression, params object[] values)
{
return ParseLambda(parsingConfig, true, parameters, resultType, expression, values);
}

/// <summary>
Expand All @@ -149,29 +163,23 @@ public static LambdaExpression ParseLambda([NotNull] ParameterExpression[] param
/// <param name="values">An object array that contains zero or more objects which are used as replacement values.</param>
/// <returns>The generated <see cref="LambdaExpression"/></returns>
[PublicAPI]
public static LambdaExpression ParseLambda(bool createParameterCtor, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, string expression, params object[] values)
public static LambdaExpression ParseLambda(bool createParameterCtor, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values)
{
Check.NotNull(parameters, nameof(parameters));
Check.Condition(parameters, p => p.Count(x => x == null) == 0, nameof(parameters));
Check.NotEmpty(expression, nameof(expression));

var parser = new ExpressionParser(parameters, expression, values, null);

return Expression.Lambda(parser.Parse(resultType, createParameterCtor), parameters);
return ParseLambda(null, createParameterCtor, parameters, resultType, expression, values);
}

/// <summary>
/// Parses an expression into a LambdaExpression.
/// </summary>
/// <param name="parsingConfig">The Configuration for the parsing.</param>
/// <param name="createParameterCtor">if set to <c>true</c> then also create a constructor for all the parameters. Note that this doesn't work for Linq-to-Database entities.</param>
/// <param name="parameters">A array from ParameterExpressions.</param>
/// <param name="resultType">Type of the result. If not specified, it will be generated dynamically.</param>
/// <param name="expression">The expression.</param>
/// <param name="parsingConfig">The Configuration for the parsing.</param>
/// <param name="values">An object array that contains zero or more objects which are used as replacement values.</param>
/// <returns>The generated <see cref="LambdaExpression"/></returns>
[PublicAPI]
public static LambdaExpression ParseLambda(bool createParameterCtor, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, string expression, ParsingConfig parsingConfig, params object[] values)
public static LambdaExpression ParseLambda([CanBeNull] ParsingConfig parsingConfig, bool createParameterCtor, [NotNull] ParameterExpression[] parameters, [CanBeNull] Type resultType, [NotNull] string expression, params object[] values)
{
Check.NotNull(parameters, nameof(parameters));
Check.Condition(parameters, p => p.Count(x => x == null) == 0, nameof(parameters));
Expand Down

0 comments on commit 02fd83b

Please sign in to comment.