|
@@ -2,13 +2,42 @@ mod commands;
|
|
|
mod models;
|
|
|
mod service;
|
|
|
|
|
|
-use std::vec;
|
|
|
+use sea_orm::{ConnectionTrait, DatabaseConnection, Statement, TransactionTrait};
|
|
|
+use std::fs::{self, File};
|
|
|
+use std::sync::Arc;
|
|
|
+use tauri::{AppHandle, Manager, path::BaseDirectory};
|
|
|
|
|
|
-use tauri::{AppHandle, Manager};
|
|
|
+// 添加 AppState 结构体
|
|
|
+#[derive(Default)]
|
|
|
+pub struct AppState {
|
|
|
+ pub conn: Arc<DatabaseConnection>,
|
|
|
+}
|
|
|
|
|
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
|
|
pub fn run() {
|
|
|
tauri::Builder::default()
|
|
|
+ .setup(|app| {
|
|
|
+ tauri::async_runtime::block_on(async {
|
|
|
+ let app_dir = app.handle().path().app_data_dir()?;
|
|
|
+ std::fs::create_dir_all(&app_dir)?;
|
|
|
+ let db_path = app_dir.join("store.sqlite");
|
|
|
+ if !db_path.exists() {
|
|
|
+ File::create(&db_path)?;
|
|
|
+ }
|
|
|
+ let db_url = format!("sqlite:{}", db_path.display());
|
|
|
+ let conn = sea_orm::Database::connect(&db_url)
|
|
|
+ .await
|
|
|
+ .map_err(|e| anyhow::anyhow!("Database connection error: {}", e))?;
|
|
|
+ conn.execute_unprepared("PRAGMA journal_mode=WAL;")
|
|
|
+ .await
|
|
|
+ .map_err(|e| anyhow::anyhow!("Failed to set WAL mode: {}", e))?;
|
|
|
+ migration_db(app, &conn).await?;
|
|
|
+ app.manage(AppState {
|
|
|
+ conn: Arc::new(conn),
|
|
|
+ });
|
|
|
+ Ok(())
|
|
|
+ })
|
|
|
+ })
|
|
|
.plugin(tauri_plugin_os::init())
|
|
|
.plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| {
|
|
|
let _ = show_window(app);
|
|
@@ -31,3 +60,50 @@ fn show_window(app: &AppHandle) {
|
|
|
.set_focus()
|
|
|
.expect("Can't Bring Window to Focus");
|
|
|
}
|
|
|
+
|
|
|
+async fn migration_db(app: &tauri::App, conn: &DatabaseConnection) -> anyhow::Result<()> {
|
|
|
+ let sql_path = app
|
|
|
+ .path()
|
|
|
+ .resolve("resources/init.sql", BaseDirectory::Resource)?;
|
|
|
+ conn.execute(Statement::from_string(
|
|
|
+ conn.get_database_backend(),
|
|
|
+ "CREATE TABLE IF NOT EXISTS seaql_migrations (
|
|
|
+ version VARCHAR(255) PRIMARY KEY,
|
|
|
+ applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
|
+ )"
|
|
|
+ .to_owned(),
|
|
|
+ ))
|
|
|
+ .await?;
|
|
|
+ let applied: Vec<String> = conn
|
|
|
+ .query_all(Statement::from_string(
|
|
|
+ conn.get_database_backend(),
|
|
|
+ "SELECT version FROM seaql_migrations".to_owned(),
|
|
|
+ ))
|
|
|
+ .await?
|
|
|
+ .into_iter()
|
|
|
+ .filter_map(|row| row.try_get("", "version").ok())
|
|
|
+ .collect();
|
|
|
+
|
|
|
+ if let Some(sql_path_stem) = sql_path.file_stem() {
|
|
|
+ if let Some(version) = sql_path_stem.to_str() {
|
|
|
+ if !applied.contains(&version.to_string()) {
|
|
|
+ let sql_str = fs::read_to_string(&sql_path)?;
|
|
|
+ let tx = conn.begin().await?;
|
|
|
+ tx.execute(Statement::from_string(conn.get_database_backend(), sql_str))
|
|
|
+ .await?;
|
|
|
+ tx.execute(Statement::from_string(
|
|
|
+ conn.get_database_backend(),
|
|
|
+ format!(
|
|
|
+ "INSERT INTO seaql_migrations (version) VALUES ('{}')",
|
|
|
+ version
|
|
|
+ ),
|
|
|
+ ))
|
|
|
+ .await?;
|
|
|
+ tx.commit().await?;
|
|
|
+ println!("✅ Applied migration: {}", version);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Ok(())
|
|
|
+}
|