use crate::config::AppConfig;
use crate::db::migrate_db;
use crate::i18n::{tr, tr_with};
use crate::utils::{is_verbose, print_err, print_info, print_ok, write_log};
use rusqlite::{Connection, Result};
use std::path::Path;
use std::fs;
use std::path::PathBuf;
pub fn get_db_path() -> PathBuf {
if let Ok(custom) = std::env::var("LIBRIUS_DB_PATH") {
return PathBuf::from(custom);
}
let base_dir = dirs::data_dir()
.unwrap_or_else(|| std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")));
let librius_dir = base_dir.join("librius");
if !librius_dir.exists() {
let _ = fs::create_dir_all(&librius_dir);
}
librius_dir.join("librius.db")
}
pub fn start_db(config: &AppConfig) -> Result<Connection> {
let db_path = if config.database.trim().is_empty() {
get_db_path()
} else {
Path::new(&config.database).to_path_buf()
};
let db_exists = db_path.exists();
if db_exists {
print_info(
&tr_with(
"db.open.existing",
&[("db_path", &db_path.display().to_string())],
),
is_verbose(),
);
} else {
print_info(
&tr_with(
"db.create.new_db",
&[("db_path", &db_path.display().to_string())],
),
is_verbose(),
);
}
let conn = Connection::open(&db_path)?;
conn.execute(
"CREATE TABLE IF NOT EXISTS log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
date TEXT NOT NULL,
operation TEXT NOT NULL,
target TEXT DEFAULT '',
message TEXT NOT NULL
);",
[],
)?;
if !db_exists {
print_info(&tr("db.schema.initializing"), is_verbose());
if let Err(e) = ensure_schema(&conn) {
print_err(&tr_with(
"db.schema.init_failed",
&[("error", &e.to_string())],
));
let _ = write_log(&conn, "DB_INIT_FAIL", "DB", &e.to_string());
return Err(e);
}
print_ok(&tr("db.schema.created"), is_verbose());
let _ = write_log(&conn, "DB_INIT_OK", "DB", &tr("log.db.schema.init"));
}
match migrate_db::run_migrations(&conn) {
Err(e) => {
print_err(&tr_with("db.migrate.failed", &[("error", &e.to_string())]));
let _ = write_log(&conn, "DB_MIGRATION_FAIL", "DB", &e.to_string());
}
Ok(result) => match result {
migrate_db::MigrationResult::Applied(patches) => {
print_ok(&tr("db.migrate.applied"), is_verbose());
let msg = &tr_with("log.db.patch_applied", &[("patches", &patches.join(", "))]);
let _ = write_log(&conn, "DB_MIGRATION_OK", "DB", msg);
}
migrate_db::MigrationResult::None => {
print_ok(&tr("db.schema.already_update"), is_verbose());
}
},
}
Ok(conn)
}
pub fn init_db(config: &AppConfig) -> Result<Connection> {
start_db(config)
}
pub fn ensure_schema(conn: &Connection) -> Result<()> {
conn.execute_batch(
"CREATE TABLE IF NOT EXISTS books (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
author TEXT NOT NULL,
editor TEXT NOT NULL,
year INTEGER NOT NULL,
isbn TEXT NOT NULL,
language TEXT,
pages INTEGER,
genre TEXT,
summary TEXT,
room TEXT,
shelf TEXT,
row TEXT,
position TEXT,
added_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);",
)?;
Ok(())
}