recern_vector/
database.rs1use std::collections::BTreeMap;
2use std::fs::{self, File};
3use std::io::Write;
4use std::path::{Path, PathBuf};
5
6use crate::collection::{Collection, CollectionConfig};
7use crate::error::{Error, Result};
8use crate::storage;
9
10pub struct Database {
15 path: PathBuf,
16 collections: BTreeMap<String, Collection>,
17}
18
19impl Database {
20 pub fn create(path: impl AsRef<Path>) -> Result<Self> {
22 let path = path.as_ref().to_path_buf();
23 if path.exists() {
24 return Err(Error::FileExists(path));
25 }
26 let db = Self {
27 path,
28 collections: BTreeMap::new(),
29 };
30 db.save()?;
31 Ok(db)
32 }
33
34 pub fn open(path: impl AsRef<Path>) -> Result<Self> {
35 let path = path.as_ref().to_path_buf();
36 let collections = storage::decode(&fs::read(&path)?)?;
37 Ok(Self { path, collections })
38 }
39
40 pub fn open_or_create(path: impl AsRef<Path>) -> Result<Self> {
41 if path.as_ref().exists() {
42 Self::open(path)
43 } else {
44 Self::create(path)
45 }
46 }
47
48 pub fn path(&self) -> &Path {
49 &self.path
50 }
51
52 pub fn create_collection(
53 &mut self,
54 name: &str,
55 config: CollectionConfig,
56 ) -> Result<&mut Collection> {
57 if name.is_empty() || name.len() > 255 {
58 return Err(Error::InvalidArgument(
59 "collection name must be 1-255 bytes".into(),
60 ));
61 }
62 if self.collections.contains_key(name) {
63 return Err(Error::CollectionExists(name.to_owned()));
64 }
65 let collection = Collection::new(name, config)?;
66 Ok(self
67 .collections
68 .entry(name.to_owned())
69 .or_insert(collection))
70 }
71
72 pub fn collection(&self, name: &str) -> Result<&Collection> {
73 self.collections
74 .get(name)
75 .ok_or_else(|| Error::CollectionNotFound(name.to_owned()))
76 }
77
78 pub fn collection_mut(&mut self, name: &str) -> Result<&mut Collection> {
79 self.collections
80 .get_mut(name)
81 .ok_or_else(|| Error::CollectionNotFound(name.to_owned()))
82 }
83
84 pub fn drop_collection(&mut self, name: &str) -> Result<()> {
85 self.collections
86 .remove(name)
87 .map(|_| ())
88 .ok_or_else(|| Error::CollectionNotFound(name.to_owned()))
89 }
90
91 pub fn collections(&self) -> impl Iterator<Item = &Collection> {
92 self.collections.values()
93 }
94
95 pub fn save(&self) -> Result<()> {
98 let bytes = storage::encode(&self.collections);
99 let mut tmp = self.path.as_os_str().to_owned();
100 tmp.push(".tmp");
101 let tmp = PathBuf::from(tmp);
102 {
103 let mut file = File::create(&tmp)?;
104 file.write_all(&bytes)?;
105 file.sync_all()?;
106 }
107 fs::rename(&tmp, &self.path)?;
108 sync_parent_dir(&self.path);
109 Ok(())
110 }
111}
112
113fn sync_parent_dir(path: &Path) {
116 let dir = match path.parent() {
117 Some(dir) if !dir.as_os_str().is_empty() => dir,
118 _ => Path::new("."),
119 };
120 if let Ok(dir) = File::open(dir) {
121 let _ = dir.sync_all();
122 }
123}