1use std::{
2 collections::HashMap,
3 error::Error,
4 fs::{self},
5 path::PathBuf,
6 sync::Mutex,
7};
8
9use crate::{
10 byte_reader::ByteReader,
11 entity::Entity,
12 entity_meta::EntityMeta,
13 id::IdType,
14 query::{DbQuery, DbQueryMut},
15 storable::Storable,
16 type_hash::TypeHash,
17};
18
19static DATABASE_CREATED: Mutex<bool> = Mutex::new(false);
20
21#[derive(Debug)]
23pub struct Database {
24 db_dir: PathBuf,
25 stored_types: HashMap<TypeHash, ()>,
26}
27
28impl Database {
29 pub fn default(clear: bool) -> DbResult<Self> {
30 Self::new(PathBuf::from("sdb/"), clear)
31 }
32
33 pub fn new(db_dir: PathBuf, clear: bool) -> DbResult<Self> {
34 let mut db_created = DATABASE_CREATED.lock().unwrap();
36 if *db_created {
37 return Err(DbError::DbInstanceExists);
38 }
39 *db_created = true;
40
41 if clear {
42 let _ = fs::remove_dir_all(&db_dir);
43 }
44
45 let _ = fs::create_dir_all(&db_dir);
46
47 let stored_types: HashMap<_, _> = fs::read_dir(&db_dir)?
48 .filter_map(|f| {
49 let name = f.as_ref().ok()?.file_name().into_string().ok()?;
50 let parts: Vec<_> = name.split('.').collect();
51 if parts.len() > 2 || parts[1] != "sdb" {
52 return None;
53 }
54
55 let type_hash = TypeHash::decode(parts[0]);
56
57 let mut opts = fs::OpenOptions::new();
58 opts.read(true);
59 opts.write(true);
60 opts.open(f.ok()?.path()).ok()?;
61
62 return Some((type_hash, ()));
63 })
64 .collect();
65
66 Ok(Database {
67 db_dir,
68 stored_types,
69 })
70 }
71
72 pub fn store<T: Entity>(&mut self, mut data: T) -> DbResult<T> {
73 let type_hash = T::type_hash();
74
75 if !self.stored_types.contains_key(&type_hash) {
76 self.add_new_type::<T>()?;
77 }
78
79 let mut existing = self.raw_read_all::<T>()?;
80
81 if !T::GENERATE_ID
82 && existing
83 .entities
84 .iter()
85 .find(|e| e.get_id() == data.get_id())
86 .is_some()
87 {
88 return Err(DbError::IdExists);
89 }
90
91 if T::GENERATE_ID {
92 data.set_id(<T::Id as IdType>::generate(existing.last_id))
93 }
94
95 existing.entities.push(data.clone());
96 existing.last_id = data.get_id();
97
98 self.raw_write_all(existing)?;
99
100 Ok(data)
101 }
102
103 pub fn write_all<T: Entity>(&mut self, entities: Vec<T>) -> DbResult<()> {
104 let type_hash = T::type_hash();
105
106 if !self.stored_types.contains_key(&type_hash) {
107 self.add_new_type::<T>()?;
108 }
109
110 let last_id = entities
111 .last()
112 .map(|e| e.get_id())
113 .unwrap_or_else(|| <T::Id as IdType>::initial());
114
115 self.raw_write_all(EntityMeta { last_id, entities })?;
116
117 Ok(())
118 }
119
120 pub fn raw_write_all<T: Entity>(&mut self, raw: EntityMeta<T>) -> DbResult<()> {
121 let type_hash = T::type_hash();
122
123 let new_data = raw.encoded();
124
125 fs::write(self.type_hash_file_path(&type_hash), new_data)?;
126
127 Ok(())
128 }
129
130 pub fn read_all<T: Entity>(&self) -> DbResult<Vec<T>> {
131 let type_hash = T::type_hash();
132
133 self.stored_types
134 .get(&type_hash)
135 .ok_or(DbError::TypeNotFound)?;
136
137 Ok(self.raw_read_all()?.entities)
138 }
139
140 pub fn raw_read_all<T: Entity>(&self) -> DbResult<EntityMeta<T>> {
141 let type_hash = T::type_hash();
142
143 let vec = fs::read(self.type_hash_file_path(&type_hash))?;
144
145 let mut reader = ByteReader::new(&vec);
146
147 EntityMeta::decoded(reader.reader_for_block())
148 }
149
150 pub fn read_all_ids<T: Entity>(&self) -> DbResult<Vec<T::Id>> {
151 Ok(self.read_all::<T>()?.iter().map(|e| e.get_id()).collect())
152 }
153
154 pub fn find_by_id<T: Entity>(&self, id: T::Id) -> DbResult<Option<T>> {
155 Ok(self.read_all::<T>()?.into_iter().find(|e| e.get_id() == id))
156 }
157
158 pub fn update_entity<T: Entity>(&mut self, entity: T) -> DbResult<()> {
159 let type_hash = T::type_hash();
160
161 self.stored_types
162 .get(&type_hash)
163 .ok_or(DbError::TypeNotFound)?;
164
165 let mut raw = self.raw_read_all::<T>()?;
166 let res = raw
167 .entities
168 .iter_mut()
169 .find(|e| e.get_id() == entity.get_id())
170 .ok_or(DbError::IdNotFound)?;
171
172 *res = entity;
173
174 self.raw_write_all(raw)?;
175
176 Ok(())
177 }
178
179 pub fn delte_entity_by_id<T: Entity>(&mut self, id: T::Id) -> DbResult<()> {
180 let type_hash = T::type_hash();
181
182 self.stored_types
183 .get(&type_hash)
184 .ok_or(DbError::TypeNotFound)?;
185
186 let mut raw = self.raw_read_all::<T>()?;
187 raw.entities = raw
188 .entities
189 .into_iter()
190 .filter(|e| e.get_id() != id)
191 .collect();
192
193 self.raw_write_all(raw)?;
194 Ok(())
195 }
196
197 pub fn delete_entity_store<T: Entity>(&mut self) -> DbResult<()> {
198 let type_hash = T::type_hash();
199 self.stored_types
200 .remove(&type_hash)
201 .ok_or(DbError::TypeNotFound)?;
202 fs::remove_file(self.type_hash_file_path(&type_hash))?;
203 Ok(())
204 }
205
206 fn add_new_type<T: Entity>(&mut self) -> DbResult<()> {
207 let type_hash = T::type_hash();
208
209 let mut opts = fs::OpenOptions::new();
210 opts.read(true);
211 opts.write(true);
212 opts.create(true);
213 opts.open(self.type_hash_file_path(&type_hash))?;
214
215 self.raw_write_all::<T>(EntityMeta {
216 last_id: <T::Id as IdType>::initial(),
217 entities: vec![],
218 })?;
219
220 self.stored_types.insert(type_hash, ());
221 Ok(())
222 }
223
224 fn type_hash_file_path(&self, type_hash: &TypeHash) -> PathBuf {
225 let mut path = self.db_dir.clone();
226 path.push(PathBuf::from(format!("{}.sdb", type_hash.encode())));
227 path
228 }
229
230 pub fn query<T: Entity>(&self) -> DbResult<DbQuery<T>> {
233 DbQuery::new(self)
234 }
235
236 pub fn query_mut<T: 'static + Entity>(&mut self) -> DbResult<DbQueryMut<T>> {
241 DbQueryMut::new(self)
242 }
243}
244
245impl Drop for Database {
246 fn drop(&mut self) {
247 *DATABASE_CREATED.lock().unwrap() = false;
248 }
249}
250
251pub type DbResult<T> = Result<T, DbError>;
252
253#[derive(Debug)]
254pub enum DbError {
255 IdExists,
256 TypeNotFound,
257 IdNotFound,
258 IoError(std::io::Error),
259 LoadError,
260 DbInstanceExists,
261 InvalidFileVersion,
262}
263
264impl PartialEq for DbError {
265 fn eq(&self, other: &Self) -> bool {
266 match self {
267 Self::IdExists => match other {
268 Self::IdExists => true,
269 _ => false,
270 },
271 Self::TypeNotFound => match other {
272 Self::TypeNotFound => true,
273 _ => false,
274 },
275 Self::IdNotFound => match other {
276 Self::IdNotFound => true,
277 _ => false,
278 },
279 Self::IoError(_) => false,
280 Self::LoadError => match other {
281 Self::LoadError => true,
282 _ => false,
283 },
284 Self::DbInstanceExists => match other {
285 Self::DbInstanceExists => true,
286 _ => false,
287 },
288 Self::InvalidFileVersion => match other {
289 Self::InvalidFileVersion => true,
290 _ => false,
291 },
292 }
293 }
294}
295
296impl From<std::io::Error> for DbError {
297 fn from(value: std::io::Error) -> Self {
298 Self::IoError(value)
299 }
300}
301
302impl std::fmt::Display for DbError {
303 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
304 write!(f, "{self:?}")
305 }
306}
307
308impl Error for DbError {}