@@ -42,7 +42,7 @@ use crate::client::{
42
42
use crate :: types:: {
43
43
CatalogConfig , CommitTableRequest , CommitTableResponse , CreateTableRequest ,
44
44
ListNamespaceResponse , ListTableResponse , LoadTableResponse , NamespaceSerde ,
45
- RenameTableRequest ,
45
+ RegisterTableRequest , RenameTableRequest ,
46
46
} ;
47
47
48
48
const ICEBERG_REST_SPEC_VERSION : & str = "0.14.1" ;
@@ -101,6 +101,10 @@ impl RestCatalogConfig {
101
101
self . url_prefixed ( & [ "tables" , "rename" ] )
102
102
}
103
103
104
+ fn register_table_endpoint ( & self , ns : & NamespaceIdent ) -> String {
105
+ self . url_prefixed ( & [ "namespaces" , & ns. to_url_string ( ) , "register" ] )
106
+ }
107
+
104
108
fn table_endpoint ( & self , table : & TableIdent ) -> String {
105
109
self . url_prefixed ( & [
106
110
"namespaces" ,
@@ -238,7 +242,7 @@ struct RestContext {
238
242
pub struct RestCatalog {
239
243
/// User config is stored as-is and never be changed.
240
244
///
241
- /// It's could be different from the config fetched from the server and used at runtime.
245
+ /// It could be different from the config fetched from the server and used at runtime.
242
246
user_config : RestCatalogConfig ,
243
247
ctx : OnceCell < RestContext > ,
244
248
/// Extensions for the FileIOBuilder.
@@ -755,13 +759,60 @@ impl Catalog for RestCatalog {
755
759
756
760
async fn register_table (
757
761
& self ,
758
- _table_ident : & TableIdent ,
759
- _metadata_location : String ,
762
+ table_ident : & TableIdent ,
763
+ metadata_location : String ,
760
764
) -> Result < Table > {
761
- Err ( Error :: new (
762
- ErrorKind :: FeatureUnsupported ,
763
- "Registering a table is not supported yet" ,
764
- ) )
765
+ let context = self . context ( ) . await ?;
766
+
767
+ let request = context
768
+ . client
769
+ . request (
770
+ Method :: POST ,
771
+ context
772
+ . config
773
+ . register_table_endpoint ( table_ident. namespace ( ) ) ,
774
+ )
775
+ . json ( & RegisterTableRequest {
776
+ name : table_ident. name . clone ( ) ,
777
+ metadata_location : metadata_location. clone ( ) ,
778
+ overwrite : Some ( false ) ,
779
+ } )
780
+ . build ( ) ?;
781
+
782
+ let http_response = context. client . query_catalog ( request) . await ?;
783
+
784
+ let response: LoadTableResponse = match http_response. status ( ) {
785
+ StatusCode :: OK => {
786
+ deserialize_catalog_response :: < LoadTableResponse > ( http_response) . await ?
787
+ }
788
+ StatusCode :: NOT_FOUND => {
789
+ return Err ( Error :: new (
790
+ ErrorKind :: NamespaceNotFound ,
791
+ "The namespace specified does not exist." ,
792
+ ) ) ;
793
+ }
794
+ StatusCode :: CONFLICT => {
795
+ return Err ( Error :: new (
796
+ ErrorKind :: TableAlreadyExists ,
797
+ "The given table already exists." ,
798
+ ) ) ;
799
+ }
800
+ _ => return Err ( deserialize_unexpected_catalog_error ( http_response) . await ) ,
801
+ } ;
802
+
803
+ let metadata_location = response. metadata_location . as_ref ( ) . ok_or ( Error :: new (
804
+ ErrorKind :: DataInvalid ,
805
+ "Metadata location missing in `register_table` response!" ,
806
+ ) ) ?;
807
+
808
+ let file_io = self . load_file_io ( Some ( metadata_location) , None ) . await ?;
809
+
810
+ Table :: builder ( )
811
+ . identifier ( table_ident. clone ( ) )
812
+ . file_io ( file_io)
813
+ . metadata ( response. metadata )
814
+ . metadata_location ( metadata_location. clone ( ) )
815
+ . build ( )
765
816
}
766
817
767
818
async fn update_table ( & self , mut commit : TableCommit ) -> Result < Table > {
@@ -2470,4 +2521,87 @@ mod tests {
2470
2521
update_table_mock. assert_async ( ) . await ;
2471
2522
load_table_mock. assert_async ( ) . await ;
2472
2523
}
2524
+
2525
+ #[ tokio:: test]
2526
+ async fn test_register_table ( ) {
2527
+ let mut server = Server :: new_async ( ) . await ;
2528
+
2529
+ let config_mock = create_config_mock ( & mut server) . await ;
2530
+
2531
+ let register_table_mock = server
2532
+ . mock ( "POST" , "/v1/namespaces/ns1/register" )
2533
+ . with_status ( 200 )
2534
+ . with_body_from_file ( format ! (
2535
+ "{}/testdata/{}" ,
2536
+ env!( "CARGO_MANIFEST_DIR" ) ,
2537
+ "load_table_response.json"
2538
+ ) )
2539
+ . create_async ( )
2540
+ . await ;
2541
+
2542
+ let catalog = RestCatalog :: new ( RestCatalogConfig :: builder ( ) . uri ( server. url ( ) ) . build ( ) ) ;
2543
+ let table_ident =
2544
+ TableIdent :: new ( NamespaceIdent :: new ( "ns1" . to_string ( ) ) , "test1" . to_string ( ) ) ;
2545
+ let metadata_location = String :: from (
2546
+ "s3://warehouse/database/table/metadata/00001-5f2f8166-244c-4eae-ac36-384ecdec81fc.gz.metadata.json" ,
2547
+ ) ;
2548
+
2549
+ let table = catalog
2550
+ . register_table ( & table_ident, metadata_location)
2551
+ . await
2552
+ . unwrap ( ) ;
2553
+
2554
+ assert_eq ! (
2555
+ & TableIdent :: from_strs( vec![ "ns1" , "test1" ] ) . unwrap( ) ,
2556
+ table. identifier( )
2557
+ ) ;
2558
+ assert_eq ! (
2559
+ "s3://warehouse/database/table/metadata/00001-5f2f8166-244c-4eae-ac36-384ecdec81fc.gz.metadata.json" ,
2560
+ table. metadata_location( ) . unwrap( )
2561
+ ) ;
2562
+
2563
+ config_mock. assert_async ( ) . await ;
2564
+ register_table_mock. assert_async ( ) . await ;
2565
+ }
2566
+
2567
+ #[ tokio:: test]
2568
+ async fn test_register_table_404 ( ) {
2569
+ let mut server = Server :: new_async ( ) . await ;
2570
+
2571
+ let config_mock = create_config_mock ( & mut server) . await ;
2572
+
2573
+ let register_table_mock = server
2574
+ . mock ( "POST" , "/v1/namespaces/ns1/register" )
2575
+ . with_status ( 404 )
2576
+ . with_body (
2577
+ r#"
2578
+ {
2579
+ "error": {
2580
+ "message": "The namespace specified does not exist",
2581
+ "type": "NoSuchNamespaceErrorException",
2582
+ "code": 404
2583
+ }
2584
+ }
2585
+ "# ,
2586
+ )
2587
+ . create_async ( )
2588
+ . await ;
2589
+
2590
+ let catalog = RestCatalog :: new ( RestCatalogConfig :: builder ( ) . uri ( server. url ( ) ) . build ( ) ) ;
2591
+
2592
+ let table_ident =
2593
+ TableIdent :: new ( NamespaceIdent :: new ( "ns1" . to_string ( ) ) , "test1" . to_string ( ) ) ;
2594
+ let metadata_location = String :: from (
2595
+ "s3://warehouse/database/table/metadata/00001-5f2f8166-244c-4eae-ac36-384ecdec81fc.gz.metadata.json" ,
2596
+ ) ;
2597
+ let table = catalog
2598
+ . register_table ( & table_ident, metadata_location)
2599
+ . await ;
2600
+
2601
+ assert ! ( table. is_err( ) ) ;
2602
+ assert ! ( table. err( ) . unwrap( ) . message( ) . contains( "does not exist" ) ) ;
2603
+
2604
+ config_mock. assert_async ( ) . await ;
2605
+ register_table_mock. assert_async ( ) . await ;
2606
+ }
2473
2607
}
0 commit comments