feat: bring simple-mode insert arity diagnostics to parity with advanced
A wrong-count simple-mode insert now shows the friendly per-column arity message at typing time (instead of a bare "expected `,`/`)`") and is blocked from dispatch at submit — unifying simple and advanced mode onto the one ADR-0027 model (structural parse + ERROR diagnostic), where they had diverged. Grammar: a simple-mode-only arity gate (dsl_insert_value_list) routes a wrong-count DSL insert tuple to the type-blind fallback so it matches structurally and the per-tuple arity diagnostic fires. The gate is gated to simple mode, so advanced behaviour is unchanged. count_tuple_values and the target-column selection (insert_target_columns) are now shared by both grammars. Diagnostic: dml_insert_arity_diagnostics is mode-aware — advanced Form B expects all columns; simple Form B/C expects the user-fillable columns (serial/shortid auto-fill). It counts the DSL Form A role and scans the keyword-less Form C tuple. New catalog keys name the fillable/auto split and the all-auto-table case. Submit: a wrong-count DSL insert now parses Ok + carries the ERROR diagnostic, so a unified Ok-arm pre-flight (dsl_insert_count_mismatch_notes) blocks dispatch and teaches; the previous Err-arm note retires. advanced_alternative_note's gate now reads the validity verdict so it still fires for the parse-Ok-with-error shape. Docs: ADR-0036 Amendment 2 (+ README index) and requirements.md H1a.
This commit is contained in:
+77
-13
@@ -1361,6 +1361,30 @@ impl App {
|
||||
source: input.to_string(),
|
||||
}];
|
||||
}
|
||||
// Issue #17: simple-mode (DSL) counterpart. A wrong-count
|
||||
// DSL insert now parses `Ok` (so the typing-time arity
|
||||
// diagnostic can fire), so dispatch is gated here — the
|
||||
// same teaching the old parse-error path showed, now with
|
||||
// the insert reliably blocked from reaching the worker.
|
||||
if let Some(notes) = crate::input_render::dsl_insert_count_mismatch_notes(
|
||||
input,
|
||||
&cmd,
|
||||
&self.schema_cache,
|
||||
) {
|
||||
self.push_output(OutputLine {
|
||||
text: crate::t!("dsl.running", input = input),
|
||||
kind: OutputKind::Echo,
|
||||
mode_at_submission: mode,
|
||||
styled_runs: None,
|
||||
});
|
||||
for note in notes {
|
||||
self.note_error(note);
|
||||
}
|
||||
self.note_error(render_usage_block(input));
|
||||
return vec![Action::JournalFailure {
|
||||
source: input.to_string(),
|
||||
}];
|
||||
}
|
||||
self.push_output(OutputLine {
|
||||
text: crate::t!("dsl.running", input = input),
|
||||
kind: OutputKind::Echo,
|
||||
@@ -1426,19 +1450,13 @@ impl App {
|
||||
{
|
||||
self.note_error(note);
|
||||
}
|
||||
// Issue #1 sub-task 2: append a teaching note when the
|
||||
// Form B `insert into <T> values (…)` line failed
|
||||
// because the user supplied more values than the
|
||||
// non-auto-generated columns expect. The parse error
|
||||
// shows the literal "expected `)`"; the note explains
|
||||
// *why* fewer values are expected and shows the
|
||||
// column-list override path.
|
||||
if mode == Mode::Simple
|
||||
&& let Some(note) =
|
||||
crate::input_render::form_b_extra_values_note(input, &self.schema_cache)
|
||||
{
|
||||
self.note_error(note);
|
||||
}
|
||||
// Issue #1 sub-task 2's Form B teaching note used to be
|
||||
// appended here, because a wrong-count Form B insert
|
||||
// failed to parse and landed in this Err arm. As of issue
|
||||
// #17 such tuples parse `Ok` (so the typing-time arity
|
||||
// diagnostic fires) and the teaching + dispatch block now
|
||||
// live in the Ok arm's `dsl_insert_count_mismatch_notes`
|
||||
// pre-flight — a single model shared with advanced mode.
|
||||
// ADR-0021 §2: append the usage block (if a
|
||||
// known command-entry keyword was consumed) or
|
||||
// the available-commands fallback (§5).
|
||||
@@ -3129,6 +3147,52 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_mode_submit_of_form_b_count_mismatch_does_not_dispatch() {
|
||||
// Issue #17 EXECUTION SAFETY. Once simple-mode wrong-count Form B
|
||||
// tuples parse `Ok` (so the typing-time arity diagnostic can
|
||||
// fire), the submit path must still NOT dispatch the insert — a
|
||||
// wrong-count insert would otherwise reach the worker and fail
|
||||
// (or, worse, write the wrong row). The unified Ok-arm pre-flight
|
||||
// must block dispatch exactly as the old parse-error path did.
|
||||
let mut app = App::new();
|
||||
install_customers_schema_two_serials(&mut app);
|
||||
type_str(&mut app, "insert into Customers values ('Oli', 52, 3)");
|
||||
let actions = submit(&mut app);
|
||||
assert!(
|
||||
!actions.iter().any(|a| matches!(a, Action::ExecuteDsl { .. })),
|
||||
"simple-mode Form B count mismatch must NOT dispatch; got: {actions:?}",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_mode_submit_of_form_b_undersupply_does_not_dispatch() {
|
||||
// Companion to the above for under-supply.
|
||||
let mut app = App::new();
|
||||
install_customers_schema_two_serials(&mut app);
|
||||
type_str(&mut app, "insert into Customers values ('Oli')");
|
||||
let actions = submit(&mut app);
|
||||
assert!(
|
||||
!actions.iter().any(|a| matches!(a, Action::ExecuteDsl { .. })),
|
||||
"simple-mode Form B under-supply must NOT dispatch; got: {actions:?}",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_mode_submit_of_form_a_count_mismatch_does_not_dispatch() {
|
||||
// Form A (explicit column list) wrong count must also not
|
||||
// dispatch — it previously parse-errored; the unified pre-flight
|
||||
// must keep it blocked.
|
||||
let mut app = App::new();
|
||||
install_customers_schema_two_serials(&mut app);
|
||||
type_str(&mut app, "insert into Customers (Name, Age) values ('Oli')");
|
||||
let actions = submit(&mut app);
|
||||
assert!(
|
||||
!actions.iter().any(|a| matches!(a, Action::ExecuteDsl { .. })),
|
||||
"simple-mode Form A count mismatch must NOT dispatch; got: {actions:?}",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_mode_submit_of_sql_construct_appends_advanced_pointer() {
|
||||
// ADR-0033 Amendment 3 (+ Amendment 5): submitting a line in
|
||||
|
||||
Reference in New Issue
Block a user