url_cleaner_engine/glue/caching/
inner.rs1use std::cell::OnceCell;
4
5use diesel::prelude::*;
6#[expect(unused_imports, reason = "Used in docs.")]
7use diesel::query_builder::SqlQuery;
8
9use crate::glue::*;
10use crate::util::*;
11
12#[derive(Default)]
28pub struct InnerCache {
29 path: CachePath,
31 connection: OnceCell<SqliteConnection>
33}
34
35impl ::core::fmt::Debug for InnerCache {
36 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
37 f.debug_struct("InnerCache")
38 .field("path", &self.path)
39 .field("connection", if self.connection.get().is_some() {&"OnceCell(..)"} else {&"OnceCell(<uninit>)"})
40 .finish()
41 }
42}
43
44impl InnerCache {
45 pub fn new(path: CachePath) -> Self {
47 path.into()
48 }
49}
50
51impl PartialEq for InnerCache {
52 fn eq(&self, other: &Self) -> bool {
53 self.path == other.path
54 }
55}
56impl Eq for InnerCache {}
57
58impl From<CachePath> for InnerCache {
59 fn from(value: CachePath) -> Self {
60 Self {
61 path: value,
62 ..Default::default()
63 }
64 }
65}
66
67impl InnerCache {
68 pub fn path(&self) -> &CachePath {
70 &self.path
71 }
72
73 pub fn connection(&mut self) -> Option<&mut SqliteConnection> {
75 self.connection.get_mut()
76 }
77
78 #[allow(clippy::missing_panics_doc, reason = "Doesn't panic, but should be replaced with OnceCell::get_or_try_init once that's stable.")]
88 pub fn connect(&mut self) -> Result<&mut SqliteConnection, ConnectCacheError> {
89 debug!(InnerCache::connect, self);
90 if self.connection.get().is_none() {
91 let mut needs_init = self.path == CachePath::Memory;
92 if let CachePath::Path(path) = &self.path && !std::fs::exists(path)? {
93 needs_init = true;
94 std::fs::File::create_new(path)?;
95 }
96 let mut connection = SqliteConnection::establish(self.path.as_str())?;
97 if needs_init {
98 diesel::sql_query(DB_INIT_COMMAND).execute(&mut connection)?;
99 }
100 self.connection.set(connection).map_err(|_| ()).expect("The connection to have just been confirmed unset.");
101 }
102 Ok(self.connection.get_mut().expect("The connection to have just been set."))
103 }
104
105 pub fn disconnect(&mut self) {
107 let _ = self.connection.take();
108 }
109
110 pub fn read(&mut self, keys: CacheEntryKeys) -> Result<Option<CacheEntryValues>, ReadFromCacheError> {
116 debug!(InnerCache::read, self, keys);
117 Ok(cache::dsl::cache
118 .filter(cache::dsl::subject.eq(keys.subject))
119 .filter(cache::dsl::key.eq(keys.key))
120 .limit(1)
121 .select(CacheEntryValues::as_select())
122 .load(self.connect()?)?
123 .first().cloned())
124 }
125
126 pub fn write(&mut self, entry: NewCacheEntry) -> Result<(), WriteToCacheError> {
132 debug!(InnerCache::write, self, entry);
133 diesel::insert_into(cache::table)
134 .values(entry)
135 .execute(self.connect()?)?;
136 Ok(())
137 }
138}
139
140impl From<InnerCache> for (CachePath, OnceCell<SqliteConnection>) {
141 fn from(value: InnerCache) -> Self {
142 (value.path, value.connection)
143 }
144}