use sqlx::Row as _;
use super::{Error, Pool};
pub enum Target {
Tag(String),
Aih(String),
}
impl Target {
fn columns(&self) -> (Option<&str>, Option<&str>) {
match self {
Target::Tag(tag) => (Some(tag.as_str()), None),
Target::Aih(aih) => (None, Some(aih.as_str())),
}
}
}
fn now() -> i64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_secs() as i64)
.unwrap_or(0)
}
pub async fn attach(
pool: &Pool,
target: &Target,
laboratory_id: &str,
) -> Result<bool, Error> {
let (tag, aih) = target.columns();
let existing = sqlx::query(
"SELECT 1 FROM objectiveai.laboratory_attachments \
WHERE tag IS NOT DISTINCT FROM $1 \
AND agent_instance_hierarchy IS NOT DISTINCT FROM $2 \
AND laboratory_id = $3",
)
.bind(tag)
.bind(aih)
.bind(laboratory_id)
.fetch_optional(&**pool)
.await?;
if existing.is_some() {
return Ok(false);
}
sqlx::query(
"INSERT INTO objectiveai.laboratory_attachments \
(tag, agent_instance_hierarchy, laboratory_id, created_at) \
VALUES ($1, $2, $3, $4)",
)
.bind(tag)
.bind(aih)
.bind(laboratory_id)
.bind(now())
.execute(&**pool)
.await?;
Ok(true)
}
pub async fn detach(
pool: &Pool,
target: &Target,
laboratory_id: &str,
) -> Result<bool, Error> {
let (tag, aih) = target.columns();
let result = sqlx::query(
"DELETE FROM objectiveai.laboratory_attachments \
WHERE tag IS NOT DISTINCT FROM $1 \
AND agent_instance_hierarchy IS NOT DISTINCT FROM $2 \
AND laboratory_id = $3",
)
.bind(tag)
.bind(aih)
.bind(laboratory_id)
.execute(&**pool)
.await?;
Ok(result.rows_affected() > 0)
}
pub async fn list(pool: &Pool, target: &Target) -> Result<Vec<String>, Error> {
let (tag, aih) = target.columns();
let rows = sqlx::query(
"SELECT laboratory_id FROM objectiveai.laboratory_attachments \
WHERE tag IS NOT DISTINCT FROM $1 \
AND agent_instance_hierarchy IS NOT DISTINCT FROM $2 \
ORDER BY created_at",
)
.bind(tag)
.bind(aih)
.fetch_all(&**pool)
.await?;
let mut out = Vec::with_capacity(rows.len());
for row in rows {
out.push(row.try_get::<String, _>(0)?);
}
Ok(out)
}