objectiveai_cli/db/
laboratory_attachments.rs1use sqlx::Row as _;
11
12use super::{Error, Pool};
13
14pub enum Target {
16 Tag(String),
18 Aih(String),
20}
21
22impl Target {
23 fn columns(&self) -> (Option<&str>, Option<&str>) {
26 match self {
27 Target::Tag(tag) => (Some(tag.as_str()), None),
28 Target::Aih(aih) => (None, Some(aih.as_str())),
29 }
30 }
31}
32
33fn now() -> i64 {
34 std::time::SystemTime::now()
35 .duration_since(std::time::UNIX_EPOCH)
36 .map(|d| d.as_secs() as i64)
37 .unwrap_or(0)
38}
39
40pub async fn attach(
44 pool: &Pool,
45 target: &Target,
46 laboratory_id: &str,
47) -> Result<bool, Error> {
48 let (tag, aih) = target.columns();
49 let existing = sqlx::query(
50 "SELECT 1 FROM objectiveai.laboratory_attachments \
51 WHERE tag IS NOT DISTINCT FROM $1 \
52 AND agent_instance_hierarchy IS NOT DISTINCT FROM $2 \
53 AND laboratory_id = $3",
54 )
55 .bind(tag)
56 .bind(aih)
57 .bind(laboratory_id)
58 .fetch_optional(&**pool)
59 .await?;
60 if existing.is_some() {
61 return Ok(false);
62 }
63 sqlx::query(
64 "INSERT INTO objectiveai.laboratory_attachments \
65 (tag, agent_instance_hierarchy, laboratory_id, created_at) \
66 VALUES ($1, $2, $3, $4)",
67 )
68 .bind(tag)
69 .bind(aih)
70 .bind(laboratory_id)
71 .bind(now())
72 .execute(&**pool)
73 .await?;
74 Ok(true)
75}
76
77pub async fn detach(
81 pool: &Pool,
82 target: &Target,
83 laboratory_id: &str,
84) -> Result<bool, Error> {
85 let (tag, aih) = target.columns();
86 let result = sqlx::query(
87 "DELETE FROM objectiveai.laboratory_attachments \
88 WHERE tag IS NOT DISTINCT FROM $1 \
89 AND agent_instance_hierarchy IS NOT DISTINCT FROM $2 \
90 AND laboratory_id = $3",
91 )
92 .bind(tag)
93 .bind(aih)
94 .bind(laboratory_id)
95 .execute(&**pool)
96 .await?;
97 Ok(result.rows_affected() > 0)
98}
99
100pub async fn list(pool: &Pool, target: &Target) -> Result<Vec<String>, Error> {
102 let (tag, aih) = target.columns();
103 let rows = sqlx::query(
104 "SELECT laboratory_id FROM objectiveai.laboratory_attachments \
105 WHERE tag IS NOT DISTINCT FROM $1 \
106 AND agent_instance_hierarchy IS NOT DISTINCT FROM $2 \
107 ORDER BY created_at",
108 )
109 .bind(tag)
110 .bind(aih)
111 .fetch_all(&**pool)
112 .await?;
113 let mut out = Vec::with_capacity(rows.len());
114 for row in rows {
115 out.push(row.try_get::<String, _>(0)?);
116 }
117 Ok(out)
118}