1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use crate::database_instance::DatabaseInstance;
use crate::db_type::{Error, Result};
use crate::table_definition::NativeModelOptions;
use crate::Models;
use crate::{upgrade, watch, Database, Model};
use std::collections::HashMap;
use std::path::Path;
use std::sync::atomic::AtomicU64;
use std::sync::{Arc, RwLock};

#[derive(Debug)]
pub(crate) struct Configuration {
    pub(crate) cache_size_bytes: Option<usize>,
}

impl Configuration {
    pub(crate) fn new_rdb_builder(&self) -> redb::Builder {
        let mut redb_builder = redb::Builder::new();
        if let Some(cache_size_bytes) = self.cache_size_bytes {
            redb_builder.set_cache_size(cache_size_bytes);
        }
        redb_builder
    }
}

#[cfg(feature = "redb1")]
impl Configuration {
    pub(crate) fn redb1_new_rdb1_builder(&self) -> redb1::Builder {
        let mut redb_builder = redb1::Builder::new();
        if let Some(cache_size_bytes) = self.cache_size_bytes {
            redb_builder.set_cache_size(cache_size_bytes);
        }
        redb_builder
    }
}
/// Builder that allows you to create a [`Database`](crate::Database) instance via [`create`](Self::create) or [`open`](Self::open) etc.
#[derive(Debug)]
pub struct Builder {
    database_configuration: Configuration,
}

impl Builder {
    fn init<'a>(
        &self,
        database_instance: DatabaseInstance,
        models: &'a Models,
    ) -> Result<Database<'a>> {
        let mut database = Database {
            instance: database_instance,
            primary_table_definitions: HashMap::new(),
            watchers: Arc::new(RwLock::new(watch::Watchers::new())),
            watchers_counter_id: AtomicU64::new(0),
        };

        for (_, model_builder) in models.models_builder.iter() {
            database.seed_model(&model_builder)?;
        }

        Ok(database)
    }
}

impl Builder {
    /// Construct a new [Builder] with sensible defaults.
    pub fn new() -> Self {
        Self {
            database_configuration: Configuration {
                cache_size_bytes: None,
            },
        }
    }

    /// Similar to [redb::Builder::set_cache_size()](https://docs.rs/redb/latest/redb/struct.Builder.html#method.set_cache_size).
    pub fn set_cache_size(&mut self, bytes: usize) -> &mut Self {
        self.database_configuration.cache_size_bytes = Some(bytes);
        self
    }

    /// Creates a new `Db` instance using the given path.
    ///
    /// Similar to [redb::Builder.create(...)](https://docs.rs/redb/latest/redb/struct.Builder.html#method.create)
    pub fn create<'a>(&self, models: &'a Models, path: impl AsRef<Path>) -> Result<Database<'a>> {
        let builder = self.database_configuration.new_rdb_builder();
        let database_instance = DatabaseInstance::create_on_disk(builder, path)?;
        self.init(database_instance, models)
    }

    /// Similar to [redb::Builder::open(...)](https://docs.rs/redb/latest/redb/struct.Builder.html#method.open)
    /// But it also upgrades the database if needed if
    pub fn open<'a>(&self, models: &'a Models, path: impl AsRef<Path>) -> Result<Database<'a>> {
        let builder = self.database_configuration.new_rdb_builder();
        let database_instance = match DatabaseInstance::open_on_disk(builder, &path) {
            Err(Error::RedbDatabaseError(redb::DatabaseError::UpgradeRequired(_))) => {
                upgrade::upgrade(&self.database_configuration, &path, &models.models_builder)
            }
            Err(error) => return Err(error),
            Ok(database_instance) => Ok(database_instance),
        }?;
        self.init(database_instance, models)
    }

    /// Creates a new [`Database`](crate::Database) instance in memory.
    pub fn create_in_memory<'a>(&self, models: &'a Models) -> Result<Database<'a>> {
        let builder = self.database_configuration.new_rdb_builder();
        let database_instance = DatabaseInstance::create_in_memory(builder)?;
        self.init(database_instance, models)
    }
}

#[derive(Debug)]
pub(crate) struct ModelBuilder {
    pub(crate) model: Model,
    pub(crate) native_model_options: NativeModelOptions,
}