Repository navigation
fix(model): name a where= value that has no model column to bind against - #4531
Merged
Merged
Conversation
where= binds every `column <operator> literal`, and the column must be the model's or an included model's. Two valid shapes failed with errors that didn't say why: - A comparison between two numbers (1 = 0, 1 = 1) threw Wheels.ColumnNotFound for a column named 1. findAll(), updateAll() and deleteAll() now mark its operator (Chr(8), outside quoted literals) so no pass binds or counts its value, and $whereClause() writes it as typed. - A literal compared with another table's column inside a subquery was masked but never got a parameter, so the SQL builder failed with "Array index [1] out of range". It now throws Wheels.UnbindableWhereValue naming the condition and the alternatives (whereIn() with a value array, or running the subquery first). A ColumnNotFound from a where with a subquery says the same. The query guide and .ai/models.md (and the app template's copy) document the rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com>
Contributor
Wheels Test Results37 230 tests 36 483 ✅ 10m 40s ⏱️ Results for commit 433ae85. ♻️ This comment has been updated with latest results. |
…de values in its error where= accepts model columns compared with values; a condition with no column, such as 1 = 0, isn't supported. It throws Wheels.ColumnNotFound as before, whose detail now says so and names the alternatives (whereIn() with an empty array for no rows; leave the condition out for every row). The guide, .ai/models.md and the changelog say the same. Wheels.UnbindableWhereValue now hides every value in the condition it echoes: a quoted literal that wasn't bound is shown as '...' rather than in its masked form. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com>
…lue echoes
Wheels.UnbindableWhereValue echoed numeric literals in the condition as written. A number that
isn't part of an identifier is now shown as ..., alongside bound values (?) and quoted
literals ('...'), and the wording says exactly that.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Peter Amiri <peter@alurium.com>
…here= value echoes" This reverts commit e848f53: only quoted and bound values need hiding, and unquoted numbers in the developer's own where text may show. The comment, the error, the spec name and the changelog now say "quoted values hidden" rather than "every value". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com>
Collaborator
Author
|
Source review approved at Unsupported literal-only predicates retain their existing error behavior, with clearer guidance. Independently verified quoted diagnostic redaction on Lucee 7/SQLite with ordinary text, doubled apostrophes and control-character data, under Final gate remains full matrix |
Collaborator
Author
|
Final approval — OK TO MERGE at
|
bpamiri
added a commit
that referenced
this pull request
Oct 12, 2026
- erase-account rescore flipped seven trials, not eight; note the eighth (a Claude Code trial) as unrescorable - reword the frozen-before-runs claim in sections 1 and 7 so it no longer reads as contradicting the two disclosed check corrections in section 5 - drop the "hardest task" label on ar-erase-account (hw-scoped-broadcast is lower) - note two erase misses were a where= subquery documentation gap since addressed (#4531), not model errors - literal-route: reconcile "six remain" with the twelve not passing (six genuine HTTP 301, six unrescorable Claude Code trials) - drop the redundant raw parens on the Qwen docs cell (raw equals rescored) - correct #4266's description (a failed enqueue raises) vs #4282 (defer an enqueue inside a datasource transaction) - state the per-trial cost guard plainly - rename the section 2 heading to "Latest results (October 2026)" Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com>
bpamiri
added a commit
that referenced
this pull request
Oct 12, 2026
* docs(web): add AI coding-agent results page at /ai Add web/sites/landing/src/pages/ai.astro (route wheels.dev/ai), a results page reporting the Round 4 coding-agent evaluation against real feature work in a Wheels app: methodology, the full per-cell results table, the bare vs shipped-docs comparison, the ten tasks, the two post-run check corrections in full, and the user-facing framework changes the rounds drove. Built with the shared BaseLayout and @wheels-dev/ui tokens, matching index.astro. Primary figures are the rescored ones; raw figures are shown in parentheses. Section headings carry stable slug ids so deep links resolve. Data tables use a horizontal-scroll wrapper to avoid page-level scroll on small screens. astro build + astro check pass; Prettier clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com> * docs(web): correct AI results page per review - erase-account rescore flipped seven trials, not eight; note the eighth (a Claude Code trial) as unrescorable - reword the frozen-before-runs claim in sections 1 and 7 so it no longer reads as contradicting the two disclosed check corrections in section 5 - drop the "hardest task" label on ar-erase-account (hw-scoped-broadcast is lower) - note two erase misses were a where= subquery documentation gap since addressed (#4531), not model errors - literal-route: reconcile "six remain" with the twelve not passing (six genuine HTTP 301, six unrescorable Claude Code trials) - drop the redundant raw parens on the Qwen docs cell (raw equals rescored) - correct #4266's description (a failed enqueue raises) vs #4282 (defer an enqueue inside a datasource transaction) - state the per-trial cost guard plainly - rename the section 2 heading to "Latest results (October 2026)" Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Peter Amiri <peter@alurium.com> --------- Signed-off-by: Peter Amiri <peter@alurium.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #4530
Problem
where=is parsed, not passed through. Eachcolumn <operator> literalis bound as a query parameter, and the column must belong to the model or anincluded model.A literal compared with another table's column inside a subquery doesn't fit that rule. For example, in
id IN (SELECT book_id FROM accesses WHERE user_id = 1), the literal was masked but never got a parameter, so the SQL builder failed withArray index [1] out of range, array size is [0](sql.cfm). The error named neither the condition nor the cause. A condition with no column, such aswhere="1 = 0", failed with aWheels.ColumnNotFoundthat didn't say why either.Change
where=accepts model columns compared with values; literal-only predicates are not supported. This PR makes the errors say so.$whereClause()now throwsWheels.UnbindableWhereValuenaming the condition, with its quoted values hidden. A bound value shows as?and any other quoted literal as'...'. Unquoted numbers in the developer's ownwheretext are shown as written.whereIn()with a value array, or run the subquery as its own query first.Wheels.ColumnNotFoundfrom awhere=now explains the rule in its detail:1 = 0), that a condition with no column isn't supported, and what to use instead;where="1 = 0"isn't supported, and that for no rows you usewhereIn()with an empty array and for every row you leave the condition out. It also covers the subquery case, with a two-stepwhereIn()example..ai/models.mdand the app template's copy say the same. The consumer-docscheckpasses.fixed) is included.Tests
New
whereUnboundLiteralSpec(model suite):where="1 = 0"throwsWheels.ColumnNotFoundwhose detail says it isn't supported and nameswhereIn()with an empty array;whereIn("id", [])returns no rows;Wheels.UnbindableWhereValuenamingWHERE views=?;SELECTand a quoted value in itsWHERE, the message contains neither value, their hex encoding, the mask sentinel, norChr(2);ColumnNotFound.Local results (production code as at bebed30; later commits change wording and a spec name only):
run-suite.sh,TZ=UTC)The complexity and docblock gates pass. The guides site builds, and
verify-docson the query page passes 12/12.🤖 Generated with Claude Code