use super::Store;
use kernex_core::error::KernexError;
use uuid::Uuid;
impl Store {
pub async fn store_fact(
&self,
sender_id: &str,
key: &str,
value: &str,
) -> Result<(), KernexError> {
let id = Uuid::new_v4().to_string();
sqlx::query(
"INSERT INTO facts (id, sender_id, key, value) VALUES (?, ?, ?, ?) \
ON CONFLICT(sender_id, key) DO UPDATE SET value = excluded.value, updated_at = datetime('now')",
)
.bind(&id)
.bind(sender_id)
.bind(key)
.bind(value)
.execute(&self.pool)
.await
.map_err(|e| KernexError::Store(format!("upsert fact failed: {e}")))?;
Ok(())
}
pub async fn get_fact(
&self,
sender_id: &str,
key: &str,
) -> Result<Option<String>, KernexError> {
let row: Option<(String,)> =
sqlx::query_as("SELECT value FROM facts WHERE sender_id = ? AND key = ?")
.bind(sender_id)
.bind(key)
.fetch_optional(&self.pool)
.await
.map_err(|e| KernexError::Store(format!("query failed: {e}")))?;
Ok(row.map(|(v,)| v))
}
pub async fn delete_fact(&self, sender_id: &str, key: &str) -> Result<bool, KernexError> {
let result = sqlx::query("DELETE FROM facts WHERE sender_id = ? AND key = ?")
.bind(sender_id)
.bind(key)
.execute(&self.pool)
.await
.map_err(|e| KernexError::Store(format!("delete failed: {e}")))?;
Ok(result.rows_affected() > 0)
}
pub async fn get_facts(&self, sender_id: &str) -> Result<Vec<(String, String)>, KernexError> {
let rows: Vec<(String, String)> =
sqlx::query_as("SELECT key, value FROM facts WHERE sender_id = ? ORDER BY key")
.bind(sender_id)
.fetch_all(&self.pool)
.await
.map_err(|e| KernexError::Store(format!("query failed: {e}")))?;
Ok(rows)
}
pub async fn delete_facts(
&self,
sender_id: &str,
key: Option<&str>,
) -> Result<u64, KernexError> {
let result = if let Some(k) = key {
sqlx::query("DELETE FROM facts WHERE sender_id = ? AND key = ?")
.bind(sender_id)
.bind(k)
.execute(&self.pool)
.await
} else {
sqlx::query("DELETE FROM facts WHERE sender_id = ?")
.bind(sender_id)
.execute(&self.pool)
.await
};
result
.map(|r| r.rows_affected())
.map_err(|e| KernexError::Store(format!("delete failed: {e}")))
}
pub async fn get_all_facts(&self) -> Result<Vec<(String, String)>, KernexError> {
let rows: Vec<(String, String)> =
sqlx::query_as("SELECT key, value FROM facts WHERE key != 'welcomed' ORDER BY key")
.fetch_all(&self.pool)
.await
.map_err(|e| KernexError::Store(format!("query failed: {e}")))?;
Ok(rows)
}
pub async fn get_all_facts_by_key(
&self,
key: &str,
) -> Result<Vec<(String, String)>, KernexError> {
let rows: Vec<(String, String)> =
sqlx::query_as("SELECT sender_id, value FROM facts WHERE key = ? ORDER BY sender_id")
.bind(key)
.fetch_all(&self.pool)
.await
.map_err(|e| KernexError::Store(format!("get facts by key failed: {e}")))?;
Ok(rows)
}
pub async fn is_new_user(&self, sender_id: &str) -> Result<bool, KernexError> {
let row: Option<(String,)> =
sqlx::query_as("SELECT value FROM facts WHERE sender_id = ? AND key = 'welcomed'")
.bind(sender_id)
.fetch_optional(&self.pool)
.await
.map_err(|e| KernexError::Store(format!("query failed: {e}")))?;
Ok(row.is_none())
}
pub async fn resolve_sender_id(&self, sender_id: &str) -> Result<String, KernexError> {
let row: Option<(String,)> = sqlx::query_as(
"SELECT canonical_sender_id FROM user_aliases WHERE alias_sender_id = ?",
)
.bind(sender_id)
.fetch_optional(&self.pool)
.await
.map_err(|e| KernexError::Store(format!("resolve alias failed: {e}")))?;
Ok(row.map(|(id,)| id).unwrap_or_else(|| sender_id.to_string()))
}
pub async fn create_alias(
&self,
alias_id: &str,
canonical_id: &str,
) -> Result<(), KernexError> {
sqlx::query(
"INSERT OR IGNORE INTO user_aliases (alias_sender_id, canonical_sender_id) \
VALUES (?, ?)",
)
.bind(alias_id)
.bind(canonical_id)
.execute(&self.pool)
.await
.map_err(|e| KernexError::Store(format!("create alias failed: {e}")))?;
Ok(())
}
pub async fn find_canonical_user(
&self,
exclude_sender_id: &str,
) -> Result<Option<String>, KernexError> {
let row: Option<(String,)> = sqlx::query_as(
"SELECT sender_id FROM facts WHERE key = 'welcomed' AND sender_id != ? LIMIT 1",
)
.bind(exclude_sender_id)
.fetch_optional(&self.pool)
.await
.map_err(|e| KernexError::Store(format!("query failed: {e}")))?;
Ok(row.map(|(id,)| id))
}
pub async fn store_limitation(
&self,
title: &str,
description: &str,
proposed_plan: &str,
) -> Result<bool, KernexError> {
let id = Uuid::new_v4().to_string();
let result = sqlx::query(
"INSERT OR IGNORE INTO limitations (id, title, description, proposed_plan) \
VALUES (?, ?, ?, ?)",
)
.bind(&id)
.bind(title)
.bind(description)
.bind(proposed_plan)
.execute(&self.pool)
.await
.map_err(|e| KernexError::Store(format!("store limitation failed: {e}")))?;
Ok(result.rows_affected() > 0)
}
pub async fn get_open_limitations(&self) -> Result<Vec<(String, String, String)>, KernexError> {
let rows: Vec<(String, String, String)> = sqlx::query_as(
"SELECT title, description, proposed_plan FROM limitations \
WHERE status = 'open' ORDER BY created_at ASC",
)
.fetch_all(&self.pool)
.await
.map_err(|e| KernexError::Store(format!("get open limitations failed: {e}")))?;
Ok(rows)
}
}