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