Skip to main content

syncular_testkit/
temp.rs

1use std::fs;
2use std::path::{Path, PathBuf};
3
4use uuid::Uuid;
5
6/// Temporary SQLite database path that removes the database and sidecar files
7/// when dropped.
8#[derive(Debug)]
9pub struct TempDbPath {
10    path: PathBuf,
11}
12
13impl TempDbPath {
14    pub fn new(prefix: impl AsRef<str>) -> Self {
15        let sanitized = sanitize_prefix(prefix.as_ref());
16        let path = std::env::temp_dir().join(format!(
17            "{sanitized}-{}-{}.sqlite",
18            std::process::id(),
19            Uuid::new_v4()
20        ));
21        Self { path }
22    }
23
24    pub fn path(&self) -> &Path {
25        &self.path
26    }
27
28    pub fn to_string_lossy(&self) -> String {
29        self.path.to_string_lossy().into_owned()
30    }
31
32    pub fn remove_now(&self) {
33        remove_sqlite_path(&self.path);
34    }
35}
36
37impl AsRef<Path> for TempDbPath {
38    fn as_ref(&self) -> &Path {
39        self.path()
40    }
41}
42
43impl Drop for TempDbPath {
44    fn drop(&mut self) {
45        remove_sqlite_path(&self.path);
46    }
47}
48
49pub fn temp_db_path(prefix: impl AsRef<str>) -> TempDbPath {
50    TempDbPath::new(prefix)
51}
52
53pub fn unique_temp_db_path(prefix: impl AsRef<str>) -> String {
54    TempDbPath::new(prefix).to_string_lossy()
55}
56
57pub fn unique_temp_file_path(prefix: impl AsRef<str>) -> String {
58    let sanitized = sanitize_prefix(prefix.as_ref());
59    std::env::temp_dir()
60        .join(format!(
61            "{sanitized}-{}-{}",
62            std::process::id(),
63            Uuid::new_v4()
64        ))
65        .to_string_lossy()
66        .into_owned()
67}
68
69fn remove_sqlite_path(path: &Path) {
70    let _ = fs::remove_file(path);
71    for suffix in ["-wal", "-shm", "-journal"] {
72        let sidecar = PathBuf::from(format!("{}{}", path.to_string_lossy(), suffix));
73        let _ = fs::remove_file(sidecar);
74    }
75}
76
77fn sanitize_prefix(prefix: &str) -> String {
78    prefix
79        .chars()
80        .map(|ch| {
81            if ch.is_ascii_alphanumeric() || ch == '-' || ch == '_' {
82                ch
83            } else {
84                '-'
85            }
86        })
87        .collect()
88}