Skip to main content

agdb/
db.rs

1pub mod db_element;
2pub mod db_error;
3pub mod db_f64;
4pub mod db_id;
5pub mod db_index;
6pub mod db_key_order;
7pub mod db_key_value;
8pub mod db_type;
9pub mod db_value;
10
11mod db_search_handlers;
12mod db_value_index;
13
14use self::db_error::DbError;
15use self::db_search_handlers::DefaultHandler;
16use self::db_search_handlers::LimitHandler;
17use self::db_search_handlers::LimitOffsetHandler;
18use self::db_search_handlers::OffsetHandler;
19use self::db_search_handlers::PathHandler;
20use crate::DbId;
21use crate::DbKeyValue;
22use crate::DbValue;
23use crate::QueryResult;
24use crate::SearchQueryAlgorithm;
25use crate::StorageData;
26use crate::Transaction;
27use crate::TransactionMut;
28use crate::collections::indexed_map::DbIndexedMap;
29use crate::command::Command;
30use crate::db::db_index::DbIndexes;
31use crate::db::db_key_value::DbKeyValues;
32use crate::graph::DbGraph;
33use crate::graph::GraphIndex;
34use crate::graph_search::GraphSearch;
35use crate::graph_search::SearchControl;
36use crate::query::Query;
37use crate::query::QueryMut;
38use crate::query::query_condition::QueryCondition;
39use crate::query::query_condition::QueryConditionData;
40use crate::query::query_condition::QueryConditionLogic;
41use crate::query::query_condition::QueryConditionModifier;
42use crate::query::query_id::QueryId;
43use crate::storage::Storage;
44use crate::storage::StorageIndex;
45use crate::storage::any_storage::AnyStorage;
46use crate::storage::file_storage::FileStorage;
47use crate::storage::file_storage_memory_mapped::FileStorageMemoryMapped;
48use crate::storage::memory_storage::MemoryStorage;
49use crate::utilities::serialize::Serialize;
50use crate::utilities::serialize::SerializeStatic;
51
52const CURRENT_VERSION: u64 = 1;
53
54#[derive(Default)]
55struct DbStorageIndex {
56    version: u64,
57    graph: StorageIndex,
58    aliases: (StorageIndex, StorageIndex),
59    indexes: StorageIndex,
60    values: StorageIndex,
61}
62
63impl Serialize for DbStorageIndex {
64    fn serialize(&self) -> Vec<u8> {
65        [
66            self.version.serialize(),
67            self.graph.serialize(),
68            self.aliases.0.serialize(),
69            self.aliases.1.serialize(),
70            self.indexes.serialize(),
71            self.values.serialize(),
72        ]
73        .concat()
74    }
75
76    fn deserialize(bytes: &[u8]) -> Result<Self, DbError> {
77        let size = i64::serialized_size_static() as usize;
78
79        let version = u64::deserialize(bytes)?;
80        let graph = StorageIndex::deserialize(&bytes[size..])?;
81        let aliases_1 = StorageIndex::deserialize(&bytes[size * 2..])?;
82        let aliases_2 = StorageIndex::deserialize(&bytes[size * 3..])?;
83        let indexes = StorageIndex::deserialize(&bytes[size * 4..])?;
84        let values = StorageIndex::deserialize(&bytes[size * 5..])?;
85
86        Ok(Self {
87            version,
88            graph,
89            aliases: (aliases_1, aliases_2),
90            indexes,
91            values,
92        })
93    }
94
95    fn serialized_size(&self) -> u64 {
96        i64::serialized_size_static() * 6
97    }
98}
99
100/// An instance of the `agdb` database. To create a database:
101///
102/// ```
103/// # let _test_file = agdb::test_utilities::test_file::TestFile::from("db1.agdb");
104/// use agdb::Db;
105///
106/// let mut db = Db::new("db1.agdb").unwrap();
107/// ```
108///
109/// This will try to create or load the database file path `db.agdb`.
110/// If the file does not exist a new database will be initialized creating
111/// the given file. If the file does exist the database will try to load
112/// it and memory map the data.
113///
114/// These are the available variants of the database to choose from:
115///
116/// - [`Db`]: \[default] File based and memory mapped database.
117/// - [`DbFile`]: File based only (no memory mapping).
118/// - [`DbMemory`]: In-memory database only.
119/// - [`DbAny`]: Database variant that can be any of the other variants.
120///
121/// For each of these there are convenient using declarations, e.g. `DbTransaction`,
122/// `DbFileTransaction`, `DbMemoryTransactionMut` etc. in case you need to name
123/// the related types of the main database type.
124///
125/// You can execute queries or transactions on the database object with
126///
127/// - [exec()](#method.exec) //immutable queries
128/// - [exec_mut()](#method.exec_mut) //mutable queries
129/// - [transaction()](#method.transaction) //immutable transactions
130/// - [transaction_mut()](#method.transaction_mut) // mutable transaction
131///
132/// # Examples
133///
134/// ```
135/// # let _test_file = agdb::test_utilities::test_file::TestFile::from("db2.agdb");
136/// use agdb::{Db, QueryBuilder, DbError};
137///
138/// let mut db = Db::new("db2.agdb").unwrap();
139///
140/// // Insert single node
141/// db.exec_mut(QueryBuilder::insert().nodes().count(1).query()).unwrap();
142///
143/// // Insert single node as a transaction
144/// db.transaction_mut(|t| -> Result<(), DbError> { t.exec_mut(QueryBuilder::insert().nodes().count(1).query())?; Ok(()) }).unwrap();
145///
146/// // Select single database element with id 1
147/// db.exec(QueryBuilder::select().ids(1).query()).unwrap();
148///
149/// // Select single database element with id 1 as a transaction
150/// db.transaction(|t| -> Result<(), DbError> { t.exec(QueryBuilder::select().ids(1).query())?; Ok(()) }).unwrap();
151///
152/// // Search the database starting at element 1
153/// db.exec(QueryBuilder::search().from(1).query()).unwrap();
154/// ```
155/// # Transactions
156///
157/// All queries are transactions. Explicit transactions take closures that are passed
158/// the transaction object to record & execute queries. You cannot explicitly commit
159/// nor rollback transactions. To commit a transaction simply return `Ok` from the
160/// transaction closure. Conversely to rollback a transaction return `Err`. Nested
161/// transactions are not allowed.
162///
163/// # Multithreading
164///
165/// The `agdb` is multithreading enabled. It is recommended to use `Arc<RwLock>`:
166///
167/// ```
168/// # let _test_file = agdb::test_utilities::test_file::TestFile::from("db3.agdb");
169/// use std::sync::{Arc, RwLock};
170/// use agdb::Db;
171///
172/// let db = Arc::new(RwLock::new(Db::new("db3.agdb").unwrap()));
173/// db.read().unwrap(); //for a read lock allowing Db::exec() and Db::transaction()
174/// db.write().unwrap(); //for a write lock allowing additionally Db::exec_mut() and Db::transaction_mut()
175/// ```
176/// Using the database in the multi-threaded environment is then the same as in a single
177/// threaded application (minus the locking). Nevertheless while Rust does prevent
178/// race conditions you still need to be on a lookout for potential deadlocks. This is
179/// one of the reasons why nested transactions are not supported by the `agdb`.
180///
181/// Akin to the Rust borrow checker rules the `agdb` can handle unlimited number
182/// of concurrent reads (transactional or regular) but only single write operation
183/// at any one time. For that reason the transactions are not database states or objects
184/// but rather a function taking a closure executing the queries in an attempt to limit
185/// their scope as much as possible (and therefore the duration of the [exclusive] lock).
186///
187/// # Storage
188///
189/// The `agdb` is using a single database file to store all of its data. Additionally
190/// a single shadow file with a `.` prefix of the main database file name is used as
191/// a write ahead log (WAL). On drop of the [`Db`] object the WAL is processed and removed
192/// aborting any unfinished transactions. Furthermore the database data is defragmented.
193///
194/// On load, if the WAL file is present (e.g. due to a crash), it will be processed
195/// restoring any consistent state that existed before the crash. Data is only
196/// written to the main file if the reverse operation has been committed to the
197/// WAL file. The WAL is then purged on commit of a transaction (all queries are
198/// transactional even if the transaction is not explicitly used).
199pub struct DbImpl<Store: StorageData> {
200    storage: Storage<Store>,
201    graph: DbGraph<Store>,
202    aliases: DbIndexedMap<String, DbId, Store>,
203    indexes: DbIndexes<Store>,
204    values: DbKeyValues<Store>,
205    undo_stack: Vec<Command>,
206}
207
208/// The default implementation of the database using memory mapped file (full ACID) with
209/// write ahead log. If your data set exceeds available (or reasonable amount) of memory
210/// consider using [`DbFile`] instead. You can load the file created with [`DbFile`] and
211/// vice versa.
212pub type Db = DbImpl<FileStorageMemoryMapped>;
213
214/// A convenience alias for the [`Transaction`] type for the default [`Db`].
215pub type DbTransaction<'a> = Transaction<'a, FileStorageMemoryMapped>;
216
217/// A convenience alias for the [`TransactionMut`] type for the default [`Db`].
218pub type DbTransactionMut<'a> = TransactionMut<'a, FileStorageMemoryMapped>;
219
220/// The file based implementation of the database (full ACID) with write ahead logging and
221/// but minimum memory footprint but slower than the default [`Db`]. You can load the file
222/// created with [`Db`] and vice versa.
223pub type DbFile = DbImpl<FileStorage>;
224
225/// A convenience alias for the [`Transaction`] type for the default [`DbFile`].
226pub type DbFileTransaction<'a> = Transaction<'a, FileStorage>;
227
228/// A convenience alias for the [`TransactionMut`] type for the default [`DbFile`].
229pub type DbFileTransactionMut<'a> = TransactionMut<'a, FileStorage>;
230
231/// The purely in-memory implementation of the database. It has no persistence but offers
232/// unmatched performance.
233pub type DbMemory = DbImpl<MemoryStorage>;
234
235/// A convenience alias for the [`Transaction`] type for the default [`DbMemory`].
236pub type DbMemoryTransaction<'a> = Transaction<'a, MemoryStorage>;
237
238/// A convenience alias for the [`TransactionMut`] type for the default [`DbMemory`].
239pub type DbMemoryTransactionMut<'a> = TransactionMut<'a, MemoryStorage>;
240
241/// A convenience alias for a Db type that can use any implemented storage (mapper, memory or file).
242pub type DbAny = DbImpl<AnyStorage>;
243
244/// A convenience alias for the [`Transaction`] type for the default [`DbAny`].
245pub type DbAnyTransaction<'a> = Transaction<'a, AnyStorage>;
246
247/// A convenience alias for the [`TransactionMut`] type for the default [`DbAny`].
248pub type DbAnyTransactionMut<'a> = TransactionMut<'a, AnyStorage>;
249
250impl<Store: StorageData> std::fmt::Debug for DbImpl<Store> {
251    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
252        f.debug_struct("agdb::Db").finish_non_exhaustive()
253    }
254}
255
256impl<Store: StorageData> DbImpl<Store> {
257    /// Tries to create or load `filename` file as `Db` object. For in-memory storage
258    /// this will either load the data from file once (if present) or create an empty database.
259    /// If used with the `DbAny` variant the database will be of variant `Db` (memory mapped). Use
260    /// `DbAny::new_*()` to construct the other variants.
261    pub fn new(filename: &str) -> Result<Self, DbError> {
262        match Self::try_new(filename) {
263            Ok(db) => Ok(db),
264            Err(error) => {
265                let mut db_error = DbError::from("Failed to create database");
266                db_error.cause = Some(Box::new(error));
267                Err(db_error)
268            }
269        }
270    }
271
272    /// Tries to create a new database with the given `data` store.
273    ///
274    /// # Examples
275    ///
276    /// ```
277    /// use agdb::{DbMemory, MemoryStorage, StorageData};
278    ///
279    /// let mut db = DbMemory::with_data(MemoryStorage::new("test").unwrap()).unwrap();
280    /// ```
281    pub fn with_data(data: Store) -> Result<Self, DbError> {
282        Self::try_new_with_storage(Storage::with_data(data)?)
283    }
284
285    /// Flushes the underlying file and copies it
286    /// to `filename` path. Consider calling `optimize_storage()`
287    /// prior to this function to reduce the size of the storage
288    /// file. If speed is of the essence you may omit that operation
289    /// at expense of the file size. For memory based storage this will
290    /// dump the internal buffer to the `filename` which can be used to
291    /// restore back the database by `DbMemory::new()`.
292    pub fn backup(&self, filename: &str) -> Result<(), DbError> {
293        self.storage.backup(filename)
294    }
295
296    /// Copies the database to `filename` path.  Consider calling
297    /// `optimize_storage()` prior to this function to reduce the
298    /// size of the storage file to be copied.
299    pub fn copy(&self, filename: &str) -> Result<Self, DbError> {
300        let storage = self.storage.copy(filename)?;
301        let index = storage.value::<DbStorageIndex>(StorageIndex(1))?;
302
303        let graph = DbGraph::from_storage(&storage, index.graph)?;
304        let aliases = DbIndexedMap::from_storage(&storage, index.aliases)?;
305        let indexes = DbIndexes::from_storage(&storage, index.indexes)?;
306        //let values = MultiMapStorage::from_storage(&storage, index.values)?;
307        let values = DbKeyValues::from_storage(&storage, index.values)?;
308
309        Ok(Self {
310            storage,
311            graph,
312            aliases,
313            indexes,
314            values,
315            undo_stack: vec![],
316        })
317    }
318
319    /// Executes immutable query:
320    ///
321    /// - Select elements
322    /// - Select values
323    /// - Select keys
324    /// - Select key count
325    /// - Select aliases
326    /// - Select all aliases
327    /// - Search
328    ///
329    /// It runs the query as a transaction and returns either the result or
330    /// error describing what went wrong (e.g. query error, logic error, data
331    /// error etc.).
332    pub fn exec<T: Query>(&self, query: T) -> Result<QueryResult, DbError> {
333        self.transaction(|transaction| transaction.exec(query))
334    }
335
336    /// Executes mutable query:
337    ///
338    /// - Insert nodes
339    /// - Insert edges
340    /// - Insert aliases
341    /// - Insert values
342    /// - Remove elements
343    /// - Remove aliases
344    /// - Remove values
345    ///
346    /// It runs the query as a transaction and returns either the result or
347    /// error describing what went wrong (e.g. query error, logic error, data
348    /// error etc.).
349    pub fn exec_mut<T: QueryMut>(&mut self, query: T) -> Result<QueryResult, DbError> {
350        self.transaction_mut(|transaction| transaction.exec_mut(query))
351    }
352
353    /// Returns the filename that was used to
354    /// construct the database.
355    pub fn filename(&self) -> &str {
356        self.storage.name()
357    }
358
359    /// Reclaims no longer used segments of the database file by packing all
360    /// used storage segments together. This operation is done automatically
361    /// when the database goes out of scope. In long running programs it might
362    /// be desired to perform the storage file optimization without fully shutting
363    /// down.
364    pub fn optimize_storage(&mut self) -> Result<(), DbError> {
365        self.storage.optimize_storage()
366    }
367
368    /// Changes the name of the database changing also the names of the files
369    /// (if the storage is file based).
370    pub fn rename(&mut self, filename: &str) -> Result<(), DbError> {
371        self.storage.rename(filename)
372    }
373
374    /// Executes immutable transaction. The transaction is running a closure `f`
375    /// that will receive `&Transaction` object to run `exec` queries as if run
376    /// on the main database object. You shall specify the return type `T`
377    /// (can be `()`) and the error type `E` that must be constructible from the `DbError`
378    /// (`E` can be `DbError`).
379    ///
380    /// Read transactions cannot be committed or rolled back but their main function is to ensure
381    /// that the database data does not change during their duration. Through its generic
382    /// parameters it also allows transforming the query results into a type `T`.
383    pub fn transaction<T, E>(
384        &self,
385        f: impl FnOnce(&Transaction<Store>) -> Result<T, E>,
386    ) -> Result<T, E> {
387        let transaction = Transaction::new(self);
388
389        f(&transaction)
390    }
391
392    /// Executes mutable transaction. The transaction is running a closure `f`
393    /// that will receive `&mut Transaction` to execute `exec` and `exec_mut` queries
394    /// as if run on the main database object. You shall specify the return type `T`
395    /// (can be `()`) and the error type `E` that must be constructible from the `DbError`
396    /// (`E` can be `DbError`).
397    ///
398    /// Write transactions are committed if the closure returns `Ok` and rolled back if
399    /// the closure returns `Err`. If the code panics and the program exits the write
400    /// ahead log (WAL) makes sure the data in the main database file is restored to a
401    /// consistent state prior to the transaction.
402    ///
403    /// Typical use case for a write transaction is to insert nodes and edges together.
404    /// When not using a transaction you could end up only with nodes being inserted.
405    ///
406    /// Through its generic parameters the transaction also allows transforming the query
407    /// results into a type `T`.
408    pub fn transaction_mut<T, E: From<DbError>>(
409        &mut self,
410        f: impl FnOnce(&mut TransactionMut<Store>) -> Result<T, E>,
411    ) -> Result<T, E> {
412        let mut transaction = TransactionMut::new(&mut *self);
413        let result = f(&mut transaction);
414
415        if result.is_ok() {
416            transaction.commit()?;
417        } else {
418            transaction.rollback()?;
419        }
420
421        result
422    }
423
424    /// Returns the database size in bytes. Depending on the underlying storage
425    /// the physical size in hardware might be higher. For example for in-memory
426    /// storage this function reports used storage but actually allocated memory
427    /// will likely be higher (expecting database growth in order to prevent too
428    /// frequent allocations). For file based storages this number will be accurate
429    /// but the actually used space on disk will be higher up to the next file system
430    /// block size.
431    pub fn size(&self) -> u64 {
432        self.storage.len()
433    }
434
435    /// Shrinks all the allocated internal storage buffers to the current size of the data
436    /// and optimizes the storage. This may further reduce the size of the database
437    /// both on disk and in memory at the cost of requiring more allocations upon inserting
438    /// more data. Best to use only when the database is used for read-only operations after
439    /// initial data population.
440    pub fn shrink_to_fit(&mut self) -> Result<(), DbError> {
441        self.graph.shrink_to_fit(&mut self.storage)?;
442        self.aliases.shrink_to_fit(&mut self.storage)?;
443        self.indexes.shrink_to_fit(&mut self.storage)?;
444        self.values.shrink_to_fit(&mut self.storage)?;
445        self.optimize_storage()
446    }
447
448    pub(crate) fn commit(&mut self) -> Result<(), DbError> {
449        self.undo_stack.clear();
450        Ok(())
451    }
452
453    pub(crate) fn rollback(&mut self) -> Result<(), DbError> {
454        let mut undo_stack = vec![];
455        std::mem::swap(&mut undo_stack, &mut self.undo_stack);
456
457        for command in undo_stack.iter().rev() {
458            match command {
459                Command::InsertAlias { id, alias } => {
460                    self.aliases.insert(&mut self.storage, alias, id)?
461                }
462                Command::InsertEdge { from, to } => self
463                    .graph
464                    .insert_edge(&mut self.storage, *from, *to)
465                    .map(|_| ())?,
466                Command::InsertIndex { key } => {
467                    self.indexes.insert(&mut self.storage, key.clone())?;
468                }
469                Command::InsertToIndex { key, value, id } => self
470                    .indexes
471                    .index_mut(key)
472                    .expect("index not found during rollback")
473                    .ids_mut()
474                    .insert(&mut self.storage, value, id)?,
475                Command::InsertKeyValue { id, key_value } => {
476                    if let Some(index) = self.indexes.index_mut(&key_value.key) {
477                        index
478                            .ids_mut()
479                            .insert(&mut self.storage, &key_value.value, id)?;
480                    }
481                    self.values
482                        .insert_value(&mut self.storage, id.as_index(), key_value)?
483                }
484                Command::InsertNode => self.graph.insert_node(&mut self.storage).map(|_| ())?,
485                Command::RemoveAlias { alias } => {
486                    self.aliases.remove_key(&mut self.storage, alias)?
487                }
488                Command::RemoveEdge { index } => {
489                    self.graph.remove_edge(&mut self.storage, *index)?
490                }
491                Command::RemoveIndex { key } => self.indexes.remove(&mut self.storage, key)?,
492                Command::RemoveKeyValue { id, key_value } => {
493                    if let Some(index) = self.indexes.index_mut(&key_value.key) {
494                        index
495                            .ids_mut()
496                            .remove_value(&mut self.storage, &key_value.value, id)?;
497                    }
498                    self.values
499                        .remove_value(&mut self.storage, id.as_index(), &key_value.key)?
500                }
501                Command::RemoveNode { index } => {
502                    self.graph.remove_node(&mut self.storage, *index)?
503                }
504                Command::ReplaceKeyValue { id, key_value } => {
505                    let old = self
506                        .values
507                        .insert_or_replace(&mut self.storage, id.as_index(), key_value)?
508                        .expect("old value not found during rollback");
509
510                    if let Some(index) = self.indexes.index_mut(&old.key) {
511                        index
512                            .ids_mut()
513                            .remove_value(&mut self.storage, &old.value, id)?;
514                        index
515                            .ids_mut()
516                            .insert(&mut self.storage, &key_value.value, id)?;
517                    }
518
519                    return Ok(());
520                }
521            }
522        }
523
524        Ok(())
525    }
526
527    pub(crate) fn alias(&self, db_id: DbId) -> Result<String, DbError> {
528        self.aliases
529            .key(&self.storage, &db_id)?
530            .ok_or(DbError::from(format!("Id '{}' not found", db_id.0)))
531    }
532
533    pub(crate) fn aliases(&self) -> Vec<(String, DbId)> {
534        self.aliases.iter(&self.storage).collect()
535    }
536
537    pub(crate) fn db_id(&self, query_id: &QueryId) -> Result<DbId, DbError> {
538        match query_id {
539            QueryId::Id(id) => Ok(DbId(self.graph_index(id.0)?.0)),
540            QueryId::Alias(alias) => Ok(self
541                .aliases
542                .value(&self.storage, alias)?
543                .ok_or(DbError::from(format!("Alias '{alias}' not found")))?),
544        }
545    }
546
547    pub(crate) fn edge_count(&self, db_id: DbId, from: bool, to: bool) -> Result<u64, DbError> {
548        let index = self.graph_index(db_id.0)?;
549
550        if let Some(node) = self.graph.node(&self.storage, index) {
551            return Ok(match (from, to) {
552                (true, true) => node.edge_count(),
553                (true, false) => node.edge_count_from(),
554                (false, true) => node.edge_count_to(),
555                (false, false) => 0,
556            });
557        }
558
559        Ok(0)
560    }
561
562    #[allow(clippy::wrong_self_convention)]
563    pub(crate) fn from_id(&self, id: DbId) -> Option<DbId> {
564        if id.0 < 0 {
565            Some(DbId(
566                self.graph.edge_from(&self.storage, GraphIndex(id.0)).0,
567            ))
568        } else {
569            None
570        }
571    }
572
573    pub(crate) fn to_id(&self, id: DbId) -> Option<DbId> {
574        if id.0 < 0 {
575            Some(DbId(self.graph.edge_to(&self.storage, GraphIndex(id.0)).0))
576        } else {
577            None
578        }
579    }
580
581    pub(crate) fn indexes(&self) -> Vec<DbKeyValue> {
582        self.indexes
583            .indexes()
584            .iter()
585            .map(|index| DbKeyValue {
586                key: index.key().clone(),
587                value: index.ids().len().into(),
588            })
589            .collect()
590    }
591
592    pub(crate) fn insert_alias(&mut self, db_id: DbId, alias: &String) -> Result<(), DbError> {
593        if let Some(old_alias) = self.aliases.key(&self.storage, &db_id)? {
594            self.undo_stack.push(Command::InsertAlias {
595                id: db_id,
596                alias: old_alias.clone(),
597            });
598            self.aliases.remove_key(&mut self.storage, &old_alias)?;
599            self.aliases.remove_key(&mut self.storage, &old_alias)?;
600        }
601
602        self.undo_stack.push(Command::RemoveAlias {
603            alias: alias.clone(),
604        });
605        self.aliases.insert(&mut self.storage, alias, &db_id)
606    }
607
608    pub(crate) fn insert_edge(&mut self, from: DbId, to: DbId) -> Result<DbId, DbError> {
609        let index =
610            self.graph
611                .insert_edge(&mut self.storage, GraphIndex(from.0), GraphIndex(to.0))?;
612        self.undo_stack.push(Command::RemoveEdge { index });
613
614        Ok(DbId(index.0))
615    }
616
617    pub(crate) fn insert_index(&mut self, key: &DbValue) -> Result<u64, DbError> {
618        if self.indexes.index(key).is_some() {
619            return Err(DbError::from(format!("Index '{key}' already exists")));
620        }
621
622        self.undo_stack
623            .push(Command::RemoveIndex { key: key.clone() });
624
625        let index = self.indexes.insert(&mut self.storage, key.clone())?;
626
627        for i in 1..self.values.len() {
628            let kvs = self.values.values(&self.storage, i)?;
629            let db_id = if self
630                .graph
631                .node(&self.storage, GraphIndex(i as i64))
632                .is_some()
633            {
634                DbId(i as i64)
635            } else {
636                DbId(-(i as i64))
637            };
638
639            for kv in kvs {
640                if kv.key == *key {
641                    index
642                        .ids_mut()
643                        .insert(&mut self.storage, &kv.value, &db_id)?;
644                }
645            }
646        }
647
648        Ok(index.ids().len())
649    }
650
651    pub(crate) fn insert_new_alias(&mut self, db_id: DbId, alias: &String) -> Result<(), DbError> {
652        self.undo_stack.push(Command::RemoveAlias {
653            alias: alias.clone(),
654        });
655        self.aliases.insert(&mut self.storage, alias, &db_id)?;
656
657        Ok(())
658    }
659
660    pub(crate) fn insert_node(&mut self) -> Result<DbId, DbError> {
661        let index = self.graph.insert_node(&mut self.storage)?;
662        self.undo_stack.push(Command::RemoveNode { index });
663
664        Ok(DbId(index.0))
665    }
666
667    pub(crate) fn insert_key_value(
668        &mut self,
669        db_id: DbId,
670        key_value: &DbKeyValue,
671    ) -> Result<(), DbError> {
672        if let Some(index) = self.indexes.index_mut(&key_value.key) {
673            index
674                .ids_mut()
675                .insert(&mut self.storage, &key_value.value, &db_id)?;
676        }
677
678        self.undo_stack.push(Command::RemoveKeyValue {
679            id: db_id,
680            key_value: key_value.clone(),
681        });
682        self.values
683            .insert_value(&mut self.storage, db_id.as_index(), key_value)?;
684        Ok(())
685    }
686
687    pub(crate) fn insert_or_replace_key_value(
688        &mut self,
689        db_id: DbId,
690        key_value: &DbKeyValue,
691    ) -> Result<(), DbError> {
692        if let Some(old) =
693            self.values
694                .insert_or_replace(&mut self.storage, db_id.as_index(), key_value)?
695        {
696            if let Some(index) = self.indexes.index_mut(&old.key) {
697                index
698                    .ids_mut()
699                    .remove_value(&mut self.storage, &old.value, &db_id)?;
700                index
701                    .ids_mut()
702                    .insert(&mut self.storage, &key_value.value, &db_id)?;
703            }
704
705            self.undo_stack.push(Command::ReplaceKeyValue {
706                id: db_id,
707                key_value: old,
708            });
709        } else {
710            if let Some(index) = self.indexes.index_mut(&key_value.key) {
711                index
712                    .ids_mut()
713                    .insert(&mut self.storage, &key_value.value, &db_id)?;
714            }
715
716            self.undo_stack.push(Command::RemoveKeyValue {
717                id: db_id,
718                key_value: key_value.clone(),
719            });
720        }
721
722        Ok(())
723    }
724
725    pub(crate) fn keys(&self, db_id: DbId) -> Result<Vec<DbValue>, DbError> {
726        self.values.keys(&self.storage, db_id.as_index())
727    }
728
729    pub(crate) fn key_count(&self, db_id: DbId) -> Result<u64, DbError> {
730        self.values.key_count(&self.storage, db_id.as_index())
731    }
732
733    pub(crate) fn node_count(&self) -> Result<u64, DbError> {
734        self.graph.node_count(&self.storage)
735    }
736
737    pub(crate) fn remove(&mut self, query_id: &QueryId) -> Result<bool, DbError> {
738        match query_id {
739            QueryId::Id(db_id) => self.remove_id(*db_id),
740            QueryId::Alias(alias) => {
741                if let Some(db_id) = self.aliases.value(&self.storage, alias)? {
742                    self.remove_node(db_id, GraphIndex(db_id.0), Some(alias.clone()))?;
743                    self.remove_all_values(db_id)?;
744                    Ok(true)
745                } else {
746                    Ok(false)
747                }
748            }
749        }
750    }
751
752    pub(crate) fn remove_id(&mut self, db_id: DbId) -> Result<bool, DbError> {
753        if let Ok(graph_index) = self.graph_index(db_id.0) {
754            if graph_index.is_node() {
755                self.remove_node(db_id, graph_index, self.aliases.key(&self.storage, &db_id)?)?;
756            } else {
757                self.remove_edge(graph_index)?;
758            }
759            self.remove_all_values(db_id)?;
760            return Ok(true);
761        }
762
763        Ok(false)
764    }
765
766    pub(crate) fn remove_alias(&mut self, alias: &String) -> Result<bool, DbError> {
767        if let Some(id) = self.aliases.value(&self.storage, alias)? {
768            self.undo_stack.push(Command::InsertAlias {
769                id,
770                alias: alias.clone(),
771            });
772            self.aliases.remove_key(&mut self.storage, alias)?;
773            self.aliases.remove_key(&mut self.storage, alias)?;
774
775            return Ok(true);
776        }
777
778        Ok(false)
779    }
780
781    pub(crate) fn remove_index(&mut self, key: &DbValue) -> Result<u64, DbError> {
782        let mut count = None;
783
784        if let Some(index) = self.indexes.index(key) {
785            for (value, id) in index.ids().iter(&self.storage) {
786                self.undo_stack.push(Command::InsertToIndex {
787                    key: key.clone(),
788                    value: value.clone(),
789                    id,
790                });
791            }
792
793            count = Some(index.ids().len());
794        }
795
796        if let Some(count) = count {
797            self.undo_stack
798                .push(Command::InsertIndex { key: key.clone() });
799            self.indexes.remove(&mut self.storage, key)?;
800            Ok(count)
801        } else {
802            Ok(0)
803        }
804    }
805
806    pub(crate) fn reserve_key_value_capacity(
807        &mut self,
808        db_id: DbId,
809        additional: u64,
810    ) -> Result<(), DbError> {
811        self.values
812            .reserve_capacity(&mut self.storage, db_id.as_index(), additional)
813    }
814
815    pub(crate) fn search_index(
816        &self,
817        key: &DbValue,
818        value: &DbValue,
819    ) -> Result<Vec<DbId>, DbError> {
820        if let Some(index) = self.indexes.index(key) {
821            Ok(index.ids().values(&self.storage, value)?)
822        } else {
823            Err(DbError::from(format!("Index '{key}' not found")))
824        }
825    }
826
827    pub(crate) fn search_from(
828        &self,
829        from: DbId,
830        algorithm: SearchQueryAlgorithm,
831        limit: u64,
832        offset: u64,
833        conditions: &Vec<QueryCondition>,
834    ) -> Result<Vec<DbId>, DbError> {
835        let search = GraphSearch::from((&self.graph, &self.storage));
836
837        let indexes = match (limit, offset) {
838            (0, 0) => match algorithm {
839                SearchQueryAlgorithm::BreadthFirst => search.breadth_first_search(
840                    GraphIndex(from.0),
841                    DefaultHandler::new(self, conditions),
842                )?,
843                SearchQueryAlgorithm::DepthFirst => search.depth_first_search(
844                    GraphIndex(from.0),
845                    DefaultHandler::new(self, conditions),
846                )?,
847                _ => search.elements(DefaultHandler::new(self, conditions))?,
848            },
849
850            (_, 0) => match algorithm {
851                SearchQueryAlgorithm::BreadthFirst => search.breadth_first_search(
852                    GraphIndex(from.0),
853                    LimitHandler::new(limit, self, conditions),
854                )?,
855                SearchQueryAlgorithm::DepthFirst => search.depth_first_search(
856                    GraphIndex(from.0),
857                    LimitHandler::new(limit, self, conditions),
858                )?,
859                _ => search.elements(LimitHandler::new(limit, self, conditions))?,
860            },
861
862            (0, _) => match algorithm {
863                SearchQueryAlgorithm::BreadthFirst => search.breadth_first_search(
864                    GraphIndex(from.0),
865                    OffsetHandler::new(offset, self, conditions),
866                )?,
867                SearchQueryAlgorithm::DepthFirst => search.depth_first_search(
868                    GraphIndex(from.0),
869                    OffsetHandler::new(offset, self, conditions),
870                )?,
871                _ => search.elements(OffsetHandler::new(offset, self, conditions))?,
872            },
873
874            (_, _) => match algorithm {
875                SearchQueryAlgorithm::BreadthFirst => search.breadth_first_search(
876                    GraphIndex(from.0),
877                    LimitOffsetHandler::new(limit, offset, self, conditions),
878                )?,
879                SearchQueryAlgorithm::DepthFirst => search.depth_first_search(
880                    GraphIndex(from.0),
881                    LimitOffsetHandler::new(limit, offset, self, conditions),
882                )?,
883                _ => search.elements(LimitOffsetHandler::new(limit, offset, self, conditions))?,
884            },
885        };
886
887        Ok(indexes.iter().map(|index| DbId(index.0)).collect())
888    }
889
890    pub(crate) fn search_to(
891        &self,
892        to: DbId,
893        algorithm: SearchQueryAlgorithm,
894        limit: u64,
895        offset: u64,
896        conditions: &Vec<QueryCondition>,
897    ) -> Result<Vec<DbId>, DbError> {
898        let search = GraphSearch::from((&self.graph, &self.storage));
899
900        let indexes = match (limit, offset) {
901            (0, 0) => match algorithm {
902                SearchQueryAlgorithm::BreadthFirst => search.breadth_first_search_reverse(
903                    GraphIndex(to.0),
904                    DefaultHandler::new(self, conditions),
905                )?,
906                _ => search.depth_first_search_reverse(
907                    GraphIndex(to.0),
908                    DefaultHandler::new(self, conditions),
909                )?,
910            },
911
912            (_, 0) => match algorithm {
913                SearchQueryAlgorithm::BreadthFirst => search.breadth_first_search_reverse(
914                    GraphIndex(to.0),
915                    LimitHandler::new(limit, self, conditions),
916                )?,
917                _ => search.depth_first_search_reverse(
918                    GraphIndex(to.0),
919                    LimitHandler::new(limit, self, conditions),
920                )?,
921            },
922
923            (0, _) => match algorithm {
924                SearchQueryAlgorithm::BreadthFirst => search.breadth_first_search_reverse(
925                    GraphIndex(to.0),
926                    OffsetHandler::new(offset, self, conditions),
927                )?,
928                _ => search.depth_first_search_reverse(
929                    GraphIndex(to.0),
930                    OffsetHandler::new(offset, self, conditions),
931                )?,
932            },
933
934            (_, _) => match algorithm {
935                SearchQueryAlgorithm::BreadthFirst => search.breadth_first_search_reverse(
936                    GraphIndex(to.0),
937                    LimitOffsetHandler::new(limit, offset, self, conditions),
938                )?,
939                _ => search.depth_first_search_reverse(
940                    GraphIndex(to.0),
941                    LimitOffsetHandler::new(limit, offset, self, conditions),
942                )?,
943            },
944        };
945
946        Ok(indexes.iter().map(|index| DbId(index.0)).collect())
947    }
948
949    pub(crate) fn search_from_to(
950        &self,
951        from: DbId,
952        to: DbId,
953        conditions: &Vec<QueryCondition>,
954    ) -> Result<Vec<DbId>, DbError> {
955        Ok(GraphSearch::from((&self.graph, &self.storage))
956            .path(
957                GraphIndex(from.0),
958                GraphIndex(to.0),
959                PathHandler::new(self, conditions),
960            )?
961            .iter()
962            .map(|index| DbId(index.0))
963            .collect())
964    }
965
966    pub(crate) fn values(&self, db_id: DbId) -> Result<Vec<DbKeyValue>, DbError> {
967        self.values.values(&self.storage, db_id.as_index())
968    }
969
970    pub(crate) fn values_by_keys(
971        &self,
972        db_id: DbId,
973        keys: &[DbValue],
974    ) -> Result<Vec<DbKeyValue>, DbError> {
975        self.values
976            .values_by_keys(&self.storage, db_id.as_index(), keys)
977    }
978
979    fn graph_index(&self, id: i64) -> Result<GraphIndex, DbError> {
980        match id.cmp(&0) {
981            std::cmp::Ordering::Less => {
982                if self.graph.edge(&self.storage, GraphIndex(id)).is_some() {
983                    return Ok(GraphIndex(id));
984                }
985            }
986            std::cmp::Ordering::Equal => {}
987            std::cmp::Ordering::Greater => {
988                if self.graph.node(&self.storage, GraphIndex(id)).is_some() {
989                    return Ok(GraphIndex(id));
990                }
991            }
992        }
993
994        Err(DbError::from(format!("Id '{id}' not found")))
995    }
996
997    fn node_edges(
998        &self,
999        graph_index: GraphIndex,
1000    ) -> Result<Vec<(GraphIndex, GraphIndex, GraphIndex)>, DbError> {
1001        let mut edges = vec![];
1002        let node = self
1003            .graph
1004            .node(&self.storage, graph_index)
1005            .ok_or(DbError::from("Data integrity corrupted"))?;
1006
1007        for edge in node.edge_iter_from() {
1008            edges.push((edge.index(), edge.index_from(), edge.index_to()));
1009        }
1010
1011        for edge in node.edge_iter_to() {
1012            let from = edge.index_from();
1013            if from != graph_index {
1014                edges.push((edge.index(), from, edge.index_to()));
1015            }
1016        }
1017
1018        Ok(edges)
1019    }
1020
1021    fn remove_edge(&mut self, graph_index: GraphIndex) -> Result<(), DbError> {
1022        let (from, to) = {
1023            let edge = self
1024                .graph
1025                .edge(&self.storage, graph_index)
1026                .ok_or(DbError::from("Graph integrity corrupted"))?;
1027            (edge.index_from(), edge.index_to())
1028        };
1029
1030        self.graph.remove_edge(&mut self.storage, graph_index)?;
1031        self.undo_stack.push(Command::InsertEdge { from, to });
1032        Ok(())
1033    }
1034
1035    fn remove_node(
1036        &mut self,
1037        db_id: DbId,
1038        graph_index: GraphIndex,
1039        alias: Option<String>,
1040    ) -> Result<(), DbError> {
1041        if let Some(alias) = alias {
1042            self.undo_stack.push(Command::InsertAlias {
1043                alias: alias.clone(),
1044                id: db_id,
1045            });
1046            self.aliases.remove_key(&mut self.storage, &alias)?;
1047            self.aliases.remove_key(&mut self.storage, &alias)?;
1048        }
1049
1050        for edge in self.node_edges(graph_index)? {
1051            self.graph.remove_edge(&mut self.storage, edge.0)?;
1052            self.undo_stack.push(Command::InsertEdge {
1053                from: edge.1,
1054                to: edge.2,
1055            });
1056            self.remove_all_values(DbId(edge.0.0))?;
1057        }
1058
1059        self.graph.remove_node(&mut self.storage, graph_index)?;
1060        self.undo_stack.push(Command::InsertNode);
1061        Ok(())
1062    }
1063
1064    pub(crate) fn remove_keys(&mut self, db_id: DbId, keys: &[DbValue]) -> Result<i64, DbError> {
1065        let mut result = 0;
1066
1067        for key_value in self.values.values(&self.storage, db_id.as_index())? {
1068            if keys.contains(&key_value.key) {
1069                if let Some(index) = self.indexes.index_mut(&key_value.key) {
1070                    index
1071                        .ids_mut()
1072                        .remove_value(&mut self.storage, &key_value.value, &db_id)?;
1073                }
1074                self.values
1075                    .remove_value(&mut self.storage, db_id.as_index(), &key_value.key)?;
1076                self.undo_stack.push(Command::InsertKeyValue {
1077                    id: db_id,
1078                    key_value,
1079                });
1080                result -= 1;
1081            }
1082        }
1083
1084        Ok(result)
1085    }
1086
1087    fn remove_all_values(&mut self, db_id: DbId) -> Result<(), DbError> {
1088        for key_value in self.values.values(&self.storage, db_id.as_index())? {
1089            if let Some(index) = self.indexes.index_mut(&key_value.key) {
1090                index
1091                    .ids_mut()
1092                    .remove_value(&mut self.storage, &key_value.value, &db_id)?;
1093            }
1094
1095            self.undo_stack.push(Command::InsertKeyValue {
1096                id: db_id,
1097                key_value,
1098            });
1099        }
1100
1101        self.values.remove(&mut self.storage, db_id.as_index())?;
1102
1103        Ok(())
1104    }
1105
1106    fn try_new_with_storage(mut storage: Storage<Store>) -> Result<Self, DbError> {
1107        let graph_storage;
1108        let aliases_storage;
1109        let indexes_storage;
1110        let values_storage;
1111
1112        if storage.value_size(StorageIndex(1)).is_err() {
1113            storage.insert(&DbStorageIndex::default())?;
1114            graph_storage = DbGraph::new(&mut storage)?;
1115            aliases_storage = DbIndexedMap::new(&mut storage)?;
1116            indexes_storage = DbIndexes::new(&mut storage)?;
1117            values_storage = DbKeyValues::new(&mut storage)?;
1118            let db_storage_index = DbStorageIndex {
1119                version: CURRENT_VERSION,
1120                graph: graph_storage.storage_index(),
1121                aliases: aliases_storage.storage_index(),
1122                indexes: indexes_storage.storage_index(),
1123                values: values_storage.storage_index(),
1124            };
1125            storage.insert_at(StorageIndex(1), 0, &db_storage_index)?;
1126        } else {
1127            let index = if let Ok(index) = storage.value::<DbStorageIndex>(StorageIndex(1)) {
1128                index
1129            } else {
1130                legacy::convert_to_current_version(&mut storage)?;
1131                storage.value::<DbStorageIndex>(StorageIndex(1))?
1132            };
1133
1134            graph_storage = DbGraph::from_storage(&storage, index.graph)?;
1135            aliases_storage = DbIndexedMap::from_storage(&storage, index.aliases)?;
1136            indexes_storage = DbIndexes::from_storage(&storage, index.indexes)?;
1137            values_storage = DbKeyValues::from_storage(&storage, index.values)?;
1138        }
1139
1140        Ok(Self {
1141            storage,
1142            graph: graph_storage,
1143            aliases: aliases_storage,
1144            indexes: indexes_storage,
1145            values: values_storage,
1146            undo_stack: vec![],
1147        })
1148    }
1149
1150    fn try_new(filename: &str) -> Result<Self, DbError> {
1151        Self::try_new_with_storage(Storage::new(filename)?)
1152    }
1153
1154    pub(crate) fn evaluate_condition(
1155        &self,
1156        index: GraphIndex,
1157        distance: u64,
1158        condition: &QueryConditionData,
1159    ) -> Result<SearchControl, DbError> {
1160        match condition {
1161            QueryConditionData::Distance(value) => Ok(value.compare_distance(distance)),
1162            QueryConditionData::Edge => Ok(SearchControl::Continue(index.is_edge())),
1163            QueryConditionData::EdgeCount(value) => Ok(SearchControl::Continue(
1164                if let Some(node) = self.graph.node(&self.storage, index) {
1165                    value.compare(node.edge_count())
1166                } else {
1167                    false
1168                },
1169            )),
1170            QueryConditionData::EdgeCountFrom(value) => Ok(SearchControl::Continue(
1171                if let Some(node) = self.graph.node(&self.storage, index) {
1172                    value.compare(node.edge_count_from())
1173                } else {
1174                    false
1175                },
1176            )),
1177            QueryConditionData::EdgeCountTo(value) => Ok(SearchControl::Continue(
1178                if let Some(node) = self.graph.node(&self.storage, index) {
1179                    value.compare(node.edge_count_to())
1180                } else {
1181                    false
1182                },
1183            )),
1184            QueryConditionData::Ids(values) => {
1185                Ok(SearchControl::Continue(values.iter().any(|id| {
1186                    index.0
1187                        == match id {
1188                            QueryId::Id(id) => id.0,
1189                            QueryId::Alias(alias) => {
1190                                self.aliases
1191                                    .value(&self.storage, alias)
1192                                    .unwrap_or_default()
1193                                    .unwrap_or_default()
1194                                    .0
1195                            }
1196                        }
1197                })))
1198            }
1199            QueryConditionData::KeyValue(kvc) => Ok(SearchControl::Continue(
1200                if let Some(value) = self.values.value(&self.storage, index.as_u64(), &kvc.key)? {
1201                    kvc.value.compare(&value)
1202                } else {
1203                    false
1204                },
1205            )),
1206            QueryConditionData::Keys(values) => {
1207                let keys = self.values.keys(&self.storage, index.as_u64())?;
1208                Ok(SearchControl::Continue(
1209                    values.iter().all(|k| keys.contains(k)),
1210                ))
1211            }
1212            QueryConditionData::Node => Ok(SearchControl::Continue(index.is_node())),
1213            QueryConditionData::Where(conditions) => {
1214                self.evaluate_conditions(index, distance, conditions)
1215            }
1216        }
1217    }
1218
1219    pub(crate) fn evaluate_conditions(
1220        &self,
1221        index: GraphIndex,
1222        distance: u64,
1223        conditions: &[QueryCondition],
1224    ) -> Result<SearchControl, DbError> {
1225        let mut result = SearchControl::Continue(true);
1226
1227        for condition in conditions {
1228            let mut control = self.evaluate_condition(index, distance, &condition.data)?;
1229
1230            match condition.modifier {
1231                QueryConditionModifier::Beyond => {
1232                    if control.is_true() {
1233                        control = control.and(SearchControl::Continue(true));
1234                    } else {
1235                        control = SearchControl::Stop(true);
1236                    }
1237                }
1238                QueryConditionModifier::Not => control.flip(),
1239                QueryConditionModifier::NotBeyond => {
1240                    if control.is_true() {
1241                        control = control.and(SearchControl::Stop(true));
1242                    } else {
1243                        control = SearchControl::Continue(true);
1244                    }
1245                }
1246                _ => {}
1247            };
1248
1249            result = match condition.logic {
1250                QueryConditionLogic::And => result.and(control),
1251                QueryConditionLogic::Or => result.or(control),
1252            };
1253        }
1254
1255        Ok(result)
1256    }
1257}
1258
1259impl<Store: StorageData> Drop for DbImpl<Store> {
1260    fn drop(&mut self) {
1261        let _ = self.storage.optimize_storage();
1262    }
1263}
1264
1265impl DbAny {
1266    /// Creates a new DbAny instance using DbFile.
1267    pub fn new_file(filename: &str) -> Result<Self, DbError> {
1268        Self::try_new_any(filename, Self::try_new_file)
1269    }
1270
1271    /// Creates a new DbAny instance using Db.
1272    pub fn new_mapped(filename: &str) -> Result<Self, DbError> {
1273        Self::try_new_any(filename, Self::try_new_mapped)
1274    }
1275
1276    /// Creates a new DbAny instance using DbMemory.
1277    pub fn new_memory(filename: &str) -> Result<Self, DbError> {
1278        Self::try_new_any(filename, Self::try_new_memory)
1279    }
1280
1281    fn try_new_any(
1282        filename: &str,
1283        init: fn(&str) -> Result<DbImpl<AnyStorage>, DbError>,
1284    ) -> Result<Self, DbError> {
1285        match init(filename) {
1286            Ok(db) => Ok(db),
1287            Err(error) => {
1288                let mut db_error = DbError::from("Failed to create database");
1289                db_error.cause = Some(Box::new(error));
1290                Err(db_error)
1291            }
1292        }
1293    }
1294
1295    fn try_new_memory(filename: &str) -> Result<DbImpl<AnyStorage>, DbError> {
1296        Self::try_new_with_storage(Storage::with_data(AnyStorage::Memory(MemoryStorage::new(
1297            filename,
1298        )?))?)
1299    }
1300
1301    fn try_new_file(filename: &str) -> Result<DbImpl<AnyStorage>, DbError> {
1302        Self::try_new_with_storage(Storage::with_data(AnyStorage::File(FileStorage::new(
1303            filename,
1304        )?))?)
1305    }
1306
1307    fn try_new_mapped(filename: &str) -> Result<DbImpl<AnyStorage>, DbError> {
1308        Self::try_new_with_storage(Storage::with_data(AnyStorage::MemoryMapped(
1309            FileStorageMemoryMapped::new(filename)?,
1310        ))?)
1311    }
1312}
1313
1314// TODO: Remove this at some point in the future as it provides support for databases created in <= 0.10.0.
1315mod legacy {
1316    use crate::DbError;
1317    use crate::DbId;
1318    use crate::DbKeyValue;
1319    use crate::StorageData;
1320    use crate::collections::map::MapIterator;
1321    use crate::collections::multi_map::MultiMapStorage;
1322    use crate::db::CURRENT_VERSION;
1323    use crate::db::DbStorageIndex;
1324    use crate::db::db_key_value::DbKeyValues;
1325    use crate::storage::Storage;
1326    use crate::storage::StorageIndex;
1327    use crate::utilities::serialize::Serialize;
1328    use crate::utilities::serialize::SerializeStatic;
1329    use std::marker::PhantomData;
1330
1331    pub(crate) struct DbStorageIndexLegacy {
1332        pub(crate) graph: StorageIndex,
1333        pub(crate) aliases: (StorageIndex, StorageIndex),
1334        pub(crate) indexes: StorageIndex,
1335        pub(crate) values: StorageIndex,
1336    }
1337
1338    impl Serialize for DbStorageIndexLegacy {
1339        fn serialize(&self) -> Vec<u8> {
1340            [
1341                self.graph.serialize(),
1342                self.aliases.0.serialize(),
1343                self.aliases.1.serialize(),
1344                self.indexes.serialize(),
1345                self.values.serialize(),
1346            ]
1347            .concat()
1348        }
1349
1350        fn deserialize(bytes: &[u8]) -> Result<Self, DbError> {
1351            let size = i64::serialized_size_static() as usize;
1352
1353            let graph = StorageIndex::deserialize(bytes)?;
1354            let aliases_1 = StorageIndex::deserialize(&bytes[size..])?;
1355            let aliases_2 = StorageIndex::deserialize(&bytes[size * 2..])?;
1356            let indexes = StorageIndex::deserialize(&bytes[size * 3..])?;
1357            let values = StorageIndex::deserialize(&bytes[size * 4..])?;
1358
1359            Ok(Self {
1360                graph,
1361                aliases: (aliases_1, aliases_2),
1362                indexes,
1363                values,
1364            })
1365        }
1366
1367        fn serialized_size(&self) -> u64 {
1368            i64::serialized_size_static() * 5
1369        }
1370    }
1371
1372    pub fn convert_to_current_version<D: StorageData>(
1373        storage: &mut Storage<D>,
1374    ) -> Result<DbStorageIndex, DbError> {
1375        let legacy_index = storage.value::<DbStorageIndexLegacy>(StorageIndex(1))?;
1376        let legacy_values =
1377            MultiMapStorage::<DbId, DbKeyValue, _>::from_storage(storage, legacy_index.values)?;
1378        let t = storage.transaction();
1379        let mut values = DbKeyValues::new(storage)?;
1380        let mut pos = 0;
1381
1382        loop {
1383            let mut it = MapIterator {
1384                pos,
1385                data: &legacy_values.data,
1386                storage,
1387                phantom_data: PhantomData,
1388            };
1389
1390            if let Some((db_id, kv)) = it.next() {
1391                pos = it.pos;
1392                values.insert_value(storage, db_id.as_index(), &kv)?;
1393            } else {
1394                break;
1395            }
1396        }
1397
1398        legacy_values.remove_from_storage(storage)?;
1399
1400        let db_storage_index = DbStorageIndex {
1401            version: CURRENT_VERSION,
1402            graph: legacy_index.graph,
1403            aliases: legacy_index.aliases,
1404            indexes: legacy_index.indexes,
1405            values: values.storage_index(),
1406        };
1407
1408        storage.replace(StorageIndex(1), &db_storage_index)?;
1409        storage.commit(t)?;
1410        storage.optimize_storage()?;
1411        Ok(db_storage_index)
1412    }
1413}
1414
1415#[cfg(test)]
1416mod tests {
1417    use super::*;
1418    use crate::test_utilities::test_file::TestFile;
1419
1420    #[test]
1421    fn db_storage_index_serialized_size() {
1422        assert_eq!(DbStorageIndex::default().serialized_size(), 48);
1423    }
1424
1425    #[test]
1426    fn derived_from_debug() {
1427        let test_file = TestFile::new();
1428        let db = Db::new(test_file.file_name()).unwrap();
1429        let _ = format!("{db:?}");
1430    }
1431
1432    #[test]
1433    fn db_storage_index_legacy_serialization() {
1434        let index = legacy::DbStorageIndexLegacy {
1435            graph: StorageIndex(1),
1436            aliases: (StorageIndex(2), StorageIndex(3)),
1437            indexes: StorageIndex(4),
1438            values: StorageIndex(5),
1439        };
1440        let serialized = index.serialize();
1441        let deserialized = legacy::DbStorageIndexLegacy::deserialize(&serialized).unwrap();
1442        assert_eq!(index.graph, deserialized.graph);
1443        assert_eq!(index.aliases.0, deserialized.aliases.0);
1444        assert_eq!(index.aliases.1, deserialized.aliases.1);
1445        assert_eq!(index.indexes, deserialized.indexes);
1446        assert_eq!(index.values, deserialized.values);
1447        assert_eq!(index.serialized_size(), deserialized.serialized_size());
1448    }
1449}