use std::error::Error; use microrm::prelude::*; use microrm::Stored; use crate::models::participant::ParticipantID; use crate::models::{ participant::Participant, conversation::{ self, Conversation, ConversationID, PendingConversation } }; pub struct ChatDatabase { db: DB, } #[derive(Database)] struct DB { conversations: microrm::IDMap, participants: microrm::IDMap, } impl ChatDatabase { pub fn new_in_memory() -> Result> { let db = DB::open_path(":memory:")?; return Ok(Self { db: db, }) } pub fn insert_conversation(&self, conversation: PendingConversation) -> Result { // First see if conversation guid already exists, update it if so let guid = conversation.guid(); let mut existing = self.stored_conversation_by_guid(guid)?; if let Some(existing) = existing.as_mut() { conversation.update(existing); existing.sync(); return Ok(existing.id()); } else { // Otherwise, insert. let inserted = self.db.conversations.insert_and_return(conversation.get_conversation())?; // Insert participants let participants = conversation.get_participants(); let inserted_participants = participants.iter() .map(|p| self.db.participants.insert(p.clone()).unwrap()) .collect::>(); inserted.connect_participants(inserted_participants); return Ok(inserted.id()); } } pub fn get_conversation_by_id(&self, id: ConversationID) -> Result, microrm::Error> { self.db.conversations .by_id(id) .map(|stored_conversation| stored_conversation .map(|stored| stored.wrapped()) ) } pub fn get_conversation_by_guid(&self, guid: &str) -> Result, microrm::Error> { self.db.conversations .with(Conversation::Guid, guid) .get() .and_then(|v| Ok(v .into_iter() .map(|c| c.wrapped()) .last() )) } pub fn all_conversations(&self) -> Result, microrm::Error> { self.db.conversations .get() .map(|v| v .into_iter() .map(|c| c.wrapped()) .collect() ) } fn upsert_participants(&self, participants: Vec) -> Vec { // Filter existing participants and add to result let existing_participants = participants.iter() .filter_map(|p| self.db.participants .with(Participant::DisplayName, &p.display_name) .get() .ok() .and_then(|v| v .into_iter() .last() .map(|p| p.id()) ) ) .collect::>(); participants.iter() .map(|p| self.db.participants.insert(p.clone()).unwrap()) .collect() } fn stored_conversation_by_guid(&self, guid: &str) -> Result>, microrm::Error> { self.db.conversations .with(Conversation::Guid, guid) .get() .map(|v| v .into_iter() .last() ) } }