Skip to content

Track the Storm 1.14.0 release - #1

Open
zantvoort wants to merge 3 commits into
mainfrom
track-storm-1.14.0
Open

Track the Storm 1.14.0 release#1
zantvoort wants to merge 3 commits into
mainfrom
track-storm-1.14.0

Conversation

@zantvoort

@zantvoort zantvoort commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Migrates the demo to Storm 1.14.0 and adopts the query API as 1.14 defines it.

Important

Do not merge until 1.14.0 is on Maven Central and the Gradle Plugin Portal. This branch resolves Storm from mavenLocal(), through a repositories entry and a pluginManagement block in settings.gradle.kts, both marked TEMPORARY. Merging before the release would leave the template unbuildable for anyone who clones it. Drop those two blocks as part of the merge.

Query API

A join widens the query, so from the join onward every clause accepts paths from any entity in the query and the Any variants are gone. Most call sites are a plain rename:

.orderByDescendingAny(Rating_.voteCount)   ->   .orderByDescending(Rating_.voteCount)

Grouping states an identity

A grouping says what one row stands for, and the generator emits the columns that express it — the key on PostgreSQL, every selected column on SQL Server and Oracle. So the queries name the entity and stop enumerating its columns:

.groupBy(Principal_.movie)          // one row per movie
.groupBy(Principal_.person)         // one row per person
.groupBy(Genre_.id)                 // one row per genre
.groupBy(MovieGenre_.genre)         // likewise, reached through the junction

The column lists these replace existed to satisfy the strictest dialect, and had to be revisited whenever an entity gained a field. MovieRepository keeps its template grouping: one row per decade is a computed value, not an identity, so it stays literal.

Paths from the query root

findGenres orders by MovieGenre_.genre.name, reaching the genre through the junction table's foreign key. A nested path starts at the root, so it needs no widening and keeps the compile-time root check that widening gives up.

scrollByGenre joins the junction table and then narrows back to the projection: a scroll key has to identify one row of the root, and a unique key on the junction table does not.

One widen() remains, in findTopMovies. It is structural rather than a leftover: the conditional innerJoin widens the root, so the single reassignable builder variable has to be declared QueryBuilder<Data, Rating, Movie>, and the unjoined initial value only fits that declaration after widening. Removing it fails compilation.

Tests

SqlCapture.run is record. @StormTest now runs each test in a transaction that is rolled back afterwards, so the tests no longer need to pick rows that other methods leave alone, and the comments saying they did are gone.

Full ./gradlew build green, tests included.

A join now widens the query, so a clause that names a joined entity uses
the plain call and the Any variants are gone. Where a query joins nothing
but references another entity of its graph, widen() says so; scrollByGenre
narrows back to the projection, because a scroll key has to identify one
row of the root and a key on the junction table does not.

SqlCapture.run is record, named so a Kotlin caller cannot resolve it to
kotlin.run.

@stormtest rolls each test back, so the tests no longer pick rows other
methods leave alone.

Resolves Storm from mavenLocal until 1.14.0 is on Maven Central and the
Gradle Plugin Portal.
findGenres reaches the genre name through the junction table's foreign key
rather than naming the genre table in short form, so the clause stays typed
to the root and the query needs no widening. The SQL is unchanged.

The remaining widen() calls stay: the two GROUP BY sites would resolve a
foreign key path's id component to the junction column while the SELECT
still projects the referenced table's key, which strict grouping rejects,
and findTopMovies joins conditionally, so its builder is widened either way.
A grouping states what one row stands for, and 1.14 emits the columns that
express it, so these queries name the entity and stop enumerating its
columns. The lists were there to satisfy the strictest dialect and had to
be revisited whenever an entity gained a field; the dialect decides now.

findMoviesSharingCast and findMostProlificActors reach the entity through
the credit's own foreign keys, so they no longer widen either: the path
starts at the query root and keeps the compile-time root check.

The SQL is equivalent, and narrower where a key already determined the
columns that were being listed.
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