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 snapshot = self.ensure_accepted_schema_snapshot::<E>()?;
148
149 Ok(describe_entity_fields_with_persisted_schema(&snapshot))
150 }
151
152 #[must_use]
159 pub fn show_entities(&self) -> Vec<crate::db::EntityCatalogDescription> {
160 self.try_show_entities().expect("session invariant")
161 }
162
163 pub fn try_show_entities(&self) -> Result<Vec<EntityCatalogDescription>, InternalError> {
165 let mut entities = Vec::with_capacity(self.db.entity_runtime_hooks.len());
166
167 for hooks in self.db.entity_runtime_hooks {
168 let store = self.db.recovered_store(hooks.store_path)?;
169 let storage = store
170 .storage_capabilities()
171 .storage_mode()
172 .as_str()
173 .to_string();
174 let accepted = self.accepted_schema_catalog_context_for_runtime_hook(hooks, store)?;
175 let snapshot = accepted.snapshot().persisted_snapshot();
176
177 entities.push(EntityCatalogDescription::new(
178 snapshot.entity_name().to_string(),
179 snapshot.entity_path().to_string(),
180 hooks.store_path.to_string(),
181 storage,
182 EntityCatalogCounts::new(
183 u32::try_from(snapshot.fields().len()).unwrap_or(u32::MAX),
184 u32::try_from(snapshot.indexes().len()).unwrap_or(u32::MAX),
185 u32::try_from(relation_field_count(snapshot.fields())).unwrap_or(u32::MAX),
186 snapshot.version().get(),
187 ),
188 ));
189 }
190
191 Ok(entities)
192 }
193
194 #[must_use]
196 pub fn show_stores(&self) -> Vec<StoreCatalogDescription> {
197 self.db.runtime_store_catalog()
198 }
199
200 #[must_use]
202 pub fn show_memory(&self) -> Vec<crate::db::MemoryCatalogDescription> {
203 self.db.runtime_memory_catalog()
204 }
205
206 #[cfg(any(test, feature = "sql-explain"))]
209 pub(in crate::db::session) fn visible_indexes_for_store_accepted_schema(
210 &self,
211 store_path: &str,
212 schema_info: &SchemaInfo,
213 ) -> Result<VisibleIndexes<'static>, QueryError> {
214 let store = self
217 .db
218 .recovered_store(store_path)
219 .map_err(QueryError::execute)?;
220 let state = store.index_state();
221 if state != IndexState::Ready {
222 return Ok(VisibleIndexes::none());
223 }
224 debug_assert_eq!(state, IndexState::Ready);
225
226 let visible_indexes = VisibleIndexes::accepted_schema_visible(schema_info);
229 debug_assert!(visible_indexes.accepted_field_path_contracts_are_consistent());
230 debug_assert!(visible_indexes.accepted_expression_contracts_are_consistent());
231 debug_assert_eq!(
232 visible_indexes.accepted_expression_index_count(),
233 Some(visible_indexes.accepted_expression_indexes().len()),
234 );
235
236 Ok(visible_indexes)
237 }
238
239 #[must_use]
245 pub fn describe_entity<E>(&self) -> EntitySchemaDescription
246 where
247 E: EntityKind<Canister = C>,
248 {
249 self.describe_entity_model(E::MODEL)
250 }
251
252 #[must_use]
254 pub fn describe_entity_model(&self, model: &'static EntityModel) -> EntitySchemaDescription {
255 describe_entity_model(model)
256 }
257
258 pub fn try_describe_entity<E>(&self) -> Result<EntitySchemaDescription, InternalError>
264 where
265 E: EntityKind<Canister = C>,
266 {
267 let snapshot = self.ensure_accepted_schema_snapshot::<E>()?;
268
269 Ok(describe_entity_model_with_persisted_schema(
270 E::MODEL,
271 &snapshot,
272 ))
273 }
274
275 pub fn storage_report(
277 &self,
278 name_to_path: &[(&'static str, &'static str)],
279 ) -> Result<StorageReport, InternalError> {
280 self.db.storage_report(name_to_path)
281 }
282
283 pub fn storage_report_default(&self) -> Result<StorageReport, InternalError> {
285 self.db.storage_report_default()
286 }
287
288 pub fn integrity_report(&self) -> Result<IntegrityReport, InternalError> {
290 self.db.integrity_report()
291 }
292}