diff --git a/skills/hotdata/SKILL.md b/skills/hotdata/SKILL.md index ad2c4ee..e583437 100644 --- a/skills/hotdata/SKILL.md +++ b/skills/hotdata/SKILL.md @@ -301,7 +301,9 @@ hotdata ingest create --datasource-id ds_01J --type one-time \ # selector.json is family-specific (what subset to read) — its fields, and the # write modes this family accepts: hotdata ingest sources fields . # destination.json is {"database_id", "schema", "table", "write_mode"} — -# write_mode: replace | upsert (upsert needs a continuous bucket ingest). +# write_mode (default replace): replace|append work on any table; the key-based +# modes upsert|update|delete need the destination table to have a declared key. +# `hotdata ingest sources fields ` reports which modes the family accepts. # Selector and destination are both IMMUTABLE after creation. # CREATE STARTS NOTHING, for every type. It returns no run id, and # `ingest logs ` is EMPTY until the scheduler claims the ingest — normal, @@ -328,7 +330,9 @@ hotdata ingest create --source "prod postgres" --table orders --schema public \ # --limit N stop after N source rows # Destination flags instead of --destination: # --database-id (required) --dest-table (defaults to the single --table) -# --dest-schema (default public) --write-mode (default replace) +# --dest-schema (default public) +# --write-mode replace|append|upsert|update|delete (default replace; upsert/ +# update/delete need the destination table to have a declared key) hotdata ingest create --datasource-id ds_01J --database-id db_123 \ --sql "SELECT id, status FROM public.orders WHERE status = 'open' LIMIT 1000" diff --git a/src/commands/ingest.rs b/src/commands/ingest.rs index d3a1e48..0846e18 100644 --- a/src/commands/ingest.rs +++ b/src/commands/ingest.rs @@ -238,15 +238,19 @@ pub enum IngestCommands { #[arg(long = "dest-schema")] dest_schema: Option, - /// How each run writes (default: replace). `upsert` needs a family - /// whose load path stamps a row key — today that is a continuous bucket - /// ingest, and `hotdata ingest sources fields ` reports which modes - /// a family accepts for which type. - /// - /// The two listed are the two the destination accepts anywhere. Offering - /// a third would be offering a request that is refused on arrival, which - /// costs the user a round trip to learn what `--help` could have said. - #[arg(long = "write-mode", value_parser = ["replace", "upsert"])] + /// How each run writes (default: `replace`). `replace` and `append` work + /// on any destination table; the key-based modes `upsert`, `update`, and + /// `delete` match rows by the table's declared key and are rejected on a + /// keyless table. This list is the service-wide vocabulary — clap catches a + /// typo up front — but which of these a *given* family or table accepts is + /// reported by `hotdata ingest sources fields `, the authoritative + /// source; a mode the family or table does not support is refused on + /// arrival. (The old list `[replace, upsert]` both omitted `append` — which + /// families advertise — and offered `upsert` as if universal: see #278.) + #[arg( + long = "write-mode", + value_parser = ["replace", "append", "upsert", "update", "delete"] + )] write_mode: Option, /// Schedule as JSON (inline, @file.json, or @-):