use std::cell::OnceCell;
use diesel::prelude::*;
#[expect(unused_imports, reason = "Used in docs.")]
use diesel::query_builder::SqlQuery;
use crate::glue::*;
use crate::util::*;
#[derive(Default)]
pub struct InnerCache {
path: CachePath,
connection: OnceCell<SqliteConnection>
}
impl ::core::fmt::Debug for InnerCache {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
f.debug_struct("InnerCache")
.field("path", &self.path)
.field("connection", if self.connection.get().is_some() {&"OnceCell(..)"} else {&"OnceCell(<uninit>)"})
.finish()
}
}
impl InnerCache {
pub fn new(path: CachePath) -> Self {
path.into()
}
}
impl PartialEq for InnerCache {
fn eq(&self, other: &Self) -> bool {
self.path == other.path
}
}
impl Eq for InnerCache {}
impl From<CachePath> for InnerCache {
fn from(value: CachePath) -> Self {
Self {
path: value,
..Default::default()
}
}
}
impl InnerCache {
pub fn path(&self) -> &CachePath {
&self.path
}
pub fn connection(&mut self) -> Option<&mut SqliteConnection> {
self.connection.get_mut()
}
#[allow(clippy::missing_panics_doc, reason = "Doesn't panic, but should be replaced with OnceCell::get_or_try_init once that's stable.")]
pub fn connect(&mut self) -> Result<&mut SqliteConnection, ConnectCacheError> {
debug!(InnerCache::connect, self);
if self.connection.get().is_none() {
let mut needs_init = self.path == CachePath::Memory;
if let CachePath::Path(path) = &self.path && !std::fs::exists(path)? {
needs_init = true;
std::fs::File::create_new(path)?;
}
let mut connection = SqliteConnection::establish(self.path.as_str())?;
if needs_init {
diesel::sql_query(DB_INIT_COMMAND).execute(&mut connection)?;
}
self.connection.set(connection).map_err(|_| ()).expect("The connection to have just been confirmed unset.");
}
Ok(self.connection.get_mut().expect("The connection to have just been set."))
}
pub fn disconnect(&mut self) {
let _ = self.connection.take();
}
pub fn read(&mut self, keys: CacheEntryKeys) -> Result<Option<CacheEntryValues>, ReadFromCacheError> {
debug!(InnerCache::read, self, keys);
Ok(cache::dsl::cache
.filter(cache::dsl::subject.eq(keys.subject))
.filter(cache::dsl::key.eq(keys.key))
.limit(1)
.select(CacheEntryValues::as_select())
.load(self.connect()?)?
.first().cloned())
}
pub fn write(&mut self, entry: NewCacheEntry) -> Result<(), WriteToCacheError> {
debug!(InnerCache::write, self, entry);
diesel::insert_into(cache::table)
.values(entry)
.execute(self.connect()?)?;
Ok(())
}
}
impl From<InnerCache> for (CachePath, OnceCell<SqliteConnection>) {
fn from(value: InnerCache) -> Self {
(value.path, value.connection)
}
}