velesdb_core/database/
collection_ops.rs1use crate::collection::AnyCollection;
9use crate::{CollectionType, DistanceMetric, Error, Result, StorageMode};
10
11use super::Database;
12
13impl Database {
14 pub(super) fn ensure_collection_name_available(&self, name: &str) -> Result<()> {
23 crate::validation::validate_collection_name(name)?;
24
25 if self.collection_exists_in_registry(name) {
26 return Err(Error::CollectionExists(name.to_string()));
27 }
28
29 let collection_path = self.data_dir.join(name);
30 if collection_path.exists() {
31 return Err(Error::CollectionExists(name.to_string()));
32 }
33
34 let total_collections = self.vector_colls.read().len()
43 + self.graph_colls.read().len()
44 + self.metadata_colls.read().len();
45 let cap = self.config.limits.max_collections;
46 if total_collections >= cap {
47 return Err(Error::GuardRail(format!(
48 "max_collections limit reached ({total_collections} / {cap}); \
49 raise `limits.max_collections` in VelesConfig to create more"
50 )));
51 }
52
53 Ok(())
54 }
55
56 pub(super) fn push_runtime_limits(&self, coll: &crate::collection::Collection) {
64 coll.set_runtime_limits(crate::collection::RuntimeLimits::from_config(
65 &self.config.limits,
66 ));
67 }
68
69 fn collection_exists_in_registry(&self, name: &str) -> bool {
71 self.vector_colls.read().contains_key(name)
72 || self.graph_colls.read().contains_key(name)
73 || self.metadata_colls.read().contains_key(name)
74 }
75
76 pub(super) fn enforce_vector_dimension_limit(&self, dimension: usize) -> Result<()> {
90 if dimension == 0 {
91 return Ok(());
92 }
93 let cap = self.config.limits.max_dimensions;
94 if dimension > cap {
95 return Err(Error::GuardRail(format!(
96 "vector dimension {dimension} exceeds configured max_dimensions cap of {cap}; \
97 raise `limits.max_dimensions` in VelesConfig to allow larger vectors"
98 )));
99 }
100 Ok(())
101 }
102
103 pub fn create_collection(
125 &self,
126 name: &str,
127 dimension: usize,
128 metric: DistanceMetric,
129 ) -> Result<()> {
130 self.create_collection_with_options(name, dimension, metric, StorageMode::default())
131 }
132
133 pub fn create_collection_with_options(
139 &self,
140 name: &str,
141 dimension: usize,
142 metric: DistanceMetric,
143 storage_mode: StorageMode,
144 ) -> Result<()> {
145 self.create_vector_collection_with_options(name, dimension, metric, storage_mode)
146 }
147
148 #[must_use]
153 pub fn get_any_collection(&self, name: &str) -> Option<AnyCollection> {
154 if let Some(c) = self.get_vector_collection(name) {
155 return Some(AnyCollection::Vector(c));
156 }
157 if let Some(c) = self.get_graph_collection(name) {
158 return Some(AnyCollection::Graph(c));
159 }
160 if let Some(c) = self.get_metadata_collection(name) {
161 return Some(AnyCollection::Metadata(c));
162 }
163 None
164 }
165
166 #[must_use]
168 pub fn collection_write_generation(&self, name: &str) -> Option<u64> {
169 if let Some(vc) = self.vector_colls.read().get(name) {
170 return Some(vc.inner.write_generation());
171 }
172 if let Some(gc) = self.graph_colls.read().get(name) {
173 return Some(gc.inner.write_generation());
174 }
175 if let Some(mc) = self.metadata_colls.read().get(name) {
176 return Some(mc.inner.write_generation());
177 }
178 None
179 }
180
181 #[must_use]
190 pub fn indexed_fields_for(&self, name: &str) -> std::collections::HashSet<String> {
191 if let Some(vc) = self.vector_colls.read().get(name) {
192 return vc.inner.indexed_field_names();
193 }
194 if let Some(gc) = self.graph_colls.read().get(name) {
195 return gc.inner.indexed_field_names();
196 }
197 if let Some(mc) = self.metadata_colls.read().get(name) {
198 return mc.inner.indexed_field_names();
199 }
200 std::collections::HashSet::new()
201 }
202
203 #[must_use]
208 pub(crate) fn match_stats_for(
209 &self,
210 name: &str,
211 ) -> Option<crate::velesql::match_planner::CollectionStats> {
212 if let Some(vc) = self.vector_colls.read().get(name) {
213 return Some(vc.inner.compute_match_collection_stats());
214 }
215 if let Some(gc) = self.graph_colls.read().get(name) {
216 return Some(gc.inner.compute_match_collection_stats());
217 }
218 if let Some(mc) = self.metadata_colls.read().get(name) {
219 return Some(mc.inner.compute_match_collection_stats());
220 }
221 None
222 }
223
224 #[must_use]
232 pub fn collection_analyze_generation(&self, name: &str) -> Option<u64> {
233 if let Some(vc) = self.vector_colls.read().get(name) {
234 return Some(vc.inner.analyze_generation());
235 }
236 if let Some(gc) = self.graph_colls.read().get(name) {
237 return Some(gc.inner.analyze_generation());
238 }
239 if let Some(mc) = self.metadata_colls.read().get(name) {
240 return Some(mc.inner.analyze_generation());
241 }
242 None
243 }
244
245 pub fn list_collections(&self) -> Vec<String> {
249 let vector_colls = self.vector_colls.read();
250 let graph_colls = self.graph_colls.read();
251 let metadata_colls = self.metadata_colls.read();
252
253 let mut names: std::collections::HashSet<String> = vector_colls.keys().cloned().collect();
254 for k in graph_colls.keys() {
255 names.insert(k.clone());
256 }
257 for k in metadata_colls.keys() {
258 names.insert(k.clone());
259 }
260 let mut result: Vec<String> = names.into_iter().collect();
261 result.sort();
262 result
263 }
264
265 pub fn delete_collection(&self, name: &str) -> Result<()> {
272 crate::validation::validate_collection_name(name)?;
273
274 if !self.collection_exists_in_registry(name) {
275 return Err(Error::CollectionNotFound(name.to_string()));
276 }
277
278 let collection_path = self.data_dir.join(name);
279 if collection_path.exists() {
280 std::fs::remove_dir_all(&collection_path)?;
281 }
282
283 self.remove_from_all_registries(name);
284
285 if let Some(ref obs) = self.observer {
286 obs.on_collection_deleted(name);
287 }
288
289 self.schema_version
290 .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
291
292 Ok(())
293 }
294
295 fn remove_from_all_registries(&self, name: &str) {
297 self.vector_colls.write().remove(name);
298 self.graph_colls.write().remove(name);
299 self.metadata_colls.write().remove(name);
300 self.collection_stats.write().remove(name);
301 }
302
303 pub fn create_collection_typed(
309 &self,
310 name: &str,
311 collection_type: &CollectionType,
312 ) -> Result<()> {
313 match collection_type {
314 CollectionType::Vector {
315 dimension,
316 metric,
317 storage_mode,
318 } => {
319 self.create_vector_collection_with_options(name, *dimension, *metric, *storage_mode)
320 }
321 CollectionType::MetadataOnly => self.create_metadata_collection(name),
322 CollectionType::Graph {
323 dimension,
324 metric,
325 schema,
326 } => self.create_graph_collection_from_type(name, *dimension, *metric, schema),
327 }
328 }
329
330 pub(super) fn read_collection_config(
335 &self,
336 name: &str,
337 ) -> Option<crate::collection::CollectionConfig> {
338 if crate::validation::validate_collection_name(name).is_err() {
339 return None;
340 }
341 let path = self.data_dir.join(name);
342 let config_path = path.join("config.json");
343 if !config_path.exists() {
344 return None;
345 }
346 let data = std::fs::read_to_string(&config_path).ok()?;
347 serde_json::from_str(&data).ok()
348 }
349
350 pub fn update_guardrails(&self, limits: &crate::guardrails::QueryLimits) {
352 for vc in self.vector_colls.read().values() {
353 vc.guard_rails().update_limits(limits);
354 }
355 for gc in self.graph_colls.read().values() {
356 gc.inner.guard_rails().update_limits(limits);
357 }
358 for mc in self.metadata_colls.read().values() {
359 mc.inner.guard_rails().update_limits(limits);
360 }
361 }
362
363 pub fn collection_diagnostics(
369 &self,
370 name: &str,
371 ) -> Result<crate::collection::CollectionDiagnostics> {
372 if let Some(c) = self.get_vector_collection(name) {
373 return Ok(c.diagnostics());
374 }
375 if let Some(c) = self.get_graph_collection(name) {
376 return Ok(c.diagnostics());
377 }
378 if let Some(c) = self.get_metadata_collection(name) {
379 return Ok(c.diagnostics());
380 }
381 Err(Error::CollectionNotFound(name.to_string()))
382 }
383}