Skip to content

fix(parse): read a :: cast as a cast, not as a column name - #340

Merged
tiagolauer merged 1 commit into
masterfrom
fix/277-cast-in-select-list
Aug 2, 2026
Merged

fix(parse): read a :: cast as a cast, not as a column name#340
tiagolauer merged 1 commit into
masterfrom
fix/277-cast-in-select-list

Conversation

@tiagolauer

Copy link
Copy Markdown
Owner

Fixes #277.

The bug

StrictRow<DB, 'select id::text as id_text from users'>  // QueryTypeError<'unknown column: id::text'>
StrictRow<DB, 'select id::text from users'>             // same

Loose mode is harmless ({ 'id::text': unknown }[]), but one cast column poisons the whole strict row. The :: syntax is clearly in-dialect for the library: $1::int in params is supported and tested.

The fix

':' is not in OperatorChar and nothing stripped a ::type suffix, so id::text fell through to BareColumnType as a literal column name.

A cast expression now resolves its operand and reports unknown for the column. That keeps the check where it is useful — a typo inside the cast still errors — without claiming a type the parser cannot know: the cast is what decides it, and SQL type names are not modelled here.

Verification

tests/cast-columns.test-d.ts, nine cases. Five red on master:

tests/cast-columns.test-d.ts(17,3): error TS2344: Type 'false' does not satisfy the constraint 'true'.
tests/cast-columns.test-d.ts(21,3): ...
tests/cast-columns.test-d.ts(25,3): ...
tests/cast-columns.test-d.ts(29,3): ...
tests/cast-columns.test-d.ts(37,3): ...
  • aliased, bare, qualified, and beside ordinary columns — all clean in strict mode now
  • naem::text still reports unknown column: naem, and p.id::text with no p source still reports unknown alias: p

Controls: loose mode is unchanged, a plain column is unchanged, and count(*)::int resolves through the same path.

tsc --noEmit clean, budget 194,259 (+1,773).

    StrictRow<DB, 'select id::text as id_text from users'>
    // was QueryTypeError<'unknown column: id::text'>

`:` is not in OperatorChar and nothing stripped a `::type` suffix, so the
whole token fell through to BareColumnType as a literal name. Loose mode was
harmless about it, but in strict mode one cast poisoned the whole row, and
`::` is clearly in-dialect for the library: `$1::int` in params is supported
and tested.

The operand is resolved as an expression of its own, so a typo inside the
cast is still caught (`naem::text` still reports `unknown column: naem`, a
bad qualifier still reports `unknown alias`). The column itself types
`unknown`: the cast is what decides the type, and this parser does not model
SQL type names.

Fixes #277

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@tiagolauer
tiagolauer force-pushed the fix/277-cast-in-select-list branch from 6506b4f to c1d5a70 Compare August 2, 2026 13:04
@tiagolauer
tiagolauer merged commit a4a4858 into master Aug 2, 2026
12 checks passed
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.

Postgres :: cast in the select list is a strict-mode false positive

1 participant