From fd07c2855755e0c98abccc291dcf1fd196bb9dff Mon Sep 17 00:00:00 2001 From: mohit Date: Thu, 29 Aug 2024 16:07:45 -0400 Subject: [PATCH 1/2] relative date time feature. --- src/Gridify/Builder/BaseQueryBuilder.cs | 33 ++++++++++++++----- src/Gridify/Gridify.csproj | 1 + test/Gridify.Tests/GridifyExtensionsShould.cs | 23 +++++++++++++ 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/src/Gridify/Builder/BaseQueryBuilder.cs b/src/Gridify/Builder/BaseQueryBuilder.cs index 9875e0fb..e51a9b05 100644 --- a/src/Gridify/Builder/BaseQueryBuilder.cs +++ b/src/Gridify/Builder/BaseQueryBuilder.cs @@ -177,7 +177,20 @@ private static object AddIndexerNullCheck(LambdaExpression mapTarget, object que // type fixer // Check if body.Type is a nullable type and get its underlying type issue #134 var underlyingBodyType = Nullable.GetUnderlyingType(body.Type); - if (value is string strValue && (underlyingBodyType ?? body.Type) != strValue.GetType()) + + if (body.Type == typeof(DateTime) || underlyingBodyType == typeof(DateTime)) + { + var dateTime = ParseRelativeDate(valueExpression.ValueToken.Text); + if (dateTime.HasValue) + { + value = dateTime.Value; + if (mapper.Configuration.DefaultDateTimeKind.HasValue) + { + value = DateTime.SpecifyKind((DateTime)value, mapper.Configuration.DefaultDateTimeKind.Value); + } + } + } + else if (value is string strValue && (underlyingBodyType ?? body.Type) != strValue.GetType()) { // handle bool, github issue #71 if (body.Type == typeof(bool) && strValue is "true" or "false" or "1" or "0") @@ -199,14 +212,6 @@ private static object AddIndexerNullCheck(LambdaExpression mapTarget, object que { return BuildAlwaysFalseQuery(parameter); } - - if (value is DateTime dateTime) - { - if (mapper.Configuration.DefaultDateTimeKind.HasValue) - { - value = DateTime.SpecifyKind(dateTime, mapper.Configuration.DefaultDateTimeKind.Value); - } - } } // handle case-Insensitive search @@ -240,4 +245,14 @@ private static LambdaExpression UpdateIndexerKey(LambdaExpression exp, string ke var body = new ReplaceExpressionVisitor(exp.Parameters[1], newValue).Visit(exp.Body); return Expression.Lambda(body, exp.Parameters); } + + private static DateTime? ParseRelativeDate(string input) + { + var parser = new Chronic.Core.Parser(); + var result = parser.Parse(input); + if (result != null) return result.Start; + + DateTime.TryParse(input, out var dateTime); + return dateTime; + } } diff --git a/src/Gridify/Gridify.csproj b/src/Gridify/Gridify.csproj index 35fd4f8e..cc03894d 100644 --- a/src/Gridify/Gridify.csproj +++ b/src/Gridify/Gridify.csproj @@ -49,6 +49,7 @@ + diff --git a/test/Gridify.Tests/GridifyExtensionsShould.cs b/test/Gridify.Tests/GridifyExtensionsShould.cs index 2e049955..89373f8b 100644 --- a/test/Gridify.Tests/GridifyExtensionsShould.cs +++ b/test/Gridify.Tests/GridifyExtensionsShould.cs @@ -676,6 +676,29 @@ public void ApplyFiltering_UnmappedFields_ShouldSkipWhenIgnored() Assert.True(actual.Any()); } + [Fact] + public void ApplyFiltering_DateTime() + { + var actual = _fakeRepository.AsQueryable() + .ApplyFiltering($"MyDateTime>{DateTime.UtcNow.ToShortDateString()}") + .ToList(); + var expected = _fakeRepository.Where(q => q.MyDateTime > DateTime.UtcNow.Date).ToList(); + + Assert.Equal(expected.Count, actual.Count); + } + + [Fact] + public void ApplyFiltering_DateTime_Relative() + { + var actual = _fakeRepository.AsQueryable() + .ApplyFiltering("MyDateTime>today") + .ToList(); + var expected = _fakeRepository.Where(q => q.MyDateTime > DateTime.UtcNow.Date).ToList(); + + Assert.Equal(expected.Count, actual.Count); + } + + #endregion From 6422cd10d6cca5cbb845ea63cb00a5f0bee3378f Mon Sep 17 00:00:00 2001 From: mohit Date: Thu, 29 Aug 2024 16:21:33 -0400 Subject: [PATCH 2/2] build and test fix --- src/Gridify/Builder/BaseQueryBuilder.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Gridify/Builder/BaseQueryBuilder.cs b/src/Gridify/Builder/BaseQueryBuilder.cs index e51a9b05..9bdd0bf6 100644 --- a/src/Gridify/Builder/BaseQueryBuilder.cs +++ b/src/Gridify/Builder/BaseQueryBuilder.cs @@ -166,19 +166,16 @@ private static object AddIndexerNullCheck(LambdaExpression mapTarget, object que object? value = valueExpression.ValueToken.Text; + var underlyingBodyType = Nullable.GetUnderlyingType(body.Type); // execute user custom Convertor if (convertor != null) value = convertor.Invoke(valueExpression.ValueToken.Text); // handle the `null` keyword in value - if (mapper.Configuration.AllowNullSearch && op.Kind is SyntaxKind.Equal or SyntaxKind.NotEqual && value.ToString() == "null") + else if (mapper.Configuration.AllowNullSearch && op.Kind is SyntaxKind.Equal or SyntaxKind.NotEqual && value.ToString() == "null") value = null; - - // type fixer - // Check if body.Type is a nullable type and get its underlying type issue #134 - var underlyingBodyType = Nullable.GetUnderlyingType(body.Type); - if (body.Type == typeof(DateTime) || underlyingBodyType == typeof(DateTime)) + else if (body.Type == typeof(DateTime) || underlyingBodyType == typeof(DateTime)) { var dateTime = ParseRelativeDate(valueExpression.ValueToken.Text); if (dateTime.HasValue)