Repository navigation
Changed answers: typed filters over Trim/Substring are re-created too, but the guide and changelog name only expression indexes #170
Description
Found by a pre-release sweep of main @ eff80b4 (lens: round-trip); reproduced by diffing a real v5.4.1 snapshot, and by a scratch test for the rendering. Holds the tag: the changelog section becomes each package's nuspec release notes, and those can't be changed after the push.
Problem
#72 changed how Trim, TrimStart, TrimEnd and Substring render in the typed translator. The translator serves typed expression indexes and also typed filters (NpgsqlTypedFilterExtensions, for indexes and exclusion constraints). The guide entry (Substring and Trim render as EF Core's queries, docs/upgrading.md:176-192) and the ### Changed answers row in CHANGELOG.md:30 mention typed expression indexes only.
Typed filters are translated at the declaration and stored as the filter string, so a 5.4.1 snapshot holds the old text, and the first migrations add re-creates the index under a changed filter. For Trim, that changes which rows the partial index covers. btrim("Code") <> '' included a row whose Code is only tabs or line breaks. btrim("Code", E' \t\n\r') <> '' leaves it out. A unique filtered index then stops checking those rows, and an exclusion constraint's typed filter is affected in the same way.
Model
b.HasComplexIndex(x => x.Title, x => x.Code.Trim() != "", indexName: "ix_title_trim");- v5.4.1 snapshot:
filter=btrim("Code") <> ''. v5.4.1's translator rendersbtrim({target}); seeNpgsqlLinqIndexTranslator.cs:166at that tag. - eff80b4:
filter=btrim("Code", E' \t\n\r') <> '', from a scratch test usingCreateIndexOperation.Filter. - The upgrade diff from the real 5.4.1 snapshot gives
DropIndex ix_title_trimand thenCreateIndex ix_title_trim … filter=btrim("Code", E' \t\n\r') <> ''. No guide section covers that pair. The gate on 934ec55 had the same operation in its output, so "matched the docs exactly" missed it.
The code change is intended and correct, since it matches EF's query. What's missing is the announcement of a changed answer.
Change
In the guide entry and the changelog row (root and PostgreSQL package), say "typed expression indexes and typed filters (on indexes and exclusion constraints)". Add what the change does to the rows a filtered unique index or exclusion constraint checks: rows that are only whitespace now fall outside a Trim() != "" filter.
Test
An upgrade test that diffs a 5.4.1 snapshot and asserts each operation maps to a guide section. At minimum, a test that pins the typed-filter rendering of Trim() next to the typed expression-index one.
Activity
CaffeinatedCoder commentedon Oct 20, 2026
Measured on a real v5.4.1 snapshot (typed filters over each method on
HasComplexIndex,HasComplexCompositeIndex,HasExpressionIndexandHasExclusionConstraint): the firstmigrations adddrops and re-creates every one of them, 8 indexes and 2 exclusion constraints, 21 operations includingCREATE EXTENSION IF NOT EXISTS btree_gist. AToLowerfilter is untouched and the second diff is empty.Substringfilters cover the same rows (substr=substringon PostgreSQL 18); trimmed filters can gain rows (= 'abc'now coversE'abc\t') or lose them (<> ''drops tabs-only values). Fixed in #173.Merge pull request #173 from CaffeinatedCoder/docs/170-171-upgrade-notes