mtotp_lib/database/
mod.rs

1use std::path::{Path, PathBuf};
2use once_cell::sync::OnceCell;
3use sea_orm::prelude::DatabaseConnection;
4use sea_orm::{ConnectionTrait, EntityTrait, Schema, Statement};
5use std::time::Duration;
6use tokio::sync::Mutex;
7
8pub mod registered;
9
10static FOLDER: OnceCell<String> = OnceCell::new();
11
12static CONNECT: OnceCell<Mutex<DatabaseConnection>> = OnceCell::new();
13
14pub async fn init(folder: String) {
15    FOLDER.set(folder).unwrap();
16    init_database().await;
17}
18
19pub(crate) async fn init_database() {
20    let folder = FOLDER.get().unwrap();
21    create_dir_if_not_exists(folder);
22    CONNECT.set(Mutex::new(
23        connect_db(join_paths(vec![folder.as_str(), "mtotp.db"]).as_str()).await
24    )).unwrap();
25    registered::init().await;
26}
27
28pub(crate) async fn connect_db(path: &str) -> DatabaseConnection {
29    let url = format!("sqlite:{}?mode=rwc", path);
30    let mut opt = sea_orm::ConnectOptions::new(url);
31    opt.max_connections(20)
32        .min_connections(5)
33        .connect_timeout(Duration::from_secs(8))
34        .idle_timeout(Duration::from_secs(8))
35        .sqlx_logging(true);
36    sea_orm::Database::connect(opt).await.unwrap()
37}
38
39pub(crate) async fn create_table_if_not_exists<E>(db: &DatabaseConnection, entity: E)
40    where
41        E: EntityTrait,
42{
43    if !has_table(db, entity.table_name()).await {
44        create_table(db, entity).await;
45    };
46}
47
48pub(crate) async fn has_table(db: &DatabaseConnection, table_name: &str) -> bool {
49    let stmt = Statement::from_string(
50        db.get_database_backend(),
51        format!(
52            "SELECT COUNT(*) AS c FROM sqlite_master WHERE type='table' AND name='{}';",
53            table_name,
54        ),
55    );
56    let rsp = db.query_one(stmt).await.unwrap().unwrap();
57    let count: i32 = rsp.try_get("", "c").unwrap();
58    count > 0
59}
60
61pub(crate) async fn create_table<E>(db: &DatabaseConnection, entity: E)
62    where
63        E: EntityTrait,
64{
65    let builder = db.get_database_backend();
66    let schema = Schema::new(builder);
67    let stmt = &schema.create_table_from_entity(entity);
68    let stmt = builder.build(stmt);
69    db.execute(stmt).await.unwrap();
70}
71
72pub(crate) async fn index_exists(
73    db: &DatabaseConnection,
74    table_name: &str,
75    index_name: &str,
76) -> bool {
77    let stmt = Statement::from_string(
78        db.get_database_backend(),
79        format!(
80            "select COUNT(*) AS c from sqlite_master where type='index' AND tbl_name='{}' AND name='{}';",
81            table_name, index_name,
82        ),
83    );
84    db.query_one(stmt)
85        .await
86        .unwrap()
87        .unwrap()
88        .try_get::<i32>("", "c")
89        .unwrap()
90        > 0
91}
92
93pub(crate) async fn create_index_a(
94    db: &DatabaseConnection,
95    table_name: &str,
96    columns: Vec<&str>,
97    index_name: &str,
98    uk: bool,
99) {
100    let stmt = Statement::from_string(
101        db.get_database_backend(),
102        format!(
103            "CREATE {} INDEX {} ON {}({});",
104            if uk { "UNIQUE" } else { "" },
105            index_name,
106            table_name,
107            columns.join(","),
108        ),
109    );
110    db.execute(stmt).await.unwrap();
111}
112
113#[allow(dead_code)]
114pub(crate) async fn create_index(
115    db: &DatabaseConnection,
116    table_name: &str,
117    columns: Vec<&str>,
118    index_name: &str,
119) {
120    create_index_a(db, table_name, columns, index_name, false).await
121}
122
123pub fn join_paths<P: AsRef<Path>>(paths: Vec<P>) -> String {
124    match paths.len() {
125        0 => String::default(),
126        _ => {
127            let mut path: PathBuf = PathBuf::new();
128            for x in paths {
129                path = path.join(x);
130            }
131            return path.to_str().unwrap().to_string();
132        }
133    }
134}
135
136pub(crate) fn create_dir_if_not_exists(path: &String) {
137    if !Path::new(path).exists() {
138        std::fs::create_dir_all(path).unwrap();
139    }
140}