From 04e1925e7eef01e86d2196ff49f471bd99e9d9ad Mon Sep 17 00:00:00 2001 From: Kenzo De Ridder Date: Wed, 26 Jun 2019 11:01:59 +0200 Subject: [PATCH 1/4] Add project files. --- .../ExpressionBuilder.Test.csproj | 1 + .../Integration/GroupBuilderTest.cs | 110 ++++++++++++++++++ ExpressionBuilder/Builders/GroupBuilder.cs | 67 +++++++++++ .../Common/CommonExtensionMethods.cs | 13 +++ ExpressionBuilder/Generics/Filter.cs | 2 +- 5 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 ExpressionBuilder.Test/Integration/GroupBuilderTest.cs create mode 100644 ExpressionBuilder/Builders/GroupBuilder.cs diff --git a/ExpressionBuilder.Test/ExpressionBuilder.Test.csproj b/ExpressionBuilder.Test/ExpressionBuilder.Test.csproj index c9e295b..e3efe55 100644 --- a/ExpressionBuilder.Test/ExpressionBuilder.Test.csproj +++ b/ExpressionBuilder.Test/ExpressionBuilder.Test.csproj @@ -71,6 +71,7 @@ + diff --git a/ExpressionBuilder.Test/Integration/GroupBuilderTest.cs b/ExpressionBuilder.Test/Integration/GroupBuilderTest.cs new file mode 100644 index 0000000..7fbc188 --- /dev/null +++ b/ExpressionBuilder.Test/Integration/GroupBuilderTest.cs @@ -0,0 +1,110 @@ +using ExpressionBuilder.Builders; +using ExpressionBuilder.Common; +using ExpressionBuilder.Generics; +using ExpressionBuilder.Operations; +using ExpressionBuilder.Test.Models; +using ExpressionBuilder.Test.Unit.Helpers; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ExpressionBuilder.Test.Integration +{ + [TestFixture] + public class GroupBuilderTest + { + private List _people; + + public List People + { + get + { + if (_people == null) + { + _people = new TestData().People; + } + + return _people; + } + } + + [TestCase(TestName = "Passing null filter should return true")] + public void GroupWithEmptyFilter() + { + var expr1 = GroupBuilder.GetFilter(null); + Assert.AreEqual(expr1.Invoke(null), true); + var expr2 = GroupBuilder.GetFilter(new Filter()); + Assert.AreEqual(expr2.Invoke(null), true); + } + + [TestCase(TestName = "Passing null array should return true")] + public void GroupWithEmptyFilterArray() + { + var andExpression = GroupBuilder.GetFilter(GroupBuilder.StartGroup(Common.Connector.And, null)); + var orExpression = GroupBuilder.GetFilter(GroupBuilder.StartGroup(Common.Connector.Or, null)); + Assert.AreEqual(andExpression.Invoke(null), true); + Assert.AreEqual(orExpression.Invoke(null), true); + Assert.AreEqual(andExpression.Invoke(null), orExpression.Invoke(null)); + } + + [TestCase(TestName = "1 passed filter should return that filter's expression")] + public void GroupWithSingleElementFilterArray() + { + var filter = new Filter(); + filter.By("Birth.Country", Operation.IsEmpty, null, (object)null, Connector.And); + var andExpression = GroupBuilder.GetFilter(GroupBuilder.StartGroup(Common.Connector.And, filter)); + var orExpression = GroupBuilder.GetFilter(GroupBuilder.StartGroup(Common.Connector.Or, filter)); + var people1 = People.Where(andExpression); + var solution = People.Where(filter); + Assert.That(people1, Is.EquivalentTo(solution)); + var people2 = People.Where(andExpression); + Assert.That(people2, Is.EquivalentTo(solution)); + } + + [TestCase(TestName = "And/Or with 2 parameters")] + public void GroupWith2Parameters() + { + var f1 = new Filter(); + f1.By("Birth.Date", Operation.IsNotNull); + var f2 = new Filter(); + f2.By("Birth.Date", Operation.GreaterThan, new DateTime(1980, 1, 1)); + var orExpression = GroupBuilder.GetFilter(GroupBuilder.StartGroup(Common.Connector.Or, f1, f2)); + var orPeople = People.Where(orExpression); + var orFilter = new Filter(); + orFilter.By("Birth.Date", Operation.IsNotNull).Or.By("Birth.Date", Operation.GreaterThan, new DateTime(1980, 1, 1)); + var orSolution = People.Where(orFilter); + Assert.That(orPeople, Is.EquivalentTo(orSolution)); + + var andExpression = GroupBuilder.GetFilter(GroupBuilder.StartGroup(Common.Connector.And, f1, f2)); + var andPeople = People.Where(andExpression); + var andFilter = new Filter(); + andFilter.By("Birth.Date", Operation.IsNotNull).And.By("Birth.Date", Operation.GreaterThan, new DateTime(1980, 1, 1)); + var andSolution = People.Where(andFilter); + Assert.That(andPeople, Is.EquivalentTo(andSolution)); + } + + [TestCase(TestName = "Group equal to builder using complex expressions (fluent interface)", Category = "ComplexExpressions")] + public void GroupUsingComplexExpressionsFluentInterface() + { + var f1 = new Filter(); + var f2 = new Filter(); + var f3 = new Filter(); + var f4 = new Filter(); + f1.By("Birth.Country", Operation.EqualTo, "USA"); + f2.By("Name", Operation.DoesNotContain, "doe"); + f3.By("Name", Operation.EndsWith, "Doe"); + f4.By("Birth.Country", Operation.IsNullOrWhiteSpace); + var orExpression = GroupBuilder.GetFilter(GroupBuilder.StartGroup(Connector.Or, GroupBuilder.StartGroup(Connector.And, f1, f2), GroupBuilder.StartGroup(Connector.And, f3, f4))); + var people = People.Where(orExpression); + var filter = new Filter(); + filter.By("Birth.Country", Operation.EqualTo, "USA").And.By("Name", Operation.DoesNotContain, "doe") + .Or + .Group.By("Name", Operation.EndsWith, "Doe").And.By("Birth.Country", Operation.IsNullOrWhiteSpace); + var solution = People.Where(filter); + Assert.That(people, Is.EquivalentTo(solution)); + } + } +} diff --git a/ExpressionBuilder/Builders/GroupBuilder.cs b/ExpressionBuilder/Builders/GroupBuilder.cs new file mode 100644 index 0000000..e9acb92 --- /dev/null +++ b/ExpressionBuilder/Builders/GroupBuilder.cs @@ -0,0 +1,67 @@ +using ExpressionBuilder.Common; +using ExpressionBuilder.Interfaces; +using System; +using System.Linq.Expressions; + +namespace ExpressionBuilder.Builders +{ + /// + /// Static class that enables creating LINQ expression trees. + /// + public static class GroupBuilder + { + /// + /// Combines zero or more LINQ Expressions into a single LINQ Expression. + /// Return true if no filters are supplied. + /// + /// + /// + /// The LINQ expressions to combine. + /// Single combined LINQ expression. + public static Expression> StartGroup(Connector connector, params Expression>[] filters) where TClass : class + { + if (filters == null) + { + return (c) => true; + } + FilterBuilder _filterBuilder = new FilterBuilder(); + if (filters.Length == 1) + { + return filters[0]; + } + Expression> predicate = null; + if (connector == Connector.And) + { + predicate = c => true; + foreach (var filter in filters) + { + predicate = predicate.And(filter); + } + } + else if (connector == Connector.Or) + { + predicate = c => false; + foreach (var filter in filters) + { + predicate = predicate.Or(filter); + } + } + return predicate; + } + + /// + /// Converts a LINQ expression to a lambda delegate. + /// + /// + /// The expression to compile + /// The function that can be used inside LINQ functions (e.g. Where, Any, ...). + public static Func GetFilter(Expression> filter) where TClass : class + { + if (filter == null) + { + return (c) => true; + } + return filter.Compile(); + } + } +} diff --git a/ExpressionBuilder/Common/CommonExtensionMethods.cs b/ExpressionBuilder/Common/CommonExtensionMethods.cs index cb8fcf8..0fddab3 100644 --- a/ExpressionBuilder/Common/CommonExtensionMethods.cs +++ b/ExpressionBuilder/Common/CommonExtensionMethods.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -76,5 +77,17 @@ public static bool IsGenericList(this object o) var oType = o.GetType(); return (oType.IsGenericType && (oType.GetGenericTypeDefinition() == typeof(System.Collections.Generic.List<>))); } + + public static Expression> Or(this Expression> expr1, Expression> expr2) + { + var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast()); + return Expression.Lambda>(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters); + } + + public static Expression> And(this Expression> expr1, Expression> expr2) + { + var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast()); + return Expression.Lambda>(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters); + } } } \ No newline at end of file diff --git a/ExpressionBuilder/Generics/Filter.cs b/ExpressionBuilder/Generics/Filter.cs index 5a7fc96..293f669 100644 --- a/ExpressionBuilder/Generics/Filter.cs +++ b/ExpressionBuilder/Generics/Filter.cs @@ -18,7 +18,7 @@ namespace ExpressionBuilder.Generics public class Filter : IFilter, IXmlSerializable where TClass : class { private readonly List> _statements; - + public IFilter Group { get From ceecebd745069a0d8e447cf5ed83f4d2a23815de Mon Sep 17 00:00:00 2001 From: Kenzo De Ridder Date: Wed, 26 Jun 2019 11:17:30 +0200 Subject: [PATCH 2/4] Added support for Expression trees --- .../Integration/GroupBuilderTest.cs | 14 +- ExpressionBuilder/Builders/GroupBuilder.cs | 4 +- ExpressionBuilder/Helpers/FilterBuilder.cs | 163 ++++++++++++++++++ 3 files changed, 172 insertions(+), 9 deletions(-) create mode 100644 ExpressionBuilder/Helpers/FilterBuilder.cs diff --git a/ExpressionBuilder.Test/Integration/GroupBuilderTest.cs b/ExpressionBuilder.Test/Integration/GroupBuilderTest.cs index 7fbc188..058c60c 100644 --- a/ExpressionBuilder.Test/Integration/GroupBuilderTest.cs +++ b/ExpressionBuilder.Test/Integration/GroupBuilderTest.cs @@ -43,8 +43,8 @@ public void GroupWithEmptyFilter() [TestCase(TestName = "Passing null array should return true")] public void GroupWithEmptyFilterArray() { - var andExpression = GroupBuilder.GetFilter(GroupBuilder.StartGroup(Common.Connector.And, null)); - var orExpression = GroupBuilder.GetFilter(GroupBuilder.StartGroup(Common.Connector.Or, null)); + var andExpression = GroupBuilder.GetFilter(GroupBuilder.Group(Common.Connector.And, null)); + var orExpression = GroupBuilder.GetFilter(GroupBuilder.Group(Common.Connector.Or, null)); Assert.AreEqual(andExpression.Invoke(null), true); Assert.AreEqual(orExpression.Invoke(null), true); Assert.AreEqual(andExpression.Invoke(null), orExpression.Invoke(null)); @@ -55,8 +55,8 @@ public void GroupWithSingleElementFilterArray() { var filter = new Filter(); filter.By("Birth.Country", Operation.IsEmpty, null, (object)null, Connector.And); - var andExpression = GroupBuilder.GetFilter(GroupBuilder.StartGroup(Common.Connector.And, filter)); - var orExpression = GroupBuilder.GetFilter(GroupBuilder.StartGroup(Common.Connector.Or, filter)); + var andExpression = GroupBuilder.GetFilter(GroupBuilder.Group(Common.Connector.And, filter)); + var orExpression = GroupBuilder.GetFilter(GroupBuilder.Group(Common.Connector.Or, filter)); var people1 = People.Where(andExpression); var solution = People.Where(filter); Assert.That(people1, Is.EquivalentTo(solution)); @@ -71,14 +71,14 @@ public void GroupWith2Parameters() f1.By("Birth.Date", Operation.IsNotNull); var f2 = new Filter(); f2.By("Birth.Date", Operation.GreaterThan, new DateTime(1980, 1, 1)); - var orExpression = GroupBuilder.GetFilter(GroupBuilder.StartGroup(Common.Connector.Or, f1, f2)); + var orExpression = Connector.Or.Group(f1, f2).GetFilter(); var orPeople = People.Where(orExpression); var orFilter = new Filter(); orFilter.By("Birth.Date", Operation.IsNotNull).Or.By("Birth.Date", Operation.GreaterThan, new DateTime(1980, 1, 1)); var orSolution = People.Where(orFilter); Assert.That(orPeople, Is.EquivalentTo(orSolution)); - var andExpression = GroupBuilder.GetFilter(GroupBuilder.StartGroup(Common.Connector.And, f1, f2)); + var andExpression = Connector.And.Group(f1, f2).GetFilter(); var andPeople = People.Where(andExpression); var andFilter = new Filter(); andFilter.By("Birth.Date", Operation.IsNotNull).And.By("Birth.Date", Operation.GreaterThan, new DateTime(1980, 1, 1)); @@ -97,7 +97,7 @@ public void GroupUsingComplexExpressionsFluentInterface() f2.By("Name", Operation.DoesNotContain, "doe"); f3.By("Name", Operation.EndsWith, "Doe"); f4.By("Birth.Country", Operation.IsNullOrWhiteSpace); - var orExpression = GroupBuilder.GetFilter(GroupBuilder.StartGroup(Connector.Or, GroupBuilder.StartGroup(Connector.And, f1, f2), GroupBuilder.StartGroup(Connector.And, f3, f4))); + var orExpression = GroupBuilder.GetFilter(GroupBuilder.Group(Connector.Or, GroupBuilder.Group(Connector.And, f1, f2), GroupBuilder.Group(Connector.And, f3, f4))); var people = People.Where(orExpression); var filter = new Filter(); filter.By("Birth.Country", Operation.EqualTo, "USA").And.By("Name", Operation.DoesNotContain, "doe") diff --git a/ExpressionBuilder/Builders/GroupBuilder.cs b/ExpressionBuilder/Builders/GroupBuilder.cs index e9acb92..da81047 100644 --- a/ExpressionBuilder/Builders/GroupBuilder.cs +++ b/ExpressionBuilder/Builders/GroupBuilder.cs @@ -18,7 +18,7 @@ public static class GroupBuilder /// /// The LINQ expressions to combine. /// Single combined LINQ expression. - public static Expression> StartGroup(Connector connector, params Expression>[] filters) where TClass : class + public static Expression> Group(this Connector connector, params Expression>[] filters) where TClass : class { if (filters == null) { @@ -55,7 +55,7 @@ public static Expression> StartGroup(Connector connec /// /// The expression to compile /// The function that can be used inside LINQ functions (e.g. Where, Any, ...). - public static Func GetFilter(Expression> filter) where TClass : class + public static Func GetFilter(this Expression> filter) where TClass : class { if (filter == null) { diff --git a/ExpressionBuilder/Helpers/FilterBuilder.cs b/ExpressionBuilder/Helpers/FilterBuilder.cs new file mode 100644 index 0000000..eeb8249 --- /dev/null +++ b/ExpressionBuilder/Helpers/FilterBuilder.cs @@ -0,0 +1,163 @@ +using ExpressionBuilder.Common; +using ExpressionBuilder.Exceptions; +using ExpressionBuilder.Interfaces; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; + +namespace ExpressionBuilder.Helpers +{ + class FilterBuilder where T : class + { + protected static Expression> GetExpression(IFilter filter) + { + var param = Expression.Parameter(typeof(T), "x"); + Expression expression = null; + var connector = Connector.And; + foreach (var statementGroup in filter.Statements) + { + var statementGroupConnector = Connector.And; + Expression partialExpr = GetPartialExpression(param, ref statementGroupConnector, statementGroup); + + expression = expression == null ? partialExpr : CombineExpressions(expression, partialExpr, connector); + connector = statementGroupConnector; + } + + expression = expression ?? Expression.Constant(true); + + return Expression.Lambda>(expression, param); + } + + private static Expression GetPartialExpression(ParameterExpression param, ref Connector connector, IEnumerable statementGroup) + { + Expression expression = null; + foreach (var statement in statementGroup) + { + Expression expr = null; + if (IsList(statement)) + { + expr = ProcessListStatement(param, statement); + } + else + { + expr = GetExpression(param, statement); + } + + expression = expression == null ? expr : CombineExpressions(expression, expr, connector); + connector = statement.Connector; + } + + return expression; + } + + private static bool IsList(IFilterStatement statement) + { + return statement.PropertyId.Contains("[") && statement.PropertyId.Contains("]"); + } + + private static Expression CombineExpressions(Expression expr1, Expression expr2, Connector connector) + { + return connector == Connector.And ? Expression.AndAlso(expr1, expr2) : Expression.OrElse(expr1, expr2); + } + + private static Expression ProcessListStatement(ParameterExpression param, IFilterStatement statement) + { + var basePropertyName = statement.PropertyId.Substring(0, statement.PropertyId.IndexOf("[")); + var propertyName = statement.PropertyId.Substring(statement.PropertyId.IndexOf("[") + 1).Replace("]", string.Empty); + + var type = param.Type.GetProperty(basePropertyName).PropertyType.GetGenericArguments()[0]; + ParameterExpression listItemParam = Expression.Parameter(type, "i"); + var lambda = Expression.Lambda(GetExpression(listItemParam, statement, propertyName), listItemParam); + var member = param.GetMemberExpression(basePropertyName); + var enumerableType = typeof(Enumerable); + var anyInfo = enumerableType.GetMethods(BindingFlags.Static | BindingFlags.Public).First(m => m.Name == "Any" && m.GetParameters().Count() == 2); + anyInfo = anyInfo.MakeGenericMethod(type); + return Expression.Call(anyInfo, member, lambda); + } + + private static Expression GetExpression(ParameterExpression param, IFilterStatement statement, string propertyName = null) + { + Expression resultExpr = null; + var memberName = propertyName ?? statement.PropertyId; + MemberExpression member = param.GetMemberExpression(memberName); + + if (Nullable.GetUnderlyingType(member.Type) != null && statement.Value != null) + { + resultExpr = Expression.Property(member, "HasValue"); + member = Expression.Property(member, "Value"); + } + + var constant1 = Expression.Constant(statement.Value); + var constant2 = Expression.Constant(statement.Value2); + + CheckPropertyValueMismatch(member, constant1); + + var safeStringExpression = statement.Operation.GetExpression(member, constant1, constant2); + resultExpr = resultExpr != null ? Expression.AndAlso(resultExpr, safeStringExpression) : safeStringExpression; + resultExpr = GetSafePropertyMember(param, memberName, resultExpr); + + if (statement.Operation.ExpectNullValues && memberName.Contains(".")) + { + resultExpr = Expression.OrElse(CheckIfParentIsNull(param, memberName), resultExpr); + } + + return resultExpr; + } + + private static void CheckPropertyValueMismatch(MemberExpression member, ConstantExpression constant1) + { + var memberType = member.Member.MemberType == MemberTypes.Property ? (member.Member as PropertyInfo).PropertyType : (member.Member as FieldInfo).FieldType; + + var constant1Type = GetConstantType(constant1); + var nullableType = constant1Type != null ? Nullable.GetUnderlyingType(constant1Type) : null; + + var constantValueIsNotNull = constant1.Value != null; + var memberAndConstantTypeDoNotMatch = nullableType == null && memberType != constant1Type; + var memberAndNullableUnderlyingTypeDoNotMatch = nullableType != null && memberType != nullableType; + + if (constantValueIsNotNull && (memberAndConstantTypeDoNotMatch || memberAndNullableUnderlyingTypeDoNotMatch)) + { + throw new PropertyValueTypeMismatchException(member.Member.Name, memberType.Name, constant1.Type.Name); + } + } + + private static Type GetConstantType(ConstantExpression constant) + { + if (constant != null && constant.Value != null && constant.Value.IsGenericList()) + { + return constant.Value.GetType().GenericTypeArguments[0]; + } + + return constant != null && constant.Value != null ? constant.Value.GetType() : null; + } + + protected static Expression GetSafePropertyMember(ParameterExpression param, string memberName, Expression expr) + { + if (!memberName.Contains(".")) + { + return expr; + } + + var index = memberName.LastIndexOf(".", StringComparison.InvariantCulture); + var parentName = memberName.Substring(0, index); + var subParam = param.GetMemberExpression(parentName); + var resultExpr = Expression.AndAlso(Expression.NotEqual(subParam, Expression.Constant(null)), expr); + return GetSafePropertyMember(param, parentName, resultExpr); + } + + protected static Expression CheckIfParentIsNull(ParameterExpression param, string memberName) + { + var parentMember = GetParentMember(param, memberName); + return Expression.Equal(parentMember, Expression.Constant(null)); + } + + private static MemberExpression GetParentMember(ParameterExpression param, string memberName) + { + var parentName = memberName.Substring(0, memberName.IndexOf(".")); + return param.GetMemberExpression(parentName); + } + } +} From ca3b7bcba20986b99b75e43fae7f82b227793f59 Mon Sep 17 00:00:00 2001 From: Kenzo De Ridder Date: Wed, 26 Jun 2019 13:15:53 +0200 Subject: [PATCH 3/4] Codacy fixes --- ExpressionBuilder.Test/Integration/GroupBuilderTest.cs | 4 ++-- ExpressionBuilder/Builders/GroupBuilder.cs | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ExpressionBuilder.Test/Integration/GroupBuilderTest.cs b/ExpressionBuilder.Test/Integration/GroupBuilderTest.cs index 058c60c..e4ae9c8 100644 --- a/ExpressionBuilder.Test/Integration/GroupBuilderTest.cs +++ b/ExpressionBuilder.Test/Integration/GroupBuilderTest.cs @@ -60,7 +60,7 @@ public void GroupWithSingleElementFilterArray() var people1 = People.Where(andExpression); var solution = People.Where(filter); Assert.That(people1, Is.EquivalentTo(solution)); - var people2 = People.Where(andExpression); + var people2 = People.Where(orExpression); Assert.That(people2, Is.EquivalentTo(solution)); } @@ -97,7 +97,7 @@ public void GroupUsingComplexExpressionsFluentInterface() f2.By("Name", Operation.DoesNotContain, "doe"); f3.By("Name", Operation.EndsWith, "Doe"); f4.By("Birth.Country", Operation.IsNullOrWhiteSpace); - var orExpression = GroupBuilder.GetFilter(GroupBuilder.Group(Connector.Or, GroupBuilder.Group(Connector.And, f1, f2), GroupBuilder.Group(Connector.And, f3, f4))); + var orExpression = Connector.Or.Group(Connector.And.Group(f1, f2), Connector.And.Group(f3, f4)).GetFilter(); var people = People.Where(orExpression); var filter = new Filter(); filter.By("Birth.Country", Operation.EqualTo, "USA").And.By("Name", Operation.DoesNotContain, "doe") diff --git a/ExpressionBuilder/Builders/GroupBuilder.cs b/ExpressionBuilder/Builders/GroupBuilder.cs index da81047..b508e9e 100644 --- a/ExpressionBuilder/Builders/GroupBuilder.cs +++ b/ExpressionBuilder/Builders/GroupBuilder.cs @@ -24,7 +24,6 @@ public static Expression> Group(this Connector connec { return (c) => true; } - FilterBuilder _filterBuilder = new FilterBuilder(); if (filters.Length == 1) { return filters[0]; From 45291bd46c44d3dc4a5800f6f439f79d4eff231d Mon Sep 17 00:00:00 2001 From: Kenzo De Ridder Date: Fri, 17 Dec 2021 09:24:42 +0100 Subject: [PATCH 4/4] Bugfix for projects that throw errors when loading all assemblies --- .../ExpressionBuilder.Test.NetCore.csproj | 14 +++---- .../Database/BuilderTest.cs | 2 +- ExpressionBuilder/ExpressionBuilder.csproj | 17 +++++--- ExpressionBuilder/Helpers/OperationHelper.cs | 39 ++++++++++++++----- 4 files changed, 48 insertions(+), 24 deletions(-) diff --git a/ExpressionBuilder.Test.NetCore/ExpressionBuilder.Test.NetCore.csproj b/ExpressionBuilder.Test.NetCore/ExpressionBuilder.Test.NetCore.csproj index dffc511..bb5be74 100644 --- a/ExpressionBuilder.Test.NetCore/ExpressionBuilder.Test.NetCore.csproj +++ b/ExpressionBuilder.Test.NetCore/ExpressionBuilder.Test.NetCore.csproj @@ -1,7 +1,7 @@ - netcoreapp2.2 + net6.0 false @@ -48,12 +48,12 @@ - - - - - - + + + + + + diff --git a/ExpressionBuilder.Test/Database/BuilderTest.cs b/ExpressionBuilder.Test/Database/BuilderTest.cs index 3f976d0..efc8f32 100644 --- a/ExpressionBuilder.Test/Database/BuilderTest.cs +++ b/ExpressionBuilder.Test/Database/BuilderTest.cs @@ -1,4 +1,4 @@ -#if (NETSTANDARD2_0 || NETSTANDARD2_1 || NETSTANDARD2_2 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2) +#if (NETSTANDARD2_0 || NETSTANDARD2_1 || NETSTANDARD2_2 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NET6_0_OR_GREATER) using ExpressionBuilder.Test.NetCore.Database; diff --git a/ExpressionBuilder/ExpressionBuilder.csproj b/ExpressionBuilder/ExpressionBuilder.csproj index cab278c..75cac15 100644 --- a/ExpressionBuilder/ExpressionBuilder.csproj +++ b/ExpressionBuilder/ExpressionBuilder.csproj @@ -1,7 +1,7 @@  - netstandard2.0;net452 + netstandard2.0 David Belmont https://github.com/dbelmont/ExpressionBuilder https://raw.githubusercontent.com/dbelmont/ExpressionBuilder/master/ExpressionBuilder/ExpressionBuilder.png @@ -19,9 +19,11 @@ Useful to turn WebApi requests parameters into expressions, create advanced search screens with the capability to save and re-run those filters, among other things. - 2.1.0.0 + 2.1.0.2 true - 2.1.0-rc + 2.1.4 + true + snupkg true LambdaExpressionBuilder @@ -30,16 +32,16 @@ - 2.2.0 + 6.0.0 - 2.2.0 + 6.0.0 4.5.0 - 4.5.0 + 5.0.0 @@ -63,4 +65,7 @@ + + + \ No newline at end of file diff --git a/ExpressionBuilder/Helpers/OperationHelper.cs b/ExpressionBuilder/Helpers/OperationHelper.cs index f7a9cb4..c01f014 100644 --- a/ExpressionBuilder/Helpers/OperationHelper.cs +++ b/ExpressionBuilder/Helpers/OperationHelper.cs @@ -29,13 +29,29 @@ static OperationHelper() /// public static void LoadDefaultOperations() { - var @interface = typeof(IOperation); - var operationsFound = AppDomain.CurrentDomain.GetAssemblies() - .Where(a => a.DefinedTypes.Any(t => t.Namespace == "ExpressionBuilder.Operations")) - .SelectMany(s => s.GetTypes()) - .Where(p => @interface.IsAssignableFrom(p) && p.IsClass && !p.IsAbstract) - .Select(t => (IOperation)Activator.CreateInstance(t)); - _operations = new HashSet(operationsFound, new OperationEqualityComparer()); + var listOfOperations = new List + { + new ExpressionBuilder.Operations.Between(), + new ExpressionBuilder.Operations.Contains(), + new ExpressionBuilder.Operations.DoesNotContain(), + new ExpressionBuilder.Operations.EndsWith(), + new ExpressionBuilder.Operations.EqualTo(), + new ExpressionBuilder.Operations.GreaterThan(), + new ExpressionBuilder.Operations.GreaterThanOrEqualTo(), + new ExpressionBuilder.Operations.In(), + new ExpressionBuilder.Operations.IsEmpty(), + new ExpressionBuilder.Operations.IsNotEmpty(), + new ExpressionBuilder.Operations.IsNotNull(), + new ExpressionBuilder.Operations.IsNotNullNorWhiteSpace(), + new ExpressionBuilder.Operations.IsNull(), + new ExpressionBuilder.Operations.IsNullOrWhiteSpace(), + new ExpressionBuilder.Operations.LessThan(), + new ExpressionBuilder.Operations.LessThanOrEqualTo(), + new ExpressionBuilder.Operations.NotEqualTo(), + new ExpressionBuilder.Operations.NotIn(), + new ExpressionBuilder.Operations.StartsWith(), + }; + _operations = new HashSet(listOfOperations, new OperationEqualityComparer()); } /// @@ -73,11 +89,14 @@ public HashSet SupportedOperations(Type type) private void GetCustomSupportedTypes() { - foreach (var supportedType in _settings.SupportedTypes) + if (_settings.SupportedTypes != null) { - if (supportedType.Type != null) + foreach (var supportedType in _settings.SupportedTypes) { - TypeGroups[supportedType.TypeGroup].Add(supportedType.Type); + if (supportedType.Type != null) + { + TypeGroups[supportedType.TypeGroup].Add(supportedType.Type); + } } } }