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:
+6
-12
@@ -138,7 +138,7 @@ fn range_value(low: &str, high: &str, ty: Type, rng: &mut SeedRng) -> Value {
|
||||
Type::DateTime => parse_datetime_range(low, high)
|
||||
.map(|(lo, hi)| Value::Text(random_datetime_between(rng, lo, hi)))
|
||||
.unwrap_or_else(|| generic_for_type(ty, rng)),
|
||||
// text / bool / blob / shortid have no range meaning.
|
||||
// text / bool / shortid have no range meaning.
|
||||
_ => generic_for_type(ty, rng),
|
||||
}
|
||||
}
|
||||
@@ -155,8 +155,8 @@ pub fn range_bounds_reason(ty: Type, low: &str, high: &str) -> Option<String> {
|
||||
Type::Real | Type::Decimal => parse_real_range(low, high).is_some(),
|
||||
Type::Date => parse_date_range(low, high).is_some(),
|
||||
Type::DateTime => parse_datetime_range(low, high).is_some(),
|
||||
// text / bool / blob / shortid have no range meaning.
|
||||
Type::Text | Type::Bool | Type::Blob | Type::ShortId => false,
|
||||
// text / bool / shortid have no range meaning.
|
||||
Type::Text | Type::Bool | Type::ShortId => false,
|
||||
};
|
||||
if ok {
|
||||
return None;
|
||||
@@ -169,7 +169,7 @@ pub fn range_bounds_reason(ty: Type, low: &str, high: &str) -> Option<String> {
|
||||
"expected two quoted datetimes, e.g. `between '2023-01-01T00:00:00' and '2024-12-31T23:59:59'`"
|
||||
.to_string()
|
||||
}
|
||||
Type::Text | Type::Bool | Type::Blob | Type::ShortId => {
|
||||
Type::Text | Type::Bool | Type::ShortId => {
|
||||
"a `between` range only applies to numeric and date/datetime columns".to_string()
|
||||
}
|
||||
})
|
||||
@@ -242,9 +242,8 @@ fn random_datetime_between(
|
||||
}
|
||||
|
||||
/// Type-based fallback generation (D8). Never produces NULL for a
|
||||
/// generatable type; `blob`/`serial`/`shortid` are handled by the
|
||||
/// executor (autogen / block guard) and yield NULL here only as a
|
||||
/// last resort.
|
||||
/// generatable type; `serial`/`shortid` are handled by the executor
|
||||
/// (autogen) and yield NULL here only as a last resort.
|
||||
fn generic_for_type(ty: Type, rng: &mut SeedRng) -> Value {
|
||||
use fake::faker::lorem::en as lorem;
|
||||
match ty {
|
||||
@@ -267,7 +266,6 @@ fn generic_for_type(ty: Type, rng: &mut SeedRng) -> Value {
|
||||
Type::Bool => Value::Bool(rng.random_range(0..2) == 1),
|
||||
Type::Date => Value::Text(format_date(random_past_date(rng, 0, RECENT_WINDOW_DAYS))),
|
||||
Type::DateTime => Value::Text(random_recent_datetime(rng)),
|
||||
Type::Blob => Value::Null,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -705,10 +703,6 @@ mod tests {
|
||||
generate_value(&Generator::Generic, Type::Bool, &mut rng),
|
||||
Value::Bool(_)
|
||||
));
|
||||
assert!(matches!(
|
||||
generate_value(&Generator::Generic, Type::Blob, &mut rng),
|
||||
Value::Null
|
||||
));
|
||||
// shortid fallback is a valid base58 id.
|
||||
let Value::Text(sid) = generate_value(&Generator::Generic, Type::ShortId, &mut rng) else {
|
||||
panic!("shortid not text")
|
||||
|
||||
Reference in New Issue
Block a user