feat: ADR-0036 Phase 3b — live typed-slot hints + highlighting for INSERT VALUES
Give each positional INSERT VALUES position its column identity so a lone
literal gets the column-typed slot (live per-column hint + mismatch
highlight) and any expression falls through to sql_expr — completing the
typed-DML-values feature for the INSERT surface (single/multi-row, Form A
and Form B).
New zero-width Node::SetColumn(&TableColumn) primitive establishes the
active column for the value position that follows (sets current_column +
pending_value_column, like an Ident{writes_column} but without consuming
input); a DynamicSubgrammar emits SetColumn(col) + the shared SET_VALUE
per position. Column mapping mirrors do_sql_insert: Form A → listed
columns; Form B → all columns in declaration order (advanced-mode Form B
auto-fills nothing; an omitted shortid in Form A is auto-filled and has no
VALUES position).
Reconcile with the per-tuple arity diagnostic (ADR-0033 §8.1): a
fixed-length typed Seq would reject wrong-arity tuples and suppress that
post-walk diagnostic, so the tuple value list is an arity-gating lookahead
— a correct-arity tuple uses the typed Seq; a wrong-arity tuple keeps the
type-blind sql_expr repeat so §8.1 fires unchanged. Correct-arity tuples
get full live feedback, including a wrong-kind literal like 'text' into an
int column.
Records ADR-0036 Amendment 1 (Phase 3b detail + the arity reconciliation);
ADR-0036 is now fully implemented.
Tests: 1947 passing (+8), 0 failed, 0 skipped, 1 ignored; clippy clean.
This commit is contained in:
@@ -20,8 +20,13 @@ validated, execution stays verbatim). **Phase 3a implemented 2026-05-26**
|
||||
— live typed-slot hints + numeric-shape highlighting for advanced-mode
|
||||
`UPDATE`/UPSERT `SET col = <literal>` value positions, via a
|
||||
**boundary-aware lookahead** (not the naive `Choice` this ADR originally
|
||||
sketched in §5 — see **Amendment 1**). Phase 3b (`INSERT … VALUES` typed
|
||||
slots — needs a per-position grammar restructure + multi-row) pending.
|
||||
sketched in §5 — see **Amendment 1**). **Phase 3b implemented 2026-05-27**
|
||||
— live per-position typed-slot hints + highlighting for advanced-mode
|
||||
`INSERT … VALUES (…)` (single- and multi-row, Form A and Form B), via a
|
||||
new zero-width `Node::SetColumn` primitive that gives each positional
|
||||
value its column identity, plus an arity-gating tuple lookahead that
|
||||
preserves the per-tuple arity diagnostic (ADR-0033 §8.1); see
|
||||
**Amendment 1**. ADR-0036 is now fully implemented.
|
||||
|
||||
**Augments** **ADR-0030 §4** and **ADR-0033 §10** — it does **not**
|
||||
supersede them and does **not** change the execution model. Advanced-mode
|
||||
@@ -373,13 +378,44 @@ deliberate throwaway.
|
||||
UPDATE SET`. Mismatch examples now caught **live** (e.g. `set k = 3.14`
|
||||
at an `int` column), matching what simple mode already does — earlier,
|
||||
better feedback than Phase 2's execution-time catch.
|
||||
- **Phase 3b (pending) — `INSERT … VALUES (…)`.** Harder: the values list
|
||||
is `Repeated(VALUE_EXPR)` with **no per-position column identity**, and
|
||||
multi-row `values (..),(..)` must be handled. It needs the DSL-style
|
||||
per-position restructure (a `DynamicSubgrammar` emitting one
|
||||
boundary-aware position per column), tracked as its own step.
|
||||
- **Phase 3b (implemented 2026-05-27) — `INSERT … VALUES (…)`.** Harder,
|
||||
because the values list is positional (no per-position column ident)
|
||||
and multi-row. The resolution, agreed with the user (full-parity
|
||||
option):
|
||||
- **A new zero-width `Node::SetColumn(&'static TableColumn)` primitive**
|
||||
establishes the active column for the value position that follows
|
||||
(sets `current_column` + `pending_value_column`, exactly as an
|
||||
`Ident { writes_column: true }` would, but without consuming an
|
||||
identifier). A `DynamicSubgrammar` (`sql_insert::sql_value_list`)
|
||||
emits `SetColumn(colᵢ)` then the shared `SET_VALUE` per position, so
|
||||
each positional value reuses 3a's routing. One new enum variant; one
|
||||
new walker arm.
|
||||
- **Column mapping** mirrors `do_sql_insert`'s positional rule:
|
||||
Form A → the listed columns in the user's order; Form B → **all**
|
||||
columns in declaration order. Note on auto-fill (correcting a loose
|
||||
statement made while scoping): advanced mode **does** auto-fill an
|
||||
*omitted* `shortid` in **Form A** (`plan_shortid_autofill`), so that
|
||||
column has no `VALUES` position and is correctly absent from the
|
||||
mapping; it does **not** auto-fill `serial` (the X4 gap); and **Form
|
||||
B auto-fills nothing** (the function returns early on an empty column
|
||||
list), so the user supplies a value for every column — hence the
|
||||
Form-B-maps-all-columns rule.
|
||||
- **Coexistence with the §8.1 arity diagnostic.** A fixed-length typed
|
||||
`Seq` would *reject* a wrong-arity tuple, suppressing the friendly
|
||||
per-tuple `insert_arity_mismatch` (ADR-0033 §8.1), which is a
|
||||
post-walk pass over the matched path and so needs the tuple to be
|
||||
accepted. So the tuple value list is an **arity-gating lookahead**
|
||||
(`tuple_value_list`): a closed tuple uses the typed `Seq` only on an
|
||||
exact value/column match; an open (mid-typing) tuple uses it while
|
||||
`count <= columns` (so the hint shows from `(` onward); every other
|
||||
case falls back to the type-blind `Repeated(sql_expr)`, leaving the
|
||||
§8.1 diagnostic to fire unchanged. Correct-arity tuples (the common
|
||||
case) thus get full live typed feedback — including a wrong-*kind*
|
||||
lone literal such as `('text')` into an `int` column, the case the
|
||||
cheaper structural option would have missed — while wrong-arity
|
||||
tuples keep the friendly arity message.
|
||||
|
||||
**Known limitation (both phases, matches the DSL).** `date` / `shortid` /
|
||||
**Known limitation (all phases, matches the DSL).** `date` / `shortid` /
|
||||
`datetime` **format** is still not validated at parse — those slots accept
|
||||
any quoted string; the format is checked at bind/execution time (Phase 2).
|
||||
So the live highlight catches *numeric-shape* mismatches (`int`/`decimal`/
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user