Skip to main content

gglib_core/paths/
database.rs

1//! Database path resolution.
2//!
3//! Provides the canonical path to the gglib `SQLite` database file.
4
5use std::path::PathBuf;
6
7use super::error::PathError;
8use super::platform::data_root;
9use super::private::create_private_dir;
10
11/// Get the path to the gglib database file.
12///
13/// Returns the path to `gglib.db` in the user data directory.
14/// This is shared between dev and release builds.
15///
16/// The `data/` subdirectory is created if it doesn't exist, and is this
17/// user's alone either way: see [`create_private_dir`].
18pub fn database_path() -> Result<PathBuf, PathError> {
19    let data_dir = data_root()?.join("data");
20
21    create_private_dir(&data_dir).map_err(|e| PathError::CreateFailed {
22        path: data_dir.clone(),
23        reason: e.to_string(),
24    })?;
25
26    Ok(data_dir.join("gglib.db"))
27}
28
29#[cfg(test)]
30mod tests {
31    use super::*;
32    use crate::paths::test_utils::{ENV_LOCK, EnvVarGuard};
33    use tempfile::tempdir;
34
35    #[test]
36    fn test_database_path_ends_with_gglib_db() {
37        // `database_path()` creates `<data root>/data`, so it runs under the
38        // lock every test that points GGLIB_DATA_DIR at a temporary root holds,
39        // and in a root of its own (#1082). Without the lock it once resolved
40        // into a neighbour's root as that root was being removed.
41        let _guard = ENV_LOCK.lock().unwrap();
42        let temp = tempdir().unwrap();
43        let _env_guard = EnvVarGuard::set("GGLIB_DATA_DIR", temp.path().to_string_lossy().as_ref());
44
45        let result = database_path();
46        assert!(result.is_ok());
47        let path = result.unwrap();
48        assert!(path.to_string_lossy().ends_with("gglib.db"));
49        assert!(
50            path.starts_with(temp.path()),
51            "the database path is outside the test's own root: {}",
52            path.display()
53        );
54    }
55}