Skip to content

Commit 39e7e9d

Browse files
authored
feat: init TableMetadataBuilder (#262)
1 parent 71cd44f commit 39e7e9d

File tree

2 files changed

+166
-8
lines changed

2 files changed

+166
-8
lines changed

crates/iceberg/src/catalog/mod.rs

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
//! Catalog API for Apache Iceberg
1919
2020
use crate::spec::{
21-
FormatVersion, Schema, Snapshot, SnapshotReference, SortOrder, UnboundPartitionSpec,
21+
FormatVersion, Schema, Snapshot, SnapshotReference, SortOrder, TableMetadataBuilder,
22+
UnboundPartitionSpec,
2223
};
2324
use crate::table::Table;
2425
use crate::{Error, ErrorKind, Result};
@@ -427,14 +428,24 @@ pub enum TableUpdate {
427428
},
428429
}
429430

431+
impl TableUpdate {
432+
/// Applies the update to the table metadata builder.
433+
pub fn apply(self, builder: TableMetadataBuilder) -> Result<TableMetadataBuilder> {
434+
match self {
435+
TableUpdate::AssignUuid { uuid } => builder.assign_uuid(uuid),
436+
_ => unimplemented!(),
437+
}
438+
}
439+
}
440+
430441
#[cfg(test)]
431442
mod tests {
432443
use crate::spec::{
433444
FormatVersion, NestedField, NullOrder, Operation, PrimitiveType, Schema, Snapshot,
434445
SnapshotReference, SnapshotRetention, SortDirection, SortField, SortOrder, Summary,
435-
Transform, Type, UnboundPartitionField, UnboundPartitionSpec,
446+
TableMetadataBuilder, Transform, Type, UnboundPartitionField, UnboundPartitionSpec,
436447
};
437-
use crate::{NamespaceIdent, TableIdent, TableRequirement, TableUpdate};
448+
use crate::{NamespaceIdent, TableCreation, TableIdent, TableRequirement, TableUpdate};
438449
use serde::de::DeserializeOwned;
439450
use serde::Serialize;
440451
use std::collections::HashMap;
@@ -1065,4 +1076,28 @@ mod tests {
10651076

10661077
test_serde_json(json, update);
10671078
}
1079+
1080+
#[test]
1081+
fn test_table_update_apply() {
1082+
let table_creation = TableCreation::builder()
1083+
.location("s3://db/table".to_string())
1084+
.name("table".to_string())
1085+
.properties(HashMap::new())
1086+
.schema(Schema::builder().build().unwrap())
1087+
.build();
1088+
let table_metadata = TableMetadataBuilder::from_table_creation(table_creation)
1089+
.unwrap()
1090+
.build()
1091+
.unwrap();
1092+
let table_metadata_builder = TableMetadataBuilder::new(table_metadata);
1093+
1094+
let uuid = uuid::Uuid::new_v4();
1095+
let update = TableUpdate::AssignUuid { uuid };
1096+
let updated_metadata = update
1097+
.apply(table_metadata_builder)
1098+
.unwrap()
1099+
.build()
1100+
.unwrap();
1101+
assert_eq!(updated_metadata.uuid(), uuid);
1102+
}
10681103
}

crates/iceberg/src/spec/table_metadata.rs

Lines changed: 128 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ use super::{
3232

3333
use _serde::TableMetadataEnum;
3434

35+
use crate::error::Result;
36+
use crate::{Error, ErrorKind, TableCreation};
3537
use chrono::{DateTime, TimeZone, Utc};
3638

3739
static MAIN_BRANCH: &str = "main";
@@ -275,6 +277,82 @@ impl TableMetadata {
275277
}
276278
}
277279

280+
/// Manipulating table metadata.
281+
pub struct TableMetadataBuilder(TableMetadata);
282+
283+
impl TableMetadataBuilder {
284+
/// Creates a new table metadata builder from the given table metadata.
285+
pub fn new(origin: TableMetadata) -> Self {
286+
Self(origin)
287+
}
288+
289+
/// Creates a new table metadata builder from the given table creation.
290+
pub fn from_table_creation(table_creation: TableCreation) -> Result<Self> {
291+
let TableCreation {
292+
name: _,
293+
location,
294+
schema,
295+
partition_spec,
296+
sort_order,
297+
properties,
298+
} = table_creation;
299+
300+
if partition_spec.is_some() {
301+
return Err(Error::new(
302+
ErrorKind::FeatureUnsupported,
303+
"Can't create table with partition spec now",
304+
));
305+
}
306+
307+
if sort_order.is_some() {
308+
return Err(Error::new(
309+
ErrorKind::FeatureUnsupported,
310+
"Can't create table with sort order now",
311+
));
312+
}
313+
314+
let table_metadata = TableMetadata {
315+
format_version: FormatVersion::V2,
316+
table_uuid: Uuid::new_v4(),
317+
location: location.ok_or_else(|| {
318+
Error::new(
319+
ErrorKind::DataInvalid,
320+
"Can't create table without location",
321+
)
322+
})?,
323+
last_sequence_number: 0,
324+
last_updated_ms: Utc::now().timestamp_millis(),
325+
last_column_id: schema.highest_field_id(),
326+
current_schema_id: schema.schema_id(),
327+
schemas: HashMap::from([(schema.schema_id(), Arc::new(schema))]),
328+
partition_specs: Default::default(),
329+
default_spec_id: 0,
330+
last_partition_id: 0,
331+
properties,
332+
current_snapshot_id: None,
333+
snapshots: Default::default(),
334+
snapshot_log: vec![],
335+
sort_orders: Default::default(),
336+
metadata_log: vec![],
337+
default_sort_order_id: 0,
338+
refs: Default::default(),
339+
};
340+
341+
Ok(Self(table_metadata))
342+
}
343+
344+
/// Changes uuid of table metadata.
345+
pub fn assign_uuid(mut self, uuid: Uuid) -> Result<Self> {
346+
self.0.table_uuid = uuid;
347+
Ok(self)
348+
}
349+
350+
/// Returns the new table metadata after changes.
351+
pub fn build(self) -> Result<TableMetadata> {
352+
Ok(self.0)
353+
}
354+
}
355+
278356
pub(super) mod _serde {
279357
/// This is a helper module that defines types to help with serialization/deserialization.
280358
/// For deserialization the input first gets read into either the [TableMetadataV1] or [TableMetadataV2] struct
@@ -838,13 +916,16 @@ mod tests {
838916

839917
use pretty_assertions::assert_eq;
840918

841-
use crate::spec::{
842-
table_metadata::TableMetadata, NestedField, NullOrder, Operation, PartitionField,
843-
PartitionSpec, PrimitiveType, Schema, Snapshot, SnapshotReference, SnapshotRetention,
844-
SortDirection, SortField, SortOrder, Summary, Transform, Type,
919+
use crate::{
920+
spec::{
921+
table_metadata::TableMetadata, NestedField, NullOrder, Operation, PartitionField,
922+
PartitionSpec, PrimitiveType, Schema, Snapshot, SnapshotReference, SnapshotRetention,
923+
SortDirection, SortField, SortOrder, Summary, Transform, Type,
924+
},
925+
TableCreation,
845926
};
846927

847-
use super::{FormatVersion, MetadataLog, SnapshotLog};
928+
use super::{FormatVersion, MetadataLog, SnapshotLog, TableMetadataBuilder};
848929

849930
fn check_table_metadata_serde(json: &str, expected_type: TableMetadata) {
850931
let desered_type: TableMetadata = serde_json::from_str(json).unwrap();
@@ -1569,4 +1650,46 @@ mod tests {
15691650
table_meta_data.sort_orders.get(&default_sort_order_id)
15701651
)
15711652
}
1653+
1654+
#[test]
1655+
fn test_table_metadata_builder_from_table_creation() {
1656+
let table_creation = TableCreation::builder()
1657+
.location("s3://db/table".to_string())
1658+
.name("table".to_string())
1659+
.properties(HashMap::new())
1660+
.schema(Schema::builder().build().unwrap())
1661+
.build();
1662+
let table_metadata = TableMetadataBuilder::from_table_creation(table_creation)
1663+
.unwrap()
1664+
.build()
1665+
.unwrap();
1666+
assert_eq!(table_metadata.location, "s3://db/table");
1667+
assert_eq!(table_metadata.schemas.len(), 1);
1668+
assert_eq!(
1669+
table_metadata
1670+
.schemas
1671+
.get(&0)
1672+
.unwrap()
1673+
.as_struct()
1674+
.fields()
1675+
.len(),
1676+
0
1677+
);
1678+
assert_eq!(table_metadata.partition_specs.len(), 0);
1679+
assert_eq!(table_metadata.properties.len(), 0);
1680+
assert_eq!(table_metadata.sort_orders.len(), 0);
1681+
}
1682+
1683+
#[test]
1684+
fn test_table_builder_from_table_metadata() {
1685+
let table_metadata = get_test_table_metadata("TableMetadataV2Valid.json");
1686+
let table_metadata_builder = TableMetadataBuilder::new(table_metadata);
1687+
let uuid = Uuid::new_v4();
1688+
let table_metadata = table_metadata_builder
1689+
.assign_uuid(uuid)
1690+
.unwrap()
1691+
.build()
1692+
.unwrap();
1693+
assert_eq!(table_metadata.uuid(), uuid);
1694+
}
15721695
}

0 commit comments

Comments
 (0)