ailake_catalog/schema_evolution.rs
1// SPDX-License-Identifier: MIT OR Apache-2.0
2//! Schema evolution request types (Phase G).
3//!
4//! `SchemaEvolution` is a pure metadata operation — no data files are rewritten.
5//! `initial-default` in each added field tells readers what value to return for
6//! old files that predate the column. Corresponds to Iceberg V2/V3 spec §4.1.1.
7
8/// Request to add a new column to the table schema.
9///
10/// # Iceberg types
11///
12/// Common type strings: `"int"`, `"long"`, `"float"`, `"double"`,
13/// `"boolean"`, `"string"`, `"date"`, `"timestamp"`, `"timestamptz"`, `"binary"`.
14///
15/// Complex types (`"list<int>"`, `"map<string,long>"`, `"struct<…>"`) are stored
16/// verbatim; `SchemaFiller` maps them to `Utf8` when injecting defaults.
17pub struct AddColumnRequest {
18 pub name: String,
19 /// Iceberg type string — see struct-level doc for accepted values.
20 pub iceberg_type: String,
21 /// `false` (nullable) is the safe default for additions so old files never error.
22 pub required: bool,
23 /// Value returned when reading records from files written before this column existed.
24 /// `None` → readers inject `null` for those rows.
25 pub initial_default: Option<serde_json::Value>,
26 /// Value written to new records when no explicit value is supplied.
27 /// Defaults to `initial_default` when omitted.
28 pub write_default: Option<serde_json::Value>,
29 /// Human-readable field documentation stored in the schema JSON.
30 pub doc: Option<String>,
31}
32
33/// Request to rename an existing column (field-id stays stable).
34pub struct RenameColumnRequest {
35 pub old_name: String,
36 pub new_name: String,
37}
38
39/// Atomic schema evolution transaction applied in a single `metadata.json` rewrite.
40///
41/// Operations are applied in order: renames first (so you can rename a column
42/// and also add a new column with the old name in one call), then additions.
43#[derive(Default)]
44pub struct SchemaEvolution {
45 pub renames: Vec<RenameColumnRequest>,
46 pub adds: Vec<AddColumnRequest>,
47}
48
49impl SchemaEvolution {
50 pub fn new() -> Self {
51 Self::default()
52 }
53
54 pub fn add_column(mut self, req: AddColumnRequest) -> Self {
55 self.adds.push(req);
56 self
57 }
58
59 pub fn rename_column(
60 mut self,
61 old_name: impl Into<String>,
62 new_name: impl Into<String>,
63 ) -> Self {
64 self.renames.push(RenameColumnRequest {
65 old_name: old_name.into(),
66 new_name: new_name.into(),
67 });
68 self
69 }
70}