native_db/
lib.rs

1//! Native DB is a Rust library that provides a simple, fast, and embedded database solution,
2//! focusing on maintaining coherence between Rust types and stored data with minimal boilerplate.
3//! It supports multiple indexes, real-time watch with filters, model migration, hot snapshot, and more.
4//!
5//! # Summary
6//! - [Api](#api)
7//! - [Quick Start](#quick-start)
8//!    - [Create a model](#create-a-model)
9//!    - [Create a database](#create-a-database)
10//!    - [Insert a model in the database](#insert-a-model-in-the-database)
11//!    - [Update a model](#update-a-model)
12//!    - [Migration](#migration)
13//! - Advanced
14//!    - [`Define a type as a key`](crate::db_type::ToKey)
15//!       - [Example with `uuid`](crate::db_type::ToKey#example-with-uuid)
16//!       - [Example with `chrono`](crate::db_type::ToKey#example-with-chrono)
17//!
18//! # Api
19//!
20//! - [`Models`] - Collection of models. *Equivalent to a schema in a traditional database*.
21//!    - [`new`](crate::Models::new) - Create a new collection of models.
22//!    - [`define`](crate::Models::define) - Define a model.
23//! - [`Builder`] - Builder to create a database.
24//!    - [`create_in_memory`](crate::Builder::create_in_memory) - Create a database in memory.
25//!    - [`create`](crate::Builder::create) - Create a database in a file.
26//!    - [`open`](crate::Builder::open) - Open a database.
27//! - [`Database`] - Database instance.
28//!    - [`compact`](crate::Database::compact) - Compact the database.
29//!    - [`check_integrity`](crate::Database::check_integrity) - Check the integrity of the database.
30//!    - [`rw_transaction`](crate::Database::rw_transaction) - Create a read-write transaction.
31//!       - [`insert`](crate::transaction::RwTransaction::insert) - Insert a item, fail if the item already exists.
32//!       - [`upsert`](crate::transaction::RwTransaction::upsert) - Upsert a item, update if the item already exists.
33//!       - [`update`](crate::transaction::RwTransaction::update) - Update a item, replace an existing item.
34//!       - [`remove`](crate::transaction::RwTransaction::remove) - Remove a item, remove an existing item.
35//!       - [`migrate`](crate::transaction::RwTransaction::migrate) - Migrate a model, affect all items.
36//!       - [`commit`](crate::transaction::RwTransaction::commit) - Commit the transaction.
37//!       - [`abort`](crate::transaction::RwTransaction::abort) - Abort the transaction.
38//!   - [`r_transaction`](crate::Database::r_transaction) - Create a read-only transaction.
39//!       - [`get`](crate::transaction::RTransaction::get) - Get a item.
40//!          - [`primary`](crate::transaction::query::RGet::primary) - Get a item by primary key.
41//!          - [`secondary`](crate::transaction::query::RGet::secondary) - Get a item by secondary key.
42//!       - [`scan`](crate::transaction::RTransaction::scan) - Scan items.
43//!          - [`primary`](crate::transaction::query::RScan::primary) - Scan items by primary key.
44//!             - [`all`](crate::transaction::query::PrimaryScan::all) - Scan all items.
45//!             - [`start_with`](crate::transaction::query::PrimaryScan::start_with) - Scan items with a primary key starting with a key.
46//!             - [`range`](crate::transaction::query::PrimaryScan::range) - Scan items with a primary key in a given range.
47//!          - [`secondary`](crate::transaction::query::RScan::secondary) - Scan items by secondary key.
48//!             - [`all`](crate::transaction::query::SecondaryScan::all) - Scan items with a given secondary key.
49//!             - [`start_with`](crate::transaction::query::SecondaryScan::start_with) - Scan items with a secondary key starting with a key.
50//!             - [`range`](crate::transaction::query::SecondaryScan::range) - Scan items with a secondary key in a given range.
51//!       - [`len`](crate::transaction::RTransaction::len) - Get the number of items.
52//!          - [`primary`](crate::transaction::query::RLen::primary) - Get the number of items by primary key.
53//!          - [`secondary`](crate::transaction::query::RLen::secondary) - Get the number of items by secondary key.    
54//!   - [`watch`](crate::Database::watch) - Watch items in real-time.  Works via [std channel](https://doc.rust-lang.org/std/sync/mpsc/fn.channel.html) based or [tokio channel](https://docs.rs/tokio/latest/tokio/sync/mpsc/fn.unbounded_channel.html) based depending on the feature `tokio`.
55//!       - [`get`](crate::watch::query::Watch::get) - Watch a item.
56//!          - [`primary`](crate::watch::query::WatchGet::primary) - Watch a item by primary key.
57//!          - [`secondary`](crate::watch::query::WatchGet::secondary) - Watch a item by secondary key.
58//!       - [`scan`](crate::watch::query::Watch::scan) - Watch items.
59//!          - [`primary`](crate::watch::query::WatchScan::primary) - Watch items by primary key.
60//!             - [`all`](crate::watch::query::WatchScanPrimary::all) - Watch all items.
61//!             - [`start_with`](crate::watch::query::WatchScanPrimary::start_with) - Watch items with a primary key starting with a key.
62//!             - [`range`](crate::watch::query::WatchScanPrimary::range) - Watch items with a primary key in a given range.
63//!          - [`secondary`](crate::watch::query::WatchScan::secondary) - Watch items by secondary key.
64//!             - [`all`](crate::watch::query::WatchScanSecondary::all) - Watch items with a given secondary key.
65//!             - [`start_with`](crate::watch::query::WatchScanSecondary::start_with) - Watch items with a secondary key starting with a key.
66//!             - [`range`](crate::watch::query::WatchScanSecondary::range) - Watch items with a secondary key in a given range.
67//!
68//!
69//! # Quick Start
70//!
71//! We will create a simple example to show how to use the library.
72//!
73//! ## Create a model
74//!
75//! > 👉 Unlike the usual database where there is a difference between *schema* and *model*, here, as we can directly use Rust types that are serialized in the database, we do not have the concept of *schema*, only that of the *model*.
76//!
77//! In this section, we will create a simple model. I have chosen a particular organization using Rust modules, which I find to be a best practice. However, it is not mandatory; you can do it as you prefer. (see [`define`](crate::Models::define) for more information)
78//!
79//! In this example:
80//! - We create a module `data` which contains **all versions of all models**.
81//! - We create a module `v1` which contains the **first version of your data**, we will put other versions later.
82//! - We create a type alias `Person` to the latest version `v1::Person`, which allows us to use the **latest version** of the model in the application.
83//!
84//! ```rust
85//! pub mod data {
86//!     use native_db::{native_db, ToKey};
87//!     use native_model::{native_model, Model};
88//!     use serde::{Deserialize, Serialize};
89//!
90//!     pub type Person = v1::Person;
91//!
92//!     pub mod v1 {
93//!         use super::*;
94//!         
95//!         #[derive(Serialize, Deserialize, Debug)]
96//!         #[native_model(id = 1, version = 1)]
97//!         #[native_db]
98//!         pub struct Person {
99//!            #[primary_key]
100//!            pub name: String,
101//!         }
102//!     }
103//! }
104//! ```
105//!
106//! ## Create a database
107//!
108//! After creating the model in the previous step, we can now create the database with the model.
109//!
110//! Note good practices: [`define`](crate::Models::define) the [`models`](crate::Models) by **specifying each version**, in our case `data::v1::Person`.
111//!
112//! ```rust
113//! # pub mod data {
114//! #     use native_db::{native_db, ToKey};
115//! #     use native_model::{native_model, Model};
116//! #     use serde::{Deserialize, Serialize};
117//! #
118//! #     pub type Person = v1::Person;
119//! #
120//! #     pub mod v1 {
121//! #         use super::*;
122//! #         
123//! #         #[derive(Serialize, Deserialize, Debug)]
124//! #         #[native_model(id = 1, version = 1)]
125//! #         #[native_db]
126//! #         pub struct Person {
127//! #            #[primary_key]
128//! #            pub name: String,
129//! #         }
130//! #     }
131//! # }
132//! use native_db::*;
133//! use once_cell::sync::Lazy;
134//!
135//! // Define the models
136//! // The lifetime of the models needs to be longer or equal to the lifetime of the database.
137//! // In many cases, it is simpler to use a static variable but it is not mandatory.
138//! static MODELS: Lazy<Models> = Lazy::new(|| {
139//!    let mut models = Models::new();
140//!    // It's a good practice to define the models by specifying the version
141//!    models.define::<data::v1::Person>().unwrap();
142//!    models
143//! });
144//!
145//! fn main() -> Result<(), db_type::Error> {
146//!     // Create the database
147//!     let db = Builder::new().create_in_memory(&MODELS)?;
148//!     Ok(())
149//! }
150//! ```
151//!
152//! ## Insert a model in the database
153//!
154//! Note a good practice: use the **latest version** of the model in your application.
155//! In our case, we use `data::Person`.
156//!
157//! ```rust
158//! # pub mod data {
159//! #     use native_db::{native_db, ToKey};
160//! #     use native_model::{native_model, Model};
161//! #     use serde::{Deserialize, Serialize};
162//! #
163//! #     pub type Person = v1::Person;
164//! #
165//! #     pub mod v1 {
166//! #         use super::*;
167//! #         
168//! #         #[derive(Serialize, Deserialize, Debug)]
169//! #         #[native_model(id = 1, version = 1)]
170//! #         #[native_db]
171//! #         pub struct Person {
172//! #            #[primary_key]
173//! #            pub name: String,
174//! #         }
175//! #     }
176//! # }
177//! use native_db::*;
178//! use once_cell::sync::Lazy;
179//! #
180//! # static MODELS: Lazy<Models> = Lazy::new(|| {
181//! #    let mut models = Models::new();
182//! #    models.define::<data::v1::Person>().unwrap();
183//! #    models
184//! # });
185//!
186//! fn main() -> Result<(), db_type::Error> {
187//!     # let db = Builder::new().create_in_memory(&MODELS)?;
188//!     // ... database creation see previous example
189//!
190//!     // Insert a person
191//!     let rw = db.rw_transaction()?;
192//!     // It's a good practice to use the latest version in your application
193//!     rw.insert(data::Person { name: "Alice".to_string() })?;
194//!     rw.commit()?;
195//!
196//!     // Get the person
197//!     let r = db.r_transaction()?;
198//!     let person: data::Person = r.get().primary("Alice".to_string())?.unwrap();
199//!     assert_eq!(person.name, "Alice");
200//!     Ok(())
201//! }
202//! ```
203//!
204//! ## Update a model
205//!
206//! We need to add the field `age` to the `Person` model, but data is already stored in the database so we need to migrate it.
207//!
208//! To do this we have to:
209//! - Create a version `v2` of the model `Person` with the new field `age`.
210//! - Implement the `From` (or `TryFrom`) trait for the previous version `v1` to the new version `v2`, so we can migrate the data.
211//!   See [native_model#Data model](https://github.com/vincent-herlemont/native_model?tab=readme-ov-file#data-model) for more information.
212//!
213//! ```rust
214//! pub mod data {
215//!     // ... same imports
216//! #    use native_db::{native_db, ToKey};
217//! #    use native_model::{native_model, Model};
218//! #    use serde::{Deserialize, Serialize};
219//!     
220//!     // Update the type alias to the latest version
221//!     pub type Person = v2::Person;
222//!
223//!     pub mod v1 {
224//!          // ... the previous version of Person
225//! #        use super::*;
226//! #       #[derive(Serialize, Deserialize, Debug)]
227//! #       #[native_model(id = 1, version = 1)]
228//! #       #[native_db]
229//! #       pub struct Person {
230//! #          #[primary_key]
231//! #          pub name: String,
232//! #       }
233//!         
234//!         impl From<v2::Person> for Person {
235//!            fn from(p: v2::Person) -> Self {
236//!               Self {
237//!                  name: p.name,
238//!               }
239//!            }
240//!         }
241//!     }
242//!
243//!     pub mod v2 {
244//!         use super::*;
245//!
246//!         #[derive(Serialize, Deserialize, Debug)]
247//!         #[native_model(id = 1, version = 2, from = v1::Person)]
248//!         #[native_db]
249//!         pub struct Person {
250//!            #[primary_key]
251//!            pub name: String,
252//!            pub age: u8,
253//!         }
254//!         
255//!         impl From<v1::Person> for Person {
256//!            fn from(p: v1::Person) -> Self {
257//!               Self {
258//!                  name: p.name,
259//!                  age: 0,
260//!               }
261//!            }
262//!         }
263//!     }
264//! }
265//! ```
266//!
267//! ## Migration
268//!
269//! After updating the model, we need to define the new version `v2` of the model `Person` and migrate the data.
270//!
271//! ```rust
272//! # pub mod data {
273//! #    // ... same imports
274//! #    use native_db::{native_db, ToKey};
275//! #    use native_model::{native_model, Model};
276//! #    use serde::{Deserialize, Serialize};
277//! #    
278//! #    // Update the type alias to the latest version
279//! #    pub type Person = v2::Person;
280//! #
281//! #    pub mod v1 {
282//! #         // ... the previous version of Person
283//! #        use super::*;
284//! #       #[derive(Serialize, Deserialize, Debug)]
285//! #       #[native_model(id = 1, version = 1)]
286//! #       #[native_db]
287//! #       pub struct Person {
288//! #          #[primary_key]
289//! #          pub name: String,
290//! #       }
291//! #         
292//! #         impl From<v2::Person> for Person {
293//! #            fn from(p: v2::Person) -> Self {
294//! #               Self {
295//! #                  name: p.name,
296//! #               }
297//! #            }
298//! #         }
299//! #     }
300//! #
301//! #     pub mod v2 {
302//! #         use super::*;
303//! #
304//! #         #[derive(Serialize, Deserialize, Debug)]
305//! #         #[native_model(id = 1, version = 2, from = v1::Person)]
306//! #         #[native_db]
307//! #         pub struct Person {
308//! #            #[primary_key]
309//! #            pub name: String,
310//! #            pub age: u8,
311//! #         }
312//! #         
313//! #         impl From<v1::Person> for Person {
314//! #            fn from(p: v1::Person) -> Self {
315//! #               Self {
316//! #                  name: p.name,
317//! #                  age: 0,
318//! #               }
319//! #            }
320//! #         }
321//! #     }
322//! # }
323//! use native_db::*;
324//! use once_cell::sync::Lazy;
325//!
326//! static MODELS: Lazy<Models> = Lazy::new(|| {
327//!    let mut models = Models::new();
328//!    // Define the models by specifying the version
329//!    models.define::<data::v1::Person>().unwrap();
330//!    models.define::<data::v2::Person>().unwrap();
331//!    models
332//! });
333//!
334//! fn main() -> Result<(), db_type::Error> {
335//!     // Create the database
336//!     let db = Builder::new().create_in_memory(&MODELS)?;
337//!
338//!     // Migrate the data in a transaction
339//!     let rw = db.rw_transaction()?;
340//!     rw.migrate::<data::Person>()?;
341//!     rw.commit()?;
342//!
343//!     // Now we can insert a person with the new field age ...
344//!
345//!     Ok(())
346//! }
347//! ```
348//!
349//! More details [`migrate`](crate::transaction::RwTransaction::migrate) method.
350//!
351mod database;
352mod database_builder;
353mod database_instance;
354
355/// A collection of type used by native_db internally (macro included).
356pub mod db_type;
357mod metadata;
358mod model;
359mod serialization;
360mod snapshot;
361mod stats;
362mod table_definition;
363pub mod upgrade;
364
365mod models;
366
367/// Database interactions here.
368pub mod transaction;
369/// Watch data in real-time.
370pub mod watch;
371
372// Re-export
373pub use db_type::Key;
374pub use db_type::ToInput;
375/// Allow to use a type as a key in the database.
376pub use db_type::ToKey;
377
378// Export
379pub use database::*;
380pub use database_builder::*;
381pub use metadata::*;
382pub use model::*;
383pub use models::*;
384
385#[cfg(doctest)]
386#[macro_use]
387extern crate doc_comment;
388
389#[cfg(doctest)]
390doc_comment! {
391    include_str!("../README.md")
392}
393
394/// Macro which link [`native_model`](https://crates.io/crates/native_model) to the Native DB. See [`Builder.define`](struct.Builder.html#method.define) for more information.
395pub use native_db_macro::*;
396pub use serialization::*;