use super::sqlite_ext::*;
const DEFAULT_JOURNAL_MODE: JournalMode = JournalMode::WAL;
const DEFAULT_SYNCHRONOUS: Synchronous = Synchronous::NORMAL;
/// Database configuration.
#[derive(Debug, Default, Copy, Clone, PartialEq, ::serde::Serialize, ::serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Config {
/// SQLite configuration.
#[serde(skip_serializing_if = "crate::serde_ext::is_default")]
pub sqlite: SqliteConfig,
}
/// SQLite database configuration.
#[derive(Debug, Default, Copy, Clone, PartialEq, ::serde::Serialize, ::serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct SqliteConfig {
#[serde(default, skip_serializing_if = "crate::serde_ext::is_default")]
pub pragma: Pragma,
}
/// Global SQLite pragma statements to make in order to configure SQLite itself,
/// see <https://sqlite.org/pragma.html>.
#[derive(Debug, Copy, Clone, PartialEq, ::serde::Serialize, ::serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Pragma {
#[serde(
default = "serde::journal_mode::default",
skip_serializing_if = "serde::journal_mode::is_default"
)]
pub journal_mode: JournalMode,
#[serde(
default = "serde::synchronous::default",
skip_serializing_if = "serde::synchronous::is_default"
)]
pub synchronous: Synchronous,
}
pub mod serde {
use super::*;
pub mod journal_mode {
use super::*;
pub fn default() -> JournalMode {
DEFAULT_JOURNAL_MODE
}
pub fn is_default(journal_mode: &JournalMode) -> bool {
matches!(journal_mode, &DEFAULT_JOURNAL_MODE)
}
}
pub mod synchronous {
use super::*;
pub fn default() -> Synchronous {
DEFAULT_SYNCHRONOUS
}
pub fn is_default(synchronous: &Synchronous) -> bool {
matches!(synchronous, &DEFAULT_SYNCHRONOUS)
}
}
}
impl Default for Pragma {
fn default() -> Self {
Self {
journal_mode: DEFAULT_JOURNAL_MODE,
synchronous: DEFAULT_SYNCHRONOUS,
}
}
}
#[cfg(test)]
mod test {
use crate::assert_matches;
use super::*;
use serde_json::json;
#[test]
fn database_config_valid_combinations() {
let cases = [
(None, None, JournalMode::WAL, Synchronous::NORMAL),
(
Some("WAL"),
Some("NORMAL"),
JournalMode::WAL,
Synchronous::NORMAL,
),
(
Some("WAL"),
Some("FULL"),
JournalMode::WAL,
Synchronous::FULL,
),
(Some("WAL"), Some("OFF"), JournalMode::WAL, Synchronous::OFF),
(
Some("DELETE"),
Some("FULL"),
JournalMode::DELETE,
Synchronous::FULL,
),
(
Some("DELETE"),
Some("EXTRA"),
JournalMode::DELETE,
Synchronous::EXTRA,
),
(
Some("WAL"),
Some("NORMAL"),
JournalMode::WAL,
Synchronous::NORMAL,
),
(
Some("DELETE"),
Some("NORMAL"),
JournalMode::DELETE,
Synchronous::NORMAL,
),
];
for (journal_mode, synchronous, expected_journal_mode, expected_synchronous) in cases {
let mut config = json!({});
if let Some(journal_mode) = journal_mode {
config["pragma"]["journalMode"] = json!(journal_mode);
}
if let Some(synchronous) = synchronous {
config["pragma"]["synchronous"] = json!(synchronous);
}
#[allow(clippy::unwrap_used)]
let config: SqliteConfig = serde_json::from_value(config).unwrap();
assert_eq!(
config.pragma,
Pragma {
journal_mode: expected_journal_mode,
synchronous: expected_synchronous
}
);
}
}
#[test]
fn invalid() {
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 pragma = json!({});
if let Some(journal_mode) = journal_mode {
pragma["journalMode"] = json!(journal_mode);
}
if let Some(synchronous) = synchronous {
pragma["synchronous"] = json!(synchronous);
}
assert_matches!(
serde_json::from_value::<Pragma>(pragma),
Err(_),
"{}",
description,
);
}
}
}