2026-08-24 01:22:00 +03:00
|
|
|
use crate::fs::*;
|
2026-08-25 12:04:07 +03:00
|
|
|
use rusqlite::Connection;
|
2026-08-31 11:46:35 +03:00
|
|
|
use std::ops::{Deref, DerefMut};
|
2026-09-09 10:19:44 +03:00
|
|
|
use log::error;
|
2026-06-15 17:06:02 +03:00
|
|
|
|
|
|
|
|
pub fn create_db() {
|
2026-08-24 01:22:00 +03:00
|
|
|
let db_file = db_path();
|
2026-06-15 17:06:02 +03:00
|
|
|
if !db_file.exists() {
|
2026-08-24 23:10:23 +03:00
|
|
|
std::fs::File::create(&db_file).expect("Database file creation failed");
|
2026-08-24 23:42:58 +03:00
|
|
|
let connection = Connection::open(&db_file).expect("Connection open failed");
|
2026-08-25 12:04:07 +03:00
|
|
|
connection
|
|
|
|
|
.execute("PRAGMA foreign_keys = ON;", [])
|
|
|
|
|
.expect("Failed to set PRAGMA");
|
2026-06-15 17:06:02 +03:00
|
|
|
|
|
|
|
|
create_tables(&connection);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn create_tables(conn: &Connection) {
|
2026-08-24 23:42:58 +03:00
|
|
|
make_card_set(conn).expect("Failed to init table");
|
|
|
|
|
make_settings(conn).expect("Failed to init table");
|
|
|
|
|
make_word_group(conn).expect("Failed to init table");
|
|
|
|
|
make_words(conn).expect("Failed to init table");
|
|
|
|
|
make_card_stats(conn).expect("Failed to init table");
|
2026-08-28 17:44:14 +03:00
|
|
|
make_history(conn).expect("Failed to init table");
|
2026-08-31 11:23:41 +03:00
|
|
|
make_custom_fields(conn).expect("Failed to init table");
|
2026-06-15 17:06:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn make_settings(conn: &Connection) -> Result<(), rusqlite::Error> {
|
|
|
|
|
let query = include_str!("../../sql/settings.sql");
|
|
|
|
|
conn.execute(query, ())?;
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn make_card_set(conn: &Connection) -> Result<(), rusqlite::Error> {
|
2026-08-29 21:31:54 +03:00
|
|
|
let query = include_str!("../../sql/decks.sql");
|
2026-06-15 17:06:02 +03:00
|
|
|
conn.execute(query, ())?;
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn make_word_group(conn: &Connection) -> Result<(), rusqlite::Error> {
|
2026-08-29 21:31:54 +03:00
|
|
|
let query = include_str!("../../sql/word_groups.sql");
|
2026-06-15 17:06:02 +03:00
|
|
|
conn.execute(query, ())?;
|
2026-08-29 21:31:54 +03:00
|
|
|
conn.execute("insert into word_groups (name) values (\"Слова\");", ())?;
|
2026-06-15 17:06:02 +03:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
fn make_words(conn: &Connection) -> Result<(), rusqlite::Error> {
|
|
|
|
|
let query = include_str!("../../sql/words.sql");
|
|
|
|
|
conn.execute(query, ())?;
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
fn make_card_stats(conn: &Connection) -> Result<(), rusqlite::Error> {
|
2026-08-29 21:31:54 +03:00
|
|
|
let query = include_str!("../../sql/states.sql");
|
2026-06-15 17:06:02 +03:00
|
|
|
conn.execute(query, ())?;
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
2026-08-13 09:06:22 +03:00
|
|
|
|
2026-08-28 17:44:14 +03:00
|
|
|
fn make_history(conn: &Connection) -> Result<(), rusqlite::Error> {
|
|
|
|
|
let query = include_str!("../../sql/history.sql");
|
|
|
|
|
conn.execute(query, ())?;
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-31 11:23:41 +03:00
|
|
|
fn make_custom_fields(conn: &Connection) -> Result<(), rusqlite::Error> {
|
|
|
|
|
let query = include_str!("../../sql/custom_fields.sql");
|
|
|
|
|
conn.execute(query, ())?;
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-13 09:06:22 +03:00
|
|
|
pub fn default_connection() -> Connection {
|
2026-08-24 01:22:00 +03:00
|
|
|
let db_file = db_path();
|
2026-08-24 23:42:58 +03:00
|
|
|
let connection = Connection::open(db_file).expect("Failed to open database");
|
2026-08-25 12:04:07 +03:00
|
|
|
connection
|
|
|
|
|
.execute("PRAGMA foreign_keys = ON;", [])
|
|
|
|
|
.expect("Failed to set PRAGMA");
|
2026-08-13 09:06:22 +03:00
|
|
|
connection
|
2026-08-30 22:15:03 +03:00
|
|
|
.query_one("PRAGMA journal_mode = WAL;", [], |row| {
|
|
|
|
|
println!("{:?}", row);
|
|
|
|
|
Ok(())
|
|
|
|
|
})
|
|
|
|
|
.unwrap_or_else(|e| {
|
|
|
|
|
println!("{}", e);
|
|
|
|
|
});
|
2026-08-30 20:32:16 +03:00
|
|
|
connection
|
|
|
|
|
.execute("PRAGMA synchronous = NORMAL;", [])
|
|
|
|
|
.expect("Failed to set PRAGMA");
|
|
|
|
|
connection
|
2026-08-15 21:32:24 +03:00
|
|
|
}
|
2026-08-31 11:46:35 +03:00
|
|
|
|
|
|
|
|
pub struct SqliteConnection(Option<Connection>);
|
|
|
|
|
impl Deref for SqliteConnection {
|
|
|
|
|
type Target = Connection;
|
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
|
self.0.as_ref().unwrap()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl DerefMut for SqliteConnection {
|
|
|
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
|
|
|
self.0.as_mut().unwrap()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for SqliteConnection {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
SqliteConnection(Some(default_connection()))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl SqliteConnection {
|
|
|
|
|
pub fn finish(&mut self) {
|
2026-09-09 10:19:44 +03:00
|
|
|
let connection = self.0.take().unwrap();
|
|
|
|
|
connection
|
|
|
|
|
.query_row("PRAGMA wal_checkpoint(TRUNCATE)", [], |_| Ok(()))
|
|
|
|
|
.unwrap_or_else(|e| {
|
|
|
|
|
error!("Ошибка при checkpoint WAL: {e}");
|
|
|
|
|
});
|
|
|
|
|
connection
|
2026-09-09 10:33:21 +03:00
|
|
|
.execute("PRAGMA optimize", [])
|
2026-09-09 10:19:44 +03:00
|
|
|
.unwrap_or_else(|e| {
|
|
|
|
|
error!("Ошибка при оптимизации БД: {e}");
|
2026-09-09 10:33:21 +03:00
|
|
|
0
|
2026-09-09 10:19:44 +03:00
|
|
|
});
|
|
|
|
|
|
2026-08-31 11:46:35 +03:00
|
|
|
self.0 = None;
|
|
|
|
|
}
|
2026-09-06 23:55:50 +03:00
|
|
|
pub fn restart(&mut self) {
|
|
|
|
|
self.0 = Some(default_connection());
|
|
|
|
|
}
|
2026-08-31 11:46:35 +03:00
|
|
|
}
|
2026-09-09 10:33:21 +03:00
|
|
|
|
|
|
|
|
impl Drop for SqliteConnection {
|
|
|
|
|
|
|
|
|
|
fn drop(&mut self) { self.finish(); }
|
|
|
|
|
}
|