docs: teach the WHERE form ladder in the skills and fix the Java joined-entity predicates - #363
Conversation
…ed-entity predicates
The query skills now state a strict preference order for building WHERE
clauses: where() first, whereAny() only for fields of joined (non-root)
entities, and the builder form last, reserved for conditions a plain
predicate cannot express. The Kotlin skill previously presented
whereBuilder { } as the way to group AND/OR conditions, which infix
and/or inside where() already covers.
Verifying the guidance against the API surfaced that the Java
QueryBuilder has no chained whereAny(path, operator, value) overload;
joined-entity predicates go through the where-lambda as
where(it -> it.whereAny(...)). The Java query skill and the Java tabs
of first-query, queries, and relationships used the non-compiling
chained form; all are corrected to the lambda form.
There was a problem hiding this comment.
🟡 Not ready to approve
Multiple updated skill examples use users.select() after previously defining users as a List<User>, so the snippets won’t compile as written.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Pull request overview
This PR updates the Storm query documentation/skills to teach a strict “WHERE form ladder” (use the weakest form that compiles) and fixes several Java joined-entity predicate examples that previously used a non-existent chained whereAny(path, ...) overload.
Changes:
- Reworked Kotlin and Java query skills to emphasize
where()→whereAny()→ builder/lambda escalation rules (and similar guidance fororderBy/groupBy). - Corrected Java join filtering examples to use the
where(it -> it.whereAny(...))lambda form for joined-entity paths. - Added the condensed rule to
storm-rules.mdso it’s available via the rules skill.
File summaries
| File | Description |
|---|---|
| website/static/skills/storm-rules.md | Adds a concise “WHERE ladder” rule to the rules skill. |
| website/static/skills/storm-query-kotlin.md | Reframes WHERE guidance around an escalation ladder; updates examples and notes. |
| website/static/skills/storm-query-java.md | Adds escalation preferences and fixes joined-entity predicate guidance/examples. |
| docs/relationships.md | Fixes Java join filtering example to use the where-lambda + whereAny. |
| docs/queries.md | Fixes Java join filtering example and adds a short explanation of the typing constraint. |
| docs/first-query.md | Fixes Java join filtering example to use the where-lambda + whereAny. |
Review details
Suppressed comments (3)
website/static/skills/storm-query-kotlin.md:469
- This code block also uses
users.select()without definingusersin the snippet (and earlierusersis a List result), so the example won’t compile as written. Start fromorm.entity<User>()to keep the snippet standalone.
users.select()
.whereBuilder {
website/static/skills/storm-query-java.md:397
- Same issue as above:
usersis aList<User>in the earlier example, sousers.select()in this snippet won’t compile. Start the chain fromorm.entity(User.class)to keep the snippet standalone.
users.select()
.innerJoin(UserRole.class).on(User.class)
website/static/skills/storm-query-java.md:415
- This snippet also uses
users.select()butusersis aList<User>in the preceding example, so this won’t compile as written. Start fromorm.entity(User.class)to avoid reusing theuserslist variable name.
users.select()
.innerJoin(UserRole.class).on(User.class)
- Files reviewed: 6/6 changed files
- Comments generated: 2
- Review effort level: Lite
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
| Consecutive `where()`/`whereAny()` calls AND together (each clause parenthesized), so an AND of a root predicate and a joined-entity predicate needs no `whereBuilder` either — each clause sits on its own rung: | ||
|
|
||
| ```kotlin | ||
| users.select() |
| Consecutive `where()` calls AND together (each clause parenthesized), so an AND of a root predicate and a joined-entity predicate is two calls, each in its weakest form — no single big lambda needed: | ||
|
|
||
| ```java | ||
| users.select() |
Summary
The query skills now state a strict preference order for building WHERE clauses — always use the weakest form that compiles:
where()— the default, typed to the root entity. Compound AND/OR conditions stay here via infixand/or(Kotlin); nested paths from the root are root-typed however deep, so navigating through a foreign key never forces an escalation.whereAny()— only for fields of explicitly joined (non-root) entities, whichwhere()rejects at compile time.whereBuilder { }(Kotlin) / thewhere(it -> ...)lambda (Java) — only for what a plain predicate cannot express: EXISTS/NOT EXISTS or id/ref/record/template matching inside compound logic, plus AND/OR grouping in Java.The Kotlin skill previously presented
whereBuilder { }as the way to group AND/OR conditions, which steered generated code toward the heaviest form for clauses that plainwhere()with infix operators expresses directly.Changes
whereBuildercase (subquery composed into compound logic), and the note that consecutivewhere()/whereAny()calls AND together. Echoed the ladder in the infix-operator, joined-entity, and block-DSL sections; fixed an example that escalated a root path toorderByAnyand an infix snippet typo.it.where(...)overit.whereAny(...)inside it).Fix found while verifying
The Java
QueryBuilderhas no chainedwhereAny(path, operator, value)overload — generated metamodel paths are root-typed, so joined-entity predicates go through the where-lambda:.where(it -> it.whereAny(UserRole_.role, EQUALS, role)). The Java query skill (3 snippets) and the Java tabs ofdocs/first-query.md,docs/queries.md, anddocs/relationships.mdused the non-compiling chained form; all are corrected, with a one-sentence explanation added inqueries.md.Note: the docs fixes live in
docs/only, so they appear at/docs/nextand reach the live/docs/*pages with the next release snapshot.