Grammar: with-pk column specs use name(type), matching add column
`create table … with pk` parsed column types as `name:type`,
while `add column` uses `name(type)`. Unify on the parens
form so column-type syntax is consistent across the DSL:
create table T with pk id(serial), name(text)
Only `COL_SPEC` changes (`:` → `( … )`); `build_create_table`
reads columns by role, so it is unaffected. The `:` that
separates table from column in `add column` / `drop column`
is unchanged. Sweeps the test suite, the typing-surface
matrix (two `after_colon` cells renamed to `after_paren`,
4 snapshots regenerated), the friendly catalog's usage
templates, ADR-0009's example, and requirements.md.
1039 passing / 0 failing / 1 ignored; clippy clean.
This commit is contained in:
+1
-1
@@ -6,7 +6,7 @@
|
||||
//! (e.g. "table does not exist").
|
||||
//!
|
||||
//! The shape supports compound primary keys natively even though
|
||||
//! only the dedicated `with pk a:int,b:int` grammar exposes them
|
||||
//! only the dedicated `with pk a(int),b(int)` grammar exposes them
|
||||
//! today. Future grammar extensions (inline column specs, `set
|
||||
//! primary key`, junction-table convenience commands) emit into
|
||||
//! the same shape.
|
||||
|
||||
@@ -796,7 +796,7 @@ pub static CHANGE: CommandNode = CommandNode {
|
||||
usage_ids: &["parse.usage.change_column"],};
|
||||
|
||||
// =================================================================
|
||||
// create_table — `create table <Name> [with pk [<col>:<type>[, ...]]]`
|
||||
// create_table — `create table <Name> [with pk [<col>(<type>)[, ...]]]`
|
||||
// (Phase C)
|
||||
// =================================================================
|
||||
|
||||
@@ -816,7 +816,7 @@ const COL_NAME: Node = Node::Hinted {
|
||||
|
||||
const COL_SPEC_NODES: &[Node] = &[
|
||||
COL_NAME,
|
||||
Node::Punct(':'),
|
||||
Node::Punct('('),
|
||||
Node::Ident {
|
||||
source: IdentSource::Types,
|
||||
role: "col_type",
|
||||
@@ -826,6 +826,7 @@ const COL_SPEC_NODES: &[Node] = &[
|
||||
writes_column: false,
|
||||
writes_user_listed_column: false,
|
||||
},
|
||||
Node::Punct(')'),
|
||||
];
|
||||
const COL_SPEC: Node = Node::Seq(COL_SPEC_NODES);
|
||||
|
||||
@@ -884,7 +885,7 @@ fn build_create_table(path: &MatchedPath) -> Result<Command, ValidationError> {
|
||||
|
||||
let pk_specs: Vec<(String, Type)> = if names.is_empty() {
|
||||
if saw_with {
|
||||
// `with pk` alone — default to id:serial.
|
||||
// `with pk` alone — default to id(serial).
|
||||
vec![("id".to_string(), Type::Serial)]
|
||||
} else {
|
||||
return Err(ValidationError {
|
||||
|
||||
+7
-7
@@ -393,7 +393,7 @@ mod tests {
|
||||
#[test]
|
||||
fn create_table_with_named_typed_pk() {
|
||||
assert_eq!(
|
||||
ok("create table Customers with pk email:text"),
|
||||
ok("create table Customers with pk email(text)"),
|
||||
Command::CreateTable {
|
||||
name: "Customers".to_string(),
|
||||
columns: vec![col("email", Type::Text)],
|
||||
@@ -405,7 +405,7 @@ mod tests {
|
||||
#[test]
|
||||
fn create_table_with_compound_pk() {
|
||||
assert_eq!(
|
||||
ok("create table OrderLines with pk order_id:int,product_id:int"),
|
||||
ok("create table OrderLines with pk order_id(int),product_id(int)"),
|
||||
Command::CreateTable {
|
||||
name: "OrderLines".to_string(),
|
||||
columns: vec![col("order_id", Type::Int), col("product_id", Type::Int),],
|
||||
@@ -417,7 +417,7 @@ mod tests {
|
||||
#[test]
|
||||
fn create_table_pk_accepts_any_user_type() {
|
||||
for ty in Type::all() {
|
||||
let input = format!("create table T with pk col:{}", ty.keyword());
|
||||
let input = format!("create table T with pk col({})", ty.keyword());
|
||||
let cmd = ok(&input);
|
||||
if let Command::CreateTable {
|
||||
columns,
|
||||
@@ -436,7 +436,7 @@ mod tests {
|
||||
#[test]
|
||||
fn create_table_pk_tolerates_whitespace() {
|
||||
assert_eq!(
|
||||
ok("create table T with pk id : serial"),
|
||||
ok("create table T with pk id ( serial )"),
|
||||
Command::CreateTable {
|
||||
name: "T".to_string(),
|
||||
columns: vec![col("id", Type::Serial)],
|
||||
@@ -444,7 +444,7 @@ mod tests {
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
ok("create table T with pk a : int , b : int"),
|
||||
ok("create table T with pk a ( int ) , b ( int )"),
|
||||
Command::CreateTable {
|
||||
name: "T".to_string(),
|
||||
columns: vec![col("a", Type::Int), col("b", Type::Int)],
|
||||
@@ -456,7 +456,7 @@ mod tests {
|
||||
#[test]
|
||||
fn create_table_keywords_are_case_insensitive() {
|
||||
assert_eq!(
|
||||
ok("CREATE TABLE Customers WITH PK email:TEXT"),
|
||||
ok("CREATE TABLE Customers WITH PK email(TEXT)"),
|
||||
Command::CreateTable {
|
||||
name: "Customers".to_string(),
|
||||
columns: vec![col("email", Type::Text)],
|
||||
@@ -760,7 +760,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn unknown_pk_type_errors_with_alternatives_listed() {
|
||||
let e = err("create table T with pk id:varchar");
|
||||
let e = err("create table T with pk id(varchar)");
|
||||
match e {
|
||||
ParseError::Invalid { message, .. } => {
|
||||
assert!(message.contains("varchar"), "{message}");
|
||||
|
||||
@@ -1076,7 +1076,7 @@ mod tests {
|
||||
#[test]
|
||||
fn walker_parses_create_table_named_typed_pk() {
|
||||
assert_eq!(
|
||||
parse("create table Customers with pk email:text").unwrap(),
|
||||
parse("create table Customers with pk email(text)").unwrap(),
|
||||
Command::CreateTable {
|
||||
name: "Customers".to_string(),
|
||||
columns: vec![col("email", Type::Text)],
|
||||
@@ -1088,7 +1088,7 @@ mod tests {
|
||||
#[test]
|
||||
fn walker_parses_create_table_compound_pk() {
|
||||
assert_eq!(
|
||||
parse("create table OrderLines with pk order_id:int,product_id:int").unwrap(),
|
||||
parse("create table OrderLines with pk order_id(int),product_id(int)").unwrap(),
|
||||
Command::CreateTable {
|
||||
name: "OrderLines".to_string(),
|
||||
columns: vec![col("order_id", Type::Int), col("product_id", Type::Int)],
|
||||
@@ -1100,7 +1100,7 @@ mod tests {
|
||||
#[test]
|
||||
fn walker_create_table_pk_tolerates_whitespace_around_punct() {
|
||||
assert_eq!(
|
||||
parse("create table T with pk id : serial").unwrap(),
|
||||
parse("create table T with pk id ( serial )").unwrap(),
|
||||
Command::CreateTable {
|
||||
name: "T".to_string(),
|
||||
columns: vec![col("id", Type::Serial)],
|
||||
@@ -1108,7 +1108,7 @@ mod tests {
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
parse("create table T with pk a : int , b : int").unwrap(),
|
||||
parse("create table T with pk a ( int ) , b ( int )").unwrap(),
|
||||
Command::CreateTable {
|
||||
name: "T".to_string(),
|
||||
columns: vec![col("a", Type::Int), col("b", Type::Int)],
|
||||
@@ -1134,7 +1134,7 @@ mod tests {
|
||||
#[test]
|
||||
fn walker_create_table_keywords_are_case_insensitive() {
|
||||
assert_eq!(
|
||||
parse("CREATE TABLE Customers WITH PK email:TEXT").unwrap(),
|
||||
parse("CREATE TABLE Customers WITH PK email(TEXT)").unwrap(),
|
||||
Command::CreateTable {
|
||||
name: "Customers".to_string(),
|
||||
columns: vec![col("email", Type::Text)],
|
||||
|
||||
Reference in New Issue
Block a user