diff --git a/PoweredSoft.DynamicLinq.Test/Helpers/QueryableAssert.cs b/PoweredSoft.DynamicLinq.Test/Helpers/QueryableAssert.cs index 01635da..15bf63d 100644 --- a/PoweredSoft.DynamicLinq.Test/Helpers/QueryableAssert.cs +++ b/PoweredSoft.DynamicLinq.Test/Helpers/QueryableAssert.cs @@ -37,5 +37,17 @@ namespace PoweredSoft.DynamicLinq.Test.Helpers { Assert.IsFalse(_sameList(a, b)); } + + public static void AreEqual(IQueryable a, IQueryable b, string message) + where T : class + { + Assert.IsTrue(_sameList(a, b), message); + } + + public static void AreNotEqual(IQueryable a, IQueryable b, string message) + where T : class + { + Assert.IsFalse(_sameList(a, b), message); + } } } diff --git a/PoweredSoft.DynamicLinq.Test/PoweredSoft.DynamicLinq.Test.csproj b/PoweredSoft.DynamicLinq.Test/PoweredSoft.DynamicLinq.Test.csproj index 3e87cb5..98ba927 100644 --- a/PoweredSoft.DynamicLinq.Test/PoweredSoft.DynamicLinq.Test.csproj +++ b/PoweredSoft.DynamicLinq.Test/PoweredSoft.DynamicLinq.Test.csproj @@ -68,6 +68,7 @@ + diff --git a/PoweredSoft.DynamicLinq.Test/StringComparision.cs b/PoweredSoft.DynamicLinq.Test/StringComparision.cs new file mode 100644 index 0000000..e29573b --- /dev/null +++ b/PoweredSoft.DynamicLinq.Test/StringComparision.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using PoweredSoft.DynamicLinq.Extensions; +using PoweredSoft.DynamicLinq.Test.Helpers; + +namespace PoweredSoft.DynamicLinq.Test +{ + [TestClass] + public class StringComparisionTests + { + internal List Persons = new List + { + new MockPersonObject { FirstName = "David", LastName = "Lebee", Age = 28 }, + new MockPersonObject { FirstName = "Michaela", LastName = "Vickar", Age = 27 }, + new MockPersonObject { FirstName = "John", LastName = "Doe", Age = 28 }, + new MockPersonObject { FirstName = "Chuck", LastName = "Norris", Age = 50 }, + new MockPersonObject { FirstName = "Michael", LastName = "Jackson", Age = 58 } + }; + + [TestMethod] + public void Equal() + { + IQueryable a, b; + + // case sensitive. + a = Persons.AsQueryable().Query(t => t.Equal("FirstName", "David", stringComparision: null)); + b = Persons.AsQueryable().Where(t => t.FirstName == "David"); + QueryableAssert.AreEqual(a, b, "CaseSensitive"); + + // not case sensitive + a = Persons.AsQueryable().Query(t => t.Equal("FirstName", "DAVID", stringComparision: StringComparison.OrdinalIgnoreCase)); + b = Persons.AsQueryable().Where(t => t.FirstName.Equals("DAVID", StringComparison.OrdinalIgnoreCase)); + QueryableAssert.AreEqual(a, b, "CaseInsensitive"); + } + + [TestMethod] + public void NotEqual() + { + IQueryable a, b; + + // case sensitive. + a = Persons.AsQueryable().Query(t => t.NotEqual("FirstName", "David", stringComparision: null)); + b = Persons.AsQueryable().Where(t => t.FirstName != "David"); + QueryableAssert.AreEqual(a, b, "CaseSensitive"); + + // not case sensitive + a = Persons.AsQueryable().Query(t => t.NotEqual("FirstName", "DAVID", stringComparision: StringComparison.OrdinalIgnoreCase)); + b = Persons.AsQueryable().Where(t => !t.FirstName.Equals("DAVID", StringComparison.OrdinalIgnoreCase)); + QueryableAssert.AreEqual(a, b, "CaseInsensitive"); + } + + [TestMethod] + public void Contains() + { + IQueryable a, b; + + // case sensitive. + a = Persons.AsQueryable().Query(t => t.Contains("FirstName", "vi", stringComparision: null)); + b = Persons.AsQueryable().Where(t => t.FirstName.Contains("vi")); + QueryableAssert.AreEqual(a, b, "CaseSensitive"); + + // not case sensitive + a = Persons.AsQueryable().Query(t => t.Contains("FirstName", "VI", stringComparision: StringComparison.OrdinalIgnoreCase)); + b = Persons.AsQueryable().Where(t => t.FirstName.IndexOf("VI", StringComparison.OrdinalIgnoreCase) > -1); + QueryableAssert.AreEqual(a, b, "CaseInsensitive"); + } + + [TestMethod] + public void StartsWith() + { + IQueryable a, b; + + // case sensitive. + a = Persons.AsQueryable().Query(t => t.StartsWith("FirstName", "Da", stringComparision: null)); + b = Persons.AsQueryable().Where(t => t.FirstName.StartsWith("Da")); + QueryableAssert.AreEqual(a, b, "CaseSensitive"); + + // not case sensitive + a = Persons.AsQueryable().Query(t => t.StartsWith("FirstName", "DA", stringComparision: StringComparison.OrdinalIgnoreCase)); + b = Persons.AsQueryable().Where(t => t.FirstName.StartsWith("DA", StringComparison.OrdinalIgnoreCase)); + QueryableAssert.AreEqual(a, b, "CaseInsensitive"); + } + + [TestMethod] + public void EndsWith() + { + IQueryable a, b; + + // case sensitive. + a = Persons.AsQueryable().Query(t => t.EndsWith("FirstName", "vid", stringComparision: null)); + b = Persons.AsQueryable().Where(t => t.FirstName.EndsWith("vid")); + QueryableAssert.AreEqual(a, b, "CaseSensitive"); + + // not case sensitive + a = Persons.AsQueryable().Query(t => t.EndsWith("FirstName", "VID", stringComparision: StringComparison.OrdinalIgnoreCase)); + b = Persons.AsQueryable().Where(t => t.FirstName.EndsWith("VID", StringComparison.OrdinalIgnoreCase)); + QueryableAssert.AreEqual(a, b, "CaseInsensitive"); + } + } +} diff --git a/PoweredSoft.DynamicLinq/Constants.cs b/PoweredSoft.DynamicLinq/Constants.cs index 4f37012..972ca15 100644 --- a/PoweredSoft.DynamicLinq/Constants.cs +++ b/PoweredSoft.DynamicLinq/Constants.cs @@ -41,9 +41,13 @@ namespace PoweredSoft.DynamicLinq internal static class Constants { + internal static readonly MethodInfo StringEqualWithComparisation = typeof(string).GetMethod("Equals", new Type[] { typeof(string), typeof(StringComparison) }); internal static readonly MethodInfo ContainsMethod = typeof(string).GetMethod("Contains"); internal static readonly MethodInfo StartsWithMethod = typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) }); + internal static readonly MethodInfo StartsWithMethodWithComparisation = typeof(string).GetMethod("StartsWith", new Type[] { typeof(string), typeof(StringComparison) }); internal static readonly MethodInfo EndsWithMethod = typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) }); + internal static readonly MethodInfo EndsWithMethodWithComparisation = typeof(string).GetMethod("EndsWith", new Type[] { typeof(string), typeof(StringComparison) }); + internal static readonly MethodInfo IndexOfMethod = typeof(string).GetMethod("IndexOf", new Type[] { typeof(string), typeof(StringComparison) }); internal static readonly MethodInfo AnyMethod = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public).First(t => t.Name == "Any" && t.GetParameters().Count() == 2); internal static readonly MethodInfo AllMethod = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public).First(t => t.Name == "All" && t.GetParameters().Count() == 2); } diff --git a/PoweredSoft.DynamicLinq/Fluent/QueryBuilder.cs b/PoweredSoft.DynamicLinq/Fluent/QueryBuilder.cs index f36cadb..e661d24 100644 --- a/PoweredSoft.DynamicLinq/Fluent/QueryBuilder.cs +++ b/PoweredSoft.DynamicLinq/Fluent/QueryBuilder.cs @@ -100,7 +100,8 @@ namespace PoweredSoft.DynamicLinq.Fluent filter.ConvertStrategy, filter.CollectionHandling, parameter: parameter, - nullChecking: IsNullCheckingEnabled + nullChecking: IsNullCheckingEnabled, + stringComparision: filter.StringComparisation ); return ret; diff --git a/PoweredSoft.DynamicLinq/Fluent/QueryBuilderBase.cs b/PoweredSoft.DynamicLinq/Fluent/QueryBuilderBase.cs index 6177818..5ff6606 100644 --- a/PoweredSoft.DynamicLinq/Fluent/QueryBuilderBase.cs +++ b/PoweredSoft.DynamicLinq/Fluent/QueryBuilderBase.cs @@ -23,7 +23,7 @@ namespace PoweredSoft.DynamicLinq.Fluent public virtual QueryBuilderBase Compare(string path, ConditionOperators conditionOperators, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, - bool and = true, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any) + bool and = true, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any, StringComparison? stringComparision = null) { Filters.Add(new QueryBuilderFilter { @@ -32,7 +32,8 @@ namespace PoweredSoft.DynamicLinq.Fluent Path = path, Value = value, ConvertStrategy = convertStrategy, - CollectionHandling = collectionHandling + CollectionHandling = collectionHandling, + StringComparisation = stringComparision }); return this; diff --git a/PoweredSoft.DynamicLinq/Fluent/QueryBuilderBase.shortcuts.cs b/PoweredSoft.DynamicLinq/Fluent/QueryBuilderBase.shortcuts.cs index 90966ea..10cb044 100644 --- a/PoweredSoft.DynamicLinq/Fluent/QueryBuilderBase.shortcuts.cs +++ b/PoweredSoft.DynamicLinq/Fluent/QueryBuilderBase.shortcuts.cs @@ -7,12 +7,12 @@ namespace PoweredSoft.DynamicLinq.Fluent public abstract partial class QueryBuilderBase { public QueryBuilderBase And(string path, ConditionOperators conditionOperator, object value, - QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any) - => Compare(path, conditionOperator, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling, and: true); + QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any, StringComparison? stringComparision = null) + => Compare(path, conditionOperator, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling, and: true, stringComparision: stringComparision); public QueryBuilderBase Or(string path, ConditionOperators conditionOperator, object value, - QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any) - => Compare(path, conditionOperator, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling, and: false); + QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any, StringComparison? stringComparision = null) + => Compare(path, conditionOperator, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling, and: false, stringComparision: stringComparision); public QueryBuilderBase And(Action subQuery) => SubQuery(subQuery, true); @@ -21,25 +21,25 @@ namespace PoweredSoft.DynamicLinq.Fluent => SubQuery(subQuery, false); #region equal - public QueryBuilderBase Equal(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any) - => And(path, ConditionOperators.Equal, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling); + public QueryBuilderBase Equal(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any, StringComparison? stringComparision = null) + => And(path, ConditionOperators.Equal, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling, stringComparision: stringComparision); - public QueryBuilderBase AndEqual(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any) - => And(path, ConditionOperators.Equal, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling); + public QueryBuilderBase AndEqual(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any, StringComparison? stringComparision = null) + => And(path, ConditionOperators.Equal, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling, stringComparision: stringComparision); - public QueryBuilderBase OrEqual(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any) - => Or(path, ConditionOperators.Equal, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling); + public QueryBuilderBase OrEqual(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any, StringComparison? stringComparision = null) + => Or(path, ConditionOperators.Equal, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling, stringComparision: stringComparision); #endregion #region not equal - public QueryBuilderBase NotEqual(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any) - => And(path, ConditionOperators.NotEqual, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling); + public QueryBuilderBase NotEqual(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any, StringComparison? stringComparision = null) + => And(path, ConditionOperators.NotEqual, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling, stringComparision: stringComparision); - public QueryBuilderBase AndNotEqual(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any) - => And(path, ConditionOperators.NotEqual, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling); + public QueryBuilderBase AndNotEqual(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any, StringComparison? stringComparision = null) + => And(path, ConditionOperators.NotEqual, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling, stringComparision: stringComparision); - public QueryBuilderBase OrNotEqual(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any) - => Or(path, ConditionOperators.NotEqual, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling); + public QueryBuilderBase OrNotEqual(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any, StringComparison? stringComparision = null) + => Or(path, ConditionOperators.NotEqual, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling, stringComparision: stringComparision); #endregion #region GreaterThan @@ -87,36 +87,36 @@ namespace PoweredSoft.DynamicLinq.Fluent #endregion #region contains - public QueryBuilderBase Contains(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any) - => And(path, ConditionOperators.Contains, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling); + public QueryBuilderBase Contains(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any, StringComparison? stringComparision = null) + => And(path, ConditionOperators.Contains, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling, stringComparision: stringComparision); - public QueryBuilderBase AndContains(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any) - => And(path, ConditionOperators.Contains, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling); + public QueryBuilderBase AndContains(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any, StringComparison? stringComparision = null) + => And(path, ConditionOperators.Contains, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling, stringComparision: stringComparision); - public QueryBuilderBase OrContains(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any) - => Or(path, ConditionOperators.Contains, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling); + public QueryBuilderBase OrContains(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any, StringComparison? stringComparision = null) + => Or(path, ConditionOperators.Contains, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling, stringComparision: stringComparision); #endregion #region starts with - public QueryBuilderBase StartsWith(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any) - => And(path, ConditionOperators.StartsWith, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling); + public QueryBuilderBase StartsWith(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any, StringComparison? stringComparision = null) + => And(path, ConditionOperators.StartsWith, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling, stringComparision: stringComparision); - public QueryBuilderBase AndStartsWith(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any) - => And(path, ConditionOperators.StartsWith, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling); + public QueryBuilderBase AndStartsWith(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any, StringComparison? stringComparision = null) + => And(path, ConditionOperators.StartsWith, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling, stringComparision: stringComparision); - public QueryBuilderBase OrStartsWith(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any) - => Or(path, ConditionOperators.StartsWith, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling); + public QueryBuilderBase OrStartsWith(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any, StringComparison? stringComparision = null) + => Or(path, ConditionOperators.StartsWith, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling, stringComparision: stringComparision); #endregion #region ends with - public QueryBuilderBase EndsWith(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any) - => And(path, ConditionOperators.EndsWith, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling); + public QueryBuilderBase EndsWith(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any, StringComparison? stringComparision = null) + => And(path, ConditionOperators.EndsWith, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling, stringComparision: stringComparision); - public QueryBuilderBase AndEndsWith(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any) - => And(path, ConditionOperators.EndsWith, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling); + public QueryBuilderBase AndEndsWith(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any, StringComparison? stringComparision = null) + => And(path, ConditionOperators.EndsWith, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling, stringComparision: stringComparision); - public QueryBuilderBase OrEndsWith(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any) - => Or(path, ConditionOperators.EndsWith, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling); + public QueryBuilderBase OrEndsWith(string path, object value, QueryConvertStrategy convertStrategy = QueryConvertStrategy.ConvertConstantToComparedPropertyOrField, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any, StringComparison? stringComparision = null) + => Or(path, ConditionOperators.EndsWith, value, convertStrategy: convertStrategy, collectionHandling: collectionHandling, stringComparision: stringComparision); #endregion } } diff --git a/PoweredSoft.DynamicLinq/Fluent/QueryBuilderFilter.cs b/PoweredSoft.DynamicLinq/Fluent/QueryBuilderFilter.cs index b9b727f..a740d11 100644 --- a/PoweredSoft.DynamicLinq/Fluent/QueryBuilderFilter.cs +++ b/PoweredSoft.DynamicLinq/Fluent/QueryBuilderFilter.cs @@ -15,5 +15,6 @@ namespace PoweredSoft.DynamicLinq.Fluent public QueryConvertStrategy ConvertStrategy { get; set; } public List Filters { get; set; } = new List(); public QueryCollectionHandling CollectionHandling { get; set; } + public StringComparison? StringComparisation { get; set; } = null; } } diff --git a/PoweredSoft.DynamicLinq/Helpers/QueryableHelpers.cs b/PoweredSoft.DynamicLinq/Helpers/QueryableHelpers.cs index f3a3a45..2704a9b 100644 --- a/PoweredSoft.DynamicLinq/Helpers/QueryableHelpers.cs +++ b/PoweredSoft.DynamicLinq/Helpers/QueryableHelpers.cs @@ -10,7 +10,7 @@ namespace PoweredSoft.DynamicLinq.Helpers { public static class QueryableHelpers { - public static Expression GetConditionExpressionForMember(ParameterExpression parameter, Expression member, ConditionOperators conditionOperator, ConstantExpression constant) + public static Expression GetConditionExpressionForMember(ParameterExpression parameter, Expression member, ConditionOperators conditionOperator, ConstantExpression constant, StringComparison? stringComparision) { if (parameter == null) throw new ArgumentNullException("parameter"); @@ -21,12 +21,25 @@ namespace PoweredSoft.DynamicLinq.Helpers if (constant == null) throw new ArgumentNullException("constant"); + + Type stringType = typeof(string); + Expression ret = null; if (conditionOperator == ConditionOperators.Equal) - ret = Expression.Equal(member, constant); + { + if (member.Type == stringType && stringComparision.HasValue) + ret = Expression.Call(member, Constants.StringEqualWithComparisation, constant, Expression.Constant(stringComparision.Value)); + else + ret = Expression.Equal(member, constant); + } else if (conditionOperator == ConditionOperators.NotEqual) - ret = Expression.NotEqual(member, constant); + { + if (member.Type == stringType && stringComparision.HasValue) + ret = Expression.Not(Expression.Call(member, Constants.StringEqualWithComparisation, constant, Expression.Constant(stringComparision.Value))); + else + ret = Expression.NotEqual(member, constant); + } else if (conditionOperator == ConditionOperators.GreaterThan) ret = Expression.GreaterThan(member, constant); else if (conditionOperator == ConditionOperators.GreaterThanOrEqual) @@ -36,11 +49,26 @@ namespace PoweredSoft.DynamicLinq.Helpers else if (conditionOperator == ConditionOperators.LessThanOrEqual) ret = Expression.LessThanOrEqual(member, constant); else if (conditionOperator == ConditionOperators.Contains) - ret = Expression.Call(member, Constants.ContainsMethod, constant); + { + if (member.Type == stringType && stringComparision.HasValue) + ret = Expression.GreaterThan(Expression.Call(member, Constants.IndexOfMethod, constant, Expression.Constant(stringComparision.Value)), Expression.Constant(-1)); + else + ret = Expression.Call(member, Constants.ContainsMethod, constant); + } else if (conditionOperator == ConditionOperators.StartsWith) - ret = Expression.Call(member, Constants.StartsWithMethod, constant); + { + if (member.Type == stringType && stringComparision.HasValue) + ret = Expression.Call(member, Constants.StartsWithMethodWithComparisation, constant, Expression.Constant(stringComparision.Value)); + else + ret = Expression.Call(member, Constants.StartsWithMethod, constant); + } else if (conditionOperator == ConditionOperators.EndsWith) - ret = Expression.Call(member, Constants.EndsWithMethod, constant); + { + if (member.Type == stringType && stringComparision.HasValue) + ret = Expression.Call(member, Constants.EndsWithMethodWithComparisation, constant, Expression.Constant(stringComparision.Value)); + else + ret = Expression.Call(member, Constants.EndsWithMethod, constant); + } else throw new ArgumentException("conditionOperator", "Must supply a known condition operator"); @@ -124,7 +152,7 @@ namespace PoweredSoft.DynamicLinq.Helpers } internal static Expression InternalCreateFilterExpression(int recursionStep, Type type, ParameterExpression parameter, Expression current, List parts, - ConditionOperators condition, object value, QueryConvertStrategy convertStrategy, QueryCollectionHandling collectionHandling, bool nullChecking) + ConditionOperators condition, object value, QueryConvertStrategy convertStrategy, QueryCollectionHandling collectionHandling, bool nullChecking, StringComparison? stringComparison) { var partStr = parts.First(); var isLast = parts.Count == 1; @@ -142,7 +170,7 @@ namespace PoweredSoft.DynamicLinq.Helpers if (isLast) { var constant = QueryableHelpers.ResolveConstant(memberExpression, value, convertStrategy); - var filterExpression = QueryableHelpers.GetConditionExpressionForMember(parameter, memberExpression, condition, constant); + var filterExpression = QueryableHelpers.GetConditionExpressionForMember(parameter, memberExpression, condition, constant, stringComparison); var lambda = Expression.Lambda(filterExpression, parameter); return lambda; } @@ -156,7 +184,7 @@ namespace PoweredSoft.DynamicLinq.Helpers { var listGenericArgumentType = memberExpression.Type.GetGenericArguments().First(); var innerParameter = Expression.Parameter(listGenericArgumentType, $"t{++recursionStep}"); - var innerLambda = InternalCreateFilterExpression(recursionStep, listGenericArgumentType, innerParameter, innerParameter, parts.Skip(1).ToList(), condition, value, convertStrategy, collectionHandling, nullChecking); + var innerLambda = InternalCreateFilterExpression(recursionStep, listGenericArgumentType, innerParameter, innerParameter, parts.Skip(1).ToList(), condition, value, convertStrategy, collectionHandling, nullChecking, stringComparison); // the collection method. var collectionMethod = GetCollectionMethod(collectionHandling); @@ -175,12 +203,12 @@ namespace PoweredSoft.DynamicLinq.Helpers { if (nullCheckExpression != null) { - var pathExpr = InternalCreateFilterExpression(recursionStep, type, parameter, memberExpression, parts.Skip(1).ToList(), condition, value, convertStrategy, collectionHandling, nullChecking); + var pathExpr = InternalCreateFilterExpression(recursionStep, type, parameter, memberExpression, parts.Skip(1).ToList(), condition, value, convertStrategy, collectionHandling, nullChecking, stringComparison); var nullCheckResult = Expression.AndAlso(nullCheckExpression, pathExpr); return nullCheckResult; } - return InternalCreateFilterExpression(recursionStep, type, parameter, memberExpression, parts.Skip(1).ToList(), condition, value, convertStrategy, collectionHandling, nullChecking); + return InternalCreateFilterExpression(recursionStep, type, parameter, memberExpression, parts.Skip(1).ToList(), condition, value, convertStrategy, collectionHandling, nullChecking, stringComparison); } } @@ -200,13 +228,14 @@ namespace PoweredSoft.DynamicLinq.Helpers QueryConvertStrategy convertStrategy, QueryCollectionHandling collectionHandling = QueryCollectionHandling.Any, ParameterExpression parameter = null, - bool nullChecking = false) + bool nullChecking = false, + StringComparison? stringComparision = null) { if (parameter == null) parameter = Expression.Parameter(typeof(T), "t"); var parts = path.Split('.').ToList(); - var result = InternalCreateFilterExpression(1, typeof(T), parameter, parameter, parts, condition, value, convertStrategy, collectionHandling, nullChecking); + var result = InternalCreateFilterExpression(1, typeof(T), parameter, parameter, parts, condition, value, convertStrategy, collectionHandling, nullChecking, stringComparision); var ret = result as Expression>; return ret; }