1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//! Core Catalog trait for Iceberg catalogs
//! New design - simpler than iceberg-rust
use async_trait::async_trait;
use std::collections::HashMap;
use crate::error::Result;
use crate::io::FileIO;
use crate::spec::{NamespaceIdent, TableCreation, TableIdent};
use crate::table::Table;
/// Core catalog operations for Iceberg tables
#[cfg_attr(not(target_family = "wasm"), async_trait)]
#[cfg_attr(target_family = "wasm", async_trait(?Send))]
pub trait Catalog: Send + Sync {
/// Get the FileIO for reading/writing data files
fn file_io(&self) -> &FileIO;
/// Create a namespace (idempotent - returns Ok if already exists)
async fn create_namespace(
&self,
namespace: &NamespaceIdent,
properties: HashMap<String, String>,
) -> Result<()>;
/// Check if a namespace exists
async fn namespace_exists(&self, namespace: &NamespaceIdent) -> Result<bool>;
/// List all namespaces in the catalog
async fn list_namespaces(&self) -> Result<Vec<NamespaceIdent>> {
Err(crate::error::Error::invalid_input(
"list_namespaces not implemented for this catalog",
))
}
/// List all tables in a namespace
async fn list_tables(&self, namespace: &NamespaceIdent) -> Result<Vec<TableIdent>>;
/// Check if a table exists
async fn table_exists(&self, identifier: &TableIdent) -> Result<bool>;
/// Create a new table
async fn create_table(
&self,
namespace: &NamespaceIdent,
creation: TableCreation,
) -> Result<Table>;
/// Load an existing table
async fn load_table(&self, identifier: &TableIdent) -> Result<Table>;
/// Delete a table
async fn drop_table(&self, identifier: &TableIdent) -> Result<()>;
/// Update table metadata location atomically
///
/// This method atomically updates the catalog's pointer to the table metadata.
/// If the current metadata location doesn't match `old_metadata_location`,
/// returns a ConcurrentModification error.
///
/// # Arguments
/// * `identifier` - The table identifier
/// * `old_metadata_location` - Expected current metadata location (for optimistic locking)
/// * `new_metadata_location` - New metadata location to set
async fn update_table_metadata(
&self,
identifier: &TableIdent,
old_metadata_location: &str,
new_metadata_location: &str,
) -> Result<()>;
/// Update table schema (optional, for schema evolution support)
///
/// This method updates the table's schema by writing new metadata with the updated schema
/// and atomically updating the catalog pointer. The default implementation returns an error
/// indicating schema evolution is not supported for this catalog type.
///
/// # Arguments
/// * `identifier` - The table identifier
/// * `new_schema` - The new schema to apply
///
/// # Returns
/// The updated Table with the new schema
async fn update_table_schema(
&self,
_identifier: &TableIdent,
_new_schema: crate::spec::Schema,
) -> Result<Table> {
Err(crate::error::Error::invalid_input(
"Schema evolution not supported for this catalog implementation",
))
}
/// Expire (remove) snapshots from a table by their IDs
///
/// This method removes the specified snapshots from the table metadata,
/// allowing their associated data files to be garbage collected.
///
/// # Arguments
/// * `identifier` - The table identifier
/// * `snapshot_ids` - List of snapshot IDs to expire
///
/// # Returns
/// Ok(()) if successful, error otherwise
///
/// # Notes
/// - The current snapshot cannot be expired
/// - Snapshots referenced by branches or tags should not be expired
async fn expire_snapshots(
&self,
_identifier: &TableIdent,
_snapshot_ids: &[i64],
) -> Result<()> {
Err(crate::error::Error::invalid_input(
"Snapshot expiration not supported for this catalog implementation",
))
}
}