reifydb_catalog/store/dictionary/
find.rs1use reifydb_core::{
5 interface::{DictionaryDef, DictionaryId, MultiVersionValues, 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 pub async fn find_dictionary(
17 rx: &mut impl QueryTransaction,
18 dictionary_id: DictionaryId,
19 ) -> crate::Result<Option<DictionaryDef>> {
20 let Some(multi) = rx.get(&DictionaryKey::encoded(dictionary_id)).await? else {
21 return Ok(None);
22 };
23
24 let row = multi.values;
25 let id = DictionaryId(dictionary::LAYOUT.get_u64(&row, dictionary::ID));
26 let namespace = NamespaceId(dictionary::LAYOUT.get_u64(&row, dictionary::NAMESPACE));
27 let name = dictionary::LAYOUT.get_utf8(&row, dictionary::NAME).to_string();
28 let value_type_ordinal = dictionary::LAYOUT.get_u8(&row, dictionary::VALUE_TYPE);
29 let id_type_ordinal = dictionary::LAYOUT.get_u8(&row, dictionary::ID_TYPE);
30
31 Ok(Some(DictionaryDef {
32 id,
33 namespace,
34 name,
35 value_type: Type::from_u8(value_type_ordinal),
36 id_type: Type::from_u8(id_type_ordinal),
37 }))
38 }
39
40 pub async fn find_dictionary_by_name(
41 rx: &mut impl QueryTransaction,
42 namespace: NamespaceId,
43 name: impl AsRef<str>,
44 ) -> crate::Result<Option<DictionaryDef>> {
45 let name = name.as_ref();
46 let batch = rx.range(NamespaceDictionaryKey::full_scan(namespace)).await?;
47 let Some(dictionary_id) = batch.items.iter().find_map(|multi: &MultiVersionValues| {
48 let row = &multi.values;
49 let dictionary_name = dictionary_namespace::LAYOUT.get_utf8(row, dictionary_namespace::NAME);
50 if name == dictionary_name {
51 Some(DictionaryId(dictionary_namespace::LAYOUT.get_u64(row, dictionary_namespace::ID)))
52 } else {
53 None
54 }
55 }) else {
56 return Ok(None);
57 };
58
59 Ok(Some(Self::get_dictionary(rx, dictionary_id).await?))
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use reifydb_core::interface::DictionaryId;
66 use reifydb_engine::test_utils::create_test_command_transaction;
67 use reifydb_type::Type;
68
69 use crate::{
70 CatalogStore, namespace::NamespaceToCreate, store::dictionary::create::DictionaryToCreate,
71 test_utils::ensure_test_namespace,
72 };
73
74 #[tokio::test]
75 async fn test_find_dictionary_exists() {
76 let mut txn = create_test_command_transaction().await;
77 let test_namespace = ensure_test_namespace(&mut txn).await;
78
79 let to_create = DictionaryToCreate {
80 namespace: test_namespace.id,
81 dictionary: "test_dict".to_string(),
82 value_type: Type::Utf8,
83 id_type: Type::Uint2,
84 fragment: None,
85 };
86
87 let created = CatalogStore::create_dictionary(&mut txn, to_create).await.unwrap();
88
89 let found = CatalogStore::find_dictionary(&mut txn, created.id)
90 .await
91 .unwrap()
92 .expect("Dictionary should exist");
93
94 assert_eq!(found.id, created.id);
95 assert_eq!(found.name, created.name);
96 assert_eq!(found.namespace, created.namespace);
97 assert_eq!(found.value_type, Type::Utf8);
98 assert_eq!(found.id_type, Type::Uint2);
99 }
100
101 #[tokio::test]
102 async fn test_find_dictionary_not_exists() {
103 let mut txn = create_test_command_transaction().await;
104
105 let result = CatalogStore::find_dictionary(&mut txn, DictionaryId(999)).await.unwrap();
106
107 assert!(result.is_none());
108 }
109
110 #[tokio::test]
111 async fn test_find_dictionary_by_name_exists() {
112 let mut txn = create_test_command_transaction().await;
113 let namespace = ensure_test_namespace(&mut txn).await;
114
115 let to_create = DictionaryToCreate {
116 namespace: namespace.id,
117 dictionary: "token_mints".to_string(),
118 value_type: Type::Utf8,
119 id_type: Type::Uint4,
120 fragment: None,
121 };
122
123 let created = CatalogStore::create_dictionary(&mut txn, to_create).await.unwrap();
124
125 let found = CatalogStore::find_dictionary_by_name(&mut txn, namespace.id, "token_mints")
126 .await
127 .unwrap()
128 .expect("Should find dictionary by name");
129
130 assert_eq!(found.id, created.id);
131 assert_eq!(found.name, "token_mints");
132 assert_eq!(found.value_type, Type::Utf8);
133 assert_eq!(found.id_type, Type::Uint4);
134 }
135
136 #[tokio::test]
137 async fn test_find_dictionary_by_name_not_exists() {
138 let mut txn = create_test_command_transaction().await;
139 let namespace = ensure_test_namespace(&mut txn).await;
140
141 let result = CatalogStore::find_dictionary_by_name(&mut txn, namespace.id, "nonexistent_dict")
142 .await
143 .unwrap();
144
145 assert!(result.is_none());
146 }
147
148 #[tokio::test]
149 async fn test_find_dictionary_by_name_different_namespace() {
150 let mut txn = create_test_command_transaction().await;
151 let namespace1 = ensure_test_namespace(&mut txn).await;
152
153 let namespace2 = CatalogStore::create_namespace(
155 &mut txn,
156 NamespaceToCreate {
157 namespace_fragment: None,
158 name: "namespace2".to_string(),
159 },
160 )
161 .await
162 .unwrap();
163
164 let to_create = DictionaryToCreate {
166 namespace: namespace1.id,
167 dictionary: "shared_name".to_string(),
168 value_type: Type::Utf8,
169 id_type: Type::Uint2,
170 fragment: None,
171 };
172
173 CatalogStore::create_dictionary(&mut txn, to_create).await.unwrap();
174
175 let result =
177 CatalogStore::find_dictionary_by_name(&mut txn, namespace2.id, "shared_name").await.unwrap();
178
179 assert!(result.is_none());
180
181 let found =
183 CatalogStore::find_dictionary_by_name(&mut txn, namespace1.id, "shared_name").await.unwrap();
184
185 assert!(found.is_some());
186 }
187}