@@ -37,6 +37,7 @@ use super::{
3737 SnapshotRef , SnapshotRetention , SortOrder , SortOrderRef , StatisticsFile , StructType ,
3838} ;
3939use crate :: error:: { Result , timestamp_ms_to_utc} ;
40+ use crate :: io:: FileIO ;
4041use crate :: { Error , ErrorKind } ;
4142
4243static MAIN_BRANCH : & str = "main" ;
@@ -464,6 +465,29 @@ impl TableMetadata {
464465 self . encryption_keys . get ( key_id)
465466 }
466467
468+ /// Read table metadata from the given location.
469+ pub async fn read_from (
470+ file_io : & FileIO ,
471+ metadata_location : impl AsRef < str > ,
472+ ) -> Result < TableMetadata > {
473+ let input_file = file_io. new_input ( metadata_location) ?;
474+ let metadata_content = input_file. read ( ) . await ?;
475+ let metadata = serde_json:: from_slice :: < TableMetadata > ( & metadata_content) ?;
476+ Ok ( metadata)
477+ }
478+
479+ /// Write table metadata to the given location.
480+ pub async fn write_to (
481+ & self ,
482+ file_io : & FileIO ,
483+ metadata_location : impl AsRef < str > ,
484+ ) -> Result < ( ) > {
485+ file_io
486+ . new_output ( metadata_location) ?
487+ . write ( serde_json:: to_vec ( self ) ?. into ( ) )
488+ . await
489+ }
490+
467491 /// Normalize this partition spec.
468492 ///
469493 /// This is an internal method
@@ -1355,10 +1379,12 @@ mod tests {
13551379
13561380 use anyhow:: Result ;
13571381 use pretty_assertions:: assert_eq;
1382+ use tempfile:: TempDir ;
13581383 use uuid:: Uuid ;
13591384
13601385 use super :: { FormatVersion , MetadataLog , SnapshotLog , TableMetadataBuilder } ;
13611386 use crate :: TableCreation ;
1387+ use crate :: io:: FileIOBuilder ;
13621388 use crate :: spec:: table_metadata:: TableMetadata ;
13631389 use crate :: spec:: {
13641390 BlobMetadata , NestedField , NullOrder , Operation , PartitionSpec , PartitionStatisticsFile ,
@@ -3050,4 +3076,49 @@ mod tests {
30503076 ) ] )
30513077 ) ;
30523078 }
3079+
3080+ #[ tokio:: test]
3081+ async fn test_table_metadata_io_read_write ( ) {
3082+ // Create a temporary directory for our test
3083+ let temp_dir = TempDir :: new ( ) . unwrap ( ) ;
3084+ let temp_path = temp_dir. path ( ) . to_str ( ) . unwrap ( ) ;
3085+
3086+ // Create a FileIO instance
3087+ let file_io = FileIOBuilder :: new_fs_io ( ) . build ( ) . unwrap ( ) ;
3088+
3089+ // Use an existing test metadata from the test files
3090+ let original_metadata: TableMetadata = get_test_table_metadata ( "TableMetadataV2Valid.json" ) ;
3091+
3092+ // Define the metadata location
3093+ let metadata_location = format ! ( "{}/metadata.json" , temp_path) ;
3094+
3095+ // Write the metadata
3096+ original_metadata
3097+ . write_to ( & file_io, & metadata_location)
3098+ . await
3099+ . unwrap ( ) ;
3100+
3101+ // Verify the file exists
3102+ assert ! ( fs:: metadata( & metadata_location) . is_ok( ) ) ;
3103+
3104+ // Read the metadata back
3105+ let read_metadata = TableMetadata :: read_from ( & file_io, & metadata_location)
3106+ . await
3107+ . unwrap ( ) ;
3108+
3109+ // Verify the metadata matches
3110+ assert_eq ! ( read_metadata, original_metadata) ;
3111+ }
3112+
3113+ #[ tokio:: test]
3114+ async fn test_table_metadata_io_read_nonexistent_file ( ) {
3115+ // Create a FileIO instance
3116+ let file_io = FileIOBuilder :: new_fs_io ( ) . build ( ) . unwrap ( ) ;
3117+
3118+ // Try to read a non-existent file
3119+ let result = TableMetadata :: read_from ( & file_io, "/nonexistent/path/metadata.json" ) . await ;
3120+
3121+ // Verify it returns an error
3122+ assert ! ( result. is_err( ) ) ;
3123+ }
30533124}
0 commit comments