feat(seed): command plumbing + walking skeleton (ADR-0048 P1.2)
End-to-end `seed <table> [count]` path, both modes: - Command::Seed AST + grammar node (show-data table slot + optional positional count) + REGISTRY registration + build_seed. - Runtime dispatch -> Database::seed -> Request::Seed worker arm -> do_seed. - do_seed (Phase-1 skeleton): generates whole rows for non-FK, non-autogen columns via the seed library and inserts them one at a time through do_insert (reusing validation / autogen autofill / FK-error / persistence). One undo step (snapshot_then wraps it) and one history.log line (only the first row carries the source); default count 20. - help (`help seed`) + parse-usage catalog entries. - Reuses CommandOutcome::Insert for the auto-show; a dedicated SeedResult (capped preview + advisory) replaces it in P1.3. 5 Tier-3 integration tests (parse, populate+persist, default-20, reproducible --seed, one history line). 2327 pass / 0 fail / 0 skip, clippy all-targets clean. Deferred to P1.3: FK sampling, identifier/constraint uniqueness, CHECK derivation, block guard, capped preview, advisory, multi-row path. Deferred to P1.4: completion/highlight/hint/validity wiring + --seed flag.
This commit is contained in:
@@ -425,6 +425,24 @@ const LIMIT_CLAUSE_NODES: &[Node] = &[
|
||||
];
|
||||
const LIMIT_CLAUSE: Node = Node::Seq(LIMIT_CLAUSE_NODES);
|
||||
|
||||
// =================================================================
|
||||
// seed — `seed <T> [<count>]` (ADR-0048, SD1)
|
||||
// =================================================================
|
||||
|
||||
/// Optional positional row count. Reuses `LIMIT_VALIDATOR` (a
|
||||
/// non-negative integer). Phase 1 has no `--seed` flag, `set` clause,
|
||||
/// or `<table>.<column>` column-fill form yet.
|
||||
const SEED_COUNT: Node = Node::NumberLit {
|
||||
validator: Some(LIMIT_VALIDATOR),
|
||||
};
|
||||
const SEED_NODES: &[Node] = &[
|
||||
// `writes_table` so a future `set <col>=…` clause's column slots
|
||||
// can resolve against this table.
|
||||
TABLE_NAME_WRITES,
|
||||
Node::Optional(&SEED_COUNT),
|
||||
];
|
||||
const SEED_SHAPE: Node = Node::Seq(SEED_NODES);
|
||||
|
||||
const UPDATE_NODES: &[Node] = &[
|
||||
TABLE_NAME_WRITES,
|
||||
Node::Word(Word::keyword("set")),
|
||||
@@ -708,6 +726,38 @@ fn build_show_limit(path: &MatchedPath) -> Result<Option<u64>, ValidationError>
|
||||
})
|
||||
}
|
||||
|
||||
/// Build a `seed <T> [<count>]` command (ADR-0048). The only
|
||||
/// `NumberLit` in a `seed` path is the optional count.
|
||||
fn build_seed(path: &MatchedPath, _source: &str) -> Result<Command, ValidationError> {
|
||||
Ok(Command::Seed {
|
||||
table: require_ident(path, "table_name")?,
|
||||
count: build_seed_count(path)?,
|
||||
// `--seed <n>` is added in a later phase; reproducibility off
|
||||
// for now.
|
||||
rng_seed: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn build_seed_count(path: &MatchedPath) -> Result<Option<u64>, ValidationError> {
|
||||
let Some(item) = path
|
||||
.items
|
||||
.iter()
|
||||
.find(|i| matches!(i.kind, MatchedKind::NumberLit))
|
||||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
item.text
|
||||
.parse::<u64>()
|
||||
.map(Some)
|
||||
.map_err(|_| ValidationError {
|
||||
message_key: "parse.custom.bind_type_mismatch",
|
||||
args: vec![
|
||||
("found", item.text.clone()),
|
||||
("expected", "non-negative integer".to_string()),
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
fn build_insert(path: &MatchedPath, _source: &str) -> Result<Command, ValidationError> {
|
||||
let table = require_ident(path, "table_name")?;
|
||||
|
||||
@@ -1452,6 +1502,14 @@ pub static SHOW: CommandNode = CommandNode {
|
||||
"parse.usage.show_index",
|
||||
],};
|
||||
|
||||
pub static SEED: CommandNode = CommandNode {
|
||||
entry: Word::keyword("seed"),
|
||||
shape: SEED_SHAPE,
|
||||
ast_builder: build_seed,
|
||||
help_id: Some("data.seed"),
|
||||
usage_ids: &["parse.usage.seed"],
|
||||
};
|
||||
|
||||
pub static INSERT: CommandNode = CommandNode {
|
||||
entry: Word::keyword("insert"),
|
||||
shape: INSERT_SHAPE,
|
||||
|
||||
Reference in New Issue
Block a user