Skip to main content

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}