hyper_scripter/
db.rs

1use crate::error::Result;
2use crate::util::read_file;
3use sqlx::{
4    sqlite::{SqliteConnectOptions, SqliteJournalMode},
5    SqlitePool,
6};
7use std::path::{Path, PathBuf};
8
9pub fn get_file() -> PathBuf {
10    crate::path::get_home().join(".script_info.db")
11}
12
13fn get_sql_file() -> PathBuf {
14    crate::path::get_home().join(".script_info.sql")
15}
16
17/// 有可能改變 need_journal 的值。
18/// 若為初始化,或資料庫已被 journal 鎖住,則不論如何都使用 journal
19pub async fn get_pool(need_journal: &mut bool) -> Result<(SqlitePool, bool)> {
20    let file = get_file();
21    if !file.exists() {
22        *need_journal = true;
23        let pool = do_migrate_may_force_pre_sql(file, true).await?;
24        return Ok((pool, true));
25    }
26
27    let mut opt = SqliteConnectOptions::new().filename(&file);
28    if !*need_journal {
29        opt = opt.journal_mode(SqliteJournalMode::Off);
30    }
31    let res = SqlitePool::connect_with(opt).await;
32    let pool = match res {
33        Err(err) => {
34            // 通常是有其它程序用 journal mode 鎖住資料庫,例如正在編輯另一個腳本
35            log::warn!("資料庫錯誤 {},嘗試用 journal 再開一次", err);
36            *need_journal = true;
37            let opt = SqliteConnectOptions::new().filename(&file);
38            SqlitePool::connect_with(opt).await?
39        }
40        Ok(pool) => pool,
41    };
42    Ok((pool, false))
43}
44
45async fn do_migrate_may_force_pre_sql(
46    file: impl AsRef<Path>,
47    force_pre_sql: bool,
48) -> Result<SqlitePool> {
49    let pre_sql = if !force_pre_sql && file.as_ref().exists() {
50        None
51    } else {
52        let sql_file = get_sql_file();
53        if sql_file.exists() {
54            Some(read_file(&sql_file)?)
55        } else {
56            None
57        }
58    };
59    let pool = crate::migration::do_migrate_with_pre_sql(file, pre_sql.as_deref()).await?;
60    Ok(pool)
61}
62
63pub async fn do_migrate(file: impl AsRef<Path>) -> Result<SqlitePool> {
64    do_migrate_may_force_pre_sql(file, false).await
65}