| |
Auto,
|
| |
}
|
| |
|
| + |
/// Database configuration.
|
| + |
#[derive(Debug, Default, Copy, Clone, Serialize, Deserialize)]
|
| + |
#[serde(rename_all = "camelCase")]
|
| + |
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
| + |
pub struct DatabaseConfig {
|
| + |
/// SQLite configuration.
|
| + |
pub sqlite: SqliteConfig,
|
| + |
}
|
| + |
|
| + |
/// SQLite-specific database configuration.
|
| + |
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
|
| + |
#[serde(rename_all = "camelCase")]
|
| + |
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
| + |
pub struct SqliteConfig {
|
| + |
/// Journal mode. WAL is recommended for concurrent access.
|
| + |
#[serde(default)]
|
| + |
pub journal_mode: node::db::JournalMode,
|
| + |
/// Synchronous flag. Controls how often SQLite syncs to disk.
|
| + |
#[serde(default)]
|
| + |
pub synchronous: node::db::Synchronous,
|
| + |
}
|
| + |
|
| + |
impl Default for SqliteConfig {
|
| + |
fn default() -> Self {
|
| + |
Self {
|
| + |
journal_mode: node::db::JournalMode::WAL,
|
| + |
synchronous: node::db::Synchronous::NORMAL,
|
| + |
}
|
| + |
}
|
| + |
}
|
| + |
|
| |
/// Proxy configuration.
|
| |
#[derive(Debug, Clone, Serialize, Deserialize)]
|
| |
#[serde(rename_all = "camelCase", tag = "mode")]
|
| |
.unwrap()
|
| |
);
|
| |
}
|
| + |
|
| + |
#[test]
|
| + |
fn database_config_valid_combinations() {
|
| + |
use super::{node, Config};
|
| + |
|
| + |
let cases = [
|
| + |
// (journal_mode, synchronous, expected_journal, expected_sync, description)
|
| + |
(
|
| + |
None,
|
| + |
None,
|
| + |
node::db::JournalMode::WAL,
|
| + |
node::db::Synchronous::NORMAL,
|
| + |
"defaults",
|
| + |
),
|
| + |
(
|
| + |
Some("wal"),
|
| + |
Some("NORMAL"),
|
| + |
node::db::JournalMode::WAL,
|
| + |
node::db::Synchronous::NORMAL,
|
| + |
"WAL+NORMAL (recommended)",
|
| + |
),
|
| + |
(
|
| + |
Some("wal"),
|
| + |
Some("FULL"),
|
| + |
node::db::JournalMode::WAL,
|
| + |
node::db::Synchronous::FULL,
|
| + |
"WAL+FULL (max durability)",
|
| + |
),
|
| + |
(
|
| + |
Some("wal"),
|
| + |
Some("OFF"),
|
| + |
node::db::JournalMode::WAL,
|
| + |
node::db::Synchronous::OFF,
|
| + |
"WAL+OFF (max performance)",
|
| + |
),
|
| + |
(
|
| + |
Some("rollback"),
|
| + |
Some("FULL"),
|
| + |
node::db::JournalMode::DELETE,
|
| + |
node::db::Synchronous::FULL,
|
| + |
"DELETE+FULL",
|
| + |
),
|
| + |
(
|
| + |
Some("rollback"),
|
| + |
Some("EXTRA"),
|
| + |
node::db::JournalMode::DELETE,
|
| + |
node::db::Synchronous::EXTRA,
|
| + |
"DELETE+EXTRA (max durability)",
|
| + |
),
|
| + |
(
|
| + |
Some("WAL"),
|
| + |
Some("NORMAL"),
|
| + |
node::db::JournalMode::WAL,
|
| + |
node::db::Synchronous::NORMAL,
|
| + |
"WAL uppercase",
|
| + |
),
|
| + |
(
|
| + |
Some("DELETE"),
|
| + |
Some("NORMAL"),
|
| + |
node::db::JournalMode::DELETE,
|
| + |
node::db::Synchronous::NORMAL,
|
| + |
"DELETE uppercase",
|
| + |
),
|
| + |
];
|
| + |
|
| + |
for (journal_mode, synchronous, expected_journal, expected_sync, description) in cases {
|
| + |
let mut json_value = json!({"alias": "example"});
|
| + |
|
| + |
if let (Some(jm), Some(sync)) = (journal_mode, synchronous) {
|
| + |
json_value["database"] = json!({
|
| + |
"sqlite": {
|
| + |
"journalMode": jm,
|
| + |
"synchronous": sync
|
| + |
}
|
| + |
});
|
| + |
}
|
| + |
|
| + |
let config: Config = serde_json::from_value(json_value)
|
| + |
.unwrap_or_else(|e| panic!("Failed to parse config for {description}: {e}"));
|
| + |
|
| + |
assert_eq!(
|
| + |
config.database.sqlite.journal_mode, expected_journal,
|
| + |
"journal_mode mismatch for {description}"
|
| + |
);
|
| + |
assert_eq!(
|
| + |
config.database.sqlite.synchronous, expected_sync,
|
| + |
"synchronous mismatch for {description}"
|
| + |
);
|
| + |
}
|
| + |
}
|
| + |
|
| + |
#[test]
|
| + |
fn database_config_rejects_invalid_values() {
|
| + |
use super::Config;
|
| + |
|
| + |
let invalid_cases = [
|
| + |
(Some("INVALID"), Some("NORMAL"), "invalid journal_mode"),
|
| + |
(Some("WAL"), Some("INVALID"), "invalid synchronous"),
|
| + |
(Some("WAL"), Some("normal"), "lowercase synchronous"),
|
| + |
(Some("Wal"), Some("NORMAL"), "mixed case journal_mode"),
|
| + |
];
|
| + |
|
| + |
for (journal_mode, synchronous, description) in invalid_cases {
|
| + |
let mut json_value = json!({"alias": "example", "database": {"sqlite": {}}});
|
| + |
if let Some(jm) = journal_mode {
|
| + |
json_value["database"]["sqlite"]["journalMode"] = json!(jm);
|
| + |
}
|
| + |
if let Some(sync) = synchronous {
|
| + |
json_value["database"]["sqlite"]["synchronous"] = json!(sync);
|
| + |
}
|
| + |
|
| + |
assert!(
|
| + |
serde_json::from_value::<Config>(json_value).is_err(),
|
| + |
"Should reject {description}"
|
| + |
);
|
| + |
}
|
| + |
}
|
| |
}
|