@@ -32,6 +32,8 @@ use super::{
3232
3333use _serde:: TableMetadataEnum ;
3434
35+ use crate :: error:: Result ;
36+ use crate :: { Error , ErrorKind , TableCreation } ;
3537use chrono:: { DateTime , TimeZone , Utc } ;
3638
3739static 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+
278356pub ( 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