feat: V5a show relationship/index <name> detail views

Fold the singular per-item forms into Command::ShowList { kind,
name: Option<String> } (name: Some = one item). Two grammar
branches reuse the relationship/index completion sources; worker
do_show_one renders a labelled detail block or a friendly
"No ... named X." line, reusing the V5 render path. Help +
parse-usage entries, two ADR-0042 near-miss rows, 5 integration
tests. Mark V5a [x] — V5's [<name>] clause now complete.
This commit is contained in:
claude@clouddev1
2026-06-07 14:04:00 +00:00
parent 757711f2bf
commit 1d898adf00
13 changed files with 272 additions and 32 deletions
+55
View File
@@ -107,12 +107,53 @@ const SHOW_TABLES: Node = Node::Word(Word::keyword("tables"));
const SHOW_RELATIONSHIPS: Node = Node::Word(Word::keyword("relationships"));
const SHOW_INDEXES: Node = Node::Word(Word::keyword("indexes"));
// `show relationship <name>` / `show index <name>` — singular
// per-item detail (V5a). The name slot reuses the existing
// completion sources (relationship / index names). Distinct
// keyword tokens from the plurals (`relationship` ≠
// `relationships`), so Choice ordering is irrelevant.
const SHOW_RELATIONSHIP_NAME: Node = Node::Ident {
source: IdentSource::Relationships,
role: "relationship_name",
validator: None,
highlight_override: None,
writes_table: false,
writes_column: false,
writes_user_listed_column: false,
writes_table_alias: false,
writes_cte_name: false,
writes_projection_alias: false,
};
const SHOW_RELATIONSHIP_NODES: &[Node] = &[
Node::Word(Word::keyword("relationship")),
SHOW_RELATIONSHIP_NAME,
];
const SHOW_RELATIONSHIP: Node = Node::Seq(SHOW_RELATIONSHIP_NODES);
const SHOW_INDEX_NAME: Node = Node::Ident {
source: IdentSource::Indexes,
role: "index_name",
validator: None,
highlight_override: None,
writes_table: false,
writes_column: false,
writes_user_listed_column: false,
writes_table_alias: false,
writes_cte_name: false,
writes_projection_alias: false,
};
const SHOW_INDEX_NODES: &[Node] =
&[Node::Word(Word::keyword("index")), SHOW_INDEX_NAME];
const SHOW_INDEX: Node = Node::Seq(SHOW_INDEX_NODES);
const SHOW_CHOICES: &[Node] = &[
SHOW_DATA,
SHOW_TABLE,
SHOW_TABLES,
SHOW_RELATIONSHIPS,
SHOW_INDEXES,
SHOW_RELATIONSHIP,
SHOW_INDEX,
];
const SHOW_SHAPE: Node = Node::Choice(SHOW_CHOICES);
@@ -576,12 +617,24 @@ fn build_show(path: &MatchedPath, _source: &str) -> Result<Command, ValidationEr
}),
Some("tables") => Ok(Command::ShowList {
kind: ShowListKind::Tables,
name: None,
}),
Some("relationships") => Ok(Command::ShowList {
kind: ShowListKind::Relationships,
name: None,
}),
Some("indexes") => Ok(Command::ShowList {
kind: ShowListKind::Indexes,
name: None,
}),
// V5a singular per-item detail — carry the named item.
Some("relationship") => Ok(Command::ShowList {
kind: ShowListKind::Relationships,
name: Some(require_ident(path, "relationship_name")?),
}),
Some("index") => Ok(Command::ShowList {
kind: ShowListKind::Indexes,
name: Some(require_ident(path, "index_name")?),
}),
_ => Err(ValidationError {
message_key: "parse.error_wrapper",
@@ -1395,6 +1448,8 @@ pub static SHOW: CommandNode = CommandNode {
"parse.usage.show_tables",
"parse.usage.show_relationships",
"parse.usage.show_indexes",
"parse.usage.show_relationship",
"parse.usage.show_index",
],};
pub static INSERT: CommandNode = CommandNode {