Skip to content

fix(config): match aliases with the case rules of the current culture again - #158

Merged
pdevito3 merged 1 commit into
mainfrom
fm/qk-restore-d1-d5-d3
Oct 1, 2026
Merged

pdevito3 merged 1 commit into
mainfrom
fm/qk-restore-d1-d5-d3

Conversation

@pdevito3

@pdevito3 pdevito3 commented Oct 1, 2026 •

Copy link
Copy Markdown
Owner

Summary

This PR restores D3 from the v1.14.2 review report. It is not a breaking change.

AliasRegexCache keeps one Regex for each alias pattern. The regexes use RegexOptions.IgnoreCase, and that option uses the culture that is current when the Regex is built. On main, the first parse fixes the case rules of an alias for all later parses, in every culture. In tr-TR, I does not match i, so the order of the parses changes the result.

v1.14.2 built a new Regex for each parse, with the case rules of the current culture. This PR keys the cache by the pattern and CultureInfo.CurrentCulture.Name. It does not use RegexOptions.CultureInvariant, because that option changes the tr-TR result against v1.14.2.

Results against v1.14.2

Config A: Price has the query name tip, and Title has the query name isim.
Config B: EqualsOperator is eşit, and AndOperator is VE.

Config Parse order Input v1.14.2 main This PR
A tr-TR, then en-US TIP > 3 in en-US x.Price > 3 UnknownFilterPropertyException same as v1.14.2
A tr-TR, then en-US ISIM == "Pancakes" in en-US x.Title == "Pancakes" UnknownFilterPropertyException same as v1.14.2
B en-US, then tr-TR Title EŞIT "Pancakes" in tr-TR ParsingException x.Title == "Pancakes" same as v1.14.2

A differential probe ran 19 cases in two parse orders (tr-TR first and en-US first) against v1.14.2 and this branch. It compared the expression, the in-memory rows, and the Postgres SQL. No difference in result or exception type remains.

The message text of the tr-TR EŞIT case is different from v1.14.2. Both versions throw ParsingException, but main has a different message and a different inner Sprache message. The message text was different before this PR and is not part of D3.

Tests

  • Unit pins in the new file QueryKit.UnitTests/AliasCultureTests.cs: a query name in en-US after tr-TR, a query name in tr-TR after en-US, and an operator alias in tr-TR after en-US. All 3 fail on main.
  • A Postgres pin in the new file QueryKit.IntegrationTests/Tests/AliasCultureTests.cs: a query name filters the rows in en-US after a tr-TR parse. It fails on main.
  • Each test uses its own alias, so the static cache does not make the result depend on the order of the tests.
  • dotnet test: unit 405 passed, integration 284 passed.

Overlap with other PRs

… again

The alias regex cache kept one Regex for each pattern. RegexOptions.IgnoreCase uses the culture that is current when the Regex is built, so the first parse fixed the case rules for all later cultures. A query name like TIP did not match in en-US after a tr-TR parse, and an operator alias matched in tr-TR after an en-US parse.

The cache key now includes CultureInfo.CurrentCulture.Name. Each culture gets the same result as v1.14.2, which built a new Regex for each parse.
@pdevito3
pdevito3 merged commit 1a6b72b into main Oct 1, 2026
2 checks passed
@pdevito3
pdevito3 deleted the fm/qk-restore-d1-d5-d3 branch October 1, 2026 20:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant