diff --git a/QueryKit.IntegrationTests/Tests/PropertyResolverTests.cs b/QueryKit.IntegrationTests/Tests/PropertyResolverTests.cs index 3c7f298..b503aaf 100644 --- a/QueryKit.IntegrationTests/Tests/PropertyResolverTests.cs +++ b/QueryKit.IntegrationTests/Tests/PropertyResolverTests.cs @@ -93,6 +93,64 @@ public async Task prevented_property_clause_under_or_does_not_return_every_row() people.Should().BeEmpty(); } + [Fact] + public async Task prevented_property_is_found_by_its_path_when_another_query_name_matches_that_path() + { + // Arrange + var testingServiceScope = new TestingServiceScope(); + var firstName = new Faker().Lorem.Sentence(); + var fakePerson = new FakeTestingPersonBuilder() + .WithFirstName(firstName) + .Build(); + var otherPerson = new FakeTestingPersonBuilder().Build(); + await testingServiceScope.InsertAsync(fakePerson, otherPerson); + + var input = $"""nick == "{firstName}" """; + var config = new QueryKitConfiguration(config => + { + config.Property(x => x.Title!).HasQueryName("firstname"); + config.Property(x => x.FirstName!).HasQueryName("nick").PreventFilter(); + }); + + // Act + var queryable = testingServiceScope.DbContext().People.ApplyQueryKitFilter(input, config); + var people = await queryable.ToListAsync(); + + // Assert + queryable.ToQueryString().Should().NotContain("WHERE"); + people.Should().Contain(x => x.Id == fakePerson.Id); + people.Should().Contain(x => x.Id == otherPerson.Id); + } + + [Fact] + public async Task property_is_not_prevented_by_another_property_whose_query_name_matches_its_path() + { + // Arrange + var testingServiceScope = new TestingServiceScope(); + var firstName = new Faker().Lorem.Sentence(); + var fakePerson = new FakeTestingPersonBuilder() + .WithFirstName(firstName) + .Build(); + var otherPerson = new FakeTestingPersonBuilder().Build(); + await testingServiceScope.InsertAsync(fakePerson, otherPerson); + + var input = $"""nick == "{firstName}" """; + var config = new QueryKitConfiguration(config => + { + config.Property(x => x.Title!).HasQueryName("firstname").PreventFilter(); + config.Property(x => x.FirstName!).HasQueryName("nick"); + }); + + // Act + var people = await testingServiceScope.DbContext().People + .ApplyQueryKitFilter(input, config) + .ToListAsync(); + + // Assert + people.Should().ContainSingle(); + people[0].Id.Should().Be(fakePerson.Id); + } + [Theory] [InlineData("first-name")] [InlineData("_first")] diff --git a/QueryKit.UnitTests/PropertyResolverTests.cs b/QueryKit.UnitTests/PropertyResolverTests.cs index 9ffb715..d3d58fe 100644 --- a/QueryKit.UnitTests/PropertyResolverTests.cs +++ b/QueryKit.UnitTests/PropertyResolverTests.cs @@ -37,6 +37,36 @@ public void prevented_property_clause_is_true_equals_true_by_default() filterExpression.ToDisplayString().Should().Be("""x => ((x.FirstName == "Ann") OrElse (True == True))"""); } + [Fact] + public void prevented_property_is_found_by_its_path_when_another_query_name_matches_that_path() + { + var input = """nick == "Ann" """; + var config = new QueryKitConfiguration(config => + { + config.Property(x => x.Title!).HasQueryName("firstname"); + config.Property(x => x.FirstName!).HasQueryName("nick").PreventFilter(); + }); + + var filterExpression = FilterParser.ParseFilter(input, config); + + filterExpression.ToDisplayString().Should().Be("x => (True == True)"); + } + + [Fact] + public void property_is_not_prevented_by_another_property_whose_query_name_matches_its_path() + { + var input = """nick == "Ann" || Age > 100"""; + var config = new QueryKitConfiguration(config => + { + config.Property(x => x.Title!).HasQueryName("firstname").PreventFilter(); + config.Property(x => x.FirstName!).HasQueryName("nick"); + }); + + var filterExpression = FilterParser.ParseFilter(input, config); + + filterExpression.ToDisplayString().Should().Be("""x => ((x.FirstName == "Ann") OrElse (x.Age > 100))"""); + } + [Fact] public void property_list_with_only_prevented_properties_is_true_by_default() { diff --git a/QueryKit/FilterParser.cs b/QueryKit/FilterParser.cs index b77608b..adb1497 100644 --- a/QueryKit/FilterParser.cs +++ b/QueryKit/FilterParser.cs @@ -729,10 +729,10 @@ private static bool IsValidPropertyName(string value) value.All(c => char.IsLetterOrDigit(c) || c == '_' || c == '.'); } - // The filter settings of a left-side property: by the name that its query name maps to, in the exact case. + // The filter settings of a left-side property: by its property path after alias replacement, in the exact case, like v1.14.2. // Derived properties and custom operations are not in this lookup. private static QueryKitPropertyInfo? GetFilterPropertyInfo(string text, IQueryKitConfiguration? config) - => config?.PropertyMappings?.GetPropertyInfo(config.PropertyMappings.GetPropertyPathByQueryName(text) ?? text); + => config?.PropertyMappings?.GetPropertyInfo(text); private static CaseInsensitiveMode ResolveCaseMode(string? propertyPath, IQueryKitConfiguration? config) {