A local-first private AI assistant for everyday use. Runs on-device models with encrypted P2P sync, and supports sharing chats publicly on ATProto.
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: Added get last entry func for chats db

madclaws 46b7a834 acaf1ef7

+54 -2
+54 -2
tiles/src/core/chats.rs
··· 3 3 //! Stuff related to chats with the models 4 4 //! 5 5 6 + use std::str::FromStr; 7 + 6 8 use crate::core::accounts::User; 7 9 use crate::runtime::mlx::ChatResponse; 8 10 use crate::utils::get_unix_time_now; 9 11 use anyhow::Result; 10 - use rusqlite::Connection; 12 + use rusqlite::types::{FromSql, FromSqlError, FromSqlResult}; 13 + use rusqlite::{Connection, OptionalExtension}; 11 14 use tilekit::modelfile::Role; 12 15 use uuid::Uuid; 13 16 // model the chats table 17 + 18 + // TODO: foreign types on foreign traits, lul 19 + // someday we can do this for traits sake 20 + // https://dev.to/iprosk/generics-in-rust-murky-waters-of-implementing-foreign-traits-on-foreign-types-584n 21 + 22 + // impl FromSql for Uuid { 23 + // fn column_result(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> { 24 + // let value_str = String::column_result(value)?; 25 + // Uuid::from_str(&value_str).map_err(|_| FromSqlError::InvalidType) 26 + // } 27 + // } 14 28 15 29 #[derive(serde::Serialize, Clone, Debug)] 16 30 pub struct Message { ··· 73 87 } 74 88 } 75 89 90 + fn get_last_entry_id(conn: &Connection, user_id: &str) -> Result<Option<Uuid>> { 91 + match conn.query_row( 92 + "select id from chats where user_id = ?1 order by id desc limit 1", 93 + [user_id], 94 + |row| row.get::<usize, String>(0), 95 + ) { 96 + Ok(res) => Uuid::from_str(&res) 97 + .map_err(Into::into) 98 + .map(|uuid| Some(uuid)), 99 + Err(rusqlite::Error::QueryReturnedNoRows) => Ok(None), 100 + Err(err) => Err(<rusqlite::Error as Into<anyhow::Error>>::into(err)), 101 + } 102 + } 103 + 76 104 #[cfg(test)] 77 105 mod tests { 78 106 use std::time::{SystemTime, UNIX_EPOCH}; ··· 84 112 use crate::{ 85 113 core::{ 86 114 accounts::{ACCOUNT, User}, 87 - chats::save_chat, 115 + chats::{get_last_entry_id, save_chat}, 88 116 }, 89 117 runtime::mlx::ChatResponse, 90 118 }; ··· 176 204 let result = save_chat(&conn, &user, "2+2", None); 177 205 178 206 assert!(result.is_err()); 207 + } 208 + 209 + #[test] 210 + fn test_get_last_entry() { 211 + let conn = setup_db_schema(); 212 + let user = create_user(); 213 + let input = "2+2"; 214 + let chat = save_chat(&conn, &user, input, None).expect("chat should be saved"); 215 + 216 + assert_eq!(chat.user_id, user.user_id); 217 + assert!(chat.response_id.is_none()); 218 + assert!(chat.context_id.is_none()); 219 + 220 + let saved = get_last_entry_id(&conn, &user.user_id); 221 + assert!(saved.is_ok()) 222 + } 223 + 224 + #[test] 225 + fn test_get_last_entry_without_entry() { 226 + let conn = setup_db_schema(); 227 + let user = create_user(); 228 + let saved = get_last_entry_id(&conn, &user.user_id); 229 + println!("{:?}", saved); 230 + assert!(saved.unwrap().is_none()) 179 231 } 180 232 181 233 struct SavedChatRow {