use std::path::PathBuf;
use anyhow::{Context, Result, bail};
use rusqlite::{Connection, OpenFlags};
const GROUP_CONTAINER: &str = "9K33E3U3T4.net.shinyfrog.bear";
const DB_RELATIVE: &str = "Application Data/database.sqlite";
pub fn db_path() -> Result<PathBuf> {
let home = std::env::var_os("HOME").context("$HOME is not set")?;
let path = PathBuf::from(home)
.join("Library")
.join("Group Containers")
.join(GROUP_CONTAINER)
.join(DB_RELATIVE);
if !path.exists() {
bail!("cannot open Bear database at {}", path.display());
}
Ok(path)
}
pub fn group_container_path() -> Result<PathBuf> {
let home = std::env::var_os("HOME").context("$HOME is not set")?;
Ok(PathBuf::from(home)
.join("Library")
.join("Group Containers")
.join(GROUP_CONTAINER))
}
pub fn open_ro() -> Result<Connection> {
let path = db_path()?;
let conn = Connection::open_with_flags(
&path,
OpenFlags::SQLITE_OPEN_READ_ONLY | OpenFlags::SQLITE_OPEN_NO_MUTEX,
)
.with_context(|| format!("cannot open Bear database at {}", path.display()))?;
conn.execute_batch("PRAGMA busy_timeout=3000; PRAGMA query_only=1;")?;
Ok(conn)
}
pub fn open_rw() -> Result<Connection> {
let path = db_path()?;
let conn = Connection::open_with_flags(
&path,
OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_NO_MUTEX,
)
.with_context(|| format!("cannot open Bear database at {}", path.display()))?;
conn.execute_batch("PRAGMA journal_mode=WAL; PRAGMA busy_timeout=5000;")?;
Ok(conn)
}
pub const COREDATA_EPOCH_OFFSET: i64 = 978_307_200;
#[inline]
pub fn coredata_to_unix(ts: f64) -> i64 {
ts as i64 + COREDATA_EPOCH_OFFSET
}
#[inline]
pub fn unix_to_coredata(ts: i64) -> f64 {
(ts - COREDATA_EPOCH_OFFSET) as f64
}
pub fn now_coredata() -> f64 {
unix_to_coredata(chrono::Utc::now().timestamp())
}
pub const SFNOTE_ENT: i64 = 5;
pub const SFNOTETAG_ENT: i64 = 13;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn roundtrip_timestamp() {
let unix = 1_700_000_000i64;
let cd = unix_to_coredata(unix);
assert_eq!(coredata_to_unix(cd), unix);
}
#[test]
fn known_coredata_value() {
assert_eq!(coredata_to_unix(0.0), COREDATA_EPOCH_OFFSET);
}
}