Skip to content

test: consolidate nullability goldens into one bounded scenario - #244

Merged
Marius Volkhart (MariusVolkhart) merged 1 commit into
mainfrom
chore/consolidate-nullability-scenario
Aug 22, 2026
Merged

test: consolidate nullability goldens into one bounded scenario#244
Marius Volkhart (MariusVolkhart) merged 1 commit into
mainfrom
chore/consolidate-nullability-scenario

Conversation

@MariusVolkhart

Copy link
Copy Markdown
Member

where_clause_narrowing was one 8-line schema and one query, added to pin #186. Every scenario directory costs a PostgreSQL Testcontainer plus a TestKit build, while queries inside a scenario are nearly free, so a directory per regression is the wrong unit — the follow-on grouping-sets fix skipped scenario coverage entirely rather than pay for another one.

Nullability inference is where Norm's defects cluster (#186, #228, #236, #239-241), and it's a generator feature rather than a SQL construct, so it gets a bucket for the same reason crud_generation and type_mappings have one. Naming it for a construct instead — joins_and_grouping — would name the delivery vehicle: the SQL in these queries is deliberately trivial, and the entire content of each golden is the inferred nullability marker.

Membership rule

A bucket named for a cross-cutting property has no boundary unless one is written down. test-scenarios/nullability/README.md states it:

A query belongs here iff its golden output's nullability differs from what raw JDBC column metadata reports for that column — i.e. it pins one nullability inference rule end-to-end.

A construct-specific bug whose symptom happens to be wrong nullability goes to that construct's scenario instead — a CTE bug to ctes, which already carries nullability-through-RETURNING goldens. So #239-241 land here; a CTE resolution bug does not.

The rule lives in README.md rather than a queries.sql comment because QueryFileParser folds every comment block into the KDoc of whichever query follows it, and blank lines don't reset the accumulator. Only trailing placement avoided leaking into generated KDoc, and the end of a SQL file isn't where the next contributor looks for scope.

Coverage

The #186 table and findClaimingRuns query carry over byte-for-byte. Six queries join them, one per inference rule that previously had only generator unit tests:

Query Rule pinned
departmentHeadcountByRollup ROLLUP null-extends a NOT NULL grouping key
departmentNameLowerByRollup expression grouping key under ROLLUP (#236)
employeesByDepartment LEFT JOIN nullability
employeesByDepartmentFiltered outer-join veto deliberately beats a proving WHERE
widgetByLowerCode strict-function narrowing through lower()
clearAccountNote narrowing stays suppressed when SET overwrites the proven column

Scenario count unchanged at 13. Goldens generated by generateGoldenFiles, never hand-edited; every result property's nullability was checked against the rule it claims to pin. :gradle-plugin:check passes.

Two issues found, not fixed here

  • :gradle-plugin:test declares no input on ../test-scenarios, so a scenario-only diff can report UP-TO-DATE with zero tests executed. Every verification run for this PR needed --rerun-tasks.
  • SqlStatement.isSingleTableStarProjection reuses a table's cached entity type when a query selects every one of its columns, discarding analyzed narrowing — so such queries bypass WHERE-clause narrowing in codegen even though the analyzer gets it right. Pre-existing, unrelated to this change.

🤖 Generated with Claude Code

The where_clause_narrowing scenario was one 8-line schema and one query,
added to pin #186. Every scenario directory costs a PostgreSQL Testcontainer
and a TestKit build, while queries inside a scenario are nearly free, so a
directory per regression is the wrong unit: the follow-on grouping-sets fix
skipped scenario coverage entirely rather than pay for another one.

Nullability inference is where Norm's defects cluster (#186, #228, #236,
#239-241), and it is a generator feature rather than a SQL construct, so it
gets a bucket for the same reason crud_generation and type_mappings have one.
Renaming to a construct — joins_and_grouping — would name the delivery
vehicle: the SQL in these queries is deliberately trivial, and the entire
content of each golden is the inferred nullability marker.

A bucket named for a cross-cutting property has no membership rule unless one
is written down, which is what made the first attempt open-ended. README.md
states it: a query belongs here iff its golden's nullability differs from what
raw JDBC column metadata reports, so it pins one inference rule end-to-end.
A construct-specific bug whose symptom is wrong nullability goes to that
construct's scenario instead — a CTE bug to ctes, which already carries
nullability-through-RETURNING goldens.

The rule lives in README.md rather than a queries.sql comment because
QueryFileParser accumulates every comment block into the KDoc of whichever
query follows it, and blank lines do not reset the accumulator. Only trailing
placement avoided the leak, and a scope rule at the end of the file is not
somewhere the next contributor would look.

The #186 table and findClaimingRuns query are carried over byte-for-byte.
Six queries join them, one per inference rule that previously had only
generator unit tests: ROLLUP null-extending a NOT NULL grouping key, an
expression grouping key under ROLLUP (#236), LEFT JOIN nullability, LEFT JOIN
with a proving WHERE where the outer-join veto deliberately wins, strict
function narrowing through lower(), and UPDATE ... SET ... RETURNING where
narrowing stays suppressed because SET overwrites the proven column.

Scenario count is unchanged at 13.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@snyk-io

snyk-io Bot commented Aug 22, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@MariusVolkhart
Marius Volkhart (MariusVolkhart) merged commit 87b9800 into main Aug 22, 2026
13 checks passed
@MariusVolkhart
Marius Volkhart (MariusVolkhart) deleted the chore/consolidate-nullability-scenario branch August 22, 2026 15:50
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