From 42ca1cc2654a0a73c4d3dd387645d1803081b158 Mon Sep 17 00:00:00 2001 From: Paul DeVito Date: Thu, 1 Oct 2026 17:18:35 +0300 Subject: [PATCH] fix(operators)!: drop constant lists in case-insensitive in and not-in InOperator(true) and NotInOperator(true) read the list from the NewArrayExpression that the parser makes. v1.14.2 also read a list that a caller passed as a ConstantExpression. Remove this second path. The operators read the list only from the parsed array. BREAKING CHANGE: a caller that passes a ConstantExpression list to InOperator(true) or NotInOperator(true) gets NullReferenceException. Pass the values as a NewArrayExpression of constants, or use a filter string. --- .../FilterParsingRegressionTests.cs | 20 ------------------- QueryKit/Operators/ComparisonOperator.cs | 6 ++---- 2 files changed, 2 insertions(+), 24 deletions(-) diff --git a/QueryKit.UnitTests/FilterParsingRegressionTests.cs b/QueryKit.UnitTests/FilterParsingRegressionTests.cs index 8533635..1555790 100644 --- a/QueryKit.UnitTests/FilterParsingRegressionTests.cs +++ b/QueryKit.UnitTests/FilterParsingRegressionTests.cs @@ -248,26 +248,6 @@ public void comparison_operator_factory_has_one_test_case_per_operator_type() ComparisonOperatorFactories().Should().HaveCount(24); } - [Theory] - [InlineData(false, new[] { "lamb" })] - [InlineData(true, new[] { "null", "other" })] - public void case_insensitive_in_operator_factory_reads_a_constant_list(bool notIn, string[] expectedFirstNames) - { - var people = new[] - { - new TestingPerson { Title = null, FirstName = "null" }, - new TestingPerson { Title = "Lamb", FirstName = "lamb" }, - new TestingPerson { Title = "other", FirstName = "other" }, - }; - Expression> title = x => x.Title; - var comparisonOperator = notIn ? ComparisonOperator.NotInOperator(true) : ComparisonOperator.InOperator(true); - - var body = comparisonOperator.GetExpression(title.Body, Expression.Constant(new List { "LAMB" }), null); - var filterExpression = Expression.Lambda>(body, title.Parameters); - - people.AsQueryable().Where(filterExpression).Select(x => x.FirstName).Should().Equal(expectedFirstNames); - } - [Fact] public void comparison_operator_factory_with_uses_all_builds_any_expression() { diff --git a/QueryKit/Operators/ComparisonOperator.cs b/QueryKit/Operators/ComparisonOperator.cs index 18834f8..b97424f 100644 --- a/QueryKit/Operators/ComparisonOperator.cs +++ b/QueryKit/Operators/ComparisonOperator.cs @@ -588,8 +588,7 @@ public override Expression GetExpression(Expression left, Expression right, T var listType = typeof(List); var caseList = Activator.CreateInstance(listType); - // A caller can pass the list as a constant, like v1.14.2. - var originalList = (values ?? ((ConstantExpression)right).Value) as IEnumerable; + var originalList = values as IEnumerable; foreach (var value in originalList!) { listType.GetMethod("Add")!.Invoke(caseList, new[] { caseMode == CaseInsensitiveMode.Upper ? value.ToUpper() : value.ToLower() }); @@ -834,8 +833,7 @@ public override Expression GetExpression(Expression left, Expression right, T var listType = typeof(List); var caseList = Activator.CreateInstance(listType); - // A caller can pass the list as a constant, like v1.14.2. - var originalList = (values ?? ((ConstantExpression)right).Value) as IEnumerable; + var originalList = values as IEnumerable; foreach (var value in originalList!) { listType.GetMethod("Add")!.Invoke(caseList, new[] { caseMode == CaseInsensitiveMode.Upper ? value.ToUpper() : value.ToLower() });