1use 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#[derive(Debug, Clone)]
32pub struct RestNamespaceConfig {
33 delimiter: String,
35 additional_headers: HashMap<String, String>,
37 uri: Option<String>,
39}
40
41impl RestNamespaceConfig {
42 const HEADER_PREFIX: &'static str = "header.";
44
45 const DEFAULT_DELIMITER: &'static str = ".";
47
48 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 pub fn delimiter(&self) -> &str {
74 &self.delimiter
75 }
76
77 pub fn additional_headers(&self) -> &HashMap<String, String> {
79 &self.additional_headers
80 }
81
82 pub fn uri(&self) -> Option<&str> {
84 self.uri.as_deref()
85 }
86}
87
88fn 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
97fn 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
113pub struct RestNamespace {
115 config: RestNamespaceConfig,
116 reqwest_config: Configuration,
117}
118
119impl RestNamespace {
120 pub fn new(properties: HashMap<String, String>) -> Self {
122 let config = RestNamespaceConfig::new(properties);
123
124 let mut client_builder = reqwest::Client::builder();
126
127 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 #[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 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 let index_name = ""; 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 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 assert!(true);
612 }
613
614 #[tokio::test]
615 async fn test_custom_headers_are_sent() {
616 let mock_server = MockServer::start().await;
618
619 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 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 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 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 let mock_server = MockServer::start().await;
684
685 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 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 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 let mock_server = MockServer::start().await;
727
728 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 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 assert!(result.is_err());
759 }
760
761 #[tokio::test]
762 #[ignore] 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 assert!(result.is_err() || result.is_ok());
776 }
777
778 #[tokio::test]
779 async fn test_create_namespace_success() {
780 let mock_server = MockServer::start().await;
782
783 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 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 assert!(result.is_ok());
814 }
815
816 #[tokio::test]
817 async fn test_create_table_success() {
818 let mock_server = MockServer::start().await;
820
821 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 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 assert!(result.is_ok());
859 }
860
861 #[tokio::test]
862 async fn test_insert_into_table_success() {
863 let mock_server = MockServer::start().await;
865
866 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 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 assert!(result.is_ok());
898 let response = result.unwrap();
899 assert_eq!(response.version, Some(2));
900 }
901
902 #[tokio::test]
903 #[ignore] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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] 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}