diff --git a/QueryKit.IntegrationTests/Tests/PropertyResolverTests.cs b/QueryKit.IntegrationTests/Tests/PropertyResolverTests.cs index 432436b..04ceb36 100644 --- a/QueryKit.IntegrationTests/Tests/PropertyResolverTests.cs +++ b/QueryKit.IntegrationTests/Tests/PropertyResolverTests.cs @@ -151,6 +151,35 @@ public async Task property_is_not_prevented_by_another_property_whose_query_name people[0].Id.Should().Be(fakePerson.Id); } + [Fact] + public async Task prevented_property_clause_by_its_query_name_under_or_does_not_return_every_row() + { + // Arrange + var testingServiceScope = new TestingServiceScope(); + var title = new Faker().Lorem.Sentence(); + var fakePerson = new FakeTestingPersonBuilder() + .WithTitle(title) + .WithFirstName("Paul") + .WithAge(30) + .Build(); + await testingServiceScope.InsertAsync(fakePerson); + + var input = $"""Title == "{title}" && (first == "Paul" || Age > 100)"""; + var config = new QueryKitConfiguration(config => + { + config.IgnoredClauseBehavior = IgnoredClauseBehavior.Remove; + config.Property(x => x.FirstName!).HasQueryName("first").PreventFilter().PreventSort(); + }); + + // Act + var people = await testingServiceScope.DbContext().People + .ApplyQueryKitFilter(input, config) + .ToListAsync(); + + // Assert + people.Should().BeEmpty(); + } + [Theory] [InlineData("first-name")] [InlineData("_first")] diff --git a/QueryKit.UnitTests/PropertyResolverTests.cs b/QueryKit.UnitTests/PropertyResolverTests.cs index 040943f..a5796cf 100644 --- a/QueryKit.UnitTests/PropertyResolverTests.cs +++ b/QueryKit.UnitTests/PropertyResolverTests.cs @@ -628,7 +628,7 @@ public void query_name_in_a_value_is_replaced() } [Fact] - public void property_prevented_for_filter_and_sort_throws_by_its_query_name() + public void property_prevented_for_filter_and_sort_is_removed_by_its_query_name() { var input = """name == "x" || Age > 100"""; var config = new QueryKitConfiguration(config => @@ -637,26 +637,9 @@ public void property_prevented_for_filter_and_sort_throws_by_its_query_name() config.Property(x => x.Title!).HasQueryName("name").PreventFilter().PreventSort(); }); - var act = () => FilterParser.ParseFilter(input, config); - - act.Should().ThrowExactly() - .WithMessage("'Title' is not allowed for filtering or sorting."); - } - - [Fact] - public void property_prevented_for_filter_and_sort_throws_by_its_query_name_before_an_operator_alias() - { - var input = """name eq "x" """; - var config = new QueryKitConfiguration(config => - { - config.EqualsOperator = "eq"; - config.Property(x => x.Title!).HasQueryName("name").PreventFilter().PreventSort(); - }); - - var act = () => FilterParser.ParseFilter(input, config); + var filterExpression = FilterParser.ParseFilter(input, config); - act.Should().ThrowExactly() - .WithMessage("'Title' is not allowed for filtering or sorting."); + filterExpression.ToDisplayString().Should().Be("x => (x.Age > 100)"); } [Fact] diff --git a/QueryKit/QueryKitPropertyMappings.cs b/QueryKit/QueryKitPropertyMappings.cs index 9408114..f793e5b 100644 --- a/QueryKit/QueryKitPropertyMappings.cs +++ b/QueryKit/QueryKitPropertyMappings.cs @@ -139,11 +139,6 @@ public string ReplaceAliasesWithPropertyPaths(string input) // (e.g. the `^` in `^^` would otherwise be read as a start-of-line anchor). var regex = AliasRegexCache.Get($@"\b{Regex.Escape(queryKitPropertyInfo.QueryName!)}\b(?=\s*{Regex.Escape(op)})"); - if (queryKitPropertyInfo is { CanSort: false, CanFilter: false} && regex.IsMatch(input)) - { - throw new InvalidOperationException($"'{queryKitPropertyInfo.Name}' is not allowed for filtering or sorting."); - } - input = regex.Replace(input, propertyPath); } }