native_db_32bit/
database_builder.rs

1use crate::db_type::Result;
2use crate::table_definition::NativeModelOptions;
3use crate::{watch, Database, DatabaseModel, Input};
4#[cfg(not(target_has_atomic = "64"))]
5use portable_atomic::AtomicU64;
6use std::collections::HashMap;
7use std::path::Path;
8#[cfg(target_has_atomic = "64")]
9use std::sync::atomic::AtomicU64;
10use std::sync::{Arc, RwLock};
11
12/// Builder that allows you to create a [`Database`](crate::Database) instance via [`create`](Self::create) or [`open`](Self::open) etc. and [define](Self::define) models.
13#[derive(Debug)]
14pub struct DatabaseBuilder {
15    cache_size_bytes: Option<usize>,
16    models_builder: HashMap<String, ModelBuilder>,
17}
18
19impl DatabaseBuilder {
20    fn new_rdb_builder(&self) -> redb::Builder {
21        let mut redb_builder = redb::Builder::new();
22        if let Some(cache_size_bytes) = self.cache_size_bytes {
23            redb_builder.set_cache_size(cache_size_bytes);
24        }
25        redb_builder
26    }
27
28    fn init<'a>(&'a self, redb_database: redb::Database) -> Result<Database<'a>> {
29        let mut database = Database {
30            instance: redb_database,
31            primary_table_definitions: HashMap::new(),
32            watchers: Arc::new(RwLock::new(watch::Watchers::new())),
33            watchers_counter_id: AtomicU64::new(0),
34        };
35
36        for (_, model_builder) in &self.models_builder {
37            database.seed_model(&model_builder)?;
38        }
39
40        Ok(database)
41    }
42}
43
44impl DatabaseBuilder {
45    /// Similar to [redb::Builder::new()](https://docs.rs/redb/latest/redb/struct.Builder.html#method.new).
46    pub fn new() -> Self {
47        Self {
48            cache_size_bytes: None,
49            models_builder: HashMap::new(),
50        }
51    }
52
53    /// Similar to [redb::Builder::set_cache_size()](https://docs.rs/redb/latest/redb/struct.Builder.html#method.set_cache_size).
54    pub fn set_cache_size(&mut self, bytes: usize) -> &mut Self {
55        self.cache_size_bytes = Some(bytes);
56        self
57    }
58
59    /// Creates a new `Db` instance using the given path.
60    ///
61    /// Similar to [redb::Builder.create(...)](https://docs.rs/redb/latest/redb/struct.Builder.html#method.create)
62    pub fn create(&self, path: impl AsRef<Path>) -> Result<Database> {
63        let db = self.new_rdb_builder().create(path)?;
64        // Ok(Self::from_redb(db))
65        self.init(db)
66    }
67
68    /// Similar to [redb::Builder::open(...)](https://docs.rs/redb/latest/redb/struct.Builder.html#method.open)
69    pub fn open(&self, path: impl AsRef<Path>) -> Result<Database> {
70        let db = self.new_rdb_builder().open(path)?;
71        // Ok(Self::from_redb(db))
72        self.init(db)
73    }
74
75    /// Creates a new [`Database`](crate::Database) instance in memory.
76    pub fn create_in_memory(&self) -> Result<Database> {
77        let in_memory_backend = redb::backends::InMemoryBackend::new();
78        let db = self.new_rdb_builder();
79        let db = db.create_with_backend(in_memory_backend)?;
80        // Ok(Self::from_redb(db))
81        self.init(db)
82    }
83
84    /// Defines a table using the given model.
85    ///
86    /// Native DB depends of `native_model` to define the model.
87    /// And `native_model` by default uses [`serde`](https://serde.rs/) to serialize and deserialize the data but
88    /// you can use any other serialization library see the documentation of [`native_model`](https://github.com/vincent-herlemont/native_model) for more information.
89    /// So in the example below we import `serde` and we use the `Serialize` and `Deserialize` traits.
90    ///
91    /// # Primary key
92    ///
93    /// The primary key is *strict*, you **must**:
94    /// - define it.
95    /// - define only one.
96    ///
97    /// If the primary key is not defined, the compiler will return an error `Primary key is not set`.
98    ///
99    /// You can define with two ways:
100    /// - `#[primary_key]` on the field
101    /// - `#[native_db(primary_key(<method_name>))]` on any type `enum`, `struct`, `tuple struct` or `unit struct`.
102    ///
103    /// The primary key is **unique**, so you can't have two instances of the model with the same primary key saved in the database.
104    ///
105    /// ## Define a simple model with a primary key
106    /// ```rust
107    /// use native_db::*;
108    /// use native_model::{native_model, Model};
109    /// use serde::{Deserialize, Serialize};
110    ///
111    /// #[derive(Serialize, Deserialize)]
112    /// #[native_model(id=1, version=1)]
113    /// #[native_db]
114    /// struct Data {
115    ///     #[primary_key]
116    ///     id: u64,
117    /// }
118    ///
119    /// fn main() -> Result<(), db_type::Error> {
120    ///     let mut builder = DatabaseBuilder::new();
121    ///     builder.define::<Data>()
122    /// }
123    /// ```
124    /// ## Define a model with a method as primary key
125    /// ```rust
126    /// use native_db::*;
127    /// use native_model::{native_model, Model};
128    /// use serde::{Deserialize, Serialize};
129    ///
130    /// #[derive(Serialize, Deserialize)]
131    /// #[native_model(id=1, version=1)]
132    /// #[native_db(
133    ///     primary_key(custom_id)
134    /// )]
135    /// struct Data(u64);
136    ///
137    /// impl Data {
138    ///   fn custom_id(&self) -> u32 {
139    ///     (self.0 + 1) as u32
140    ///   }
141    /// }
142    ///
143    /// ```
144    ///
145    /// ## Secondary key
146    ///
147    /// The secondary key is *flexible*, you can:
148    /// - define it or not.
149    /// - define one or more.
150    ///
151    /// You can define with two ways:
152    /// - `#[secondary_key]` on the field
153    /// - `#[native_db(secondary_key(<method_name>, <options>))]` on any type `enum`, `struct`, `tuple struct` or `unit struct`.
154    ///
155    /// The secondary key can have two options:
156    /// - [`unique`](#unique) (default: false)
157    /// - [`optional`](#optional) (default: false)
158    ///
159    /// ## Define a model with a secondary key
160    /// ```rust
161    /// use native_db::*;
162    /// use native_model::{native_model, Model};
163    /// use serde::{Deserialize, Serialize};
164    ///
165    /// #[derive(Serialize, Deserialize)]
166    /// #[native_model(id=1, version=1)]
167    /// #[native_db]
168    /// struct Data {
169    ///     #[primary_key]
170    ///     id: u64,
171    ///     #[secondary_key]
172    ///     name: String,
173    /// }
174    /// ```
175    ///
176    /// ## Define a model wit a secondary key optional and unique
177    /// ```rust
178    /// use native_db::*;
179    /// use native_model::{native_model, Model};
180    /// use serde::{Deserialize, Serialize};
181    ///
182    /// #[derive(Serialize, Deserialize)]
183    /// #[native_model(id=1, version=1)]
184    /// #[native_db]
185    /// struct Data {
186    ///     #[primary_key]
187    ///     id: u64,
188    ///     #[secondary_key(unique, optional)]
189    ///     name: Option<String>,
190    /// }
191    /// ```
192    /// - Note: the secondary key can be `unique` **or** `optional` as well.
193    ///
194    /// ## Unique
195    ///
196    /// This means that each instance of the model must have a unique value for the secondary key.
197    /// If the value is not unique, the [`insert`](crate::transaction::RwTransaction::insert) method will return an error.
198    ///
199    /// ## Optional
200    ///
201    /// This means that an instance of the model can have a value for the secondary key or not.
202    /// When`optional` is set the value **must** be an [`Option`](https://doc.rust-lang.org/std/option/enum.Option.html).
203    /// if the value is not an [`Option`](https://doc.rust-lang.org/std/option/enum.Option.html) the compiler will return
204    /// an error `error[E0282]: type annotations needed: cannot infer type`.
205    ///  
206    /// Under the hood, the secondary key is stored in a separate redb table. So if the secondary key is optional,
207    /// the value will be stored in the table only if the value is not `None`.
208    ///
209    /// # Define a model with a secondary key and a custom secondary key optional
210    /// ```rust
211    /// use native_db::*;
212    /// use native_model::{native_model, Model};
213    /// use serde::{Deserialize, Serialize};
214    ///
215    /// #[derive(Serialize, Deserialize)]
216    /// #[native_model(id=1, version=1)]
217    /// #[native_db(
218    ///     secondary_key(custom_name, optional)
219    /// )]
220    /// struct Data {
221    ///     #[primary_key]
222    ///     id: u64,
223    ///     #[secondary_key]
224    ///     name: String,
225    ///     flag: bool,
226    /// }
227    ///
228    /// impl Data {
229    ///     fn custom_name(&self) -> Option<String> {
230    ///         if self.flag {
231    ///             Some(self.name.clone().to_uppercase())
232    ///         } else {
233    ///             None
234    ///         }
235    ///     }
236    /// }
237    /// ```
238    /// # Define multiple models
239    ///
240    /// To define multiple models, you **must** use different `id` for each model. If you use the same `id` for two models,
241    /// the program will panic with the message `The table <table_name> has the same native model version as the table <table_name> and it's not allowed`.
242    ///
243    /// Example:
244    /// ```rust
245    /// use native_db::*;
246    /// use native_model::{native_model, Model};
247    /// use serde::{Deserialize, Serialize};
248    ///
249    /// #[derive(Serialize, Deserialize)]
250    /// #[native_model(id=1, version=1)]
251    /// #[native_db]
252    /// struct Animal {
253    ///     #[primary_key]
254    ///     name: String,
255    /// }
256    ///
257    /// #[derive(Serialize, Deserialize)]
258    /// #[native_model(id=2, version=1)]
259    /// #[native_db]
260    /// struct Vegetable {
261    ///     #[primary_key]
262    ///     name: String,
263    /// }
264    ///
265    /// fn main() -> Result<(), db_type::Error> {
266    ///     let mut builder = DatabaseBuilder::new();
267    ///     builder.define::<Animal>()?;
268    ///     builder.define::<Vegetable>()
269    /// }
270    /// ```
271    pub fn define<T: Input>(&mut self) -> Result<()> {
272        let mut new_model_builder = ModelBuilder {
273            model: T::native_db_model(),
274            native_model_options: NativeModelOptions::default(),
275        };
276
277        new_model_builder.native_model_options.native_model_id = T::native_model_id();
278        new_model_builder.native_model_options.native_model_version = T::native_model_version();
279
280        // Set native model legacy
281        for model in self.models_builder.values_mut() {
282            if model.native_model_options.native_model_version
283                > new_model_builder.native_model_options.native_model_version
284            {
285                model.native_model_options.native_model_legacy = false;
286                new_model_builder.native_model_options.native_model_legacy = true;
287            } else {
288                model.native_model_options.native_model_legacy = true;
289                new_model_builder.native_model_options.native_model_legacy = false;
290            }
291
292            // Panic if native model version are the same
293            if model.native_model_options.native_model_id
294                == new_model_builder.native_model_options.native_model_id
295                && model.native_model_options.native_model_version
296                    == new_model_builder.native_model_options.native_model_version
297            {
298                panic!(
299                    "The table {} has the same native model version as the table {} and it's not allowed",
300                    model.model.primary_key.unique_table_name,
301                    new_model_builder.model.primary_key.unique_table_name,
302                );
303            }
304        }
305
306        self.models_builder.insert(
307            new_model_builder
308                .model
309                .primary_key
310                .unique_table_name
311                .clone(),
312            new_model_builder,
313        );
314
315        // for secondary_key in model.secondary_keys {
316        //     model_builder.secondary_tables.insert(
317        //         secondary_key.clone(),
318        //         redb::TableDefinition::new(&secondary_key.table_name).into(),
319        //     );
320        // }
321        // self.primary_table_definitions
322        //     .insert(model.primary_key.table_name, primary_table_definition);
323
324        Ok(())
325    }
326}
327
328#[derive(Debug)]
329pub(crate) struct ModelBuilder {
330    pub(crate) model: DatabaseModel,
331    pub(crate) native_model_options: NativeModelOptions,
332}