cargo fmt
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
use anyhow::Result;
|
||||
use diesel::prelude::*;
|
||||
use async_trait::async_trait;
|
||||
use diesel::prelude::*;
|
||||
|
||||
pub use std::sync::Arc;
|
||||
pub use tokio::sync::Mutex;
|
||||
@@ -31,7 +31,8 @@ pub struct Database {
|
||||
impl Database {
|
||||
pub fn new(path: &str) -> Result<Self> {
|
||||
let mut connection = SqliteConnection::establish(path)?;
|
||||
connection.run_pending_migrations(MIGRATIONS)
|
||||
connection
|
||||
.run_pending_migrations(MIGRATIONS)
|
||||
.map_err(|e| anyhow::anyhow!("Error running migrations: {}", e))?;
|
||||
|
||||
Ok(Self { connection })
|
||||
|
||||
@@ -7,4 +7,4 @@ pub mod settings;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use repository::Repository;
|
||||
pub use repository::Repository;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::models::participant::Participant;
|
||||
use chrono::{DateTime, NaiveDateTime};
|
||||
use uuid::Uuid;
|
||||
use crate::models::participant::Participant;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Conversation {
|
||||
@@ -33,18 +33,17 @@ impl From<kordophone::model::Conversation> for Conversation {
|
||||
fn from(value: kordophone::model::Conversation) -> Self {
|
||||
Self {
|
||||
guid: value.guid,
|
||||
unread_count: u16::try_from(value.unread_count).unwrap(),
|
||||
unread_count: u16::try_from(value.unread_count).unwrap(),
|
||||
display_name: value.display_name,
|
||||
last_message_preview: value.last_message_preview,
|
||||
date: DateTime::from_timestamp(
|
||||
value.date.unix_timestamp(),
|
||||
value.date.unix_timestamp_nanos()
|
||||
.try_into()
|
||||
.unwrap_or(0),
|
||||
)
|
||||
.unwrap()
|
||||
.naive_local(),
|
||||
participants: value.participant_display_names
|
||||
value.date.unix_timestamp_nanos().try_into().unwrap_or(0),
|
||||
)
|
||||
.unwrap()
|
||||
.naive_local(),
|
||||
participants: value
|
||||
.participant_display_names
|
||||
.into_iter()
|
||||
.map(|p| p.into())
|
||||
.collect(),
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
use diesel::prelude::*;
|
||||
use crate::models::{db::participant::InsertableRecord as InsertableParticipant, Conversation};
|
||||
use chrono::NaiveDateTime;
|
||||
use crate::models::{
|
||||
Conversation,
|
||||
db::participant::InsertableRecord as InsertableParticipant,
|
||||
};
|
||||
use diesel::prelude::*;
|
||||
|
||||
#[derive(Queryable, Selectable, Insertable, AsChangeset, Clone, Identifiable)]
|
||||
#[diesel(table_name = crate::schema::conversations)]
|
||||
@@ -33,11 +30,11 @@ impl From<Conversation> for (Record, Vec<InsertableParticipant>) {
|
||||
fn from(conversation: Conversation) -> Self {
|
||||
(
|
||||
Record::from(conversation.clone()),
|
||||
|
||||
conversation.participants
|
||||
conversation
|
||||
.participants
|
||||
.into_iter()
|
||||
.map(InsertableParticipant::from)
|
||||
.collect()
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -53,4 +50,4 @@ impl From<Record> for Conversation {
|
||||
participants: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use diesel::prelude::*;
|
||||
use chrono::NaiveDateTime;
|
||||
use crate::models::{Message, Participant};
|
||||
use chrono::NaiveDateTime;
|
||||
use diesel::prelude::*;
|
||||
|
||||
#[derive(Queryable, Selectable, Insertable, AsChangeset, Clone, Identifiable, Debug)]
|
||||
#[diesel(table_name = crate::schema::messages)]
|
||||
@@ -21,10 +21,11 @@ impl From<Message> for Record {
|
||||
} else {
|
||||
Some(serde_json::to_string(&message.file_transfer_guids).unwrap_or_default())
|
||||
};
|
||||
|
||||
let attachment_metadata = message.attachment_metadata
|
||||
|
||||
let attachment_metadata = message
|
||||
.attachment_metadata
|
||||
.map(|metadata| serde_json::to_string(&metadata).unwrap_or_default());
|
||||
|
||||
|
||||
Self {
|
||||
id: message.id,
|
||||
sender_participant_id: match message.sender {
|
||||
@@ -41,13 +42,15 @@ impl From<Message> for Record {
|
||||
|
||||
impl From<Record> for Message {
|
||||
fn from(record: Record) -> Self {
|
||||
let file_transfer_guids = record.file_transfer_guids
|
||||
let file_transfer_guids = record
|
||||
.file_transfer_guids
|
||||
.and_then(|json| serde_json::from_str(&json).ok())
|
||||
.unwrap_or_default();
|
||||
|
||||
let attachment_metadata = record.attachment_metadata
|
||||
|
||||
let attachment_metadata = record
|
||||
.attachment_metadata
|
||||
.and_then(|json| serde_json::from_str(&json).ok());
|
||||
|
||||
|
||||
Self {
|
||||
id: record.id,
|
||||
// We'll set the proper sender later when loading participant info
|
||||
@@ -59,4 +62,3 @@ impl From<Record> for Message {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
pub mod conversation;
|
||||
pub mod message;
|
||||
pub mod participant;
|
||||
pub mod message;
|
||||
@@ -1,6 +1,6 @@
|
||||
use diesel::prelude::*;
|
||||
use crate::models::Participant;
|
||||
use crate::schema::conversation_participants;
|
||||
use diesel::prelude::*;
|
||||
|
||||
#[derive(Queryable, Selectable, AsChangeset, Identifiable)]
|
||||
#[diesel(table_name = crate::schema::participants)]
|
||||
@@ -27,7 +27,7 @@ impl From<Participant> for InsertableRecord {
|
||||
Participant::Remote { display_name, .. } => InsertableRecord {
|
||||
display_name: Some(display_name),
|
||||
is_me: false,
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,7 @@ impl From<Participant> for Record {
|
||||
id: 0, // This will be set by the database
|
||||
display_name: Some(display_name),
|
||||
is_me: false,
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use crate::models::participant::Participant;
|
||||
use chrono::{DateTime, NaiveDateTime};
|
||||
use kordophone::model::message::AttachmentMetadata;
|
||||
use kordophone::model::outgoing_message::OutgoingMessage;
|
||||
use std::collections::HashMap;
|
||||
use uuid::Uuid;
|
||||
use crate::models::participant::Participant;
|
||||
use kordophone::model::outgoing_message::OutgoingMessage;
|
||||
use kordophone::model::message::AttachmentMetadata;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Message {
|
||||
pub id: String,
|
||||
pub sender: Participant,
|
||||
@@ -35,12 +35,10 @@ impl From<kordophone::model::Message> for Message {
|
||||
text: value.text,
|
||||
date: DateTime::from_timestamp(
|
||||
value.date.unix_timestamp(),
|
||||
value.date.unix_timestamp_nanos()
|
||||
.try_into()
|
||||
.unwrap_or(0),
|
||||
)
|
||||
.unwrap()
|
||||
.naive_local(),
|
||||
value.date.unix_timestamp_nanos().try_into().unwrap_or(0),
|
||||
)
|
||||
.unwrap()
|
||||
.naive_local(),
|
||||
file_transfer_guids: value.file_transfer_guids,
|
||||
attachment_metadata: value.attachment_metadata,
|
||||
}
|
||||
@@ -107,7 +105,10 @@ impl MessageBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn attachment_metadata(mut self, attachment_metadata: HashMap<String, AttachmentMetadata>) -> Self {
|
||||
pub fn attachment_metadata(
|
||||
mut self,
|
||||
attachment_metadata: HashMap<String, AttachmentMetadata>,
|
||||
) -> Self {
|
||||
self.attachment_metadata = Some(attachment_metadata);
|
||||
self
|
||||
}
|
||||
@@ -123,4 +124,3 @@ impl MessageBuilder {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
pub mod conversation;
|
||||
pub mod participant;
|
||||
pub mod message;
|
||||
pub mod db;
|
||||
pub mod message;
|
||||
pub mod participant;
|
||||
|
||||
pub use conversation::Conversation;
|
||||
pub use message::Message;
|
||||
pub use participant::Participant;
|
||||
pub use message::Message;
|
||||
@@ -4,16 +4,13 @@ use diesel::query_dsl::BelongingToDsl;
|
||||
|
||||
use crate::{
|
||||
models::{
|
||||
Conversation,
|
||||
Message,
|
||||
Participant,
|
||||
db::conversation::Record as ConversationRecord,
|
||||
db::participant::{
|
||||
ConversationParticipant,
|
||||
Record as ParticipantRecord,
|
||||
InsertableRecord as InsertableParticipantRecord
|
||||
},
|
||||
db::message::Record as MessageRecord,
|
||||
db::participant::{
|
||||
ConversationParticipant, InsertableRecord as InsertableParticipantRecord,
|
||||
Record as ParticipantRecord,
|
||||
},
|
||||
Conversation, Message, Participant,
|
||||
},
|
||||
schema,
|
||||
};
|
||||
@@ -28,9 +25,9 @@ impl<'a> Repository<'a> {
|
||||
}
|
||||
|
||||
pub fn insert_conversation(&mut self, conversation: Conversation) -> Result<()> {
|
||||
use crate::schema::conversation_participants::dsl::*;
|
||||
use crate::schema::conversations::dsl::*;
|
||||
use crate::schema::participants::dsl::*;
|
||||
use crate::schema::conversation_participants::dsl::*;
|
||||
|
||||
let (db_conversation, db_participants) = conversation.into();
|
||||
|
||||
@@ -76,7 +73,8 @@ impl<'a> Repository<'a> {
|
||||
.load::<ParticipantRecord>(self.connection)?;
|
||||
|
||||
let mut model_conversation: Conversation = conversation.into();
|
||||
model_conversation.participants = db_participants.into_iter().map(|p| p.into()).collect();
|
||||
model_conversation.participants =
|
||||
db_participants.into_iter().map(|p| p.into()).collect();
|
||||
|
||||
return Ok(Some(model_conversation));
|
||||
}
|
||||
@@ -102,7 +100,8 @@ impl<'a> Repository<'a> {
|
||||
.load::<ParticipantRecord>(self.connection)?;
|
||||
|
||||
let mut model_conversation: Conversation = db_conversation.into();
|
||||
model_conversation.participants = db_participants.into_iter().map(|p| p.into()).collect();
|
||||
model_conversation.participants =
|
||||
db_participants.into_iter().map(|p| p.into()).collect();
|
||||
|
||||
result.push(model_conversation);
|
||||
}
|
||||
@@ -111,8 +110,8 @@ impl<'a> Repository<'a> {
|
||||
}
|
||||
|
||||
pub fn insert_message(&mut self, conversation_guid: &str, message: Message) -> Result<()> {
|
||||
use crate::schema::messages::dsl::*;
|
||||
use crate::schema::conversation_messages::dsl::*;
|
||||
use crate::schema::messages::dsl::*;
|
||||
|
||||
// Handle participant if message has a remote sender
|
||||
let sender = message.sender.clone();
|
||||
@@ -136,9 +135,13 @@ impl<'a> Repository<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn insert_messages(&mut self, conversation_guid: &str, in_messages: Vec<Message>) -> Result<()> {
|
||||
use crate::schema::messages::dsl::*;
|
||||
pub fn insert_messages(
|
||||
&mut self,
|
||||
conversation_guid: &str,
|
||||
in_messages: Vec<Message>,
|
||||
) -> Result<()> {
|
||||
use crate::schema::conversation_messages::dsl::*;
|
||||
use crate::schema::messages::dsl::*;
|
||||
|
||||
// Local insertable struct for the join table
|
||||
#[derive(Insertable)]
|
||||
@@ -154,7 +157,8 @@ impl<'a> Repository<'a> {
|
||||
|
||||
// Build the collections of insertable records
|
||||
let mut db_messages: Vec<MessageRecord> = Vec::with_capacity(in_messages.len());
|
||||
let mut conv_msg_records: Vec<InsertableConversationMessage> = Vec::with_capacity(in_messages.len());
|
||||
let mut conv_msg_records: Vec<InsertableConversationMessage> =
|
||||
Vec::with_capacity(in_messages.len());
|
||||
|
||||
for message in in_messages {
|
||||
// Handle participant if message has a remote sender
|
||||
@@ -186,9 +190,12 @@ impl<'a> Repository<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_messages_for_conversation(&mut self, conversation_guid: &str) -> Result<Vec<Message>> {
|
||||
use crate::schema::messages::dsl::*;
|
||||
pub fn get_messages_for_conversation(
|
||||
&mut self,
|
||||
conversation_guid: &str,
|
||||
) -> Result<Vec<Message>> {
|
||||
use crate::schema::conversation_messages::dsl::*;
|
||||
use crate::schema::messages::dsl::*;
|
||||
use crate::schema::participants::dsl::*;
|
||||
|
||||
let message_records = conversation_messages
|
||||
@@ -201,7 +208,7 @@ impl<'a> Repository<'a> {
|
||||
let mut result = Vec::new();
|
||||
for message_record in message_records {
|
||||
let mut message: Message = message_record.clone().into();
|
||||
|
||||
|
||||
// If there's a sender_participant_id, load the participant info
|
||||
if let Some(pid) = message_record.sender_participant_id {
|
||||
let participant = participants
|
||||
@@ -216,9 +223,12 @@ impl<'a> Repository<'a> {
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn get_last_message_for_conversation(&mut self, conversation_guid: &str) -> Result<Option<Message>> {
|
||||
use crate::schema::messages::dsl::*;
|
||||
pub fn get_last_message_for_conversation(
|
||||
&mut self,
|
||||
conversation_guid: &str,
|
||||
) -> Result<Option<Message>> {
|
||||
use crate::schema::conversation_messages::dsl::*;
|
||||
use crate::schema::messages::dsl::*;
|
||||
|
||||
let message_record = conversation_messages
|
||||
.filter(conversation_id.eq(conversation_guid))
|
||||
@@ -247,7 +257,11 @@ impl<'a> Repository<'a> {
|
||||
let conversation = self.get_conversation_by_guid(conversation_guid)?;
|
||||
if let Some(mut conversation) = conversation {
|
||||
if let Some(last_message) = self.get_last_message_for_conversation(conversation_guid)? {
|
||||
log::debug!("Updating conversation metadata: {} message: {:?}", conversation_guid, last_message);
|
||||
log::debug!(
|
||||
"Updating conversation metadata: {} message: {:?}",
|
||||
conversation_guid,
|
||||
last_message
|
||||
);
|
||||
conversation.date = last_message.date;
|
||||
conversation.last_message_preview = Some(last_message.text.clone());
|
||||
self.insert_conversation(conversation)?;
|
||||
@@ -261,14 +275,21 @@ impl<'a> Repository<'a> {
|
||||
// This is a workaround since the Sqlite backend doesn't support `RETURNING`
|
||||
// Huge caveat with this is that it depends on whatever the last insert was, prevents concurrent inserts.
|
||||
fn last_insert_id(&mut self) -> Result<i32> {
|
||||
Ok(diesel::select(diesel::dsl::sql::<diesel::sql_types::Integer>("last_insert_rowid()"))
|
||||
.get_result(self.connection)?)
|
||||
Ok(
|
||||
diesel::select(diesel::dsl::sql::<diesel::sql_types::Integer>(
|
||||
"last_insert_rowid()",
|
||||
))
|
||||
.get_result(self.connection)?,
|
||||
)
|
||||
}
|
||||
|
||||
fn get_or_create_participant(&mut self, participant: &Participant) -> Option<i32> {
|
||||
match participant {
|
||||
Participant::Me => None,
|
||||
Participant::Remote { display_name: p_name, .. } => {
|
||||
Participant::Remote {
|
||||
display_name: p_name,
|
||||
..
|
||||
} => {
|
||||
use crate::schema::participants::dsl::*;
|
||||
|
||||
let existing_participant = participants
|
||||
|
||||
@@ -28,9 +28,9 @@ diesel::table! {
|
||||
|
||||
diesel::table! {
|
||||
messages (id) {
|
||||
id -> Text, // guid
|
||||
text -> Text,
|
||||
sender_participant_id -> Nullable<Integer>,
|
||||
id -> Text, // guid
|
||||
text -> Text,
|
||||
sender_participant_id -> Nullable<Integer>,
|
||||
date -> Timestamp,
|
||||
file_transfer_guids -> Nullable<Text>, // JSON array of file transfer GUIDs
|
||||
attachment_metadata -> Nullable<Text>, // JSON string of attachment metadata
|
||||
@@ -53,8 +53,12 @@ diesel::table! {
|
||||
|
||||
diesel::joinable!(conversation_participants -> conversations (conversation_id));
|
||||
diesel::joinable!(conversation_participants -> participants (participant_id));
|
||||
diesel::allow_tables_to_appear_in_same_query!(conversations, participants, conversation_participants);
|
||||
diesel::allow_tables_to_appear_in_same_query!(
|
||||
conversations,
|
||||
participants,
|
||||
conversation_participants
|
||||
);
|
||||
|
||||
diesel::joinable!(conversation_messages -> conversations (conversation_id));
|
||||
diesel::joinable!(conversation_messages -> messages (message_id));
|
||||
diesel::allow_tables_to_appear_in_same_query!(conversations, messages, conversation_messages);
|
||||
diesel::allow_tables_to_appear_in_same_query!(conversations, messages, conversation_messages);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use diesel::*;
|
||||
use serde::{Serialize, de::DeserializeOwned};
|
||||
use anyhow::Result;
|
||||
use diesel::*;
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
|
||||
#[derive(Insertable, Queryable, AsChangeset)]
|
||||
#[diesel(table_name = crate::schema::settings)]
|
||||
@@ -18,16 +18,15 @@ impl<'a> Settings<'a> {
|
||||
Self { connection }
|
||||
}
|
||||
|
||||
pub fn put<T: Serialize>(
|
||||
&mut self,
|
||||
k: &str,
|
||||
v: &T,
|
||||
) -> Result<()> {
|
||||
pub fn put<T: Serialize>(&mut self, k: &str, v: &T) -> Result<()> {
|
||||
use crate::schema::settings::dsl::*;
|
||||
let bytes = bincode::serialize(v)?;
|
||||
|
||||
diesel::insert_into(settings)
|
||||
.values(SettingsRow { key: k, value: &bytes })
|
||||
.values(SettingsRow {
|
||||
key: k,
|
||||
value: &bytes,
|
||||
})
|
||||
.on_conflict(key)
|
||||
.do_update()
|
||||
.set(value.eq(&bytes))
|
||||
@@ -36,10 +35,7 @@ impl<'a> Settings<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get<T: DeserializeOwned>(
|
||||
&mut self,
|
||||
k: &str,
|
||||
) -> Result<Option<T>> {
|
||||
pub fn get<T: DeserializeOwned>(&mut self, k: &str) -> Result<Option<T>> {
|
||||
use crate::schema::settings::dsl::*;
|
||||
let blob: Option<Vec<u8>> = settings
|
||||
.select(value)
|
||||
@@ -49,7 +45,7 @@ impl<'a> Settings<'a> {
|
||||
|
||||
Ok(match blob {
|
||||
Some(b) => Some(bincode::deserialize(&b)?),
|
||||
None => None,
|
||||
None => None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -60,12 +56,8 @@ impl<'a> Settings<'a> {
|
||||
|
||||
pub fn list_keys(&mut self) -> Result<Vec<String>> {
|
||||
use crate::schema::settings::dsl::*;
|
||||
let keys: Vec<String> = settings
|
||||
.select(key)
|
||||
.load(self.connection)?;
|
||||
|
||||
let keys: Vec<String> = settings.select(key).load(self.connection)?;
|
||||
|
||||
Ok(keys)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use crate::{
|
||||
database::{Database, DatabaseAccess},
|
||||
database::{Database, DatabaseAccess},
|
||||
models::{
|
||||
conversation::{Conversation, ConversationBuilder},
|
||||
participant::Participant,
|
||||
message::Message,
|
||||
participant::Participant,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -11,9 +11,17 @@ use crate::{
|
||||
fn participants_equal_ignoring_id(a: &Participant, b: &Participant) -> bool {
|
||||
match (a, b) {
|
||||
(Participant::Me, Participant::Me) => true,
|
||||
(Participant::Remote { display_name: name_a, .. },
|
||||
Participant::Remote { display_name: name_b, .. }) => name_a == name_b,
|
||||
_ => false
|
||||
(
|
||||
Participant::Remote {
|
||||
display_name: name_a,
|
||||
..
|
||||
},
|
||||
Participant::Remote {
|
||||
display_name: name_b,
|
||||
..
|
||||
},
|
||||
) => name_a == name_b,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +29,9 @@ fn participants_vec_equal_ignoring_id(a: &[Participant], b: &[Participant]) -> b
|
||||
if a.len() != b.len() {
|
||||
return false;
|
||||
}
|
||||
a.iter().zip(b.iter()).all(|(a, b)| participants_equal_ignoring_id(a, b))
|
||||
a.iter()
|
||||
.zip(b.iter())
|
||||
.all(|(a, b)| participants_equal_ignoring_id(a, b))
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -40,27 +50,33 @@ async fn test_add_conversation() {
|
||||
.display_name("Test Conversation")
|
||||
.build();
|
||||
|
||||
repository.insert_conversation(test_conversation.clone()).unwrap();
|
||||
repository
|
||||
.insert_conversation(test_conversation.clone())
|
||||
.unwrap();
|
||||
|
||||
// Try to fetch with id now
|
||||
// Try to fetch with id now
|
||||
let conversation = repository.get_conversation_by_guid(guid).unwrap().unwrap();
|
||||
assert_eq!(conversation.guid, "test");
|
||||
|
||||
// Modify the conversation and update it
|
||||
let modified_conversation = test_conversation.into_builder()
|
||||
let modified_conversation = test_conversation
|
||||
.into_builder()
|
||||
.display_name("Modified Conversation")
|
||||
.build();
|
||||
|
||||
repository.insert_conversation(modified_conversation.clone()).unwrap();
|
||||
repository
|
||||
.insert_conversation(modified_conversation.clone())
|
||||
.unwrap();
|
||||
|
||||
// Make sure we still only have one conversation.
|
||||
// Make sure we still only have one conversation.
|
||||
let all_conversations = repository.all_conversations(i32::MAX, 0).unwrap();
|
||||
assert_eq!(all_conversations.len(), 1);
|
||||
|
||||
// And make sure the display name was updated
|
||||
// And make sure the display name was updated
|
||||
let conversation = repository.get_conversation_by_guid(guid).unwrap().unwrap();
|
||||
assert_eq!(conversation.display_name.unwrap(), "Modified Conversation");
|
||||
}).await;
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -81,7 +97,10 @@ async fn test_conversation_participants() {
|
||||
let read_conversation = repository.get_conversation_by_guid(&guid).unwrap().unwrap();
|
||||
let read_participants = read_conversation.participants;
|
||||
|
||||
assert!(participants_vec_equal_ignoring_id(&participants, &read_participants));
|
||||
assert!(participants_vec_equal_ignoring_id(
|
||||
&participants,
|
||||
&read_participants
|
||||
));
|
||||
|
||||
// Try making another conversation with the same participants
|
||||
let conversation = ConversationBuilder::new()
|
||||
@@ -94,8 +113,12 @@ async fn test_conversation_participants() {
|
||||
let read_conversation = repository.get_conversation_by_guid(&guid).unwrap().unwrap();
|
||||
let read_participants: Vec<Participant> = read_conversation.participants;
|
||||
|
||||
assert!(participants_vec_equal_ignoring_id(&participants, &read_participants));
|
||||
}).await;
|
||||
assert!(participants_vec_equal_ignoring_id(
|
||||
&participants,
|
||||
&read_participants
|
||||
));
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -132,9 +155,16 @@ async fn test_all_conversations_with_participants() {
|
||||
let conv1 = all_conversations.iter().find(|c| c.guid == guid1).unwrap();
|
||||
let conv2 = all_conversations.iter().find(|c| c.guid == guid2).unwrap();
|
||||
|
||||
assert!(participants_vec_equal_ignoring_id(&conv1.participants, &participants1));
|
||||
assert!(participants_vec_equal_ignoring_id(&conv2.participants, &participants2));
|
||||
}).await;
|
||||
assert!(participants_vec_equal_ignoring_id(
|
||||
&conv1.participants,
|
||||
&participants1
|
||||
));
|
||||
assert!(participants_vec_equal_ignoring_id(
|
||||
&conv2.participants,
|
||||
&participants2
|
||||
));
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -163,11 +193,17 @@ async fn test_messages() {
|
||||
.build();
|
||||
|
||||
// Insert both messages
|
||||
repository.insert_message(&conversation_id, message1.clone()).unwrap();
|
||||
repository.insert_message(&conversation_id, message2.clone()).unwrap();
|
||||
repository
|
||||
.insert_message(&conversation_id, message1.clone())
|
||||
.unwrap();
|
||||
repository
|
||||
.insert_message(&conversation_id, message2.clone())
|
||||
.unwrap();
|
||||
|
||||
// Retrieve messages
|
||||
let messages = repository.get_messages_for_conversation(&conversation_id).unwrap();
|
||||
let messages = repository
|
||||
.get_messages_for_conversation(&conversation_id)
|
||||
.unwrap();
|
||||
assert_eq!(messages.len(), 2);
|
||||
|
||||
// Verify first message (from Me)
|
||||
@@ -181,9 +217,13 @@ async fn test_messages() {
|
||||
if let Participant::Remote { display_name, .. } = &retrieved_message2.sender {
|
||||
assert_eq!(display_name, "Alice");
|
||||
} else {
|
||||
panic!("Expected Remote participant. Got: {:?}", retrieved_message2.sender);
|
||||
panic!(
|
||||
"Expected Remote participant. Got: {:?}",
|
||||
retrieved_message2.sender
|
||||
);
|
||||
}
|
||||
}).await;
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -191,9 +231,7 @@ async fn test_message_ordering() {
|
||||
let mut db = Database::new_in_memory().unwrap();
|
||||
db.with_repository(|repository| {
|
||||
// Create a conversation
|
||||
let conversation = ConversationBuilder::new()
|
||||
.display_name("Test Chat")
|
||||
.build();
|
||||
let conversation = ConversationBuilder::new().display_name("Test Chat").build();
|
||||
let conversation_id = conversation.guid.clone();
|
||||
repository.insert_conversation(conversation).unwrap();
|
||||
|
||||
@@ -215,19 +253,28 @@ async fn test_message_ordering() {
|
||||
.build();
|
||||
|
||||
// Insert messages
|
||||
repository.insert_message(&conversation_id, message1).unwrap();
|
||||
repository.insert_message(&conversation_id, message2).unwrap();
|
||||
repository.insert_message(&conversation_id, message3).unwrap();
|
||||
repository
|
||||
.insert_message(&conversation_id, message1)
|
||||
.unwrap();
|
||||
repository
|
||||
.insert_message(&conversation_id, message2)
|
||||
.unwrap();
|
||||
repository
|
||||
.insert_message(&conversation_id, message3)
|
||||
.unwrap();
|
||||
|
||||
// Retrieve messages and verify order
|
||||
let messages = repository.get_messages_for_conversation(&conversation_id).unwrap();
|
||||
let messages = repository
|
||||
.get_messages_for_conversation(&conversation_id)
|
||||
.unwrap();
|
||||
assert_eq!(messages.len(), 3);
|
||||
|
||||
// Messages should be ordered by date
|
||||
for i in 1..messages.len() {
|
||||
assert!(messages[i].date > messages[i-1].date);
|
||||
assert!(messages[i].date > messages[i - 1].date);
|
||||
}
|
||||
}).await;
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -245,10 +292,7 @@ async fn test_insert_messages_batch() {
|
||||
|
||||
// Prepare a batch of messages with increasing timestamps
|
||||
let now = chrono::Utc::now().naive_utc();
|
||||
let message1 = Message::builder()
|
||||
.text("Hi".to_string())
|
||||
.date(now)
|
||||
.build();
|
||||
let message1 = Message::builder().text("Hi".to_string()).date(now).build();
|
||||
|
||||
let message2 = Message::builder()
|
||||
.text("Hello".to_string())
|
||||
@@ -280,7 +324,9 @@ async fn test_insert_messages_batch() {
|
||||
.unwrap();
|
||||
|
||||
// Retrieve messages and verify
|
||||
let retrieved_messages = repository.get_messages_for_conversation(&conversation_id).unwrap();
|
||||
let retrieved_messages = repository
|
||||
.get_messages_for_conversation(&conversation_id)
|
||||
.unwrap();
|
||||
assert_eq!(retrieved_messages.len(), original_messages.len());
|
||||
|
||||
// Ensure ordering by date
|
||||
@@ -299,8 +345,14 @@ async fn test_insert_messages_batch() {
|
||||
match (&original.sender, &retrieved.sender) {
|
||||
(Participant::Me, Participant::Me) => {}
|
||||
(
|
||||
Participant::Remote { display_name: o_name, .. },
|
||||
Participant::Remote { display_name: r_name, .. },
|
||||
Participant::Remote {
|
||||
display_name: o_name,
|
||||
..
|
||||
},
|
||||
Participant::Remote {
|
||||
display_name: r_name,
|
||||
..
|
||||
},
|
||||
) => assert_eq!(o_name, r_name),
|
||||
_ => panic!(
|
||||
"Sender mismatch: original {:?}, retrieved {:?}",
|
||||
@@ -310,7 +362,10 @@ async fn test_insert_messages_batch() {
|
||||
}
|
||||
|
||||
// Make sure the last message is the last one we inserted
|
||||
let last_message = repository.get_last_message_for_conversation(&conversation_id).unwrap().unwrap();
|
||||
let last_message = repository
|
||||
.get_last_message_for_conversation(&conversation_id)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert_eq!(last_message.id, message4.id);
|
||||
})
|
||||
.await;
|
||||
@@ -329,7 +384,7 @@ async fn test_settings() {
|
||||
let keys = settings.list_keys().unwrap();
|
||||
assert_eq!(keys.len(), 0);
|
||||
|
||||
// Try encoding a struct
|
||||
// Try encoding a struct
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)]
|
||||
struct TestStruct {
|
||||
name: String,
|
||||
@@ -342,13 +397,34 @@ async fn test_settings() {
|
||||
};
|
||||
|
||||
settings.put("test_struct", &test_struct).unwrap();
|
||||
assert_eq!(settings.get::<TestStruct>("test_struct").unwrap().unwrap(), test_struct);
|
||||
assert_eq!(
|
||||
settings.get::<TestStruct>("test_struct").unwrap().unwrap(),
|
||||
test_struct
|
||||
);
|
||||
|
||||
// Test with an option<string>
|
||||
settings.put("test_struct_option", &Option::<String>::None).unwrap();
|
||||
assert!(settings.get::<Option<String>>("test_struct_option").unwrap().unwrap().is_none());
|
||||
settings
|
||||
.put("test_struct_option", &Option::<String>::None)
|
||||
.unwrap();
|
||||
assert!(settings
|
||||
.get::<Option<String>>("test_struct_option")
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.is_none());
|
||||
|
||||
settings.put("test_struct_option", &Option::<String>::Some("test".to_string())).unwrap();
|
||||
assert_eq!(settings.get::<Option<String>>("test_struct_option").unwrap().unwrap(), Some("test".to_string()));
|
||||
}).await;
|
||||
settings
|
||||
.put(
|
||||
"test_struct_option",
|
||||
&Option::<String>::Some("test".to_string()),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
settings
|
||||
.get::<Option<String>>("test_struct_option")
|
||||
.unwrap()
|
||||
.unwrap(),
|
||||
Some("test".to_string())
|
||||
);
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user