From c36f6491bd21db76fdd4f26f75ba52373ded70ae Mon Sep 17 00:00:00 2001 From: Dennis Oehme Date: Thu, 4 Jan 2024 15:30:05 +0100 Subject: [PATCH 1/7] chore: update to dotnet8, update packages (cherry picked from commit dfb0a3cc2183acb3cc6a5b76ab356391c3bf08e0) --- FluentSearchEngine.csproj | 14 +++++++------- .../FluentSearchEngine.Tests.csproj | 8 ++++---- .../SearchQueryBuilderTest.cs | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/FluentSearchEngine.csproj b/FluentSearchEngine.csproj index df9e269..c915fd7 100644 --- a/FluentSearchEngine.csproj +++ b/FluentSearchEngine.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 enable disable Ziad M.Fathy @@ -12,7 +12,7 @@ Search, Search Engine, Fluent, Filtering, Index Beta Version False - 2.0.0 + 2.2.0 @@ -24,12 +24,12 @@ - + - - - - + + + + diff --git a/Tests/FluentSearchEngine.Tests/FluentSearchEngine.Tests.csproj b/Tests/FluentSearchEngine.Tests/FluentSearchEngine.Tests.csproj index 6fa630b..29f3bcc 100644 --- a/Tests/FluentSearchEngine.Tests/FluentSearchEngine.Tests.csproj +++ b/Tests/FluentSearchEngine.Tests/FluentSearchEngine.Tests.csproj @@ -1,15 +1,15 @@ - net6.0 + net8.0 enable enable - - - + + + diff --git a/Tests/FluentSearchEngine.Tests/SearchQueryBuilderTest.cs b/Tests/FluentSearchEngine.Tests/SearchQueryBuilderTest.cs index 26707cf..10a058b 100644 --- a/Tests/FluentSearchEngine.Tests/SearchQueryBuilderTest.cs +++ b/Tests/FluentSearchEngine.Tests/SearchQueryBuilderTest.cs @@ -55,7 +55,7 @@ public void WithinRadius_WhenCalled_OnGeoModel_ShouldMatchQuery() //assert searchQuery.Should().NotBeNull(); - filter.Should().Be("_geoRadius(21.654640,21.241000,2000)"); + filter.Should().Be("_geoRadius(21.654640, 21.241000, 2000)"); } [Fact] From eeaf3516da38430629708f243a36c434b8e76e23 Mon Sep 17 00:00:00 2001 From: Dennis Oehme Date: Thu, 4 Jan 2024 16:45:34 +0100 Subject: [PATCH 2/7] feat(qb): add more filters (cherry picked from commit c493dc6b6d4485c6bdb280de3c98506ddbf8e1c6) --- Extensions/GenericExtensions.cs | 24 ++++++++++++++++++++++++ Extensions/StringExtensions.cs | 31 +++++++++++++++++++++++++++---- 2 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 Extensions/GenericExtensions.cs diff --git a/Extensions/GenericExtensions.cs b/Extensions/GenericExtensions.cs new file mode 100644 index 0000000..01aebf9 --- /dev/null +++ b/Extensions/GenericExtensions.cs @@ -0,0 +1,24 @@ +using FluentSearchEngine.GenericEvaluators.Interfaces; + +namespace FluentSearchEngine.Extensions; + +public static class GenericExtensions +{ + public static IValue IsNotNull(this IValue value) + { + value.Filter.Append(" IS NOT NULL"); + return value; + } + + public static IValue IsNull(this IValue value) + { + value.Filter.Append(" IS NULL"); + return value; + } + + public static IValue Exists(this IValue value) + { + value.Filter.Append(" EXISTS"); + return value; + } +} diff --git a/Extensions/StringExtensions.cs b/Extensions/StringExtensions.cs index 8f57875..f5ea210 100644 --- a/Extensions/StringExtensions.cs +++ b/Extensions/StringExtensions.cs @@ -18,15 +18,38 @@ public static string AddWhiteSpaceBeforeToLower(object value) return originalText; } - public static IValue Like(this IStringsEvaluator value, string text) + public static IValue ExactSame(this IStringsEvaluator value, string text) + { + value.Filter.Append(AddWhiteSpaceBeforeToLower($"= '{text}'")); + return (IValue)value; + } + + public static IValue NotExactSame(this IStringsEvaluator value, string text) { - value.Filter.Append(AddWhiteSpaceBeforeToLower($"LIKE '{text}'")); + value.Filter.Append(AddWhiteSpaceBeforeToLower($"!= '{text}'")); return (IValue)value; } - public static IValue ExactSame(this IStringsEvaluator value, string text) + public static IValue IsEmpty(this IStringsEvaluator value) { - value.Filter.Append(AddWhiteSpaceBeforeToLower($"= '{text}'")); + value.Filter.Append(AddWhiteSpaceBeforeToLower("IS EMPTY")); + return (IValue)value; + } + + public static IValue IsNotEmpty(this IStringsEvaluator value) + { + value.Filter.Append(AddWhiteSpaceBeforeToLower("IS NOT EMPTY")); + return (IValue)value; + } + public static IValue IsNull(this IStringsEvaluator value) + { + value.Filter.Append(AddWhiteSpaceBeforeToLower("IS NULL")); + return (IValue)value; + } + + public static IValue IsNotNull(this IStringsEvaluator value) + { + value.Filter.Append(AddWhiteSpaceBeforeToLower("IS NOT NULL")); return (IValue)value; } } From fc62f2818cf0653ebb66098d61f922b525af5f1b Mon Sep 17 00:00:00 2001 From: Dennis Oehme Date: Thu, 4 Jan 2024 17:42:05 +0100 Subject: [PATCH 3/7] feat: added support for generic filters --- Extensions/GenericExtensions.cs | 12 ++++----- .../Interfaces/IBooleanEvaluator`1.cs | 2 +- .../Interfaces/ICollectionEvaluator`1.cs | 2 +- .../Interfaces/IDateTimeEvaluator`1.cs | 2 +- .../Interfaces/IGenericEvaluator.cs | 6 +++++ .../Interfaces/INumbersEvaluator`1.cs | 2 +- .../Interfaces/IStringsEvaluator`1.cs | 2 +- .../Extensions/CommonExtensionsTest.cs | 26 +++++++++++++++++++ .../Extensions/GenericExtensionsTest.cs | 26 +++++++++++++++++++ 9 files changed, 69 insertions(+), 11 deletions(-) create mode 100644 GenericEvaluators/Interfaces/IGenericEvaluator.cs create mode 100644 Tests/FluentSearchEngine.Tests/Extensions/CommonExtensionsTest.cs create mode 100644 Tests/FluentSearchEngine.Tests/Extensions/GenericExtensionsTest.cs diff --git a/Extensions/GenericExtensions.cs b/Extensions/GenericExtensions.cs index 01aebf9..3c5086f 100644 --- a/Extensions/GenericExtensions.cs +++ b/Extensions/GenericExtensions.cs @@ -4,21 +4,21 @@ namespace FluentSearchEngine.Extensions; public static class GenericExtensions { - public static IValue IsNotNull(this IValue value) + public static IValue IsNotNull(this IGenericEvaluator value) { value.Filter.Append(" IS NOT NULL"); - return value; + return (IValue)value; } - public static IValue IsNull(this IValue value) + public static IValue IsNull(this IGenericEvaluator value) { value.Filter.Append(" IS NULL"); - return value; + return (IValue)value; } - public static IValue Exists(this IValue value) + public static IValue Exists(this IGenericEvaluator value) { value.Filter.Append(" EXISTS"); - return value; + return (IValue)value; } } diff --git a/GenericEvaluators/Interfaces/IBooleanEvaluator`1.cs b/GenericEvaluators/Interfaces/IBooleanEvaluator`1.cs index 5575812..b6238b1 100644 --- a/GenericEvaluators/Interfaces/IBooleanEvaluator`1.cs +++ b/GenericEvaluators/Interfaces/IBooleanEvaluator`1.cs @@ -1,6 +1,6 @@ namespace FluentSearchEngine.GenericEvaluators.Interfaces { - public interface IBooleanEvaluator : IFilter + public interface IBooleanEvaluator : IGenericEvaluator { } } diff --git a/GenericEvaluators/Interfaces/ICollectionEvaluator`1.cs b/GenericEvaluators/Interfaces/ICollectionEvaluator`1.cs index 844e856..6aa6f09 100644 --- a/GenericEvaluators/Interfaces/ICollectionEvaluator`1.cs +++ b/GenericEvaluators/Interfaces/ICollectionEvaluator`1.cs @@ -1,6 +1,6 @@ namespace FluentSearchEngine.GenericEvaluators.Interfaces { - public interface ICollectionEvaluator : IFilter + public interface ICollectionEvaluator : IGenericEvaluator { } } diff --git a/GenericEvaluators/Interfaces/IDateTimeEvaluator`1.cs b/GenericEvaluators/Interfaces/IDateTimeEvaluator`1.cs index f7b93a5..c8cd162 100644 --- a/GenericEvaluators/Interfaces/IDateTimeEvaluator`1.cs +++ b/GenericEvaluators/Interfaces/IDateTimeEvaluator`1.cs @@ -1,6 +1,6 @@ namespace FluentSearchEngine.GenericEvaluators.Interfaces { - public interface IDateTimeEvaluator : IFilter + public interface IDateTimeEvaluator : IGenericEvaluator { } } diff --git a/GenericEvaluators/Interfaces/IGenericEvaluator.cs b/GenericEvaluators/Interfaces/IGenericEvaluator.cs new file mode 100644 index 0000000..55fd944 --- /dev/null +++ b/GenericEvaluators/Interfaces/IGenericEvaluator.cs @@ -0,0 +1,6 @@ +namespace FluentSearchEngine.GenericEvaluators.Interfaces +{ + public interface IGenericEvaluator : IFilter + { + } +} diff --git a/GenericEvaluators/Interfaces/INumbersEvaluator`1.cs b/GenericEvaluators/Interfaces/INumbersEvaluator`1.cs index 2d7d8f8..ccb54e4 100644 --- a/GenericEvaluators/Interfaces/INumbersEvaluator`1.cs +++ b/GenericEvaluators/Interfaces/INumbersEvaluator`1.cs @@ -1,6 +1,6 @@ namespace FluentSearchEngine.GenericEvaluators.Interfaces { - public interface INumbersEvaluator : IFilter + public interface INumbersEvaluator : IGenericEvaluator { } } diff --git a/GenericEvaluators/Interfaces/IStringsEvaluator`1.cs b/GenericEvaluators/Interfaces/IStringsEvaluator`1.cs index 1f787fd..c6b3e55 100644 --- a/GenericEvaluators/Interfaces/IStringsEvaluator`1.cs +++ b/GenericEvaluators/Interfaces/IStringsEvaluator`1.cs @@ -1,6 +1,6 @@ namespace FluentSearchEngine.GenericEvaluators.Interfaces { - public interface IStringsEvaluator : IFilter + public interface IStringsEvaluator : IGenericEvaluator, IFilter { } } diff --git a/Tests/FluentSearchEngine.Tests/Extensions/CommonExtensionsTest.cs b/Tests/FluentSearchEngine.Tests/Extensions/CommonExtensionsTest.cs new file mode 100644 index 0000000..4f2932e --- /dev/null +++ b/Tests/FluentSearchEngine.Tests/Extensions/CommonExtensionsTest.cs @@ -0,0 +1,26 @@ +using FluentAssertions; +using FluentSearchEngine.Extensions; +using FluentSearchEngine.GenericEvaluators; +using Xunit; + +namespace FluentSearchEngine.Tests.Extensions; + +public class CommonExtensionsTest +{ + [Fact] + public void Exists() + { + //arrange + var evaluator = new SearchQueryBuilder() + .Value(x => x.Age).Exists() + .Value(x => x.Name).Exists(); + + //act + var searchQuery = evaluator.Evaluate(); + var filter = (string)searchQuery.Filter; + + //assert + searchQuery.Should().NotBeNull(); + filter.Should().Be("age EXISTS AND name EXISTS"); + } +} diff --git a/Tests/FluentSearchEngine.Tests/Extensions/GenericExtensionsTest.cs b/Tests/FluentSearchEngine.Tests/Extensions/GenericExtensionsTest.cs new file mode 100644 index 0000000..b01ed68 --- /dev/null +++ b/Tests/FluentSearchEngine.Tests/Extensions/GenericExtensionsTest.cs @@ -0,0 +1,26 @@ +using FluentAssertions; +using FluentSearchEngine.Extensions; +using FluentSearchEngine.GenericEvaluators; +using Xunit; + +namespace FluentSearchEngine.Tests.Extensions; + +public class GenericExtensionsTest +{ + [Fact] + public void Exists() + { + //arrange + var evaluator = new SearchQueryBuilder() + .Value(x => x.Age).Exists() + .Value(x => x.Name).Exists(); + + //act + var searchQuery = evaluator.Evaluate(); + var filter = (string)searchQuery.Filter; + + //assert + searchQuery.Should().NotBeNull(); + filter.Should().Be("age EXISTS AND name EXISTS"); + } +} From 377caefa1861b829567a9cf267b2c2a65f7ee170 Mon Sep 17 00:00:00 2001 From: Dennis Oehme Date: Thu, 4 Jan 2024 17:59:32 +0100 Subject: [PATCH 4/7] chore: remove unnecessary/duplicated interface --- GenericEvaluators/Interfaces/IStringsEvaluator`1.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GenericEvaluators/Interfaces/IStringsEvaluator`1.cs b/GenericEvaluators/Interfaces/IStringsEvaluator`1.cs index c6b3e55..5b0f6e6 100644 --- a/GenericEvaluators/Interfaces/IStringsEvaluator`1.cs +++ b/GenericEvaluators/Interfaces/IStringsEvaluator`1.cs @@ -1,6 +1,6 @@ namespace FluentSearchEngine.GenericEvaluators.Interfaces { - public interface IStringsEvaluator : IGenericEvaluator, IFilter + public interface IStringsEvaluator : IGenericEvaluator { } } From 60fbcd7f543c9c5c06c371c6f08c8ad396e46724 Mon Sep 17 00:00:00 2001 From: Dennis Oehme Date: Thu, 4 Jan 2024 18:00:56 +0100 Subject: [PATCH 5/7] ci: update CI to .net8 --- .github/workflows/dotnet.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 27d679a..c62b908 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -15,11 +15,11 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: - dotnet-version: 7.0.x + dotnet-version: 8.0.x - name: Restore dependencies run: dotnet restore - name: Build From d334261fe042f316bad324ab7b3a2a642cb48043 Mon Sep 17 00:00:00 2001 From: Dennis Oehme Date: Thu, 4 Jan 2024 19:11:41 +0100 Subject: [PATCH 6/7] chore: remove duplicated test, adjust file naming for consistency --- ...ricEvaluator.cs => IGenericEvaluator`1.cs} | 0 .../Extensions/CommonExtensionsTest.cs | 26 ------------------- 2 files changed, 26 deletions(-) rename GenericEvaluators/Interfaces/{IGenericEvaluator.cs => IGenericEvaluator`1.cs} (100%) delete mode 100644 Tests/FluentSearchEngine.Tests/Extensions/CommonExtensionsTest.cs diff --git a/GenericEvaluators/Interfaces/IGenericEvaluator.cs b/GenericEvaluators/Interfaces/IGenericEvaluator`1.cs similarity index 100% rename from GenericEvaluators/Interfaces/IGenericEvaluator.cs rename to GenericEvaluators/Interfaces/IGenericEvaluator`1.cs diff --git a/Tests/FluentSearchEngine.Tests/Extensions/CommonExtensionsTest.cs b/Tests/FluentSearchEngine.Tests/Extensions/CommonExtensionsTest.cs deleted file mode 100644 index 4f2932e..0000000 --- a/Tests/FluentSearchEngine.Tests/Extensions/CommonExtensionsTest.cs +++ /dev/null @@ -1,26 +0,0 @@ -using FluentAssertions; -using FluentSearchEngine.Extensions; -using FluentSearchEngine.GenericEvaluators; -using Xunit; - -namespace FluentSearchEngine.Tests.Extensions; - -public class CommonExtensionsTest -{ - [Fact] - public void Exists() - { - //arrange - var evaluator = new SearchQueryBuilder() - .Value(x => x.Age).Exists() - .Value(x => x.Name).Exists(); - - //act - var searchQuery = evaluator.Evaluate(); - var filter = (string)searchQuery.Filter; - - //assert - searchQuery.Should().NotBeNull(); - filter.Should().Be("age EXISTS AND name EXISTS"); - } -} From 7338ba11f3919742820cd78817b0a2eb92e5e7a0 Mon Sep 17 00:00:00 2001 From: Dennis Oehme Date: Thu, 4 Jan 2024 20:48:04 +0100 Subject: [PATCH 7/7] style: remove AddWhiteSpaceBeforeToLower --- Extensions/BooleanExtensions.cs | 4 ++-- Extensions/CollectionExpressions.cs | 2 +- Extensions/DateTimeExtensions.cs | 9 +++++---- Extensions/NumericExtensions.cs | 21 +++++++-------------- Extensions/StringExtensions.cs | 25 ++++--------------------- 5 files changed, 19 insertions(+), 42 deletions(-) diff --git a/Extensions/BooleanExtensions.cs b/Extensions/BooleanExtensions.cs index 59c810c..fca4e2f 100644 --- a/Extensions/BooleanExtensions.cs +++ b/Extensions/BooleanExtensions.cs @@ -6,13 +6,13 @@ public static class BooleanExtensions { public static IValue IsTrue(this IBooleanEvaluator value) { - value.Filter.Append(StringExtensions.AddWhiteSpaceBeforeToLower("= true")); + value.Filter.Append(" = true"); return (IValue)value; } public static IValue IsFalse(this IBooleanEvaluator value) { - value.Filter.Append(StringExtensions.AddWhiteSpaceBeforeToLower("= false")); + value.Filter.Append(" = false"); return (IValue)value; } } diff --git a/Extensions/CollectionExpressions.cs b/Extensions/CollectionExpressions.cs index 34f7b9f..8b4a899 100644 --- a/Extensions/CollectionExpressions.cs +++ b/Extensions/CollectionExpressions.cs @@ -6,7 +6,7 @@ public static class CollectionExpressions { public static IValue Contains(this ICollectionEvaluator value, TData itemToSearch) { - value.Filter.Append(StringExtensions.AddWhiteSpaceBeforeToLower($"= '{itemToSearch}'")); + value.Filter.Append($" = '{itemToSearch}'"); return (IValue)value; } } diff --git a/Extensions/DateTimeExtensions.cs b/Extensions/DateTimeExtensions.cs index 6723587..0117112 100644 --- a/Extensions/DateTimeExtensions.cs +++ b/Extensions/DateTimeExtensions.cs @@ -6,20 +6,21 @@ public static class DateTimeExtensions { public static IValue After(this IDateTimeEvaluator value, DateTime dateTime) { - value.Filter.Append(StringExtensions.AddWhiteSpaceBeforeToLower($"> {dateTime.ToUnixEpoch()}")); + value.Filter.Append($" > {dateTime.ToUnixEpoch()}"); return (IValue)value; } public static IValue AfterOrEqual(this IDateTimeEvaluator value, DateTime dateTime) { - value.Filter.Append(StringExtensions.AddWhiteSpaceBeforeToLower($">= {dateTime}")); + value.Filter.Append($" >= {dateTime}"); return (IValue)value; } public static double ToUnixEpoch(this DateTime date) { - DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); - TimeSpan diff = date.ToUniversalTime() - origin; + var origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); + var diff = date.ToUniversalTime() - origin; + return Math.Floor(diff.TotalSeconds); } } diff --git a/Extensions/NumericExtensions.cs b/Extensions/NumericExtensions.cs index 50aeb5e..e405c4b 100644 --- a/Extensions/NumericExtensions.cs +++ b/Extensions/NumericExtensions.cs @@ -7,50 +7,43 @@ public static class NumericExtensions { public static IValue IsEqual(this INumbersEvaluator value, decimal number) { - value.Filter.Append( - StringExtensions.AddWhiteSpaceBeforeToLower($"= {number.ToString(CultureInfo.InvariantCulture)}")); + value.Filter.Append($" = {number.ToString(CultureInfo.InvariantCulture)}"); return (IValue)value; } public static IValue IsNotEqual(this INumbersEvaluator value, int number) { - value.Filter.Append( - StringExtensions.AddWhiteSpaceBeforeToLower($"!= {number.ToString(CultureInfo.InvariantCulture)}")); + value.Filter.Append($" != {number.ToString(CultureInfo.InvariantCulture)}"); return (IValue)value; } public static IValue GreaterThan(this INumbersEvaluator value, int number) { - value.Filter.Append( - StringExtensions.AddWhiteSpaceBeforeToLower($"> {number.ToString(CultureInfo.InvariantCulture)}")); + value.Filter.Append($" > {number.ToString(CultureInfo.InvariantCulture)}"); return (IValue)value; } public static IValue GreaterThanOrEquals(this INumbersEvaluator value, int number) { - value.Filter.Append( - StringExtensions.AddWhiteSpaceBeforeToLower($">= {number.ToString(CultureInfo.InvariantCulture)}")); + value.Filter.Append($" >= {number.ToString(CultureInfo.InvariantCulture)}"); return (IValue)value; } public static IValue GreaterThanOrEquals(this INumbersEvaluator value, double number) { - value.Filter.Append( - StringExtensions.AddWhiteSpaceBeforeToLower($">= {number.ToString(CultureInfo.InvariantCulture)}")); + value.Filter.Append($" >= {number.ToString(CultureInfo.InvariantCulture)}"); return (IValue)value; } public static IValue LowerThanOrEquals(this INumbersEvaluator value, int number) { - value.Filter.Append( - StringExtensions.AddWhiteSpaceBeforeToLower($"<= {number.ToString(CultureInfo.InvariantCulture)}")); + value.Filter.Append($" <= {number.ToString(CultureInfo.InvariantCulture)}"); return (IValue)value; } public static IValue LowerThan(this INumbersEvaluator value, int number) { - value.Filter.Append( - StringExtensions.AddWhiteSpaceBeforeToLower($"< {number.ToString(CultureInfo.InvariantCulture)}")); + value.Filter.Append($" < {number.ToString(CultureInfo.InvariantCulture)}"); return (IValue)value; } } diff --git a/Extensions/StringExtensions.cs b/Extensions/StringExtensions.cs index f5ea210..4de1693 100644 --- a/Extensions/StringExtensions.cs +++ b/Extensions/StringExtensions.cs @@ -12,44 +12,27 @@ public static string FirstCharToLowerCase(this string str) return str; } - public static string AddWhiteSpaceBeforeToLower(object value) - { - var originalText = " " + value.ToString()!.FirstCharToLowerCase(); - return originalText; - } - public static IValue ExactSame(this IStringsEvaluator value, string text) { - value.Filter.Append(AddWhiteSpaceBeforeToLower($"= '{text}'")); + value.Filter.Append($" = '{text}'"); return (IValue)value; } public static IValue NotExactSame(this IStringsEvaluator value, string text) { - value.Filter.Append(AddWhiteSpaceBeforeToLower($"!= '{text}'")); + value.Filter.Append($" != '{text}'"); return (IValue)value; } public static IValue IsEmpty(this IStringsEvaluator value) { - value.Filter.Append(AddWhiteSpaceBeforeToLower("IS EMPTY")); + value.Filter.Append(" IS EMPTY"); return (IValue)value; } public static IValue IsNotEmpty(this IStringsEvaluator value) { - value.Filter.Append(AddWhiteSpaceBeforeToLower("IS NOT EMPTY")); - return (IValue)value; - } - public static IValue IsNull(this IStringsEvaluator value) - { - value.Filter.Append(AddWhiteSpaceBeforeToLower("IS NULL")); - return (IValue)value; - } - - public static IValue IsNotNull(this IStringsEvaluator value) - { - value.Filter.Append(AddWhiteSpaceBeforeToLower("IS NOT NULL")); + value.Filter.Append(" IS NOT EMPTY"); return (IValue)value; } }