use std::error::Error; use anyhow::Result; use diesel::prelude::*; use diesel::query_dsl::BelongingToDsl; use crate::{models::{ conversation::{ self, Conversation, DbConversation }, participant::{ConversationParticipant, DbParticipant, Participant} }, schema}; use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!(); pub struct ChatDatabase { db: SqliteConnection, } impl ChatDatabase { pub fn new_in_memory() -> Result { let mut db = SqliteConnection::establish(":memory:")?; db.run_pending_migrations(MIGRATIONS) .map_err(|e| anyhow::anyhow!("Error running migrations: {}", e))?; return Ok(Self { db: db, }) } pub fn insert_conversation(&mut self, conversation: Conversation) -> Result<()> { use crate::schema::conversations::dsl::*; use crate::schema::participants::dsl::*; use crate::schema::conversation_participants::dsl::*; let (db_conversation, db_participants) = conversation.into(); diesel::replace_into(conversations) .values(&db_conversation) .execute(&mut self.db)?; diesel::replace_into(participants) .values(&db_participants) .execute(&mut self.db)?; // Sqlite backend doesn't support batch insert, so we have to do this manually for participant in db_participants { let pid = participants .select(schema::participants::id) .filter(schema::participants::display_name.eq(&participant.display_name)) .first::(&mut self.db)?; diesel::replace_into(conversation_participants) .values(( conversation_id.eq(&db_conversation.id), participant_id.eq(pid), )) .execute(&mut self.db)?; } Ok(()) } pub fn get_conversation_by_guid(&mut self, match_guid: &str) -> Result> { use crate::schema::conversations::dsl::*; use crate::schema::participants::dsl::*; let result = conversations .find(match_guid) .first::(&mut self.db) .optional()?; if let Some(conversation) = result { let dbParticipants = ConversationParticipant::belonging_to(&conversation) .inner_join(participants) .select(DbParticipant::as_select()) .load::(&mut self.db)?; let mut modelConversation: Conversation = conversation.into(); modelConversation.participants = dbParticipants.into_iter().map(|p| p.into()).collect(); return Ok(Some(modelConversation)); } Ok(None) } pub fn all_conversations(&mut self) -> Result> { use crate::schema::conversations::dsl::*; use crate::schema::participants::dsl::*; let db_conversations = conversations .load::(&mut self.db)?; let mut result = Vec::new(); for db_conversation in db_conversations { let db_participants = ConversationParticipant::belonging_to(&db_conversation) .inner_join(participants) .select(DbParticipant::as_select()) .load::(&mut self.db)?; let mut model_conversation: Conversation = db_conversation.into(); model_conversation.participants = db_participants.into_iter().map(|p| p.into()).collect(); result.push(model_conversation); } Ok(result) } }