1use 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#[derive(Debug, Clone)]
29pub struct RestNamespaceConfig {
30 delimiter: String,
32 additional_headers: HashMap<String, String>,
34 uri: Option<String>,
36}
37
38impl RestNamespaceConfig {
39 const HEADER_PREFIX: &'static str = "header.";
41
42 const DEFAULT_DELIMITER: &'static str = ".";
44
45 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 pub fn delimiter(&self) -> &str {
71 &self.delimiter
72 }
73
74 pub fn additional_headers(&self) -> &HashMap<String, String> {
76 &self.additional_headers
77 }
78
79 pub fn uri(&self) -> Option<&str> {
81 self.uri.as_deref()
82 }
83}
84
85fn 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
94fn 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
108pub struct RestNamespace {
110 config: RestNamespaceConfig,
111 reqwest_config: Configuration,
112}
113
114impl RestNamespace {
115 pub fn new(properties: HashMap<String, String>) -> Self {
117 let config = RestNamespaceConfig::new(properties);
118
119 let mut client_builder = reqwest::Client::builder();
121
122 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 #[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 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 let index_name = ""; 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 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 assert!(true);
607 }
608
609 #[tokio::test]
610 async fn test_custom_headers_are_sent() {
611 let mock_server = MockServer::start().await;
613
614 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 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 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 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 let mock_server = MockServer::start().await;
679
680 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 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 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 let mock_server = MockServer::start().await;
722
723 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 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 assert!(result.is_err());
754 }
755
756 #[tokio::test]
757 #[ignore] 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 assert!(result.is_err() || result.is_ok());
771 }
772
773 #[tokio::test]
774 async fn test_create_namespace_success() {
775 let mock_server = MockServer::start().await;
777
778 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 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 assert!(result.is_ok());
809 }
810
811 #[tokio::test]
812 async fn test_create_table_success() {
813 let mock_server = MockServer::start().await;
815
816 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 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 assert!(result.is_ok());
854 }
855
856 #[tokio::test]
857 async fn test_insert_into_table_success() {
858 let mock_server = MockServer::start().await;
860
861 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 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 assert!(result.is_ok());
893 let response = result.unwrap();
894 assert_eq!(response.version, Some(2));
895 }
896
897 #[tokio::test]
898 #[ignore] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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}