kernex_memory/store/
facts.rs1use super::Store;
4use kernex_core::error::KernexError;
5use uuid::Uuid;
6
7impl Store {
8 pub async fn store_fact(
10 &self,
11 sender_id: &str,
12 key: &str,
13 value: &str,
14 ) -> Result<(), KernexError> {
15 let id = Uuid::new_v4().to_string();
16 sqlx::query(
17 "INSERT INTO facts (id, sender_id, key, value) VALUES (?, ?, ?, ?) \
18 ON CONFLICT(sender_id, key) DO UPDATE SET value = excluded.value, updated_at = datetime('now')",
19 )
20 .bind(&id)
21 .bind(sender_id)
22 .bind(key)
23 .bind(value)
24 .execute(&self.pool)
25 .await
26 .map_err(|e| KernexError::Store(format!("upsert fact failed: {e}")))?;
27
28 Ok(())
29 }
30
31 pub async fn get_fact(
33 &self,
34 sender_id: &str,
35 key: &str,
36 ) -> Result<Option<String>, KernexError> {
37 let row: Option<(String,)> =
38 sqlx::query_as("SELECT value FROM facts WHERE sender_id = ? AND key = ?")
39 .bind(sender_id)
40 .bind(key)
41 .fetch_optional(&self.pool)
42 .await
43 .map_err(|e| KernexError::Store(format!("query failed: {e}")))?;
44
45 Ok(row.map(|(v,)| v))
46 }
47
48 pub async fn delete_fact(&self, sender_id: &str, key: &str) -> Result<bool, KernexError> {
50 let result = sqlx::query("DELETE FROM facts WHERE sender_id = ? AND key = ?")
51 .bind(sender_id)
52 .bind(key)
53 .execute(&self.pool)
54 .await
55 .map_err(|e| KernexError::Store(format!("delete failed: {e}")))?;
56
57 Ok(result.rows_affected() > 0)
58 }
59
60 pub async fn get_facts(&self, sender_id: &str) -> Result<Vec<(String, String)>, KernexError> {
62 let rows: Vec<(String, String)> =
63 sqlx::query_as("SELECT key, value FROM facts WHERE sender_id = ? ORDER BY key")
64 .bind(sender_id)
65 .fetch_all(&self.pool)
66 .await
67 .map_err(|e| KernexError::Store(format!("query failed: {e}")))?;
68
69 Ok(rows)
70 }
71
72 pub async fn delete_facts(
74 &self,
75 sender_id: &str,
76 key: Option<&str>,
77 ) -> Result<u64, KernexError> {
78 let result = if let Some(k) = key {
79 sqlx::query("DELETE FROM facts WHERE sender_id = ? AND key = ?")
80 .bind(sender_id)
81 .bind(k)
82 .execute(&self.pool)
83 .await
84 } else {
85 sqlx::query("DELETE FROM facts WHERE sender_id = ?")
86 .bind(sender_id)
87 .execute(&self.pool)
88 .await
89 };
90
91 result
92 .map(|r| r.rows_affected())
93 .map_err(|e| KernexError::Store(format!("delete failed: {e}")))
94 }
95
96 pub async fn get_all_facts(&self) -> Result<Vec<(String, String)>, KernexError> {
98 let rows: Vec<(String, String)> =
99 sqlx::query_as("SELECT key, value FROM facts WHERE key != 'welcomed' ORDER BY key")
100 .fetch_all(&self.pool)
101 .await
102 .map_err(|e| KernexError::Store(format!("query failed: {e}")))?;
103
104 Ok(rows)
105 }
106
107 pub async fn get_all_facts_by_key(
109 &self,
110 key: &str,
111 ) -> Result<Vec<(String, String)>, KernexError> {
112 let rows: Vec<(String, String)> =
113 sqlx::query_as("SELECT sender_id, value FROM facts WHERE key = ? ORDER BY sender_id")
114 .bind(key)
115 .fetch_all(&self.pool)
116 .await
117 .map_err(|e| KernexError::Store(format!("get facts by key failed: {e}")))?;
118 Ok(rows)
119 }
120
121 pub async fn is_new_user(&self, sender_id: &str) -> Result<bool, KernexError> {
123 let row: Option<(String,)> =
124 sqlx::query_as("SELECT value FROM facts WHERE sender_id = ? AND key = 'welcomed'")
125 .bind(sender_id)
126 .fetch_optional(&self.pool)
127 .await
128 .map_err(|e| KernexError::Store(format!("query failed: {e}")))?;
129
130 Ok(row.is_none())
131 }
132
133 pub async fn resolve_sender_id(&self, sender_id: &str) -> Result<String, KernexError> {
137 let row: Option<(String,)> = sqlx::query_as(
138 "SELECT canonical_sender_id FROM user_aliases WHERE alias_sender_id = ?",
139 )
140 .bind(sender_id)
141 .fetch_optional(&self.pool)
142 .await
143 .map_err(|e| KernexError::Store(format!("resolve alias failed: {e}")))?;
144
145 Ok(row.map(|(id,)| id).unwrap_or_else(|| sender_id.to_string()))
146 }
147
148 pub async fn create_alias(
150 &self,
151 alias_id: &str,
152 canonical_id: &str,
153 ) -> Result<(), KernexError> {
154 sqlx::query(
155 "INSERT OR IGNORE INTO user_aliases (alias_sender_id, canonical_sender_id) \
156 VALUES (?, ?)",
157 )
158 .bind(alias_id)
159 .bind(canonical_id)
160 .execute(&self.pool)
161 .await
162 .map_err(|e| KernexError::Store(format!("create alias failed: {e}")))?;
163
164 Ok(())
165 }
166
167 pub async fn find_canonical_user(
169 &self,
170 exclude_sender_id: &str,
171 ) -> Result<Option<String>, KernexError> {
172 let row: Option<(String,)> = sqlx::query_as(
173 "SELECT sender_id FROM facts WHERE key = 'welcomed' AND sender_id != ? LIMIT 1",
174 )
175 .bind(exclude_sender_id)
176 .fetch_optional(&self.pool)
177 .await
178 .map_err(|e| KernexError::Store(format!("query failed: {e}")))?;
179
180 Ok(row.map(|(id,)| id))
181 }
182
183 pub async fn store_limitation(
187 &self,
188 title: &str,
189 description: &str,
190 proposed_plan: &str,
191 ) -> Result<bool, KernexError> {
192 let id = Uuid::new_v4().to_string();
193 let result = sqlx::query(
194 "INSERT OR IGNORE INTO limitations (id, title, description, proposed_plan) \
195 VALUES (?, ?, ?, ?)",
196 )
197 .bind(&id)
198 .bind(title)
199 .bind(description)
200 .bind(proposed_plan)
201 .execute(&self.pool)
202 .await
203 .map_err(|e| KernexError::Store(format!("store limitation failed: {e}")))?;
204
205 Ok(result.rows_affected() > 0)
206 }
207
208 pub async fn get_open_limitations(&self) -> Result<Vec<(String, String, String)>, KernexError> {
210 let rows: Vec<(String, String, String)> = sqlx::query_as(
211 "SELECT title, description, proposed_plan FROM limitations \
212 WHERE status = 'open' ORDER BY created_at ASC",
213 )
214 .fetch_all(&self.pool)
215 .await
216 .map_err(|e| KernexError::Store(format!("get open limitations failed: {e}")))?;
217
218 Ok(rows)
219 }
220}