1use std::collections::HashMap;
21use std::str::FromStr;
22use std::sync::Arc;
23
24use async_trait::async_trait;
25use futures::lock::{Mutex, MutexGuard};
26use itertools::Itertools;
27
28use super::namespace_state::NamespaceState;
29use crate::encryption::kms::{KeyManagementClient, KmsClientFactory};
30use crate::io::{FileIO, FileIOBuilder, MemoryStorageFactory, StorageFactory};
31use crate::runtime::Runtime;
32use crate::spec::{TableMetadata, TableMetadataBuilder};
33use crate::table::Table;
34use crate::{
35 Catalog, CatalogBuilder, Error, ErrorKind, MetadataLocation, Namespace, NamespaceIdent, Result,
36 TableCommit, TableCreation, TableIdent,
37};
38
39pub const MEMORY_CATALOG_WAREHOUSE: &str = "warehouse";
41
42const LOCATION: &str = "location";
44
45#[derive(Debug)]
47pub struct MemoryCatalogBuilder {
48 config: MemoryCatalogConfig,
49 storage_factory: Option<Arc<dyn StorageFactory>>,
50 kms_client_factory: Option<Arc<dyn KmsClientFactory>>,
51 runtime: Option<Runtime>,
52}
53
54impl Default for MemoryCatalogBuilder {
55 fn default() -> Self {
56 Self {
57 config: MemoryCatalogConfig {
58 name: None,
59 warehouse: "".to_string(),
60 props: HashMap::new(),
61 },
62 storage_factory: None,
63 kms_client_factory: None,
64 runtime: None,
65 }
66 }
67}
68
69impl CatalogBuilder for MemoryCatalogBuilder {
70 type C = MemoryCatalog;
71
72 fn with_storage_factory(mut self, storage_factory: Arc<dyn StorageFactory>) -> Self {
73 self.storage_factory = Some(storage_factory);
74 self
75 }
76
77 fn with_kms_client_factory(mut self, kms_client_factory: Arc<dyn KmsClientFactory>) -> Self {
78 self.kms_client_factory = Some(kms_client_factory);
79 self
80 }
81
82 fn with_runtime(mut self, runtime: Runtime) -> Self {
83 self.runtime = Some(runtime);
84 self
85 }
86
87 fn load(
88 mut self,
89 name: impl Into<String>,
90 props: HashMap<String, String>,
91 ) -> impl Future<Output = Result<Self::C>> + Send {
92 self.config.name = Some(name.into());
93
94 if props.contains_key(MEMORY_CATALOG_WAREHOUSE) {
95 self.config.warehouse = props
96 .get(MEMORY_CATALOG_WAREHOUSE)
97 .cloned()
98 .unwrap_or_default()
99 }
100
101 self.config.props = props
103 .into_iter()
104 .filter(|(k, _)| k != MEMORY_CATALOG_WAREHOUSE)
105 .collect();
106
107 async move {
108 if self.config.name.is_none() {
109 Err(Error::new(
110 ErrorKind::DataInvalid,
111 "Catalog name is required",
112 ))
113 } else if self.config.warehouse.is_empty() {
114 Err(Error::new(
115 ErrorKind::DataInvalid,
116 "Catalog warehouse is required",
117 ))
118 } else {
119 let runtime = self.runtime.unwrap_or_else(Runtime::current);
120 let kms_client = match self.kms_client_factory {
121 Some(factory) => Some(factory.create_kms_client(&self.config.props).await?),
122 None => None,
123 };
124 MemoryCatalog::new(self.config, self.storage_factory, runtime, kms_client)
125 }
126 }
127 }
128}
129
130#[derive(Clone, Debug)]
131pub(crate) struct MemoryCatalogConfig {
132 name: Option<String>,
133 warehouse: String,
134 props: HashMap<String, String>,
135}
136
137#[derive(Debug)]
139pub struct MemoryCatalog {
140 root_namespace_state: Mutex<NamespaceState>,
141 file_io: FileIO,
142 warehouse_location: String,
143 runtime: Runtime,
144 kms_client: Option<Arc<dyn KeyManagementClient>>,
145}
146
147impl MemoryCatalog {
148 fn new(
150 config: MemoryCatalogConfig,
151 storage_factory: Option<Arc<dyn StorageFactory>>,
152 runtime: Runtime,
153 kms_client: Option<Arc<dyn KeyManagementClient>>,
154 ) -> Result<Self> {
155 let factory = storage_factory.unwrap_or_else(|| Arc::new(MemoryStorageFactory));
157
158 Ok(Self {
159 root_namespace_state: Mutex::new(NamespaceState::default()),
160 file_io: FileIOBuilder::new(factory).with_props(config.props).build(),
161 warehouse_location: config.warehouse,
162 runtime,
163 kms_client,
164 })
165 }
166
167 async fn load_table_from_locked_state(
169 &self,
170 table_ident: &TableIdent,
171 root_namespace_state: &MutexGuard<'_, NamespaceState>,
172 ) -> Result<Table> {
173 let metadata_location = root_namespace_state.get_existing_table_location(table_ident)?;
174 let metadata = TableMetadata::read_from(&self.file_io, metadata_location).await?;
175
176 let mut builder = Table::builder()
177 .identifier(table_ident.clone())
178 .metadata(metadata)
179 .metadata_location(metadata_location.to_string())
180 .file_io(self.file_io.clone())
181 .runtime(self.runtime.clone());
182 if let Some(kms_client) = self.kms_client.clone() {
183 builder = builder.kms_client(kms_client);
184 }
185 builder.build()
186 }
187}
188
189#[async_trait]
190impl Catalog for MemoryCatalog {
191 async fn list_namespaces(
193 &self,
194 maybe_parent: Option<&NamespaceIdent>,
195 ) -> Result<Vec<NamespaceIdent>> {
196 let root_namespace_state = self.root_namespace_state.lock().await;
197
198 match maybe_parent {
199 None => {
200 let namespaces = root_namespace_state
201 .list_top_level_namespaces()
202 .into_iter()
203 .map(|str| NamespaceIdent::new(str.to_string()))
204 .collect_vec();
205
206 Ok(namespaces)
207 }
208 Some(parent_namespace_ident) => {
209 let namespaces = root_namespace_state
210 .list_namespaces_under(parent_namespace_ident)?
211 .into_iter()
212 .map(|name| {
213 let mut names = parent_namespace_ident.iter().cloned().collect::<Vec<_>>();
214 names.push(name.to_string());
215 NamespaceIdent::from_vec(names)
216 })
217 .collect::<Result<Vec<_>>>()?;
218
219 Ok(namespaces)
220 }
221 }
222 }
223
224 async fn create_namespace(
226 &self,
227 namespace_ident: &NamespaceIdent,
228 properties: HashMap<String, String>,
229 ) -> Result<Namespace> {
230 let mut root_namespace_state = self.root_namespace_state.lock().await;
231
232 root_namespace_state.insert_new_namespace(namespace_ident, properties.clone())?;
233 let namespace = Namespace::with_properties(namespace_ident.clone(), properties);
234
235 Ok(namespace)
236 }
237
238 async fn get_namespace(&self, namespace_ident: &NamespaceIdent) -> Result<Namespace> {
240 let root_namespace_state = self.root_namespace_state.lock().await;
241
242 let namespace = Namespace::with_properties(
243 namespace_ident.clone(),
244 root_namespace_state
245 .get_properties(namespace_ident)?
246 .clone(),
247 );
248
249 Ok(namespace)
250 }
251
252 async fn namespace_exists(&self, namespace_ident: &NamespaceIdent) -> Result<bool> {
254 let guarded_namespaces = self.root_namespace_state.lock().await;
255
256 Ok(guarded_namespaces.namespace_exists(namespace_ident))
257 }
258
259 async fn update_namespace(
265 &self,
266 namespace_ident: &NamespaceIdent,
267 properties: HashMap<String, String>,
268 ) -> Result<()> {
269 let mut root_namespace_state = self.root_namespace_state.lock().await;
270
271 root_namespace_state.replace_properties(namespace_ident, properties)
272 }
273
274 async fn drop_namespace(&self, namespace_ident: &NamespaceIdent) -> Result<()> {
276 let mut root_namespace_state = self.root_namespace_state.lock().await;
277
278 root_namespace_state.remove_existing_namespace(namespace_ident)
279 }
280
281 async fn list_tables(&self, namespace_ident: &NamespaceIdent) -> Result<Vec<TableIdent>> {
283 let root_namespace_state = self.root_namespace_state.lock().await;
284
285 let table_names = root_namespace_state.list_tables(namespace_ident)?;
286 let table_idents = table_names
287 .into_iter()
288 .map(|table_name| TableIdent::new(namespace_ident.clone(), table_name.clone()))
289 .collect_vec();
290
291 Ok(table_idents)
292 }
293
294 async fn create_table(
296 &self,
297 namespace_ident: &NamespaceIdent,
298 table_creation: TableCreation,
299 ) -> Result<Table> {
300 let mut root_namespace_state = self.root_namespace_state.lock().await;
301
302 let table_name = table_creation.name.clone();
303 let table_ident = TableIdent::new(namespace_ident.clone(), table_name);
304
305 let (table_creation, location) = match table_creation.location.clone() {
306 Some(location) => (table_creation, location),
307 None => {
308 let namespace_properties = root_namespace_state.get_properties(namespace_ident)?;
309 let location_prefix = match namespace_properties.get(LOCATION) {
310 Some(namespace_location) => namespace_location.clone(),
311 None => format!("{}/{}", self.warehouse_location, namespace_ident.join("/")),
312 };
313
314 let location = format!("{}/{}", location_prefix, table_ident.name());
315
316 let new_table_creation = TableCreation {
317 location: Some(location.clone()),
318 ..table_creation
319 };
320
321 (new_table_creation, location)
322 }
323 };
324
325 let metadata = TableMetadataBuilder::from_table_creation(table_creation)?
326 .build()?
327 .metadata;
328 let metadata_location = MetadataLocation::new_with_metadata(location, &metadata);
329
330 metadata.write_to(&self.file_io, &metadata_location).await?;
331
332 root_namespace_state.insert_new_table(&table_ident, metadata_location.to_string())?;
333
334 let mut builder = Table::builder()
335 .file_io(self.file_io.clone())
336 .metadata_location(metadata_location.to_string())
337 .metadata(metadata)
338 .identifier(table_ident)
339 .runtime(self.runtime.clone());
340 if let Some(kms_client) = self.kms_client.clone() {
341 builder = builder.kms_client(kms_client);
342 }
343 builder.build()
344 }
345
346 async fn load_table(&self, table_ident: &TableIdent) -> Result<Table> {
348 let root_namespace_state = self.root_namespace_state.lock().await;
349
350 self.load_table_from_locked_state(table_ident, &root_namespace_state)
351 .await
352 }
353
354 async fn drop_table(&self, table_ident: &TableIdent) -> Result<()> {
356 let mut root_namespace_state = self.root_namespace_state.lock().await;
357
358 root_namespace_state.remove_existing_table(table_ident)?;
359 Ok(())
360 }
361
362 async fn purge_table(&self, table_ident: &TableIdent) -> Result<()> {
363 let table_info = self.load_table(table_ident).await?;
364 self.drop_table(table_ident).await?;
365 crate::catalog::utils::drop_table_data(&table_info).await
366 }
367
368 async fn table_exists(&self, table_ident: &TableIdent) -> Result<bool> {
370 let root_namespace_state = self.root_namespace_state.lock().await;
371
372 root_namespace_state.table_exists(table_ident)
373 }
374
375 async fn rename_table(
377 &self,
378 src_table_ident: &TableIdent,
379 dst_table_ident: &TableIdent,
380 ) -> Result<()> {
381 let mut root_namespace_state = self.root_namespace_state.lock().await;
382
383 let mut new_root_namespace_state = root_namespace_state.clone();
384 let metadata_location = new_root_namespace_state
385 .get_existing_table_location(src_table_ident)?
386 .clone();
387 new_root_namespace_state.remove_existing_table(src_table_ident)?;
388 new_root_namespace_state.insert_new_table(dst_table_ident, metadata_location)?;
389 *root_namespace_state = new_root_namespace_state;
390
391 Ok(())
392 }
393
394 async fn register_table(
395 &self,
396 table_ident: &TableIdent,
397 metadata_location: String,
398 ) -> Result<Table> {
399 let mut root_namespace_state = self.root_namespace_state.lock().await;
400 root_namespace_state.insert_new_table(&table_ident.clone(), metadata_location.clone())?;
401
402 let metadata = TableMetadata::read_from(&self.file_io, &metadata_location).await?;
403
404 let mut builder = Table::builder()
405 .file_io(self.file_io.clone())
406 .metadata_location(metadata_location)
407 .metadata(metadata)
408 .identifier(table_ident.clone())
409 .runtime(self.runtime.clone());
410 if let Some(kms_client) = self.kms_client.clone() {
411 builder = builder.kms_client(kms_client);
412 }
413 builder.build()
414 }
415
416 async fn update_table(&self, commit: TableCommit) -> Result<Table> {
418 let mut root_namespace_state = self.root_namespace_state.lock().await;
419
420 let current_table = self
421 .load_table_from_locked_state(commit.identifier(), &root_namespace_state)
422 .await?;
423
424 let staged_table = commit.apply(current_table)?;
426
427 let metadata_location =
429 MetadataLocation::from_str(staged_table.metadata_location_result()?)?;
430 staged_table
431 .metadata()
432 .write_to(staged_table.file_io(), &metadata_location)
433 .await?;
434
435 let updated_table = root_namespace_state.commit_table_update(staged_table)?;
437
438 Ok(updated_table)
439 }
440}
441
442#[cfg(test)]
443pub(crate) mod tests {
444 use std::collections::HashSet;
445 use std::hash::Hash;
446 use std::iter::FromIterator;
447 use std::vec;
448
449 use regex::Regex;
450 use tempfile::TempDir;
451
452 use super::*;
453 use crate::encryption::kms::MemoryKmsClientFactory;
454 use crate::io::{FileIO, LocalFsStorageFactory};
455 use crate::spec::{NestedField, PartitionSpec, PrimitiveType, Schema, SortOrder, Type};
456 use crate::test_utils::test_runtime;
457 use crate::transaction::{ApplyTransactionAction, Transaction};
458
459 fn temp_path() -> String {
460 let temp_dir = TempDir::new().unwrap();
461 temp_dir.path().to_str().unwrap().to_string()
462 }
463
464 pub(crate) async fn new_memory_catalog() -> impl Catalog {
465 let warehouse_location = temp_path();
466 MemoryCatalogBuilder::default()
467 .load(
468 "memory",
469 HashMap::from([(MEMORY_CATALOG_WAREHOUSE.to_string(), warehouse_location)]),
470 )
471 .await
472 .unwrap()
473 }
474
475 async fn create_namespace<C: Catalog>(catalog: &C, namespace_ident: &NamespaceIdent) {
476 let _ = catalog
477 .create_namespace(namespace_ident, HashMap::new())
478 .await
479 .unwrap();
480 }
481
482 async fn create_namespaces<C: Catalog>(catalog: &C, namespace_idents: &Vec<&NamespaceIdent>) {
483 for namespace_ident in namespace_idents {
484 let _ = create_namespace(catalog, namespace_ident).await;
485 }
486 }
487
488 fn to_set<T: Eq + Hash>(vec: Vec<T>) -> HashSet<T> {
489 HashSet::from_iter(vec)
490 }
491
492 fn simple_table_schema() -> Schema {
493 Schema::builder()
494 .with_fields(vec![
495 NestedField::required(1, "foo", Type::Primitive(PrimitiveType::Int)).into(),
496 ])
497 .build()
498 .unwrap()
499 }
500
501 async fn create_table<C: Catalog>(catalog: &C, table_ident: &TableIdent) -> Table {
502 catalog
503 .create_table(
504 &table_ident.namespace,
505 TableCreation::builder()
506 .name(table_ident.name().into())
507 .schema(simple_table_schema())
508 .build(),
509 )
510 .await
511 .unwrap()
512 }
513
514 async fn create_tables<C: Catalog>(catalog: &C, table_idents: Vec<&TableIdent>) {
515 for table_ident in table_idents {
516 create_table(catalog, table_ident).await;
517 }
518 }
519
520 async fn create_table_with_namespace<C: Catalog>(catalog: &C) -> Table {
521 let namespace_ident = NamespaceIdent::new("abc".into());
522 create_namespace(catalog, &namespace_ident).await;
523
524 let table_ident = TableIdent::new(namespace_ident, "test".to_string());
525 create_table(catalog, &table_ident).await
526 }
527
528 fn assert_table_eq(table: &Table, expected_table_ident: &TableIdent, expected_schema: &Schema) {
529 assert_eq!(table.identifier(), expected_table_ident);
530
531 let metadata = table.metadata();
532
533 assert_eq!(metadata.current_schema().as_ref(), expected_schema);
534
535 let expected_partition_spec = PartitionSpec::builder((*expected_schema).clone())
536 .with_spec_id(0)
537 .build()
538 .unwrap();
539
540 assert_eq!(
541 metadata
542 .partition_specs_iter()
543 .map(|p| p.as_ref())
544 .collect_vec(),
545 vec![&expected_partition_spec]
546 );
547
548 let expected_sorted_order = SortOrder::builder()
549 .with_order_id(0)
550 .with_fields(vec![])
551 .build(expected_schema)
552 .unwrap();
553
554 assert_eq!(
555 metadata
556 .sort_orders_iter()
557 .map(|s| s.as_ref())
558 .collect_vec(),
559 vec![&expected_sorted_order]
560 );
561
562 assert_eq!(metadata.properties(), &HashMap::new());
563
564 assert!(!table.readonly());
565 }
566
567 const UUID_REGEX_STR: &str = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
568
569 fn assert_table_metadata_location_matches(table: &Table, regex_str: &str) {
570 let actual = table.metadata_location().unwrap().to_string();
571 let regex = Regex::new(regex_str).unwrap();
572 assert!(
573 regex.is_match(&actual),
574 "Expected metadata location to match regex, but got location: {actual} and regex: {regex}"
575 )
576 }
577
578 #[tokio::test]
579 async fn test_list_namespaces_returns_empty_vector() {
580 let catalog = new_memory_catalog().await;
581
582 assert_eq!(catalog.list_namespaces(None).await.unwrap(), vec![]);
583 }
584
585 #[tokio::test]
586 async fn test_list_namespaces_returns_single_namespace() {
587 let catalog = new_memory_catalog().await;
588 let namespace_ident = NamespaceIdent::new("abc".into());
589 create_namespace(&catalog, &namespace_ident).await;
590
591 assert_eq!(catalog.list_namespaces(None).await.unwrap(), vec![
592 namespace_ident
593 ]);
594 }
595
596 #[tokio::test]
597 async fn test_list_namespaces_returns_multiple_namespaces() {
598 let catalog = new_memory_catalog().await;
599 let namespace_ident_1 = NamespaceIdent::new("a".into());
600 let namespace_ident_2 = NamespaceIdent::new("b".into());
601 create_namespaces(&catalog, &vec![&namespace_ident_1, &namespace_ident_2]).await;
602
603 assert_eq!(
604 to_set(catalog.list_namespaces(None).await.unwrap()),
605 to_set(vec![namespace_ident_1, namespace_ident_2])
606 );
607 }
608
609 #[tokio::test]
610 async fn test_list_namespaces_returns_only_top_level_namespaces() {
611 let catalog = new_memory_catalog().await;
612 let namespace_ident_1 = NamespaceIdent::new("a".into());
613 let namespace_ident_2 = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
614 let namespace_ident_3 = NamespaceIdent::new("b".into());
615 create_namespaces(&catalog, &vec![
616 &namespace_ident_1,
617 &namespace_ident_2,
618 &namespace_ident_3,
619 ])
620 .await;
621
622 assert_eq!(
623 to_set(catalog.list_namespaces(None).await.unwrap()),
624 to_set(vec![namespace_ident_1, namespace_ident_3])
625 );
626 }
627
628 #[tokio::test]
629 async fn test_list_namespaces_returns_no_namespaces_under_parent() {
630 let catalog = new_memory_catalog().await;
631 let namespace_ident_1 = NamespaceIdent::new("a".into());
632 let namespace_ident_2 = NamespaceIdent::new("b".into());
633 create_namespaces(&catalog, &vec![&namespace_ident_1, &namespace_ident_2]).await;
634
635 assert_eq!(
636 catalog
637 .list_namespaces(Some(&namespace_ident_1))
638 .await
639 .unwrap(),
640 vec![]
641 );
642 }
643
644 #[tokio::test]
645 async fn test_list_namespaces_returns_namespace_under_parent() {
646 let catalog = new_memory_catalog().await;
647 let namespace_ident_1 = NamespaceIdent::new("a".into());
648 let namespace_ident_2 = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
649 let namespace_ident_3 = NamespaceIdent::new("c".into());
650 create_namespaces(&catalog, &vec![
651 &namespace_ident_1,
652 &namespace_ident_2,
653 &namespace_ident_3,
654 ])
655 .await;
656
657 assert_eq!(
658 to_set(catalog.list_namespaces(None).await.unwrap()),
659 to_set(vec![namespace_ident_1.clone(), namespace_ident_3])
660 );
661
662 assert_eq!(
663 catalog
664 .list_namespaces(Some(&namespace_ident_1))
665 .await
666 .unwrap(),
667 vec![namespace_ident_2]
668 );
669 }
670
671 #[tokio::test]
672 async fn test_list_namespaces_returns_multiple_namespaces_under_parent() {
673 let catalog = new_memory_catalog().await;
674 let namespace_ident_1 = NamespaceIdent::new("a".to_string());
675 let namespace_ident_2 = NamespaceIdent::from_strs(vec!["a", "a"]).unwrap();
676 let namespace_ident_3 = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
677 let namespace_ident_4 = NamespaceIdent::from_strs(vec!["a", "c"]).unwrap();
678 let namespace_ident_5 = NamespaceIdent::new("b".into());
679 create_namespaces(&catalog, &vec![
680 &namespace_ident_1,
681 &namespace_ident_2,
682 &namespace_ident_3,
683 &namespace_ident_4,
684 &namespace_ident_5,
685 ])
686 .await;
687
688 assert_eq!(
689 to_set(
690 catalog
691 .list_namespaces(Some(&namespace_ident_1))
692 .await
693 .unwrap()
694 ),
695 to_set(vec![
696 namespace_ident_2,
697 namespace_ident_3,
698 namespace_ident_4,
699 ])
700 );
701 }
702
703 #[tokio::test]
704 async fn test_namespace_exists_returns_false() {
705 let catalog = new_memory_catalog().await;
706 let namespace_ident = NamespaceIdent::new("a".into());
707 create_namespace(&catalog, &namespace_ident).await;
708
709 assert!(
710 !catalog
711 .namespace_exists(&NamespaceIdent::new("b".into()))
712 .await
713 .unwrap()
714 );
715 }
716
717 #[tokio::test]
718 async fn test_namespace_exists_returns_true() {
719 let catalog = new_memory_catalog().await;
720 let namespace_ident = NamespaceIdent::new("a".into());
721 create_namespace(&catalog, &namespace_ident).await;
722
723 assert!(catalog.namespace_exists(&namespace_ident).await.unwrap());
724 }
725
726 #[tokio::test]
727 async fn test_create_namespace_with_empty_properties() {
728 let catalog = new_memory_catalog().await;
729 let namespace_ident = NamespaceIdent::new("a".into());
730
731 assert_eq!(
732 catalog
733 .create_namespace(&namespace_ident, HashMap::new())
734 .await
735 .unwrap(),
736 Namespace::new(namespace_ident.clone())
737 );
738
739 assert_eq!(
740 catalog.get_namespace(&namespace_ident).await.unwrap(),
741 Namespace::with_properties(namespace_ident, HashMap::new())
742 );
743 }
744
745 #[tokio::test]
746 async fn test_create_namespace_with_properties() {
747 let catalog = new_memory_catalog().await;
748 let namespace_ident = NamespaceIdent::new("abc".into());
749
750 let mut properties: HashMap<String, String> = HashMap::new();
751 properties.insert("k".into(), "v".into());
752
753 assert_eq!(
754 catalog
755 .create_namespace(&namespace_ident, properties.clone())
756 .await
757 .unwrap(),
758 Namespace::with_properties(namespace_ident.clone(), properties.clone())
759 );
760
761 assert_eq!(
762 catalog.get_namespace(&namespace_ident).await.unwrap(),
763 Namespace::with_properties(namespace_ident, properties)
764 );
765 }
766
767 #[tokio::test]
768 async fn test_create_namespace_throws_error_if_namespace_already_exists() {
769 let catalog = new_memory_catalog().await;
770 let namespace_ident = NamespaceIdent::new("a".into());
771 create_namespace(&catalog, &namespace_ident).await;
772
773 assert_eq!(
774 catalog
775 .create_namespace(&namespace_ident, HashMap::new())
776 .await
777 .unwrap_err()
778 .to_string(),
779 format!(
780 "NamespaceAlreadyExists => Cannot create namespace {:?}. Namespace already exists.",
781 &namespace_ident
782 )
783 );
784
785 assert_eq!(
786 catalog.get_namespace(&namespace_ident).await.unwrap(),
787 Namespace::with_properties(namespace_ident, HashMap::new())
788 );
789 }
790
791 #[tokio::test]
792 async fn test_create_nested_namespace() {
793 let catalog = new_memory_catalog().await;
794 let parent_namespace_ident = NamespaceIdent::new("a".into());
795 create_namespace(&catalog, &parent_namespace_ident).await;
796
797 let child_namespace_ident = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
798
799 assert_eq!(
800 catalog
801 .create_namespace(&child_namespace_ident, HashMap::new())
802 .await
803 .unwrap(),
804 Namespace::new(child_namespace_ident.clone())
805 );
806
807 assert_eq!(
808 catalog.get_namespace(&child_namespace_ident).await.unwrap(),
809 Namespace::with_properties(child_namespace_ident, HashMap::new())
810 );
811 }
812
813 #[tokio::test]
814 async fn test_create_deeply_nested_namespace() {
815 let catalog = new_memory_catalog().await;
816 let namespace_ident_a = NamespaceIdent::new("a".into());
817 let namespace_ident_a_b = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
818 create_namespaces(&catalog, &vec![&namespace_ident_a, &namespace_ident_a_b]).await;
819
820 let namespace_ident_a_b_c = NamespaceIdent::from_strs(vec!["a", "b", "c"]).unwrap();
821
822 assert_eq!(
823 catalog
824 .create_namespace(&namespace_ident_a_b_c, HashMap::new())
825 .await
826 .unwrap(),
827 Namespace::new(namespace_ident_a_b_c.clone())
828 );
829
830 assert_eq!(
831 catalog.get_namespace(&namespace_ident_a_b_c).await.unwrap(),
832 Namespace::with_properties(namespace_ident_a_b_c, HashMap::new())
833 );
834 }
835
836 #[tokio::test]
837 async fn test_create_nested_namespace_throws_error_if_top_level_namespace_doesnt_exist() {
838 let catalog = new_memory_catalog().await;
839
840 let nested_namespace_ident = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
841
842 assert_eq!(
843 catalog
844 .create_namespace(&nested_namespace_ident, HashMap::new())
845 .await
846 .unwrap_err()
847 .to_string(),
848 format!(
849 "NamespaceNotFound => No such namespace: {:?}",
850 NamespaceIdent::new("a".into())
851 )
852 );
853
854 assert_eq!(catalog.list_namespaces(None).await.unwrap(), vec![]);
855 }
856
857 #[tokio::test]
858 async fn test_create_deeply_nested_namespace_throws_error_if_intermediate_namespace_doesnt_exist()
859 {
860 let catalog = new_memory_catalog().await;
861
862 let namespace_ident_a = NamespaceIdent::new("a".into());
863 create_namespace(&catalog, &namespace_ident_a).await;
864
865 let namespace_ident_a_b_c = NamespaceIdent::from_strs(vec!["a", "b", "c"]).unwrap();
866
867 assert_eq!(
868 catalog
869 .create_namespace(&namespace_ident_a_b_c, HashMap::new())
870 .await
871 .unwrap_err()
872 .to_string(),
873 format!(
874 "NamespaceNotFound => No such namespace: {:?}",
875 NamespaceIdent::from_strs(vec!["a", "b"]).unwrap()
876 )
877 );
878
879 assert_eq!(catalog.list_namespaces(None).await.unwrap(), vec![
880 namespace_ident_a.clone()
881 ]);
882
883 assert_eq!(
884 catalog
885 .list_namespaces(Some(&namespace_ident_a))
886 .await
887 .unwrap(),
888 vec![]
889 );
890 }
891
892 #[tokio::test]
893 async fn test_get_namespace() {
894 let catalog = new_memory_catalog().await;
895 let namespace_ident = NamespaceIdent::new("abc".into());
896
897 let mut properties: HashMap<String, String> = HashMap::new();
898 properties.insert("k".into(), "v".into());
899 let _ = catalog
900 .create_namespace(&namespace_ident, properties.clone())
901 .await
902 .unwrap();
903
904 assert_eq!(
905 catalog.get_namespace(&namespace_ident).await.unwrap(),
906 Namespace::with_properties(namespace_ident, properties)
907 )
908 }
909
910 #[tokio::test]
911 async fn test_get_nested_namespace() {
912 let catalog = new_memory_catalog().await;
913 let namespace_ident_a = NamespaceIdent::new("a".into());
914 let namespace_ident_a_b = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
915 create_namespaces(&catalog, &vec![&namespace_ident_a, &namespace_ident_a_b]).await;
916
917 assert_eq!(
918 catalog.get_namespace(&namespace_ident_a_b).await.unwrap(),
919 Namespace::with_properties(namespace_ident_a_b, HashMap::new())
920 );
921 }
922
923 #[tokio::test]
924 async fn test_get_deeply_nested_namespace() {
925 let catalog = new_memory_catalog().await;
926 let namespace_ident_a = NamespaceIdent::new("a".into());
927 let namespace_ident_a_b = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
928 let namespace_ident_a_b_c = NamespaceIdent::from_strs(vec!["a", "b", "c"]).unwrap();
929 create_namespaces(&catalog, &vec![
930 &namespace_ident_a,
931 &namespace_ident_a_b,
932 &namespace_ident_a_b_c,
933 ])
934 .await;
935
936 assert_eq!(
937 catalog.get_namespace(&namespace_ident_a_b_c).await.unwrap(),
938 Namespace::with_properties(namespace_ident_a_b_c, HashMap::new())
939 );
940 }
941
942 #[tokio::test]
943 async fn test_get_namespace_throws_error_if_namespace_doesnt_exist() {
944 let catalog = new_memory_catalog().await;
945 create_namespace(&catalog, &NamespaceIdent::new("a".into())).await;
946
947 let non_existent_namespace_ident = NamespaceIdent::new("b".into());
948 assert_eq!(
949 catalog
950 .get_namespace(&non_existent_namespace_ident)
951 .await
952 .unwrap_err()
953 .to_string(),
954 format!("NamespaceNotFound => No such namespace: {non_existent_namespace_ident:?}")
955 )
956 }
957
958 #[tokio::test]
959 async fn test_update_namespace() {
960 let catalog = new_memory_catalog().await;
961 let namespace_ident = NamespaceIdent::new("abc".into());
962 create_namespace(&catalog, &namespace_ident).await;
963
964 let mut new_properties: HashMap<String, String> = HashMap::new();
965 new_properties.insert("k".into(), "v".into());
966
967 catalog
968 .update_namespace(&namespace_ident, new_properties.clone())
969 .await
970 .unwrap();
971
972 assert_eq!(
973 catalog.get_namespace(&namespace_ident).await.unwrap(),
974 Namespace::with_properties(namespace_ident, new_properties)
975 )
976 }
977
978 #[tokio::test]
979 async fn test_update_nested_namespace() {
980 let catalog = new_memory_catalog().await;
981 let namespace_ident_a = NamespaceIdent::new("a".into());
982 let namespace_ident_a_b = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
983 create_namespaces(&catalog, &vec![&namespace_ident_a, &namespace_ident_a_b]).await;
984
985 let mut new_properties = HashMap::new();
986 new_properties.insert("k".into(), "v".into());
987
988 catalog
989 .update_namespace(&namespace_ident_a_b, new_properties.clone())
990 .await
991 .unwrap();
992
993 assert_eq!(
994 catalog.get_namespace(&namespace_ident_a_b).await.unwrap(),
995 Namespace::with_properties(namespace_ident_a_b, new_properties)
996 );
997 }
998
999 #[tokio::test]
1000 async fn test_update_deeply_nested_namespace() {
1001 let catalog = new_memory_catalog().await;
1002 let namespace_ident_a = NamespaceIdent::new("a".into());
1003 let namespace_ident_a_b = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
1004 let namespace_ident_a_b_c = NamespaceIdent::from_strs(vec!["a", "b", "c"]).unwrap();
1005 create_namespaces(&catalog, &vec![
1006 &namespace_ident_a,
1007 &namespace_ident_a_b,
1008 &namespace_ident_a_b_c,
1009 ])
1010 .await;
1011
1012 let mut new_properties = HashMap::new();
1013 new_properties.insert("k".into(), "v".into());
1014
1015 catalog
1016 .update_namespace(&namespace_ident_a_b_c, new_properties.clone())
1017 .await
1018 .unwrap();
1019
1020 assert_eq!(
1021 catalog.get_namespace(&namespace_ident_a_b_c).await.unwrap(),
1022 Namespace::with_properties(namespace_ident_a_b_c, new_properties)
1023 );
1024 }
1025
1026 #[tokio::test]
1027 async fn test_update_namespace_throws_error_if_namespace_doesnt_exist() {
1028 let catalog = new_memory_catalog().await;
1029 create_namespace(&catalog, &NamespaceIdent::new("abc".into())).await;
1030
1031 let non_existent_namespace_ident = NamespaceIdent::new("def".into());
1032 assert_eq!(
1033 catalog
1034 .update_namespace(&non_existent_namespace_ident, HashMap::new())
1035 .await
1036 .unwrap_err()
1037 .to_string(),
1038 format!("NamespaceNotFound => No such namespace: {non_existent_namespace_ident:?}")
1039 )
1040 }
1041
1042 #[tokio::test]
1043 async fn test_drop_namespace() {
1044 let catalog = new_memory_catalog().await;
1045 let namespace_ident = NamespaceIdent::new("abc".into());
1046 create_namespace(&catalog, &namespace_ident).await;
1047
1048 catalog.drop_namespace(&namespace_ident).await.unwrap();
1049
1050 assert!(!catalog.namespace_exists(&namespace_ident).await.unwrap())
1051 }
1052
1053 #[tokio::test]
1054 async fn test_drop_nested_namespace() {
1055 let catalog = new_memory_catalog().await;
1056 let namespace_ident_a = NamespaceIdent::new("a".into());
1057 let namespace_ident_a_b = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
1058 create_namespaces(&catalog, &vec![&namespace_ident_a, &namespace_ident_a_b]).await;
1059
1060 catalog.drop_namespace(&namespace_ident_a_b).await.unwrap();
1061
1062 assert!(
1063 !catalog
1064 .namespace_exists(&namespace_ident_a_b)
1065 .await
1066 .unwrap()
1067 );
1068
1069 assert!(catalog.namespace_exists(&namespace_ident_a).await.unwrap());
1070 }
1071
1072 #[tokio::test]
1073 async fn test_drop_deeply_nested_namespace() {
1074 let catalog = new_memory_catalog().await;
1075 let namespace_ident_a = NamespaceIdent::new("a".into());
1076 let namespace_ident_a_b = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
1077 let namespace_ident_a_b_c = NamespaceIdent::from_strs(vec!["a", "b", "c"]).unwrap();
1078 create_namespaces(&catalog, &vec![
1079 &namespace_ident_a,
1080 &namespace_ident_a_b,
1081 &namespace_ident_a_b_c,
1082 ])
1083 .await;
1084
1085 catalog
1086 .drop_namespace(&namespace_ident_a_b_c)
1087 .await
1088 .unwrap();
1089
1090 assert!(
1091 !catalog
1092 .namespace_exists(&namespace_ident_a_b_c)
1093 .await
1094 .unwrap()
1095 );
1096
1097 assert!(
1098 catalog
1099 .namespace_exists(&namespace_ident_a_b)
1100 .await
1101 .unwrap()
1102 );
1103
1104 assert!(catalog.namespace_exists(&namespace_ident_a).await.unwrap());
1105 }
1106
1107 #[tokio::test]
1108 async fn test_drop_namespace_throws_error_if_namespace_doesnt_exist() {
1109 let catalog = new_memory_catalog().await;
1110
1111 let non_existent_namespace_ident = NamespaceIdent::new("abc".into());
1112 assert_eq!(
1113 catalog
1114 .drop_namespace(&non_existent_namespace_ident)
1115 .await
1116 .unwrap_err()
1117 .to_string(),
1118 format!("NamespaceNotFound => No such namespace: {non_existent_namespace_ident:?}")
1119 )
1120 }
1121
1122 #[tokio::test]
1123 async fn test_drop_namespace_throws_error_if_nested_namespace_doesnt_exist() {
1124 let catalog = new_memory_catalog().await;
1125 create_namespace(&catalog, &NamespaceIdent::new("a".into())).await;
1126
1127 let non_existent_namespace_ident =
1128 NamespaceIdent::from_vec(vec!["a".into(), "b".into()]).unwrap();
1129 assert_eq!(
1130 catalog
1131 .drop_namespace(&non_existent_namespace_ident)
1132 .await
1133 .unwrap_err()
1134 .to_string(),
1135 format!("NamespaceNotFound => No such namespace: {non_existent_namespace_ident:?}")
1136 )
1137 }
1138
1139 #[tokio::test]
1140 async fn test_dropping_a_namespace_also_drops_namespaces_nested_under_that_one() {
1141 let catalog = new_memory_catalog().await;
1142 let namespace_ident_a = NamespaceIdent::new("a".into());
1143 let namespace_ident_a_b = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
1144 create_namespaces(&catalog, &vec![&namespace_ident_a, &namespace_ident_a_b]).await;
1145
1146 catalog.drop_namespace(&namespace_ident_a).await.unwrap();
1147
1148 assert!(!catalog.namespace_exists(&namespace_ident_a).await.unwrap());
1149
1150 assert!(
1151 !catalog
1152 .namespace_exists(&namespace_ident_a_b)
1153 .await
1154 .unwrap()
1155 );
1156 }
1157
1158 #[tokio::test]
1159 async fn test_create_table_with_location() {
1160 let tmp_dir = TempDir::new().unwrap();
1161 let catalog = new_memory_catalog().await;
1162 let namespace_ident = NamespaceIdent::new("a".into());
1163 create_namespace(&catalog, &namespace_ident).await;
1164
1165 let table_name = "abc";
1166 let location = tmp_dir.path().to_str().unwrap().to_string();
1167 let table_creation = TableCreation::builder()
1168 .name(table_name.into())
1169 .location(location.clone())
1170 .schema(simple_table_schema())
1171 .build();
1172
1173 let expected_table_ident = TableIdent::new(namespace_ident.clone(), table_name.into());
1174
1175 assert_table_eq(
1176 &catalog
1177 .create_table(&namespace_ident, table_creation)
1178 .await
1179 .unwrap(),
1180 &expected_table_ident,
1181 &simple_table_schema(),
1182 );
1183
1184 let table = catalog.load_table(&expected_table_ident).await.unwrap();
1185
1186 assert_table_eq(&table, &expected_table_ident, &simple_table_schema());
1187
1188 assert!(
1189 table
1190 .metadata_location()
1191 .unwrap()
1192 .to_string()
1193 .starts_with(&location)
1194 )
1195 }
1196
1197 #[tokio::test]
1198 async fn test_create_table_falls_back_to_namespace_location_if_table_location_is_missing() {
1199 let warehouse_location = temp_path();
1200 let catalog = MemoryCatalogBuilder::default()
1201 .load(
1202 "memory",
1203 HashMap::from([(
1204 MEMORY_CATALOG_WAREHOUSE.to_string(),
1205 warehouse_location.clone(),
1206 )]),
1207 )
1208 .await
1209 .unwrap();
1210
1211 let namespace_ident = NamespaceIdent::new("a".into());
1212 let mut namespace_properties = HashMap::new();
1213 let namespace_location = temp_path();
1214 namespace_properties.insert(LOCATION.to_string(), namespace_location.to_string());
1215 catalog
1216 .create_namespace(&namespace_ident, namespace_properties)
1217 .await
1218 .unwrap();
1219
1220 let table_name = "tbl1";
1221 let expected_table_ident = TableIdent::new(namespace_ident.clone(), table_name.into());
1222 let expected_table_metadata_location_regex =
1223 format!("^{namespace_location}/tbl1/metadata/00000-{UUID_REGEX_STR}.metadata.json$",);
1224
1225 let table = catalog
1226 .create_table(
1227 &namespace_ident,
1228 TableCreation::builder()
1229 .name(table_name.into())
1230 .schema(simple_table_schema())
1231 .build(),
1233 )
1234 .await
1235 .unwrap();
1236 assert_table_eq(&table, &expected_table_ident, &simple_table_schema());
1237 assert_table_metadata_location_matches(&table, &expected_table_metadata_location_regex);
1238
1239 let table = catalog.load_table(&expected_table_ident).await.unwrap();
1240 assert_table_eq(&table, &expected_table_ident, &simple_table_schema());
1241 assert_table_metadata_location_matches(&table, &expected_table_metadata_location_regex);
1242 }
1243
1244 #[tokio::test]
1245 async fn test_create_table_in_nested_namespace_falls_back_to_nested_namespace_location_if_table_location_is_missing()
1246 {
1247 let warehouse_location = temp_path();
1248 let catalog = MemoryCatalogBuilder::default()
1249 .load(
1250 "memory",
1251 HashMap::from([(
1252 MEMORY_CATALOG_WAREHOUSE.to_string(),
1253 warehouse_location.clone(),
1254 )]),
1255 )
1256 .await
1257 .unwrap();
1258
1259 let namespace_ident = NamespaceIdent::new("a".into());
1260 let mut namespace_properties = HashMap::new();
1261 let namespace_location = temp_path();
1262 namespace_properties.insert(LOCATION.to_string(), namespace_location.to_string());
1263 catalog
1264 .create_namespace(&namespace_ident, namespace_properties)
1265 .await
1266 .unwrap();
1267
1268 let nested_namespace_ident = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
1269 let mut nested_namespace_properties = HashMap::new();
1270 let nested_namespace_location = temp_path();
1271 nested_namespace_properties
1272 .insert(LOCATION.to_string(), nested_namespace_location.to_string());
1273 catalog
1274 .create_namespace(&nested_namespace_ident, nested_namespace_properties)
1275 .await
1276 .unwrap();
1277
1278 let table_name = "tbl1";
1279 let expected_table_ident =
1280 TableIdent::new(nested_namespace_ident.clone(), table_name.into());
1281 let expected_table_metadata_location_regex = format!(
1282 "^{nested_namespace_location}/tbl1/metadata/00000-{UUID_REGEX_STR}.metadata.json$",
1283 );
1284
1285 let table = catalog
1286 .create_table(
1287 &nested_namespace_ident,
1288 TableCreation::builder()
1289 .name(table_name.into())
1290 .schema(simple_table_schema())
1291 .build(),
1293 )
1294 .await
1295 .unwrap();
1296 assert_table_eq(&table, &expected_table_ident, &simple_table_schema());
1297 assert_table_metadata_location_matches(&table, &expected_table_metadata_location_regex);
1298
1299 let table = catalog.load_table(&expected_table_ident).await.unwrap();
1300 assert_table_eq(&table, &expected_table_ident, &simple_table_schema());
1301 assert_table_metadata_location_matches(&table, &expected_table_metadata_location_regex);
1302 }
1303
1304 #[tokio::test]
1305 async fn test_create_table_falls_back_to_warehouse_location_if_both_table_location_and_namespace_location_are_missing()
1306 {
1307 let warehouse_location = temp_path();
1308 let catalog = MemoryCatalogBuilder::default()
1309 .load(
1310 "memory",
1311 HashMap::from([(
1312 MEMORY_CATALOG_WAREHOUSE.to_string(),
1313 warehouse_location.clone(),
1314 )]),
1315 )
1316 .await
1317 .unwrap();
1318
1319 let namespace_ident = NamespaceIdent::new("a".into());
1320 let namespace_properties = HashMap::new();
1322 catalog
1323 .create_namespace(&namespace_ident, namespace_properties)
1324 .await
1325 .unwrap();
1326
1327 let table_name = "tbl1";
1328 let expected_table_ident = TableIdent::new(namespace_ident.clone(), table_name.into());
1329 let expected_table_metadata_location_regex =
1330 format!("^{warehouse_location}/a/tbl1/metadata/00000-{UUID_REGEX_STR}.metadata.json$");
1331
1332 let table = catalog
1333 .create_table(
1334 &namespace_ident,
1335 TableCreation::builder()
1336 .name(table_name.into())
1337 .schema(simple_table_schema())
1338 .build(),
1340 )
1341 .await
1342 .unwrap();
1343 assert_table_eq(&table, &expected_table_ident, &simple_table_schema());
1344 assert_table_metadata_location_matches(&table, &expected_table_metadata_location_regex);
1345
1346 let table = catalog.load_table(&expected_table_ident).await.unwrap();
1347 assert_table_eq(&table, &expected_table_ident, &simple_table_schema());
1348 assert_table_metadata_location_matches(&table, &expected_table_metadata_location_regex);
1349 }
1350
1351 #[tokio::test]
1352 async fn test_create_table_in_nested_namespace_falls_back_to_warehouse_location_if_both_table_location_and_namespace_location_are_missing()
1353 {
1354 let warehouse_location = temp_path();
1355 let catalog = MemoryCatalogBuilder::default()
1356 .load(
1357 "memory",
1358 HashMap::from([(
1359 MEMORY_CATALOG_WAREHOUSE.to_string(),
1360 warehouse_location.clone(),
1361 )]),
1362 )
1363 .await
1364 .unwrap();
1365
1366 let namespace_ident = NamespaceIdent::new("a".into());
1367 catalog
1368 .create_namespace(&namespace_ident, HashMap::new())
1370 .await
1371 .unwrap();
1372
1373 let nested_namespace_ident = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
1374 catalog
1375 .create_namespace(&nested_namespace_ident, HashMap::new())
1377 .await
1378 .unwrap();
1379
1380 let table_name = "tbl1";
1381 let expected_table_ident =
1382 TableIdent::new(nested_namespace_ident.clone(), table_name.into());
1383 let expected_table_metadata_location_regex = format!(
1384 "^{warehouse_location}/a/b/tbl1/metadata/00000-{UUID_REGEX_STR}.metadata.json$"
1385 );
1386
1387 let table = catalog
1388 .create_table(
1389 &nested_namespace_ident,
1390 TableCreation::builder()
1391 .name(table_name.into())
1392 .schema(simple_table_schema())
1393 .build(),
1395 )
1396 .await
1397 .unwrap();
1398 assert_table_eq(&table, &expected_table_ident, &simple_table_schema());
1399 assert_table_metadata_location_matches(&table, &expected_table_metadata_location_regex);
1400
1401 let table = catalog.load_table(&expected_table_ident).await.unwrap();
1402 assert_table_eq(&table, &expected_table_ident, &simple_table_schema());
1403 assert_table_metadata_location_matches(&table, &expected_table_metadata_location_regex);
1404 }
1405
1406 #[tokio::test]
1407 async fn test_create_table_throws_error_if_table_location_and_namespace_location_and_warehouse_location_are_missing()
1408 {
1409 let catalog = MemoryCatalogBuilder::default()
1410 .load("memory", HashMap::from([]))
1411 .await;
1412
1413 assert!(catalog.is_err());
1414 assert_eq!(
1415 catalog.unwrap_err().to_string(),
1416 "DataInvalid => Catalog warehouse is required"
1417 );
1418 }
1419
1420 #[tokio::test]
1421 async fn test_create_table_throws_error_if_table_with_same_name_already_exists() {
1422 let catalog = new_memory_catalog().await;
1423 let namespace_ident = NamespaceIdent::new("a".into());
1424 create_namespace(&catalog, &namespace_ident).await;
1425 let table_name = "tbl1";
1426 let table_ident = TableIdent::new(namespace_ident.clone(), table_name.into());
1427 create_table(&catalog, &table_ident).await;
1428
1429 let tmp_dir = TempDir::new().unwrap();
1430 let location = tmp_dir.path().to_str().unwrap().to_string();
1431
1432 assert_eq!(
1433 catalog
1434 .create_table(
1435 &namespace_ident,
1436 TableCreation::builder()
1437 .name(table_name.into())
1438 .schema(simple_table_schema())
1439 .location(location)
1440 .build()
1441 )
1442 .await
1443 .unwrap_err()
1444 .to_string(),
1445 format!(
1446 "TableAlreadyExists => Cannot create table {:?}. Table already exists.",
1447 &table_ident
1448 )
1449 );
1450 }
1451
1452 #[tokio::test]
1453 async fn test_list_tables_returns_empty_vector() {
1454 let catalog = new_memory_catalog().await;
1455 let namespace_ident = NamespaceIdent::new("a".into());
1456 create_namespace(&catalog, &namespace_ident).await;
1457
1458 assert_eq!(catalog.list_tables(&namespace_ident).await.unwrap(), vec![]);
1459 }
1460
1461 #[tokio::test]
1462 async fn test_list_tables_returns_a_single_table() {
1463 let catalog = new_memory_catalog().await;
1464 let namespace_ident = NamespaceIdent::new("n1".into());
1465 create_namespace(&catalog, &namespace_ident).await;
1466
1467 let table_ident = TableIdent::new(namespace_ident.clone(), "tbl1".into());
1468 create_table(&catalog, &table_ident).await;
1469
1470 assert_eq!(catalog.list_tables(&namespace_ident).await.unwrap(), vec![
1471 table_ident
1472 ]);
1473 }
1474
1475 #[tokio::test]
1476 async fn test_list_tables_returns_multiple_tables() {
1477 let catalog = new_memory_catalog().await;
1478 let namespace_ident = NamespaceIdent::new("n1".into());
1479 create_namespace(&catalog, &namespace_ident).await;
1480
1481 let table_ident_1 = TableIdent::new(namespace_ident.clone(), "tbl1".into());
1482 let table_ident_2 = TableIdent::new(namespace_ident.clone(), "tbl2".into());
1483 let _ = create_tables(&catalog, vec![&table_ident_1, &table_ident_2]).await;
1484
1485 assert_eq!(
1486 to_set(catalog.list_tables(&namespace_ident).await.unwrap()),
1487 to_set(vec![table_ident_1, table_ident_2])
1488 );
1489 }
1490
1491 #[tokio::test]
1492 async fn test_list_tables_returns_tables_from_correct_namespace() {
1493 let catalog = new_memory_catalog().await;
1494 let namespace_ident_1 = NamespaceIdent::new("n1".into());
1495 let namespace_ident_2 = NamespaceIdent::new("n2".into());
1496 create_namespaces(&catalog, &vec![&namespace_ident_1, &namespace_ident_2]).await;
1497
1498 let table_ident_1 = TableIdent::new(namespace_ident_1.clone(), "tbl1".into());
1499 let table_ident_2 = TableIdent::new(namespace_ident_1.clone(), "tbl2".into());
1500 let table_ident_3 = TableIdent::new(namespace_ident_2.clone(), "tbl1".into());
1501 let _ = create_tables(&catalog, vec![
1502 &table_ident_1,
1503 &table_ident_2,
1504 &table_ident_3,
1505 ])
1506 .await;
1507
1508 assert_eq!(
1509 to_set(catalog.list_tables(&namespace_ident_1).await.unwrap()),
1510 to_set(vec![table_ident_1, table_ident_2])
1511 );
1512
1513 assert_eq!(
1514 to_set(catalog.list_tables(&namespace_ident_2).await.unwrap()),
1515 to_set(vec![table_ident_3])
1516 );
1517 }
1518
1519 #[tokio::test]
1520 async fn test_list_tables_returns_table_under_nested_namespace() {
1521 let catalog = new_memory_catalog().await;
1522 let namespace_ident_a = NamespaceIdent::new("a".into());
1523 let namespace_ident_a_b = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
1524 create_namespaces(&catalog, &vec![&namespace_ident_a, &namespace_ident_a_b]).await;
1525
1526 let table_ident = TableIdent::new(namespace_ident_a_b.clone(), "tbl1".into());
1527 create_table(&catalog, &table_ident).await;
1528
1529 assert_eq!(
1530 catalog.list_tables(&namespace_ident_a_b).await.unwrap(),
1531 vec![table_ident]
1532 );
1533 }
1534
1535 #[tokio::test]
1536 async fn test_list_tables_throws_error_if_namespace_doesnt_exist() {
1537 let catalog = new_memory_catalog().await;
1538
1539 let non_existent_namespace_ident = NamespaceIdent::new("n1".into());
1540
1541 assert_eq!(
1542 catalog
1543 .list_tables(&non_existent_namespace_ident)
1544 .await
1545 .unwrap_err()
1546 .to_string(),
1547 format!("NamespaceNotFound => No such namespace: {non_existent_namespace_ident:?}"),
1548 );
1549 }
1550
1551 #[tokio::test]
1552 async fn test_drop_table() {
1553 let catalog = new_memory_catalog().await;
1554 let namespace_ident = NamespaceIdent::new("n1".into());
1555 create_namespace(&catalog, &namespace_ident).await;
1556 let table_ident = TableIdent::new(namespace_ident.clone(), "tbl1".into());
1557 create_table(&catalog, &table_ident).await;
1558
1559 catalog.drop_table(&table_ident).await.unwrap();
1560 }
1561
1562 #[tokio::test]
1563 async fn test_drop_table_drops_table_under_nested_namespace() {
1564 let catalog = new_memory_catalog().await;
1565 let namespace_ident_a = NamespaceIdent::new("a".into());
1566 let namespace_ident_a_b = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
1567 create_namespaces(&catalog, &vec![&namespace_ident_a, &namespace_ident_a_b]).await;
1568
1569 let table_ident = TableIdent::new(namespace_ident_a_b.clone(), "tbl1".into());
1570 create_table(&catalog, &table_ident).await;
1571
1572 catalog.drop_table(&table_ident).await.unwrap();
1573
1574 assert_eq!(
1575 catalog.list_tables(&namespace_ident_a_b).await.unwrap(),
1576 vec![]
1577 );
1578 }
1579
1580 #[tokio::test]
1581 async fn test_drop_table_throws_error_if_namespace_doesnt_exist() {
1582 let catalog = new_memory_catalog().await;
1583
1584 let non_existent_namespace_ident = NamespaceIdent::new("n1".into());
1585 let non_existent_table_ident =
1586 TableIdent::new(non_existent_namespace_ident.clone(), "tbl1".into());
1587
1588 assert_eq!(
1589 catalog
1590 .drop_table(&non_existent_table_ident)
1591 .await
1592 .unwrap_err()
1593 .to_string(),
1594 format!("NamespaceNotFound => No such namespace: {non_existent_namespace_ident:?}"),
1595 );
1596 }
1597
1598 #[tokio::test]
1599 async fn test_drop_table_throws_error_if_table_doesnt_exist() {
1600 let catalog = new_memory_catalog().await;
1601 let namespace_ident = NamespaceIdent::new("n1".into());
1602 create_namespace(&catalog, &namespace_ident).await;
1603
1604 let non_existent_table_ident = TableIdent::new(namespace_ident.clone(), "tbl1".into());
1605
1606 assert_eq!(
1607 catalog
1608 .drop_table(&non_existent_table_ident)
1609 .await
1610 .unwrap_err()
1611 .to_string(),
1612 format!("TableNotFound => No such table: {non_existent_table_ident:?}"),
1613 );
1614 }
1615
1616 #[tokio::test]
1617 async fn test_table_exists_returns_true() {
1618 let catalog = new_memory_catalog().await;
1619 let namespace_ident = NamespaceIdent::new("n1".into());
1620 create_namespace(&catalog, &namespace_ident).await;
1621 let table_ident = TableIdent::new(namespace_ident.clone(), "tbl1".into());
1622 create_table(&catalog, &table_ident).await;
1623
1624 assert!(catalog.table_exists(&table_ident).await.unwrap());
1625 }
1626
1627 #[tokio::test]
1628 async fn test_table_exists_returns_false() {
1629 let catalog = new_memory_catalog().await;
1630 let namespace_ident = NamespaceIdent::new("n1".into());
1631 create_namespace(&catalog, &namespace_ident).await;
1632 let non_existent_table_ident = TableIdent::new(namespace_ident.clone(), "tbl1".into());
1633
1634 assert!(
1635 !catalog
1636 .table_exists(&non_existent_table_ident)
1637 .await
1638 .unwrap()
1639 );
1640 }
1641
1642 #[tokio::test]
1643 async fn test_table_exists_under_nested_namespace() {
1644 let catalog = new_memory_catalog().await;
1645 let namespace_ident_a = NamespaceIdent::new("a".into());
1646 let namespace_ident_a_b = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
1647 create_namespaces(&catalog, &vec![&namespace_ident_a, &namespace_ident_a_b]).await;
1648
1649 let table_ident = TableIdent::new(namespace_ident_a_b.clone(), "tbl1".into());
1650 create_table(&catalog, &table_ident).await;
1651
1652 assert!(catalog.table_exists(&table_ident).await.unwrap());
1653
1654 let non_existent_table_ident = TableIdent::new(namespace_ident_a_b.clone(), "tbl2".into());
1655 assert!(
1656 !catalog
1657 .table_exists(&non_existent_table_ident)
1658 .await
1659 .unwrap()
1660 );
1661 }
1662
1663 #[tokio::test]
1664 async fn test_table_exists_throws_error_if_namespace_doesnt_exist() {
1665 let catalog = new_memory_catalog().await;
1666
1667 let non_existent_namespace_ident = NamespaceIdent::new("n1".into());
1668 let non_existent_table_ident =
1669 TableIdent::new(non_existent_namespace_ident.clone(), "tbl1".into());
1670
1671 assert_eq!(
1672 catalog
1673 .table_exists(&non_existent_table_ident)
1674 .await
1675 .unwrap_err()
1676 .to_string(),
1677 format!("NamespaceNotFound => No such namespace: {non_existent_namespace_ident:?}"),
1678 );
1679 }
1680
1681 #[tokio::test]
1682 async fn test_rename_table_in_same_namespace() {
1683 let catalog = new_memory_catalog().await;
1684 let namespace_ident = NamespaceIdent::new("n1".into());
1685 create_namespace(&catalog, &namespace_ident).await;
1686 let src_table_ident = TableIdent::new(namespace_ident.clone(), "tbl1".into());
1687 let dst_table_ident = TableIdent::new(namespace_ident.clone(), "tbl2".into());
1688 create_table(&catalog, &src_table_ident).await;
1689
1690 catalog
1691 .rename_table(&src_table_ident, &dst_table_ident)
1692 .await
1693 .unwrap();
1694
1695 assert_eq!(catalog.list_tables(&namespace_ident).await.unwrap(), vec![
1696 dst_table_ident
1697 ],);
1698 }
1699
1700 #[tokio::test]
1701 async fn test_rename_table_across_namespaces() {
1702 let catalog = new_memory_catalog().await;
1703 let src_namespace_ident = NamespaceIdent::new("a".into());
1704 let dst_namespace_ident = NamespaceIdent::new("b".into());
1705 create_namespaces(&catalog, &vec![&src_namespace_ident, &dst_namespace_ident]).await;
1706 let src_table_ident = TableIdent::new(src_namespace_ident.clone(), "tbl1".into());
1707 let dst_table_ident = TableIdent::new(dst_namespace_ident.clone(), "tbl2".into());
1708 create_table(&catalog, &src_table_ident).await;
1709
1710 catalog
1711 .rename_table(&src_table_ident, &dst_table_ident)
1712 .await
1713 .unwrap();
1714
1715 assert_eq!(
1716 catalog.list_tables(&src_namespace_ident).await.unwrap(),
1717 vec![],
1718 );
1719
1720 assert_eq!(
1721 catalog.list_tables(&dst_namespace_ident).await.unwrap(),
1722 vec![dst_table_ident],
1723 );
1724 }
1725
1726 #[tokio::test]
1727 async fn test_rename_table_src_table_is_same_as_dst_table() {
1728 let catalog = new_memory_catalog().await;
1729 let namespace_ident = NamespaceIdent::new("n1".into());
1730 create_namespace(&catalog, &namespace_ident).await;
1731 let table_ident = TableIdent::new(namespace_ident.clone(), "tbl".into());
1732 create_table(&catalog, &table_ident).await;
1733
1734 catalog
1735 .rename_table(&table_ident, &table_ident)
1736 .await
1737 .unwrap();
1738
1739 assert_eq!(catalog.list_tables(&namespace_ident).await.unwrap(), vec![
1740 table_ident
1741 ],);
1742 }
1743
1744 #[tokio::test]
1745 async fn test_rename_table_across_nested_namespaces() {
1746 let catalog = new_memory_catalog().await;
1747 let namespace_ident_a = NamespaceIdent::new("a".into());
1748 let namespace_ident_a_b = NamespaceIdent::from_strs(vec!["a", "b"]).unwrap();
1749 let namespace_ident_a_b_c = NamespaceIdent::from_strs(vec!["a", "b", "c"]).unwrap();
1750 create_namespaces(&catalog, &vec![
1751 &namespace_ident_a,
1752 &namespace_ident_a_b,
1753 &namespace_ident_a_b_c,
1754 ])
1755 .await;
1756
1757 let src_table_ident = TableIdent::new(namespace_ident_a_b_c.clone(), "tbl1".into());
1758 create_tables(&catalog, vec![&src_table_ident]).await;
1759
1760 let dst_table_ident = TableIdent::new(namespace_ident_a_b.clone(), "tbl1".into());
1761 catalog
1762 .rename_table(&src_table_ident, &dst_table_ident)
1763 .await
1764 .unwrap();
1765
1766 assert!(!catalog.table_exists(&src_table_ident).await.unwrap());
1767
1768 assert!(catalog.table_exists(&dst_table_ident).await.unwrap());
1769 }
1770
1771 #[tokio::test]
1772 async fn test_rename_table_throws_error_if_src_namespace_doesnt_exist() {
1773 let catalog = new_memory_catalog().await;
1774
1775 let non_existent_src_namespace_ident = NamespaceIdent::new("n1".into());
1776 let src_table_ident =
1777 TableIdent::new(non_existent_src_namespace_ident.clone(), "tbl1".into());
1778
1779 let dst_namespace_ident = NamespaceIdent::new("n2".into());
1780 create_namespace(&catalog, &dst_namespace_ident).await;
1781 let dst_table_ident = TableIdent::new(dst_namespace_ident.clone(), "tbl1".into());
1782
1783 assert_eq!(
1784 catalog
1785 .rename_table(&src_table_ident, &dst_table_ident)
1786 .await
1787 .unwrap_err()
1788 .to_string(),
1789 format!("NamespaceNotFound => No such namespace: {non_existent_src_namespace_ident:?}"),
1790 );
1791 }
1792
1793 #[tokio::test]
1794 async fn test_rename_table_throws_error_if_dst_namespace_doesnt_exist() {
1795 let catalog = new_memory_catalog().await;
1796 let src_namespace_ident = NamespaceIdent::new("n1".into());
1797 let src_table_ident = TableIdent::new(src_namespace_ident.clone(), "tbl1".into());
1798 create_namespace(&catalog, &src_namespace_ident).await;
1799 create_table(&catalog, &src_table_ident).await;
1800
1801 let non_existent_dst_namespace_ident = NamespaceIdent::new("n2".into());
1802 let dst_table_ident =
1803 TableIdent::new(non_existent_dst_namespace_ident.clone(), "tbl1".into());
1804 assert_eq!(
1805 catalog
1806 .rename_table(&src_table_ident, &dst_table_ident)
1807 .await
1808 .unwrap_err()
1809 .to_string(),
1810 format!("NamespaceNotFound => No such namespace: {non_existent_dst_namespace_ident:?}"),
1811 );
1812 }
1813
1814 #[tokio::test]
1815 async fn test_rename_table_throws_error_if_src_table_doesnt_exist() {
1816 let catalog = new_memory_catalog().await;
1817 let namespace_ident = NamespaceIdent::new("n1".into());
1818 create_namespace(&catalog, &namespace_ident).await;
1819 let src_table_ident = TableIdent::new(namespace_ident.clone(), "tbl1".into());
1820 let dst_table_ident = TableIdent::new(namespace_ident.clone(), "tbl2".into());
1821
1822 assert_eq!(
1823 catalog
1824 .rename_table(&src_table_ident, &dst_table_ident)
1825 .await
1826 .unwrap_err()
1827 .to_string(),
1828 format!("TableNotFound => No such table: {src_table_ident:?}"),
1829 );
1830 }
1831
1832 #[tokio::test]
1833 async fn test_rename_table_throws_error_if_dst_table_already_exists() {
1834 let catalog = new_memory_catalog().await;
1835 let namespace_ident = NamespaceIdent::new("n1".into());
1836 create_namespace(&catalog, &namespace_ident).await;
1837 let src_table_ident = TableIdent::new(namespace_ident.clone(), "tbl1".into());
1838 let dst_table_ident = TableIdent::new(namespace_ident.clone(), "tbl2".into());
1839 create_tables(&catalog, vec![&src_table_ident, &dst_table_ident]).await;
1840
1841 assert_eq!(
1842 catalog
1843 .rename_table(&src_table_ident, &dst_table_ident)
1844 .await
1845 .unwrap_err()
1846 .to_string(),
1847 format!(
1848 "TableAlreadyExists => Cannot create table {:?}. Table already exists.",
1849 &dst_table_ident
1850 ),
1851 );
1852 }
1853
1854 #[tokio::test]
1855 async fn test_register_table() {
1856 let catalog = new_memory_catalog().await;
1858 let namespace_ident = NamespaceIdent::new("test_namespace".into());
1859 create_namespace(&catalog, &namespace_ident).await;
1860
1861 let source_table_ident = TableIdent::new(namespace_ident.clone(), "source_table".into());
1863 create_table(&catalog, &source_table_ident).await;
1864
1865 let source_table = catalog.load_table(&source_table_ident).await.unwrap();
1867 let metadata_location = source_table.metadata_location().unwrap().to_string();
1868
1869 let register_table_ident =
1871 TableIdent::new(namespace_ident.clone(), "register_table".into());
1872 let registered_table = catalog
1873 .register_table(®ister_table_ident, metadata_location.clone())
1874 .await
1875 .unwrap();
1876
1877 assert_eq!(registered_table.identifier(), ®ister_table_ident);
1879
1880 assert_eq!(
1882 registered_table.metadata_location().unwrap().to_string(),
1883 metadata_location
1884 );
1885
1886 assert!(catalog.table_exists(®ister_table_ident).await.unwrap());
1888
1889 let loaded_table = catalog.load_table(®ister_table_ident).await.unwrap();
1891 assert_eq!(loaded_table.identifier(), ®ister_table_ident);
1892 assert_eq!(
1893 loaded_table.metadata_location().unwrap().to_string(),
1894 metadata_location
1895 );
1896 }
1897
1898 #[tokio::test]
1899 async fn test_update_table() {
1900 let catalog = new_memory_catalog().await;
1901
1902 let table = create_table_with_namespace(&catalog).await;
1903
1904 assert!(!table.metadata().properties().contains_key("key"));
1906
1907 tokio::time::sleep(std::time::Duration::from_millis(2)).await;
1911
1912 let tx = Transaction::new(&table);
1914 let updated_table = tx
1915 .update_table_properties()
1916 .set("key".to_string(), "value".to_string())
1917 .apply(tx)
1918 .unwrap()
1919 .commit(&catalog)
1920 .await
1921 .unwrap();
1922
1923 assert_eq!(
1924 updated_table.metadata().properties().get("key").unwrap(),
1925 "value"
1926 );
1927
1928 assert_eq!(table.identifier(), updated_table.identifier());
1929 assert_eq!(table.metadata().uuid(), updated_table.metadata().uuid());
1930 assert_ne!(table.metadata_location(), updated_table.metadata_location());
1931
1932 assert!(
1933 table.metadata().metadata_log().len() < updated_table.metadata().metadata_log().len()
1934 );
1935 }
1936
1937 #[tokio::test]
1938 async fn test_update_table_fails_if_table_doesnt_exist() {
1939 let catalog = new_memory_catalog().await;
1940
1941 let namespace_ident = NamespaceIdent::new("a".into());
1942 create_namespace(&catalog, &namespace_ident).await;
1943
1944 let table_ident = TableIdent::new(namespace_ident, "test".to_string());
1946 let table = build_table(table_ident);
1947
1948 let tx = Transaction::new(&table);
1949 let err = tx
1950 .update_table_properties()
1951 .set("key".to_string(), "value".to_string())
1952 .apply(tx)
1953 .unwrap()
1954 .commit(&catalog)
1955 .await
1956 .unwrap_err();
1957 assert_eq!(err.kind(), ErrorKind::TableNotFound);
1958 }
1959
1960 const FIXTURE_MASTER_KEY_ID: &str = "master-1";
1963 const FIXTURE_MASTER_KEY_BYTES: [u8; 16] = [
1964 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
1965 0x0f,
1966 ];
1967
1968 fn fixture_kms_factory() -> MemoryKmsClientFactory {
1970 use crate::encryption::SensitiveBytes;
1971
1972 let factory = MemoryKmsClientFactory::new();
1973 factory
1974 .add_master_key_bytes(
1975 FIXTURE_MASTER_KEY_ID,
1976 SensitiveBytes::new(FIXTURE_MASTER_KEY_BYTES),
1977 )
1978 .unwrap();
1979 factory
1980 }
1981
1982 fn load_encrypted_fixture_metadata() -> TableMetadata {
1985 let manifest_dir = env!("CARGO_MANIFEST_DIR");
1986 let metadata_json = std::fs::read_to_string(format!(
1987 "{manifest_dir}/testdata/table_metadata/TableMetadataV3ValidEncryption.json"
1988 ))
1989 .unwrap();
1990 let mut metadata: TableMetadata = serde_json::from_str(&metadata_json).unwrap();
1991
1992 let manifest_list_path =
1993 format!("{manifest_dir}/testdata/manifests_lists/manifest-list-v3-encrypted.avro");
1994 let snapshot = metadata.snapshots.get_mut(&1).unwrap();
1995 let mut patched = snapshot.as_ref().clone();
1996 patched.manifest_list = manifest_list_path;
1997 *snapshot = Arc::new(patched);
1998
1999 metadata
2000 }
2001
2002 #[tokio::test]
2003 async fn catalog_kms_factory_client_reaches_table_encryption_manager() {
2004 let warehouse = temp_path();
2005 let catalog = MemoryCatalogBuilder::default()
2006 .with_storage_factory(Arc::new(LocalFsStorageFactory))
2007 .with_kms_client_factory(Arc::new(fixture_kms_factory()))
2008 .load(
2009 "memory",
2010 HashMap::from([(MEMORY_CATALOG_WAREHOUSE.to_string(), warehouse)]),
2011 )
2012 .await
2013 .unwrap();
2014
2015 let namespace_ident = NamespaceIdent::new("enc_ns".into());
2016 create_namespace(&catalog, &namespace_ident).await;
2017
2018 let metadata = load_encrypted_fixture_metadata();
2019 let metadata_dir = TempDir::new().unwrap();
2020 let metadata_location =
2021 format!("{}/v1.metadata.json", metadata_dir.path().to_str().unwrap());
2022 std::fs::write(&metadata_location, serde_json::to_vec(&metadata).unwrap()).unwrap();
2023
2024 let table_ident = TableIdent::new(namespace_ident, "enc".to_string());
2025 catalog
2026 .register_table(&table_ident, metadata_location)
2027 .await
2028 .unwrap();
2029
2030 let table = catalog.load_table(&table_ident).await.unwrap();
2031 assert!(
2032 table.encryption_manager().is_some(),
2033 "factory-built KMS client should have reached the table's EncryptionManager"
2034 );
2035
2036 let snapshot_ref = table.metadata().current_snapshot().unwrap();
2037 let manifest_list = table
2038 .object_cache()
2039 .get_manifest_list(snapshot_ref, &table.metadata_ref())
2040 .await
2041 .unwrap();
2042 assert_eq!(manifest_list.entries().len(), 0);
2043 }
2044
2045 fn build_table(ident: TableIdent) -> Table {
2046 let file_io = FileIO::new_with_fs();
2047
2048 let temp_dir = TempDir::new().unwrap();
2049 let location = temp_dir.path().to_str().unwrap().to_string();
2050
2051 let table_creation = TableCreation::builder()
2052 .name(ident.name().to_string())
2053 .schema(simple_table_schema())
2054 .location(location)
2055 .build();
2056 let metadata = TableMetadataBuilder::from_table_creation(table_creation)
2057 .unwrap()
2058 .build()
2059 .unwrap()
2060 .metadata;
2061
2062 Table::builder()
2063 .identifier(ident)
2064 .metadata(metadata)
2065 .file_io(file_io)
2066 .runtime(test_runtime())
2067 .build()
2068 .unwrap()
2069 }
2070}