Conversation
pdevito3
force-pushed
the
fm/qk-breaking-has-conversion-query-name
branch
from
October 1, 2026 14:34
46be5e9 to
88598b9
Compare
This was referenced Oct 1, 2026
pdevito3
force-pushed
the
fm/qk-breaking-has-conversion-query-name
branch
from
October 1, 2026 21:16
88598b9 to
f3fcc5e
Compare
The 1.x fix finds the conversion by the property path only where v1.14.2 threw. This change uses the property path for every HasConversion lookup, so it also changes results that v1.14.2 gave for accepted filters.
BREAKING CHANGE: a null literal on a converted reference type without a query name matches null rows, not rows equal to a value built from the text null. A child path such as Email.Value on a converted parent with a query name compares the parent. A converted int, int?, enum, or Guid with a query name and HasConversion<string>() goes through the string conversion: an int filter such as count == 2 throws, and a Guid filter builds new Guid("...") instead of a Guid constant.
pdevito3
force-pushed
the
fm/qk-breaking-has-conversion-query-name
branch
from
October 1, 2026 21:59
f3fcc5e to
6709a0d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
For later consideration in a major version. Do not merge now. #134 restored the v1.14.2 behavior to keep v1.x compatible (restore commit
76d3a7d). This PR re-applies the behavior ofb817eb3(#107). The captain decides on this PR separately.Split. The non-breaking part of this PR moved to #169. That PR fixes issue #106 and every other input that threw on v1.14.2. #169 merged to main as
3114c96. This PR is rebased on current main and has one commit (fix(filter)!: find HasConversion by the property path). This commit carries only the changes to results that v1.14.2 gave.Summary
ParseFilterreplaces a query name with the property path before the parser runs. On v1.14.2, theHasConversionlookups then search by query name, with the property path as the input. If the query name is different from the property name, the lookup finds nothing.#169 uses the property path only where v1.14.2 threw. This PR makes every lookup in
QueryKit/FilterParser.csuse the property path:CreateRightExprand the left-side member lookup useGetPropertyInfo(path)orreference.Mapping, notGetPropertyInfoByQueryName.GetPropertyInfo.nullliteral on a converted reference type or a converted nullable struct gives a null constant.Breaking changes (results that v1.14.2 gave)
A differential driver compares this branch with QueryKit 1.14.2 on 4840 filters (expression text, rows in memory, and EF Core Npgsql SQL). The results of this branch are identical to the results of this PR before the split.
Email == null(also!= nulland== "null") on a converted reference type without a query name. v1.14.2 buildsnew EmailAddress("null"), the SQL is= 'null', and the filter matches no row. This PR compares the property against null.Email.Value == "a@x.com"on a convertedEmailwith a query name. v1.14.2 compares the childx.Email.Value. This PR compares the parent, like the same filter without a query name. Note: without a query name, v1.14.2 already compares the parent.int,int?, or enum with a query name andHasConversion<string>(). v1.14.2 compares by type (for examplecount == 2givesx.Number == 2). This PR sends the value through the string conversion, andcount == 2throwsParsingException("The binary operator Equal is not defined for the types 'System.Int32' and 'System.String'").HasConversion<string>(). v1.14.2 gives a Guid constant. This PR givesnew Guid("..."). The rows are the same, but the expression text changes. Text that is not a Guid (for exampleqn == "ab7afb17") givesnew Guid("ab7afb17"), which still throws when the query runs.Decision needed before a merge: the
int,int?, and enum change makes filters that work on v1.14.2 throw. The original PR text did not list it, and it looks unintended. The unit testint_with_query_name_and_has_conversion_throwsrecords the current result of this PR.Migration
nullon a converted reference type without a query name, it now matches rows where the property is null. Before, it matched rows that equal a value built from the textnull.int,int?, or enum property has a query name andHasConversion<string>(), a filter on it now throws.README
The "HasConversion Support" section gets one new paragraph. It says that QueryKit finds the conversion by the query name or by the property name, that
nullcompares against null, and that a nullable struct property uses the conversion.Interaction with other PRs
J5 and J-bis (#154) remove the query-name rewrite from
ParseFilterand resolve query names in the grammar. This PR uses the resolved property path, so the lookups also work with J5 and J-bis.Tests
Changes on top of #169:
Unit (
QueryKit.UnitTests/HasConversionTests.cs):child_property_of_converted_parent_with_query_name_compares_the_childbecomeschild_property_of_converted_parent_with_query_name_compares_parent.null_on_reference_type_with_has_conversion_matches_no_rowbecomescan_filter_null_on_reference_type_with_has_conversion.int_with_query_name_and_has_conversion_compares_the_intbecomesint_with_query_name_and_has_conversion_throws.guid_with_query_name_and_has_conversion_compares_a_guid_constantbecomesguid_with_query_name_and_has_conversion_builds_a_guid_from_the_string.Postgres integration (
QueryKit.IntegrationTests/Tests/HasConversionTests.cs):email_value_with_query_name_and_has_conversion_compares_the_childbecomescan_filter_by_email_value_with_query_name_and_has_conversion.null_email_with_has_conversion_matches_no_rowbecomescan_filter_by_null_email_with_has_conversion.dotnet buildsucceeds.dotnet testpasses 470 unit tests and 297 Postgres integration tests (Testcontainers), with 0 failures.