feat(types)!: drop the blob column type (ADR-0005 Amendment 2)
blob was a dead-end: declarable but never fillable (no literal in either mode, seed-unsupported), so a blob column could only ever hold NULL. Remove Type::Blob + Value/CellValue::Blob + the base64 CSV path + the grammar slot + completion/render/type-change/seed handling + the binder refusal (whose message also carried a user-facing "DSL" copy-rule bug). The vocabulary is now nine types; base64 stays (clipboard OSC-52). Backward compat is the ADR-0015 migration framework's first real use: a v1->v2 format bump (CURRENT_SCHEMA_VERSION across serializer/parser/skeleton) with a migrator that rewrites `type: blob` -> `type: text`, and a forced .db rebuild from the migrated text when a blob column was actually converted (the stale .db keeps a STRICT BLOB engine column). Conversion to text is non-destructive and CSV-free. Covered by a full-stack integration test and a Tier-4 PTY test that opens a real legacy v1-blob project. Also sweeps the nine-type vocabulary through CLAUDE.md, requirements.md, the website (type reference, seed doc, highlight grammar), and the ADR-0030/0033/ 0035 cross-references; CHANGELOG Removed entry; handoff-79. BREAKING CHANGE: the `blob` column type is removed. Existing projects that declared a blob column are migrated on first open (the column becomes text; the original project.yaml is kept as a .v1.bak).
This commit is contained in:
@@ -617,69 +617,6 @@ fn seed_refuses_when_a_parent_table_is_empty() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seed_refuses_a_not_null_blob_column() {
|
||||
let (_project, db, _dir) = open_project_db();
|
||||
let rt = rt();
|
||||
let mut payload = ColumnSpec::new("payload", Type::Blob);
|
||||
payload.not_null = true;
|
||||
rt.block_on(db.create_table(
|
||||
"Files".to_string(),
|
||||
vec![ColumnSpec::new("id", Type::Serial), payload],
|
||||
vec!["id".to_string()],
|
||||
None,
|
||||
))
|
||||
.expect("create Files");
|
||||
|
||||
let err = rt
|
||||
.block_on(db.seed(
|
||||
"Files".into(),
|
||||
None,
|
||||
Some(2),
|
||||
Vec::new(),
|
||||
Some(1),
|
||||
Some("seed Files 2".into()),
|
||||
))
|
||||
.expect_err("seed must refuse a NOT NULL blob");
|
||||
let msg = err.to_string();
|
||||
assert!(
|
||||
msg.contains("payload") && msg.to_lowercase().contains("blob"),
|
||||
"error should name the un-generatable blob column: {msg}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seed_omits_a_nullable_blob_column() {
|
||||
let (project, db, _dir) = open_project_db();
|
||||
let rt = rt();
|
||||
rt.block_on(db.create_table(
|
||||
"Files".to_string(),
|
||||
vec![
|
||||
ColumnSpec::new("id", Type::Serial),
|
||||
ColumnSpec::new("name", Type::Text),
|
||||
// nullable blob → omitted (→ NULL), seed still succeeds.
|
||||
ColumnSpec::new("payload", Type::Blob),
|
||||
],
|
||||
vec!["id".to_string()],
|
||||
None,
|
||||
))
|
||||
.expect("create Files");
|
||||
|
||||
let res = rt
|
||||
.block_on(db.seed(
|
||||
"Files".into(),
|
||||
None,
|
||||
Some(3),
|
||||
Vec::new(),
|
||||
Some(1),
|
||||
Some("seed Files 3".into()),
|
||||
))
|
||||
.expect("seed succeeds despite the nullable blob");
|
||||
assert_eq!(res.produced, 3);
|
||||
let csv = read_csv(&project, "Files").expect("Files CSV");
|
||||
assert_eq!(data_row_count(&csv), 3);
|
||||
}
|
||||
|
||||
// — uniqueness, junction distinct-combos, IN-CHECK (D10 / D14 / D17) —
|
||||
|
||||
/// The `n`th comma-separated field of each data row (the generated
|
||||
|
||||
Reference in New Issue
Block a user