use super::DAL;
use crate::context::Context;
use crate::database::universal_types::UniversalUuid;
use crate::error::ContextError;
use diesel::prelude::*;
use tracing::warn;
#[derive(Clone)]
pub struct ContextDAL<'a> {
dal: &'a DAL,
}
impl<'a> ContextDAL<'a> {
pub fn new(dal: &'a DAL) -> Self {
Self { dal }
}
pub async fn create<T>(
&self,
context: &Context<T>,
) -> Result<Option<UniversalUuid>, ContextError>
where
T: serde::Serialize + for<'de> serde::Deserialize<'de> + std::fmt::Debug + Send + 'static,
{
use super::models::NewUnifiedDbContext;
use crate::database::schema::unified::contexts;
use crate::database::universal_types::UniversalTimestamp;
let value = context.to_json()?;
let trimmed_value = value
.chars()
.filter(|c| !c.is_whitespace())
.collect::<String>();
if trimmed_value == "{}" {
warn!("Skipping insertion of empty context");
return Ok(None);
}
let id = UniversalUuid::new_v4();
let now = UniversalTimestamp::now();
let new_context = NewUnifiedDbContext {
id,
value,
created_at: now,
updated_at: now,
};
crate::interact_on_backend!(self.dal, |conn| {
diesel::insert_into(contexts::table)
.values(&new_context)
.execute(conn)
})?;
Ok(Some(id))
}
pub async fn read<T>(&self, id: UniversalUuid) -> Result<Context<T>, ContextError>
where
T: serde::Serialize + for<'de> serde::Deserialize<'de> + std::fmt::Debug + Send + 'static,
{
use super::models::UnifiedDbContext;
use crate::database::schema::unified::contexts;
let db_context: UnifiedDbContext =
crate::interact_on_backend!(self.dal, |conn| contexts::table.find(id).first(conn))?;
Ok(Context::<T>::from_json(db_context.value)?)
}
pub async fn update<T>(
&self,
id: UniversalUuid,
context: &Context<T>,
) -> Result<(), ContextError>
where
T: serde::Serialize + for<'de> serde::Deserialize<'de> + std::fmt::Debug + Send + 'static,
{
use crate::database::schema::unified::contexts;
use crate::database::universal_types::UniversalTimestamp;
let value = context.to_json()?;
let now = UniversalTimestamp::now();
crate::interact_on_backend!(self.dal, |conn| {
diesel::update(contexts::table.find(id))
.set((contexts::value.eq(value), contexts::updated_at.eq(now)))
.execute(conn)
})?;
Ok(())
}
pub async fn delete(&self, id: UniversalUuid) -> Result<(), ContextError> {
use crate::database::schema::unified::contexts;
crate::interact_on_backend!(self.dal, |conn| diesel::delete(contexts::table.find(id))
.execute(conn))?;
Ok(())
}
pub async fn list<T>(&self, limit: i64, offset: i64) -> Result<Vec<Context<T>>, ContextError>
where
T: serde::Serialize + for<'de> serde::Deserialize<'de> + std::fmt::Debug + Send + 'static,
{
use super::models::UnifiedDbContext;
use crate::database::schema::unified::contexts;
let db_contexts: Vec<UnifiedDbContext> = crate::interact_on_backend!(self.dal, |conn| {
contexts::table
.limit(limit)
.offset(offset)
.order(contexts::created_at.desc())
.load(conn)
})?;
let mut results = Vec::new();
for db_context in db_contexts {
let context = Context::<T>::from_json(db_context.value)?;
results.push(context);
}
Ok(results)
}
}