lance_namespace/
rest.rs

1//! REST implementation of Lance Namespace
2
3use std::collections::HashMap;
4
5use async_trait::async_trait;
6use bytes::Bytes;
7
8use lance_namespace_reqwest_client::{
9    apis::{configuration::Configuration, namespace_api, table_api, transaction_api},
10    models::{
11        AlterTransactionRequest, AlterTransactionResponse, CountTableRowsRequest,
12        CreateEmptyTableRequest, CreateEmptyTableResponse, CreateNamespaceRequest,
13        CreateNamespaceResponse, CreateTableIndexRequest, CreateTableIndexResponse,
14        CreateTableRequest, CreateTableResponse, DeleteFromTableRequest, DeleteFromTableResponse,
15        DeregisterTableRequest, DeregisterTableResponse, DescribeNamespaceRequest,
16        DescribeNamespaceResponse, DescribeTableIndexStatsRequest, DescribeTableIndexStatsResponse,
17        DescribeTableRequest, DescribeTableResponse, DescribeTransactionRequest,
18        DescribeTransactionResponse, DropNamespaceRequest, DropNamespaceResponse, DropTableRequest,
19        DropTableResponse, InsertIntoTableRequest, InsertIntoTableResponse, ListNamespacesRequest,
20        ListNamespacesResponse, ListTableIndicesRequest, ListTableIndicesResponse,
21        ListTablesRequest, ListTablesResponse, MergeInsertIntoTableRequest,
22        MergeInsertIntoTableResponse, NamespaceExistsRequest, QueryTableRequest,
23        RegisterTableRequest, RegisterTableResponse, TableExistsRequest, UpdateTableRequest,
24        UpdateTableResponse,
25    },
26};
27
28use crate::namespace::{LanceNamespace, NamespaceError, Result};
29
30/// Configuration for REST namespace
31#[derive(Debug, Clone)]
32pub struct RestNamespaceConfig {
33    /// The delimiter used for object identifiers
34    delimiter: String,
35    /// Additional headers to send with requests
36    additional_headers: HashMap<String, String>,
37    /// The base URI for the REST API
38    uri: Option<String>,
39}
40
41impl RestNamespaceConfig {
42    /// Header prefix for additional headers
43    const HEADER_PREFIX: &'static str = "header.";
44
45    /// Default delimiter
46    const DEFAULT_DELIMITER: &'static str = ".";
47
48    /// Create a new configuration from a map of properties
49    pub fn new(properties: HashMap<String, String>) -> Self {
50        let delimiter = properties
51            .get("delimiter")
52            .cloned()
53            .unwrap_or_else(|| Self::DEFAULT_DELIMITER.to_string());
54
55        let uri = properties.get("uri").cloned();
56
57        let mut additional_headers = HashMap::new();
58        for (key, value) in &properties {
59            if key.starts_with(Self::HEADER_PREFIX) {
60                let header_name = &key[Self::HEADER_PREFIX.len()..];
61                additional_headers.insert(header_name.to_string(), value.clone());
62            }
63        }
64
65        Self {
66            delimiter,
67            additional_headers,
68            uri,
69        }
70    }
71
72    /// Get the delimiter
73    pub fn delimiter(&self) -> &str {
74        &self.delimiter
75    }
76
77    /// Get additional headers
78    pub fn additional_headers(&self) -> &HashMap<String, String> {
79        &self.additional_headers
80    }
81
82    /// Get the URI
83    pub fn uri(&self) -> Option<&str> {
84        self.uri.as_deref()
85    }
86}
87
88/// Convert an object identifier (list of strings) to a delimited string
89fn object_id_str(id: &Option<Vec<String>>, delimiter: &str) -> Result<String> {
90    match id {
91        Some(id_parts) if !id_parts.is_empty() => Ok(id_parts.join(delimiter)),
92        Some(_) => Ok(delimiter.to_string()),
93        None => Err(NamespaceError::Other("Object ID is required".to_string())),
94    }
95}
96
97/// Convert API error to namespace error
98fn convert_api_error<T: std::fmt::Debug>(
99    err: lance_namespace_reqwest_client::apis::Error<T>,
100) -> NamespaceError {
101    use lance_namespace_reqwest_client::apis::Error;
102    match err {
103        Error::Reqwest(e) => NamespaceError::Io(std::io::Error::new(
104            std::io::ErrorKind::Other,
105            e.to_string(),
106        )),
107        Error::Serde(e) => NamespaceError::Other(format!("Serialization error: {}", e)),
108        Error::Io(e) => NamespaceError::Io(e),
109        Error::ResponseError(e) => NamespaceError::Other(format!("Response error: {:?}", e)),
110    }
111}
112
113/// REST implementation of Lance Namespace
114pub struct RestNamespace {
115    config: RestNamespaceConfig,
116    reqwest_config: Configuration,
117}
118
119impl RestNamespace {
120    /// Create a new REST namespace with the given configuration
121    pub fn new(properties: HashMap<String, String>) -> Self {
122        let config = RestNamespaceConfig::new(properties);
123
124        // Build reqwest client with custom headers if provided
125        let mut client_builder = reqwest::Client::builder();
126
127        // Add custom headers to the client
128        if !config.additional_headers().is_empty() {
129            let mut headers = reqwest::header::HeaderMap::new();
130            for (key, value) in config.additional_headers() {
131                if let (Ok(header_name), Ok(header_value)) = (
132                    reqwest::header::HeaderName::from_bytes(key.as_bytes()),
133                    reqwest::header::HeaderValue::from_str(value),
134                ) {
135                    headers.insert(header_name, header_value);
136                }
137            }
138            client_builder = client_builder.default_headers(headers);
139        }
140
141        let client = client_builder
142            .build()
143            .unwrap_or_else(|_| reqwest::Client::new());
144
145        let mut reqwest_config = Configuration::new();
146        reqwest_config.client = client;
147        if let Some(uri) = config.uri() {
148            reqwest_config.base_path = uri.to_string();
149        }
150
151        Self {
152            config,
153            reqwest_config,
154        }
155    }
156
157    /// Create a new REST namespace with custom configuration (for testing)
158    #[cfg(test)]
159    pub fn with_configuration(
160        properties: HashMap<String, String>,
161        reqwest_config: Configuration,
162    ) -> Self {
163        let config = RestNamespaceConfig::new(properties);
164
165        Self {
166            config,
167            reqwest_config,
168        }
169    }
170}
171
172#[async_trait]
173impl LanceNamespace for RestNamespace {
174    async fn list_namespaces(
175        &self,
176        request: ListNamespacesRequest,
177    ) -> Result<ListNamespacesResponse> {
178        let id = object_id_str(&request.id, self.config.delimiter())?;
179
180        namespace_api::list_namespaces(
181            &self.reqwest_config,
182            &id,
183            Some(self.config.delimiter()),
184            request.page_token.as_deref(),
185            request.limit,
186        )
187        .await
188        .map_err(convert_api_error)
189    }
190
191    async fn describe_namespace(
192        &self,
193        request: DescribeNamespaceRequest,
194    ) -> Result<DescribeNamespaceResponse> {
195        let id = object_id_str(&request.id, self.config.delimiter())?;
196
197        namespace_api::describe_namespace(
198            &self.reqwest_config,
199            &id,
200            request,
201            Some(self.config.delimiter()),
202        )
203        .await
204        .map_err(convert_api_error)
205    }
206
207    async fn create_namespace(
208        &self,
209        request: CreateNamespaceRequest,
210    ) -> Result<CreateNamespaceResponse> {
211        let id = object_id_str(&request.id, self.config.delimiter())?;
212
213        namespace_api::create_namespace(
214            &self.reqwest_config,
215            &id,
216            request,
217            Some(self.config.delimiter()),
218        )
219        .await
220        .map_err(convert_api_error)
221    }
222
223    async fn drop_namespace(&self, request: DropNamespaceRequest) -> Result<DropNamespaceResponse> {
224        let id = object_id_str(&request.id, self.config.delimiter())?;
225
226        namespace_api::drop_namespace(
227            &self.reqwest_config,
228            &id,
229            request,
230            Some(self.config.delimiter()),
231        )
232        .await
233        .map_err(convert_api_error)
234    }
235
236    async fn namespace_exists(&self, request: NamespaceExistsRequest) -> Result<()> {
237        let id = object_id_str(&request.id, self.config.delimiter())?;
238
239        namespace_api::namespace_exists(
240            &self.reqwest_config,
241            &id,
242            request,
243            Some(self.config.delimiter()),
244        )
245        .await
246        .map_err(convert_api_error)
247    }
248
249    async fn list_tables(&self, request: ListTablesRequest) -> Result<ListTablesResponse> {
250        let id = object_id_str(&request.id, self.config.delimiter())?;
251
252        table_api::list_tables(
253            &self.reqwest_config,
254            &id,
255            Some(self.config.delimiter()),
256            request.page_token.as_deref(),
257            request.limit,
258        )
259        .await
260        .map_err(convert_api_error)
261    }
262
263    async fn describe_table(&self, request: DescribeTableRequest) -> Result<DescribeTableResponse> {
264        let id = object_id_str(&request.id, self.config.delimiter())?;
265
266        table_api::describe_table(
267            &self.reqwest_config,
268            &id,
269            request,
270            Some(self.config.delimiter()),
271        )
272        .await
273        .map_err(convert_api_error)
274    }
275
276    async fn register_table(&self, request: RegisterTableRequest) -> Result<RegisterTableResponse> {
277        let id = object_id_str(&request.id, self.config.delimiter())?;
278
279        table_api::register_table(
280            &self.reqwest_config,
281            &id,
282            request,
283            Some(self.config.delimiter()),
284        )
285        .await
286        .map_err(convert_api_error)
287    }
288
289    async fn table_exists(&self, request: TableExistsRequest) -> Result<()> {
290        let id = object_id_str(&request.id, self.config.delimiter())?;
291
292        table_api::table_exists(
293            &self.reqwest_config,
294            &id,
295            request,
296            Some(self.config.delimiter()),
297        )
298        .await
299        .map_err(convert_api_error)
300    }
301
302    async fn drop_table(&self, request: DropTableRequest) -> Result<DropTableResponse> {
303        let id = object_id_str(&request.id, self.config.delimiter())?;
304
305        table_api::drop_table(
306            &self.reqwest_config,
307            &id,
308            request,
309            Some(self.config.delimiter()),
310        )
311        .await
312        .map_err(convert_api_error)
313    }
314
315    async fn deregister_table(
316        &self,
317        request: DeregisterTableRequest,
318    ) -> Result<DeregisterTableResponse> {
319        let id = object_id_str(&request.id, self.config.delimiter())?;
320
321        table_api::deregister_table(
322            &self.reqwest_config,
323            &id,
324            request,
325            Some(self.config.delimiter()),
326        )
327        .await
328        .map_err(convert_api_error)
329    }
330
331    async fn count_table_rows(&self, request: CountTableRowsRequest) -> Result<i64> {
332        let id = object_id_str(&request.id, self.config.delimiter())?;
333
334        table_api::count_table_rows(
335            &self.reqwest_config,
336            &id,
337            request,
338            Some(self.config.delimiter()),
339        )
340        .await
341        .map_err(convert_api_error)
342    }
343
344    async fn create_table(
345        &self,
346        request: CreateTableRequest,
347        request_data: Bytes,
348    ) -> Result<CreateTableResponse> {
349        let id = object_id_str(&request.id, self.config.delimiter())?;
350
351        let properties_json = request
352            .properties
353            .as_ref()
354            .map(|props| serde_json::to_string(props).unwrap_or_else(|_| "{}".to_string()));
355
356        use lance_namespace_reqwest_client::models::create_table_request::Mode;
357        let mode = request.mode.as_ref().map(|m| match m {
358            Mode::Create => "create",
359            Mode::ExistOk => "exist_ok",
360            Mode::Overwrite => "overwrite",
361        });
362
363        table_api::create_table(
364            &self.reqwest_config,
365            &id,
366            request_data.to_vec(),
367            Some(self.config.delimiter()),
368            mode,
369            request.location.as_deref(),
370            properties_json.as_deref(),
371        )
372        .await
373        .map_err(convert_api_error)
374    }
375
376    async fn create_empty_table(
377        &self,
378        request: CreateEmptyTableRequest,
379    ) -> Result<CreateEmptyTableResponse> {
380        let id = object_id_str(&request.id, self.config.delimiter())?;
381
382        table_api::create_empty_table(
383            &self.reqwest_config,
384            &id,
385            request,
386            Some(self.config.delimiter()),
387        )
388        .await
389        .map_err(convert_api_error)
390    }
391
392    async fn insert_into_table(
393        &self,
394        request: InsertIntoTableRequest,
395        request_data: Bytes,
396    ) -> Result<InsertIntoTableResponse> {
397        let id = object_id_str(&request.id, self.config.delimiter())?;
398
399        use lance_namespace_reqwest_client::models::insert_into_table_request::Mode;
400        let mode = request.mode.as_ref().map(|m| match m {
401            Mode::Append => "append",
402            Mode::Overwrite => "overwrite",
403        });
404
405        table_api::insert_into_table(
406            &self.reqwest_config,
407            &id,
408            request_data.to_vec(),
409            Some(self.config.delimiter()),
410            mode,
411        )
412        .await
413        .map_err(convert_api_error)
414    }
415
416    async fn merge_insert_into_table(
417        &self,
418        request: MergeInsertIntoTableRequest,
419        request_data: Bytes,
420    ) -> Result<MergeInsertIntoTableResponse> {
421        let id = object_id_str(&request.id, self.config.delimiter())?;
422
423        let on = request.on.as_deref().ok_or_else(|| {
424            NamespaceError::Other("'on' field is required for merge insert".to_string())
425        })?;
426
427        table_api::merge_insert_into_table(
428            &self.reqwest_config,
429            &id,
430            on,
431            request_data.to_vec(),
432            Some(self.config.delimiter()),
433            request.when_matched_update_all,
434            request.when_matched_update_all_filt.as_deref(),
435            request.when_not_matched_insert_all,
436            request.when_not_matched_by_source_delete,
437            request.when_not_matched_by_source_delete_filt.as_deref(),
438        )
439        .await
440        .map_err(convert_api_error)
441    }
442
443    async fn update_table(&self, request: UpdateTableRequest) -> Result<UpdateTableResponse> {
444        let id = object_id_str(&request.id, self.config.delimiter())?;
445
446        table_api::update_table(
447            &self.reqwest_config,
448            &id,
449            request,
450            Some(self.config.delimiter()),
451        )
452        .await
453        .map_err(convert_api_error)
454    }
455
456    async fn delete_from_table(
457        &self,
458        request: DeleteFromTableRequest,
459    ) -> Result<DeleteFromTableResponse> {
460        let id = object_id_str(&request.id, self.config.delimiter())?;
461
462        table_api::delete_from_table(
463            &self.reqwest_config,
464            &id,
465            request,
466            Some(self.config.delimiter()),
467        )
468        .await
469        .map_err(convert_api_error)
470    }
471
472    async fn query_table(&self, request: QueryTableRequest) -> Result<Bytes> {
473        let id = object_id_str(&request.id, self.config.delimiter())?;
474
475        let response = table_api::query_table(
476            &self.reqwest_config,
477            &id,
478            request,
479            Some(self.config.delimiter()),
480        )
481        .await
482        .map_err(convert_api_error)?;
483
484        // Convert response to bytes
485        let bytes = response.bytes().await.map_err(|e| {
486            NamespaceError::Io(std::io::Error::new(
487                std::io::ErrorKind::Other,
488                e.to_string(),
489            ))
490        })?;
491
492        Ok(bytes)
493    }
494
495    async fn create_table_index(
496        &self,
497        request: CreateTableIndexRequest,
498    ) -> Result<CreateTableIndexResponse> {
499        let id = object_id_str(&request.id, self.config.delimiter())?;
500
501        table_api::create_table_index(
502            &self.reqwest_config,
503            &id,
504            request,
505            Some(self.config.delimiter()),
506        )
507        .await
508        .map_err(convert_api_error)
509    }
510
511    async fn list_table_indices(
512        &self,
513        request: ListTableIndicesRequest,
514    ) -> Result<ListTableIndicesResponse> {
515        let id = object_id_str(&request.id, self.config.delimiter())?;
516
517        table_api::list_table_indices(
518            &self.reqwest_config,
519            &id,
520            request,
521            Some(self.config.delimiter()),
522        )
523        .await
524        .map_err(convert_api_error)
525    }
526
527    async fn describe_table_index_stats(
528        &self,
529        request: DescribeTableIndexStatsRequest,
530    ) -> Result<DescribeTableIndexStatsResponse> {
531        let id = object_id_str(&request.id, self.config.delimiter())?;
532
533        // Note: The index_name parameter seems to be missing from the request structure
534        // This might need to be adjusted based on the actual API
535        let index_name = ""; // This should come from somewhere in the request
536
537        table_api::describe_table_index_stats(
538            &self.reqwest_config,
539            &id,
540            index_name,
541            request,
542            Some(self.config.delimiter()),
543        )
544        .await
545        .map_err(convert_api_error)
546    }
547
548    async fn describe_transaction(
549        &self,
550        request: DescribeTransactionRequest,
551    ) -> Result<DescribeTransactionResponse> {
552        let id = object_id_str(&request.id, self.config.delimiter())?;
553
554        transaction_api::describe_transaction(
555            &self.reqwest_config,
556            &id,
557            request,
558            Some(self.config.delimiter()),
559        )
560        .await
561        .map_err(convert_api_error)
562    }
563
564    async fn alter_transaction(
565        &self,
566        request: AlterTransactionRequest,
567    ) -> Result<AlterTransactionResponse> {
568        let id = object_id_str(&request.id, self.config.delimiter())?;
569
570        transaction_api::alter_transaction(
571            &self.reqwest_config,
572            &id,
573            request,
574            Some(self.config.delimiter()),
575        )
576        .await
577        .map_err(convert_api_error)
578    }
579}
580
581#[cfg(test)]
582mod tests {
583    use super::*;
584    use bytes::Bytes;
585    use lance_namespace_reqwest_client::models::{create_table_request, insert_into_table_request};
586    use wiremock::matchers::{method, path};
587    use wiremock::{Mock, MockServer, ResponseTemplate};
588
589    /// Create a test REST namespace instance
590    fn create_test_namespace() -> RestNamespace {
591        let mut properties = HashMap::new();
592        properties.insert("uri".to_string(), "http://localhost:8080".to_string());
593        properties.insert("delimiter".to_string(), ".".to_string());
594        RestNamespace::new(properties)
595    }
596
597    #[test]
598    fn test_rest_namespace_creation() {
599        let mut properties = HashMap::new();
600        properties.insert("uri".to_string(), "http://example.com".to_string());
601        properties.insert("delimiter".to_string(), "/".to_string());
602        properties.insert(
603            "header.Authorization".to_string(),
604            "Bearer token".to_string(),
605        );
606        properties.insert("header.X-Custom".to_string(), "value".to_string());
607
608        let _namespace = RestNamespace::new(properties);
609
610        // Successfully created the namespace
611        assert!(true);
612    }
613
614    #[tokio::test]
615    async fn test_custom_headers_are_sent() {
616        // Start a mock server
617        let mock_server = MockServer::start().await;
618
619        // Create mock that expects custom headers
620        Mock::given(method("GET"))
621            .and(path("/v1/namespace/test/list"))
622            .and(wiremock::matchers::header(
623                "Authorization",
624                "Bearer test-token",
625            ))
626            .and(wiremock::matchers::header(
627                "X-Custom-Header",
628                "custom-value",
629            ))
630            .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
631                "namespaces": []
632            })))
633            .mount(&mock_server)
634            .await;
635
636        // Create namespace with custom headers
637        let mut properties = HashMap::new();
638        properties.insert("uri".to_string(), mock_server.uri());
639        properties.insert(
640            "header.Authorization".to_string(),
641            "Bearer test-token".to_string(),
642        );
643        properties.insert(
644            "header.X-Custom-Header".to_string(),
645            "custom-value".to_string(),
646        );
647
648        let namespace = RestNamespace::new(properties);
649
650        let request = ListNamespacesRequest {
651            id: Some(vec!["test".to_string()]),
652            page_token: None,
653            limit: None,
654        };
655
656        let result = namespace.list_namespaces(request).await;
657
658        // Should succeed, meaning headers were sent correctly
659        assert!(result.is_ok());
660    }
661
662    #[test]
663    fn test_default_configuration() {
664        let properties = HashMap::new();
665        let _namespace = RestNamespace::new(properties);
666
667        // The default delimiter should be "." as per the Java implementation
668        assert!(true);
669    }
670
671    #[test]
672    fn test_with_custom_uri() {
673        let mut properties = HashMap::new();
674        properties.insert("uri".to_string(), "https://api.example.com/v1".to_string());
675
676        let _namespace = RestNamespace::new(properties);
677        assert!(true);
678    }
679
680    #[tokio::test]
681    async fn test_list_namespaces_success() {
682        // Start a mock server
683        let mock_server = MockServer::start().await;
684
685        // Create mock response
686        Mock::given(method("GET"))
687            .and(path("/v1/namespace/test/list"))
688            .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
689                "namespaces": [
690                    "namespace1",
691                    "namespace2"
692                ]
693            })))
694            .mount(&mock_server)
695            .await;
696
697        // Create namespace with mock server URL
698        let mut properties = HashMap::new();
699        properties.insert("uri".to_string(), mock_server.uri());
700        properties.insert("delimiter".to_string(), ".".to_string());
701
702        let mut reqwest_config = Configuration::new();
703        reqwest_config.base_path = mock_server.uri();
704
705        let namespace = RestNamespace::with_configuration(properties, reqwest_config);
706
707        let request = ListNamespacesRequest {
708            id: Some(vec!["test".to_string()]),
709            page_token: None,
710            limit: Some(10),
711        };
712
713        let result = namespace.list_namespaces(request).await;
714
715        // Should succeed with mock server
716        assert!(result.is_ok());
717        let response = result.unwrap();
718        assert_eq!(response.namespaces.len(), 2);
719        assert_eq!(response.namespaces[0], "namespace1");
720        assert_eq!(response.namespaces[1], "namespace2");
721    }
722
723    #[tokio::test]
724    async fn test_list_namespaces_error() {
725        // Start a mock server
726        let mock_server = MockServer::start().await;
727
728        // Create mock error response
729        Mock::given(method("GET"))
730            .and(path("/v1/namespace/test/list"))
731            .respond_with(ResponseTemplate::new(404).set_body_json(serde_json::json!({
732                "error": {
733                    "message": "Namespace not found",
734                    "type": "NamespaceNotFoundException"
735                }
736            })))
737            .mount(&mock_server)
738            .await;
739
740        // Create namespace with mock server URL
741        let mut properties = HashMap::new();
742        properties.insert("uri".to_string(), mock_server.uri());
743
744        let mut reqwest_config = Configuration::new();
745        reqwest_config.base_path = mock_server.uri();
746
747        let namespace = RestNamespace::with_configuration(properties, reqwest_config);
748
749        let request = ListNamespacesRequest {
750            id: Some(vec!["test".to_string()]),
751            page_token: None,
752            limit: Some(10),
753        };
754
755        let result = namespace.list_namespaces(request).await;
756
757        // Should return an error
758        assert!(result.is_err());
759    }
760
761    #[tokio::test]
762    #[ignore] // Requires a running server
763    async fn test_list_namespaces_integration() {
764        let namespace = create_test_namespace();
765        let request = ListNamespacesRequest {
766            id: Some(vec!["test".to_string()]),
767            page_token: None,
768            limit: Some(10),
769        };
770
771        let result = namespace.list_namespaces(request).await;
772
773        // The actual assertion depends on whether the server is running
774        // In a real test, you would either mock the server or ensure it's running
775        assert!(result.is_err() || result.is_ok());
776    }
777
778    #[tokio::test]
779    async fn test_create_namespace_success() {
780        // Start a mock server
781        let mock_server = MockServer::start().await;
782
783        // Create mock response
784        Mock::given(method("POST"))
785            .and(path("/v1/namespace/test.newnamespace/create"))
786            .respond_with(ResponseTemplate::new(201).set_body_json(serde_json::json!({
787                "namespace": {
788                    "identifier": ["test", "newnamespace"],
789                    "properties": {}
790                }
791            })))
792            .mount(&mock_server)
793            .await;
794
795        // Create namespace with mock server URL
796        let mut properties = HashMap::new();
797        properties.insert("uri".to_string(), mock_server.uri());
798
799        let mut reqwest_config = Configuration::new();
800        reqwest_config.base_path = mock_server.uri();
801
802        let namespace = RestNamespace::with_configuration(properties, reqwest_config);
803
804        let request = CreateNamespaceRequest {
805            id: Some(vec!["test".to_string(), "newnamespace".to_string()]),
806            properties: None,
807            mode: None,
808        };
809
810        let result = namespace.create_namespace(request).await;
811
812        // Should succeed with mock server
813        assert!(result.is_ok());
814    }
815
816    #[tokio::test]
817    async fn test_create_table_success() {
818        // Start a mock server
819        let mock_server = MockServer::start().await;
820
821        // Create mock response
822        Mock::given(method("POST"))
823            .and(path("/v1/table/test.namespace.table/create"))
824            .respond_with(ResponseTemplate::new(201).set_body_json(serde_json::json!({
825                "table": {
826                    "identifier": ["test", "namespace", "table"],
827                    "location": "/path/to/table",
828                    "version": 1
829                }
830            })))
831            .mount(&mock_server)
832            .await;
833
834        // Create namespace with mock server URL
835        let mut properties = HashMap::new();
836        properties.insert("uri".to_string(), mock_server.uri());
837
838        let mut reqwest_config = Configuration::new();
839        reqwest_config.base_path = mock_server.uri();
840
841        let namespace = RestNamespace::with_configuration(properties, reqwest_config);
842
843        let request = CreateTableRequest {
844            id: Some(vec![
845                "test".to_string(),
846                "namespace".to_string(),
847                "table".to_string(),
848            ]),
849            location: None,
850            mode: Some(create_table_request::Mode::Create),
851            properties: None,
852        };
853
854        let data = Bytes::from("arrow data here");
855        let result = namespace.create_table(request, data).await;
856
857        // Should succeed with mock server
858        assert!(result.is_ok());
859    }
860
861    #[tokio::test]
862    async fn test_insert_into_table_success() {
863        // Start a mock server
864        let mock_server = MockServer::start().await;
865
866        // Create mock response
867        Mock::given(method("POST"))
868            .and(path("/v1/table/test.namespace.table/insert"))
869            .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
870                "version": 2
871            })))
872            .mount(&mock_server)
873            .await;
874
875        // Create namespace with mock server URL
876        let mut properties = HashMap::new();
877        properties.insert("uri".to_string(), mock_server.uri());
878
879        let mut reqwest_config = Configuration::new();
880        reqwest_config.base_path = mock_server.uri();
881
882        let namespace = RestNamespace::with_configuration(properties, reqwest_config);
883
884        let request = InsertIntoTableRequest {
885            id: Some(vec![
886                "test".to_string(),
887                "namespace".to_string(),
888                "table".to_string(),
889            ]),
890            mode: Some(insert_into_table_request::Mode::Append),
891        };
892
893        let data = Bytes::from("arrow data here");
894        let result = namespace.insert_into_table(request, data).await;
895
896        // Should succeed with mock server
897        assert!(result.is_ok());
898        let response = result.unwrap();
899        assert_eq!(response.version, Some(2));
900    }
901
902    #[tokio::test]
903    #[ignore] // Requires a running server
904    async fn test_create_namespace_integration() {
905        let namespace = create_test_namespace();
906        let request = CreateNamespaceRequest {
907            id: Some(vec!["test".to_string(), "namespace".to_string()]),
908            properties: None,
909            mode: None,
910        };
911
912        let result = namespace.create_namespace(request).await;
913        assert!(result.is_err() || result.is_ok());
914    }
915
916    #[tokio::test]
917    #[ignore] // Requires a running server
918    async fn test_describe_namespace() {
919        let namespace = create_test_namespace();
920        let request = DescribeNamespaceRequest {
921            id: Some(vec!["test".to_string(), "namespace".to_string()]),
922        };
923
924        let result = namespace.describe_namespace(request).await;
925        assert!(result.is_err() || result.is_ok());
926    }
927
928    #[tokio::test]
929    #[ignore] // Requires a running server
930    async fn test_list_tables() {
931        let namespace = create_test_namespace();
932        let request = ListTablesRequest {
933            id: Some(vec!["test".to_string(), "namespace".to_string()]),
934            page_token: None,
935            limit: Some(10),
936        };
937
938        let result = namespace.list_tables(request).await;
939        assert!(result.is_err() || result.is_ok());
940    }
941
942    #[tokio::test]
943    #[ignore] // Requires a running server
944    async fn test_create_table() {
945        let namespace = create_test_namespace();
946        let request = CreateTableRequest {
947            id: Some(vec![
948                "test".to_string(),
949                "namespace".to_string(),
950                "table".to_string(),
951            ]),
952            location: None,
953            mode: Some(create_table_request::Mode::Create),
954            properties: None,
955        };
956
957        let data = Bytes::from("test data");
958        let result = namespace.create_table(request, data).await;
959        assert!(result.is_err() || result.is_ok());
960    }
961
962    #[tokio::test]
963    #[ignore] // Requires a running server
964    async fn test_drop_table() {
965        let namespace = create_test_namespace();
966        let request = DropTableRequest {
967            id: Some(vec![
968                "test".to_string(),
969                "namespace".to_string(),
970                "table".to_string(),
971            ]),
972        };
973
974        let result = namespace.drop_table(request).await;
975        assert!(result.is_err() || result.is_ok());
976    }
977
978    #[tokio::test]
979    #[ignore] // Requires a running server
980    async fn test_insert_into_table_append() {
981        let namespace = create_test_namespace();
982        let request = InsertIntoTableRequest {
983            id: Some(vec![
984                "test".to_string(),
985                "namespace".to_string(),
986                "table".to_string(),
987            ]),
988            mode: Some(insert_into_table_request::Mode::Append),
989        };
990
991        let data = Bytes::from("test data");
992        let result = namespace.insert_into_table(request, data).await;
993        assert!(result.is_err() || result.is_ok());
994    }
995
996    #[tokio::test]
997    #[ignore] // Requires a running server
998    async fn test_insert_into_table_overwrite() {
999        let namespace = create_test_namespace();
1000        let request = InsertIntoTableRequest {
1001            id: Some(vec![
1002                "test".to_string(),
1003                "namespace".to_string(),
1004                "table".to_string(),
1005            ]),
1006            mode: Some(insert_into_table_request::Mode::Overwrite),
1007        };
1008
1009        let data = Bytes::from("test data");
1010        let result = namespace.insert_into_table(request, data).await;
1011        assert!(result.is_err() || result.is_ok());
1012    }
1013
1014    #[tokio::test]
1015    #[ignore] // Requires a running server
1016    async fn test_merge_insert_into_table() {
1017        let namespace = create_test_namespace();
1018        let request = MergeInsertIntoTableRequest {
1019            id: Some(vec![
1020                "test".to_string(),
1021                "namespace".to_string(),
1022                "table".to_string(),
1023            ]),
1024            on: Some("id".to_string()),
1025            when_matched_update_all: Some(true),
1026            when_matched_update_all_filt: None,
1027            when_not_matched_insert_all: Some(true),
1028            when_not_matched_by_source_delete: Some(false),
1029            when_not_matched_by_source_delete_filt: None,
1030        };
1031
1032        let data = Bytes::from("test data");
1033        let result = namespace.merge_insert_into_table(request, data).await;
1034        assert!(result.is_err() || result.is_ok());
1035    }
1036
1037    #[tokio::test]
1038    #[ignore] // Requires a running server
1039    async fn test_delete_from_table() {
1040        let namespace = create_test_namespace();
1041        let request = DeleteFromTableRequest {
1042            id: Some(vec![
1043                "test".to_string(),
1044                "namespace".to_string(),
1045                "table".to_string(),
1046            ]),
1047            predicate: "id > 10".to_string(),
1048        };
1049
1050        let result = namespace.delete_from_table(request).await;
1051        assert!(result.is_err() || result.is_ok());
1052    }
1053
1054    #[tokio::test]
1055    #[ignore] // Requires a running server
1056    async fn test_describe_transaction() {
1057        let namespace = create_test_namespace();
1058        let request = DescribeTransactionRequest {
1059            id: Some(vec!["test".to_string(), "transaction".to_string()]),
1060        };
1061
1062        let result = namespace.describe_transaction(request).await;
1063        assert!(result.is_err() || result.is_ok());
1064    }
1065
1066    #[tokio::test]
1067    #[ignore] // Requires a running server
1068    async fn test_alter_transaction() {
1069        let namespace = create_test_namespace();
1070        let request = AlterTransactionRequest {
1071            id: Some(vec!["test".to_string(), "transaction".to_string()]),
1072            actions: vec![],
1073        };
1074
1075        let result = namespace.alter_transaction(request).await;
1076        assert!(result.is_err() || result.is_ok());
1077    }
1078}