parser: make to and table independently optional in add column

Previously the grammar accepted only `to table` together or
neither. The user-stated convention is that bare table
identifiers are accepted in unambiguous positions (matching
how `add 1:n relationship from <T>.<col> to <T>.<col>` takes
bare table names). Both `to` and `table` are now or_not'd
independently, so all four combinations parse identically.

Updates the in-app `help` listing to advertise the new
shape: `add column [to] [table] <T>: <col> (<type>)`.

3 new parser tests cover the variants.
This commit is contained in:
claude@clouddev1
2026-05-08 09:16:50 +00:00
parent 1b27a0c9b1
commit 41cef5399b
2 changed files with 52 additions and 7 deletions
+51 -6
View File
@@ -129,14 +129,19 @@ fn command_parser<'a>()
.ignore_then(identifier())
.map(|name| Command::DropTable { name });
// `to table` is optional — both `add column to table T: c (text)`
// and `add column T: c (text)` parse identically.
let to_table_optional = keyword_ci("to")
.ignore_then(keyword_ci("table"))
.or_not();
// Both `to` and `table` are independently optional —
// `add column to table T: c (text)`,
// `add column to T: c (text)`,
// `add column table T: c (text)`,
// and `add column T: c (text)` all parse identically.
// Matches the convention elsewhere in the DSL where bare
// identifiers are accepted in unambiguous positions.
let optional_to = keyword_ci("to").or_not();
let optional_table = keyword_ci("table").or_not();
let add_column = keyword_ci("add")
.ignore_then(keyword_ci("column"))
.ignore_then(to_table_optional)
.ignore_then(optional_to)
.ignore_then(optional_table)
.ignore_then(identifier())
.then_ignore(just(':').padded())
.then(identifier())
@@ -764,6 +769,46 @@ mod tests {
}
}
#[test]
fn add_column_accepts_bare_table_name() {
// `to table` are both optional; bare table identifier
// is accepted in this unambiguous position.
assert_eq!(
ok("add column Customers: Name (text)"),
Command::AddColumn {
table: "Customers".to_string(),
column: "Name".to_string(),
ty: Type::Text,
}
);
}
#[test]
fn add_column_accepts_to_alone() {
// `to` without `table`.
assert_eq!(
ok("add column to Customers: Name (text)"),
Command::AddColumn {
table: "Customers".to_string(),
column: "Name".to_string(),
ty: Type::Text,
}
);
}
#[test]
fn add_column_accepts_table_alone() {
// `table` without `to`.
assert_eq!(
ok("add column table Customers: Name (text)"),
Command::AddColumn {
table: "Customers".to_string(),
column: "Name".to_string(),
ty: Type::Text,
}
);
}
#[test]
fn add_column_tolerates_whitespace_around_punctuation() {
assert_eq!(