2026-01-21 12:34:59 +01:00
|
|
|
// Copyright (C) 2024-2026 Whiterun LLC
|
2024-03-04 16:40:50 +01:00
|
|
|
//
|
|
|
|
|
// This software is licensed under the GNU Affero General Public License (AGPL), version 3.0 or later.
|
|
|
|
|
// A copy of the license can be found in the LICENSE file or at https://www.gnu.org/licenses/agpl-3.0.html
|
|
|
|
|
|
2025-08-15 18:07:15 +02:00
|
|
|
use anyhow::{bail, Result};
|
2024-03-04 16:40:50 +01:00
|
|
|
use rusqlite::{params, Connection};
|
|
|
|
|
|
2025-08-18 22:30:10 +02:00
|
|
|
pub const DB_VERSION: u32 = 4;
|
2025-08-15 18:07:15 +02:00
|
|
|
const DB_VERSION_KEY: &str = "db_version";
|
|
|
|
|
|
|
|
|
|
/// Create the config table
|
|
|
|
|
pub fn create_table(conn: &Connection) {
|
|
|
|
|
conn.execute(
|
|
|
|
|
"CREATE TABLE config (
|
|
|
|
|
key TEXT PRIMARY KEY,
|
|
|
|
|
value TEXT
|
|
|
|
|
)",
|
|
|
|
|
[],
|
|
|
|
|
)
|
|
|
|
|
.expect("failed to create config table");
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-04 16:40:50 +01:00
|
|
|
/// Add or update config entry
|
|
|
|
|
pub fn config_set(conn: &Connection, key: &str, value: &str) {
|
|
|
|
|
let mut stmt = conn
|
|
|
|
|
.prepare("INSERT OR REPLACE INTO config (key, value) VALUES (?, ?)")
|
|
|
|
|
.unwrap();
|
|
|
|
|
stmt.execute(params![key, value]).unwrap();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get config entry
|
|
|
|
|
pub fn config_get(conn: &Connection, key: &str) -> Result<Option<String>> {
|
|
|
|
|
let mut stmt = conn.prepare("SELECT value FROM config WHERE key = ?")?;
|
|
|
|
|
|
|
|
|
|
let mut row = stmt.query([key])?;
|
2024-05-09 11:25:27 +02:00
|
|
|
if let Some(r) = row.next()? {
|
|
|
|
|
Ok(r.get(0)?)
|
|
|
|
|
} else {
|
|
|
|
|
Ok(None)
|
|
|
|
|
}
|
2024-03-04 16:40:50 +01:00
|
|
|
}
|
2025-08-15 18:07:15 +02:00
|
|
|
|
|
|
|
|
/// Check database version and panic if it doesn't match expected version
|
|
|
|
|
pub fn check_db_version(conn: &Connection) -> Result<()> {
|
|
|
|
|
let version_str = config_get(conn, DB_VERSION_KEY)?;
|
|
|
|
|
|
|
|
|
|
match version_str {
|
|
|
|
|
Some(version_str) => {
|
|
|
|
|
let version: u32 = version_str.parse().unwrap_or(0);
|
|
|
|
|
if version != DB_VERSION {
|
|
|
|
|
bail!(
|
|
|
|
|
"Database version mismatch. Expected {}, got {}",
|
|
|
|
|
DB_VERSION,
|
|
|
|
|
version
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
None => {
|
|
|
|
|
bail!(
|
|
|
|
|
"Database version not found. Expected version {}",
|
|
|
|
|
DB_VERSION
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Set database version
|
|
|
|
|
pub fn set_db_version(conn: &Connection) {
|
|
|
|
|
config_set(conn, DB_VERSION_KEY, &DB_VERSION.to_string());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
|
|
|
|
use rusqlite::Connection;
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_db_version_functionality() {
|
|
|
|
|
// Create a new in-memory database
|
|
|
|
|
let conn = Connection::open_in_memory().unwrap();
|
|
|
|
|
|
|
|
|
|
// Create the config table using the shared function
|
|
|
|
|
create_table(&conn);
|
|
|
|
|
|
|
|
|
|
// Test setting the version
|
|
|
|
|
set_db_version(&conn);
|
|
|
|
|
|
|
|
|
|
// Test getting the version
|
|
|
|
|
let version_str = config_get(&conn, DB_VERSION_KEY).unwrap().unwrap();
|
|
|
|
|
let version: u32 = version_str.parse().unwrap();
|
|
|
|
|
assert_eq!(version, DB_VERSION);
|
|
|
|
|
|
|
|
|
|
// Test version check should pass
|
|
|
|
|
check_db_version(&conn).unwrap();
|
|
|
|
|
|
|
|
|
|
// Test with wrong version
|
|
|
|
|
config_set(&conn, DB_VERSION_KEY, "1");
|
|
|
|
|
let result = check_db_version(&conn);
|
|
|
|
|
assert!(result.is_err());
|
|
|
|
|
assert!(result
|
|
|
|
|
.unwrap_err()
|
|
|
|
|
.to_string()
|
|
|
|
|
.contains("Database version mismatch"));
|
|
|
|
|
|
|
|
|
|
// Test with missing version
|
|
|
|
|
conn.execute("DELETE FROM config WHERE key = ?", [DB_VERSION_KEY])
|
|
|
|
|
.unwrap();
|
|
|
|
|
let result = check_db_version(&conn);
|
|
|
|
|
assert!(result.is_err());
|
|
|
|
|
assert!(result
|
|
|
|
|
.unwrap_err()
|
|
|
|
|
.to_string()
|
|
|
|
|
.contains("Database version not found"));
|
|
|
|
|
}
|
|
|
|
|
}
|