sqlite_graphrag/storage/
connection.rs1use crate::errors::AppError;
2use crate::pragmas::apply_connection_pragmas;
3use rusqlite::Connection;
4use sqlite_vec::sqlite3_vec_init;
5use std::path::Path;
6
7pub fn register_vec_extension() {
10 #[allow(clippy::missing_transmute_annotations)]
11 unsafe {
12 rusqlite::ffi::sqlite3_auto_extension(Some(std::mem::transmute(
13 sqlite3_vec_init as *const (),
14 )));
15 }
16}
17
18pub fn open_rw(path: &Path) -> Result<Connection, AppError> {
19 let conn = Connection::open(path)?;
20 apply_connection_pragmas(&conn)?;
21 apply_secure_permissions(path);
22 Ok(conn)
23}
24
25pub fn ensure_schema(conn: &mut Connection) -> Result<(), AppError> {
26 crate::migrations::runner()
27 .run(conn)
28 .map_err(|e| AppError::Internal(anyhow::anyhow!("migration failed: {e}")))?;
29 conn.execute_batch(&format!(
30 "PRAGMA user_version = {};",
31 crate::constants::SCHEMA_USER_VERSION
32 ))?;
33 Ok(())
34}
35
36#[allow(unused_variables)]
41fn apply_secure_permissions(path: &Path) {
42 #[cfg(unix)]
43 {
44 use std::os::unix::fs::PermissionsExt;
45 let candidates = [
46 path.to_path_buf(),
47 path.with_extension(format!(
48 "{}-wal",
49 path.extension()
50 .and_then(|e| e.to_str())
51 .unwrap_or("sqlite")
52 )),
53 path.with_extension(format!(
54 "{}-shm",
55 path.extension()
56 .and_then(|e| e.to_str())
57 .unwrap_or("sqlite")
58 )),
59 ];
60 for file in candidates.iter() {
61 if file.exists() {
62 if let Ok(meta) = std::fs::metadata(file) {
63 let mut perms = meta.permissions();
64 perms.set_mode(0o600);
65 let _ = std::fs::set_permissions(file, perms);
66 }
67 }
68 }
69 }
70}
71
72pub fn open_ro(path: &Path) -> Result<Connection, AppError> {
73 let conn = Connection::open_with_flags(
74 path,
75 rusqlite::OpenFlags::SQLITE_OPEN_READ_ONLY | rusqlite::OpenFlags::SQLITE_OPEN_URI,
76 )?;
77 conn.execute_batch("PRAGMA foreign_keys = ON;")?;
78 Ok(conn)
79}