reifydb_catalog/store/dictionary/
list.rs

1// Copyright (c) reifydb.com 2025
2// This file is licensed under the AGPL-3.0-or-later, see license.md file
3
4use reifydb_core::{
5	interface::{DictionaryDef, DictionaryId, NamespaceId, QueryTransaction},
6	key::{DictionaryKey, NamespaceDictionaryKey},
7};
8use reifydb_type::Type;
9
10use crate::{
11	CatalogStore,
12	store::dictionary::layout::{dictionary, dictionary_namespace},
13};
14
15impl CatalogStore {
16	/// List all dictionaries in a namespace
17	pub async fn list_dictionaries(
18		rx: &mut impl QueryTransaction,
19		namespace: NamespaceId,
20	) -> crate::Result<Vec<DictionaryDef>> {
21		// Collect dictionary IDs first to avoid borrow conflict
22		let batch = rx.range(NamespaceDictionaryKey::full_scan(namespace)).await?;
23		let dictionary_ids: Vec<DictionaryId> = batch
24			.items
25			.iter()
26			.map(|multi| {
27				let row = &multi.values;
28				DictionaryId(dictionary_namespace::LAYOUT.get_u64(row, dictionary_namespace::ID))
29			})
30			.collect();
31
32		let mut dictionaries = Vec::new();
33		for dictionary_id in dictionary_ids {
34			if let Some(dictionary) = Self::find_dictionary(rx, dictionary_id).await? {
35				dictionaries.push(dictionary);
36			}
37		}
38
39		Ok(dictionaries)
40	}
41
42	/// List all dictionaries in the database
43	pub async fn list_all_dictionaries(rx: &mut impl QueryTransaction) -> crate::Result<Vec<DictionaryDef>> {
44		let mut dictionaries = Vec::new();
45
46		let batch = rx.range(DictionaryKey::full_scan()).await?;
47		for multi in batch.items {
48			let row = &multi.values;
49			let id = DictionaryId(dictionary::LAYOUT.get_u64(&row, dictionary::ID));
50			let namespace = NamespaceId(dictionary::LAYOUT.get_u64(&row, dictionary::NAMESPACE));
51			let name = dictionary::LAYOUT.get_utf8(&row, dictionary::NAME).to_string();
52			let value_type_ordinal = dictionary::LAYOUT.get_u8(&row, dictionary::VALUE_TYPE);
53			let id_type_ordinal = dictionary::LAYOUT.get_u8(&row, dictionary::ID_TYPE);
54
55			dictionaries.push(DictionaryDef {
56				id,
57				namespace,
58				name,
59				value_type: Type::from_u8(value_type_ordinal),
60				id_type: Type::from_u8(id_type_ordinal),
61			});
62		}
63
64		Ok(dictionaries)
65	}
66}
67
68#[cfg(test)]
69mod tests {
70	use reifydb_engine::test_utils::create_test_command_transaction;
71	use reifydb_type::Type;
72
73	use crate::{
74		CatalogStore, namespace::NamespaceToCreate, store::dictionary::create::DictionaryToCreate,
75		test_utils::ensure_test_namespace,
76	};
77
78	#[tokio::test]
79	async fn test_list_dictionaries_empty() {
80		let mut txn = create_test_command_transaction().await;
81		let namespace = ensure_test_namespace(&mut txn).await;
82
83		let result = CatalogStore::list_dictionaries(&mut txn, namespace.id).await.unwrap();
84
85		assert!(result.is_empty());
86	}
87
88	#[tokio::test]
89	async fn test_list_dictionaries_multiple() {
90		let mut txn = create_test_command_transaction().await;
91		let namespace = ensure_test_namespace(&mut txn).await;
92
93		// Create multiple dictionaries
94		for i in 0..3 {
95			let to_create = DictionaryToCreate {
96				namespace: namespace.id,
97				dictionary: format!("dict_{}", i),
98				value_type: Type::Utf8,
99				id_type: Type::Uint2,
100				fragment: None,
101			};
102			CatalogStore::create_dictionary(&mut txn, to_create).await.unwrap();
103		}
104
105		let result = CatalogStore::list_dictionaries(&mut txn, namespace.id).await.unwrap();
106
107		assert_eq!(result.len(), 3);
108	}
109
110	#[tokio::test]
111	async fn test_list_dictionaries_different_namespaces() {
112		let mut txn = create_test_command_transaction().await;
113		let namespace1 = ensure_test_namespace(&mut txn).await;
114
115		let namespace2 = CatalogStore::create_namespace(
116			&mut txn,
117			NamespaceToCreate {
118				namespace_fragment: None,
119				name: "namespace2".to_string(),
120			},
121		)
122		.await
123		.unwrap();
124
125		// Create 2 dictionaries in namespace1
126		for i in 0..2 {
127			let to_create = DictionaryToCreate {
128				namespace: namespace1.id,
129				dictionary: format!("ns1_dict_{}", i),
130				value_type: Type::Utf8,
131				id_type: Type::Uint2,
132				fragment: None,
133			};
134			CatalogStore::create_dictionary(&mut txn, to_create).await.unwrap();
135		}
136
137		// Create 3 dictionaries in namespace2
138		for i in 0..3 {
139			let to_create = DictionaryToCreate {
140				namespace: namespace2.id,
141				dictionary: format!("ns2_dict_{}", i),
142				value_type: Type::Uint8,
143				id_type: Type::Uint4,
144				fragment: None,
145			};
146			CatalogStore::create_dictionary(&mut txn, to_create).await.unwrap();
147		}
148
149		// Verify namespace1 has 2 dictionaries
150		let ns1_dicts = CatalogStore::list_dictionaries(&mut txn, namespace1.id).await.unwrap();
151		assert_eq!(ns1_dicts.len(), 2);
152
153		// Verify namespace2 has 3 dictionaries
154		let ns2_dicts = CatalogStore::list_dictionaries(&mut txn, namespace2.id).await.unwrap();
155		assert_eq!(ns2_dicts.len(), 3);
156	}
157
158	#[tokio::test]
159	async fn test_list_all_dictionaries() {
160		let mut txn = create_test_command_transaction().await;
161		let namespace1 = ensure_test_namespace(&mut txn).await;
162
163		let namespace2 = CatalogStore::create_namespace(
164			&mut txn,
165			NamespaceToCreate {
166				namespace_fragment: None,
167				name: "namespace2".to_string(),
168			},
169		)
170		.await
171		.unwrap();
172
173		// Create dictionaries in both namespaces
174		for i in 0..2 {
175			let to_create = DictionaryToCreate {
176				namespace: namespace1.id,
177				dictionary: format!("ns1_dict_{}", i),
178				value_type: Type::Utf8,
179				id_type: Type::Uint2,
180				fragment: None,
181			};
182			CatalogStore::create_dictionary(&mut txn, to_create).await.unwrap();
183		}
184
185		for i in 0..3 {
186			let to_create = DictionaryToCreate {
187				namespace: namespace2.id,
188				dictionary: format!("ns2_dict_{}", i),
189				value_type: Type::Uint8,
190				id_type: Type::Uint4,
191				fragment: None,
192			};
193			CatalogStore::create_dictionary(&mut txn, to_create).await.unwrap();
194		}
195
196		// List all dictionaries
197		let all_dicts = CatalogStore::list_all_dictionaries(&mut txn).await.unwrap();
198		assert_eq!(all_dicts.len(), 5);
199	}
200}