2g: advanced-mode highlight + engine.* wiring + matrix tests
Cross-cut verification matrix for ADR-0032 Phase 2 is now fully populated with concrete test references — every row green. Filling the matrix surfaced three real gaps that this commit closes. 1. Advanced-mode syntax highlighting (ADR-0030 §8 matrix row). The `ui.rs` Advanced branch routed through `plain_input_spans`, bypassing the highlight walker entirely. In production SQL keywords past the entry word rendered as plain identifiers. Fix: mode-aware variants of `highlight_runs`, `render_input_runs`, `lex_to_runs`, and `input_diagnostics`; the Advanced render path now uses the highlighted form with `Mode::Advanced`. `plain_input_spans` removed (unused). 2. Engine.* key wiring (ADR-0032 §11.4 / §13 matrix rows + handoff §3.3 follow-up). The four Phase-2 engine.* catalog entries were authored in 2d but never reached: `translate_generic` discarded the engine message and returned a vague catalog entry. Fix: pattern-match the engine message text for the four Phase-2 categories (aggregate misuse, group-by required, compound arity mismatch fallback, scalar-subquery cardinality) inside `translate_generic`, routing each to its engine-neutral catalog entry. 3. Matrix-coverage tests. Thirteen new tests covering the rows that had no explicit coverage: - 3 SQL keyword/operator/CASE highlight tests - 4 engine.* engine-message tests - 3 sql_expr column-completion tests (WHERE, HAVING) - 3 predicate-warning slot tests (CASE, ORDER BY, projection) - 1 all-10-playground-types recovery test (tests/sql_select.rs) Plan document (docs/plans/20260520-adr-0032-phase-2.md) updated: every (TBD) row in the cross-cut matrix replaced with a concrete test file::function reference and a green status marker. Test totals: 1428 → 1441 passing (+13 new). Clippy clean.
This commit is contained in:
@@ -343,6 +343,96 @@ fn database_run_select_computed_expression_stays_typeless() {
|
||||
assert_eq!(data.column_types, vec![None]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn database_run_select_recovers_all_ten_playground_types() {
|
||||
// ADR-0032 §12 + Amendment 1 — every playground type
|
||||
// round-trips through column-origin metadata on a bare
|
||||
// projection ref. One table holds one column of each
|
||||
// type; a SELECT of that column produces the right
|
||||
// `column_types[0]` entry.
|
||||
//
|
||||
// `serial` is auto-generated, so we use it as the PK and
|
||||
// don't supply a value at insert. `shortid` is also
|
||||
// auto-generated when omitted.
|
||||
let (_p, db, _dir) = open_project_db();
|
||||
let rt = rt();
|
||||
rt.block_on(async {
|
||||
db.create_table(
|
||||
"AllTypes".to_string(),
|
||||
vec![
|
||||
ColumnSpec::new("pk", Type::Serial),
|
||||
ColumnSpec::new("col_text", Type::Text),
|
||||
ColumnSpec::new("col_int", Type::Int),
|
||||
ColumnSpec::new("col_real", Type::Real),
|
||||
ColumnSpec::new("col_decimal", Type::Decimal),
|
||||
ColumnSpec::new("col_bool", Type::Bool),
|
||||
ColumnSpec::new("col_date", Type::Date),
|
||||
ColumnSpec::new("col_datetime", Type::DateTime),
|
||||
ColumnSpec::new("col_blob", Type::Blob),
|
||||
ColumnSpec::new("col_shortid", Type::ShortId),
|
||||
],
|
||||
vec!["pk".to_string()],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.expect("create table");
|
||||
// Blob has no DSL literal form, so col_blob takes the
|
||||
// default NULL on insert. Column-origin metadata is
|
||||
// based on the column DEFINITION, not the row value
|
||||
// (Amendment 1), so the type recovery still succeeds.
|
||||
db.insert(
|
||||
"AllTypes".to_string(),
|
||||
Some(vec![
|
||||
"col_text".to_string(),
|
||||
"col_int".to_string(),
|
||||
"col_real".to_string(),
|
||||
"col_decimal".to_string(),
|
||||
"col_bool".to_string(),
|
||||
"col_date".to_string(),
|
||||
"col_datetime".to_string(),
|
||||
]),
|
||||
vec![
|
||||
Value::Text("hello".to_string()),
|
||||
Value::Number("42".to_string()),
|
||||
Value::Number("3.14".to_string()),
|
||||
Value::Number("1.50".to_string()),
|
||||
Value::Bool(true),
|
||||
Value::Text("2026-05-20".to_string()),
|
||||
Value::Text("2026-05-20T12:00:00".to_string()),
|
||||
],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.expect("insert row");
|
||||
});
|
||||
|
||||
// Each row pairs a column name with the expected
|
||||
// playground type recovered by column-origin lookup.
|
||||
let cases: &[(&str, Type)] = &[
|
||||
("pk", Type::Serial),
|
||||
("col_text", Type::Text),
|
||||
("col_int", Type::Int),
|
||||
("col_real", Type::Real),
|
||||
("col_decimal", Type::Decimal),
|
||||
("col_bool", Type::Bool),
|
||||
("col_date", Type::Date),
|
||||
("col_datetime", Type::DateTime),
|
||||
("col_blob", Type::Blob),
|
||||
("col_shortid", Type::ShortId),
|
||||
];
|
||||
for (col, expected_type) in cases {
|
||||
let sql = format!("select {col} from AllTypes");
|
||||
let data = rt
|
||||
.block_on(db.run_select(sql.clone(), None))
|
||||
.expect("SELECT runs");
|
||||
assert_eq!(
|
||||
data.column_types,
|
||||
vec![Some(*expected_type)],
|
||||
"type recovery failed for `{sql}`",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn database_run_select_appends_to_history_when_source_present() {
|
||||
let (project, db, _dir) = open_project_db();
|
||||
|
||||
Reference in New Issue
Block a user