99//! All changes are made atomically - either all updates succeed or none are applied.
1010//! Requirements are checked first to ensure concurrent modifications don't corrupt state.
1111
12- use std:: collections:: HashMap ;
13-
1412use iceberg_rust_spec:: {
1513 spec:: {
1614 partition:: PartitionSpec ,
@@ -24,6 +22,8 @@ use iceberg_rust_spec::{
2422 view_metadata:: Materialization ,
2523} ;
2624use serde_derive:: { Deserialize , Serialize } ;
25+ use std:: collections:: HashMap ;
26+ use std:: time:: { SystemTime , UNIX_EPOCH } ;
2727use uuid:: Uuid ;
2828
2929use crate :: error:: Error ;
@@ -417,6 +417,9 @@ pub fn apply_table_updates(
417417 metadata : & mut TableMetadata ,
418418 updates : Vec < TableUpdate > ,
419419) -> Result < ( ) , Error > {
420+ let mut added_schema_id = None ;
421+ let mut added_spec_id = None ;
422+ let mut added_sort_order_id = None ;
420423 for update in updates {
421424 match update {
422425 TableUpdate :: UpgradeFormatVersion { format_version } => {
@@ -431,25 +434,63 @@ pub fn apply_table_updates(
431434 schema,
432435 last_column_id,
433436 } => {
434- metadata. schemas . insert ( * schema. schema_id ( ) , schema) ;
437+ let schema_id = * schema. schema_id ( ) ;
438+ metadata. schemas . insert ( schema_id, schema) ;
439+ added_schema_id = Some ( schema_id) ;
435440 if let Some ( last_column_id) = last_column_id {
436441 metadata. last_column_id = last_column_id;
437442 }
438443 }
439444 TableUpdate :: SetCurrentSchema { schema_id } => {
440- metadata. current_schema_id = schema_id;
445+ if schema_id == -1 {
446+ if let Some ( added_schema_id) = added_schema_id {
447+ metadata. current_schema_id = added_schema_id;
448+ } else {
449+ return Err ( Error :: InvalidFormat (
450+ "Cannot set current schema to -1 without adding a schema first"
451+ . to_string ( ) ,
452+ ) ) ;
453+ }
454+ } else {
455+ metadata. current_schema_id = schema_id;
456+ }
441457 }
442458 TableUpdate :: AddSpec { spec } => {
443- metadata. partition_specs . insert ( * spec. spec_id ( ) , spec) ;
459+ let spec_id = * spec. spec_id ( ) ;
460+ metadata. partition_specs . insert ( spec_id, spec) ;
461+ added_spec_id = Some ( spec_id) ;
444462 }
445463 TableUpdate :: SetDefaultSpec { spec_id } => {
446- metadata. default_spec_id = spec_id;
464+ if spec_id == -1 {
465+ if let Some ( added_spec_id) = added_spec_id {
466+ metadata. default_spec_id = added_spec_id;
467+ } else {
468+ return Err ( Error :: InvalidFormat (
469+ "Cannot set default spec to -1 without adding a spec first" . to_string ( ) ,
470+ ) ) ;
471+ }
472+ } else {
473+ metadata. default_spec_id = spec_id;
474+ }
447475 }
448476 TableUpdate :: AddSortOrder { sort_order } => {
449- metadata. sort_orders . insert ( sort_order. order_id , sort_order) ;
477+ let sort_order_id = sort_order. order_id ;
478+ metadata. sort_orders . insert ( sort_order_id, sort_order) ;
479+ added_sort_order_id = Some ( sort_order_id) ;
450480 }
451481 TableUpdate :: SetDefaultSortOrder { sort_order_id } => {
452- metadata. default_sort_order_id = sort_order_id;
482+ if sort_order_id == -1 {
483+ if let Some ( added_sort_order_id) = added_sort_order_id {
484+ metadata. default_sort_order_id = added_sort_order_id;
485+ } else {
486+ return Err ( Error :: InvalidFormat (
487+ "Cannot set default sort order to -1 without adding a sort order first"
488+ . to_string ( ) ,
489+ ) ) ;
490+ }
491+ } else {
492+ metadata. default_sort_order_id = sort_order_id;
493+ }
453494 }
454495 TableUpdate :: AddSnapshot { snapshot } => {
455496 metadata. snapshot_log . push ( SnapshotLog {
@@ -489,6 +530,12 @@ pub fn apply_table_updates(
489530 }
490531 } ;
491532 }
533+
534+ // Lastly make sure `last-updated-ms` field is up-to-date
535+ metadata. last_updated_ms = SystemTime :: now ( )
536+ . duration_since ( UNIX_EPOCH )
537+ . unwrap ( )
538+ . as_millis ( ) as i64 ;
492539 Ok ( ( ) )
493540}
494541
0 commit comments