icydb_core/db/session/
catalog.rs1#[cfg(any(test, feature = "sql-explain"))]
10use crate::db::{IndexState, QueryError, query::plan::VisibleIndexes};
11use crate::{
12 db::{
13 DbSession, EntityCatalogCounts, EntityCatalogDescription, EntityFieldDescription,
14 EntitySchemaDescription, IntegrityReport, StorageReport, StoreCatalogDescription,
15 schema::{
16 AcceptedFieldKind, PersistedFieldSnapshot, SchemaInfo, describe_entity_fields,
17 describe_entity_fields_with_persisted_schema, describe_entity_model,
18 describe_entity_model_with_persisted_schema, show_indexes_for_model,
19 show_indexes_for_model_with_runtime_state,
20 show_indexes_for_schema_info_with_runtime_state,
21 },
22 },
23 entity::EntityKind,
24 error::InternalError,
25 model::entity::EntityModel,
26 traits::{CanisterKind, Path},
27};
28
29fn relation_field_count(fields: &[PersistedFieldSnapshot]) -> usize {
30 fields
31 .iter()
32 .filter(|field| persisted_kind_is_relation_field(field.kind()))
33 .count()
34}
35
36fn persisted_kind_is_relation_field(kind: &AcceptedFieldKind) -> bool {
37 match kind {
38 AcceptedFieldKind::Relation { .. } => true,
39 AcceptedFieldKind::List(inner) | AcceptedFieldKind::Set(inner) => {
40 matches!(inner.as_ref(), AcceptedFieldKind::Relation { .. })
41 }
42 _ => false,
43 }
44}
45
46impl<C: CanisterKind> DbSession<C> {
47 #[must_use]
54 pub fn show_indexes<E>(&self) -> Vec<String>
55 where
56 E: EntityKind<Canister = C>,
57 {
58 self.show_indexes_for_store_model(E::Store::PATH, E::MODEL)
59 }
60
61 #[must_use]
67 pub fn show_indexes_for_model(&self, model: &'static EntityModel) -> Vec<String> {
68 show_indexes_for_model(model)
69 }
70
71 pub fn try_show_indexes<E>(&self) -> Result<Vec<String>, InternalError>
76 where
77 E: EntityKind<Canister = C>,
78 {
79 let schema = self.accepted_schema_info_for_entity::<E>()?;
80
81 Ok(self.show_indexes_for_store_schema_info(E::Store::PATH, &schema))
82 }
83
84 pub(in crate::db) fn show_indexes_for_store_model(
88 &self,
89 store_path: &str,
90 model: &'static EntityModel,
91 ) -> Vec<String> {
92 let runtime_state = self
93 .db
94 .with_store_registry(|registry| registry.try_get_store(store_path).ok())
95 .map(|store| store.index_state());
96
97 show_indexes_for_model_with_runtime_state(model, runtime_state)
98 }
99
100 pub(in crate::db) fn show_indexes_for_store_schema_info(
104 &self,
105 store_path: &str,
106 schema: &SchemaInfo,
107 ) -> Vec<String> {
108 let runtime_state = self
109 .db
110 .with_store_registry(|registry| registry.try_get_store(store_path).ok())
111 .map(|store| store.index_state());
112
113 show_indexes_for_schema_info_with_runtime_state(schema, runtime_state)
114 }
115
116 #[must_use]
122 pub fn show_columns<E>(&self) -> Vec<EntityFieldDescription>
123 where
124 E: EntityKind<Canister = C>,
125 {
126 self.show_columns_for_model(E::MODEL)
127 }
128
129 #[must_use]
131 pub fn show_columns_for_model(
132 &self,
133 model: &'static EntityModel,
134 ) -> Vec<EntityFieldDescription> {
135 describe_entity_fields(model)
136 }
137
138 pub fn try_show_columns<E>(&self) -> Result<Vec<EntityFieldDescription>, InternalError>
144 where
145 E: EntityKind<Canister = C>,
146 {
147 let catalog = self.accepted_schema_catalog_context_for_query::<E>()?;
148
149 describe_entity_fields_with_persisted_schema(
150 catalog.snapshot(),
151 catalog.value_catalog_handle(),
152 )
153 }
154
155 #[must_use]
162 pub fn show_entities(&self) -> Vec<crate::db::EntityCatalogDescription> {
163 self.try_show_entities().expect("session invariant")
164 }
165
166 pub fn try_show_entities(&self) -> Result<Vec<EntityCatalogDescription>, InternalError> {
168 let mut entities = Vec::with_capacity(self.db.entity_runtime_hooks.len());
169
170 for hooks in self.db.entity_runtime_hooks {
171 let store = self.db.recovered_store(hooks.store_path)?;
172 let storage = store
173 .storage_capabilities()
174 .storage_mode()
175 .as_str()
176 .to_string();
177 let accepted = self.accepted_schema_catalog_context_for_runtime_hook(hooks, store)?;
178 let snapshot = accepted.snapshot().persisted_snapshot();
179
180 entities.push(EntityCatalogDescription::new(
181 snapshot.entity_name().to_string(),
182 snapshot.entity_path().to_string(),
183 hooks.store_path.to_string(),
184 storage,
185 EntityCatalogCounts::new(
186 u32::try_from(snapshot.fields().len()).unwrap_or(u32::MAX),
187 u32::try_from(snapshot.indexes().len()).unwrap_or(u32::MAX),
188 u32::try_from(relation_field_count(snapshot.fields())).unwrap_or(u32::MAX),
189 snapshot.version().get(),
190 ),
191 ));
192 }
193
194 Ok(entities)
195 }
196
197 #[must_use]
199 pub fn show_stores(&self) -> Vec<StoreCatalogDescription> {
200 self.db.runtime_store_catalog()
201 }
202
203 #[must_use]
205 pub fn show_memory(&self) -> Vec<crate::db::MemoryCatalogDescription> {
206 self.db.runtime_memory_catalog()
207 }
208
209 #[cfg(any(test, feature = "sql-explain"))]
212 pub(in crate::db::session) fn visible_indexes_for_store_accepted_schema(
213 &self,
214 store_path: &str,
215 schema_info: &SchemaInfo,
216 ) -> Result<VisibleIndexes<'static>, QueryError> {
217 let store = self
220 .db
221 .recovered_store(store_path)
222 .map_err(QueryError::execute)?;
223 let state = store.index_state();
224 if state != IndexState::Ready {
225 return Ok(VisibleIndexes::none());
226 }
227 debug_assert_eq!(state, IndexState::Ready);
228
229 let visible_indexes = VisibleIndexes::accepted_schema_visible(schema_info);
232 debug_assert!(visible_indexes.accepted_field_path_contracts_are_consistent());
233 debug_assert!(visible_indexes.accepted_expression_contracts_are_consistent());
234 debug_assert_eq!(
235 visible_indexes.accepted_expression_index_count(),
236 Some(visible_indexes.accepted_expression_indexes().len()),
237 );
238
239 Ok(visible_indexes)
240 }
241
242 #[must_use]
248 pub fn describe_entity<E>(&self) -> EntitySchemaDescription
249 where
250 E: EntityKind<Canister = C>,
251 {
252 self.describe_entity_model(E::MODEL)
253 }
254
255 #[must_use]
257 pub fn describe_entity_model(&self, model: &'static EntityModel) -> EntitySchemaDescription {
258 describe_entity_model(model)
259 }
260
261 pub fn try_describe_entity<E>(&self) -> Result<EntitySchemaDescription, InternalError>
267 where
268 E: EntityKind<Canister = C>,
269 {
270 let catalog = self.accepted_schema_catalog_context_for_query::<E>()?;
271
272 describe_entity_model_with_persisted_schema(
273 E::MODEL,
274 catalog.snapshot(),
275 catalog.value_catalog_handle(),
276 )
277 }
278
279 pub fn storage_report(
281 &self,
282 name_to_path: &[(&'static str, &'static str)],
283 ) -> Result<StorageReport, InternalError> {
284 self.db.storage_report(name_to_path)
285 }
286
287 pub fn storage_report_default(&self) -> Result<StorageReport, InternalError> {
289 self.db.storage_report_default()
290 }
291
292 pub fn integrity_report(&self) -> Result<IntegrityReport, InternalError> {
294 self.db.integrity_report()
295 }
296}