From b1f171136abbf0275eb03f3cfc06a0f6d18afb31 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 25 Apr 2025 16:34:00 -0700 Subject: [PATCH] refactor: with_repository/with_settings --- kordophone-db/src/database.rs | 18 +- kordophone-db/src/repository.rs | 37 ++-- kordophone-db/src/settings.rs | 16 +- kordophone-db/src/tests/mod.rs | 305 ++++++++++++++++---------------- kpcli/src/db/mod.rs | 100 ++++++----- 5 files changed, 249 insertions(+), 227 deletions(-) diff --git a/kordophone-db/src/database.rs b/kordophone-db/src/database.rs index 29bb6fd..ca53285 100644 --- a/kordophone-db/src/database.rs +++ b/kordophone-db/src/database.rs @@ -8,7 +8,7 @@ use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!(); pub struct Database { - pub connection: SqliteConnection, + connection: SqliteConnection, } impl Database { @@ -24,11 +24,19 @@ impl Database { Self::new(":memory:") } - pub fn get_repository(&mut self) -> Repository { - Repository::new(self) + pub fn with_repository(&mut self, f: F) -> R + where + F: FnOnce(&mut Repository) -> R, + { + let mut repository = Repository::new(&mut self.connection); + f(&mut repository) } - pub fn get_settings(&mut self) -> Settings { - Settings::new(self) + pub fn with_settings(&mut self, f: F) -> R + where + F: FnOnce(&mut Settings) -> R, + { + let mut settings = Settings::new(&mut self.connection); + f(&mut settings) } } \ No newline at end of file diff --git a/kordophone-db/src/repository.rs b/kordophone-db/src/repository.rs index d6f48ee..a82457a 100644 --- a/kordophone-db/src/repository.rs +++ b/kordophone-db/src/repository.rs @@ -3,7 +3,6 @@ use diesel::prelude::*; use diesel::query_dsl::BelongingToDsl; use crate::{ - database::Database, models::{ Conversation, Message, @@ -20,12 +19,12 @@ use crate::{ }; pub struct Repository<'a> { - db: &'a mut Database, + connection: &'a mut SqliteConnection, } impl<'a> Repository<'a> { - pub fn new(db: &'a mut Database) -> Self { - Self { db } + pub fn new(connection: &'a mut SqliteConnection) -> Self { + Self { connection } } pub fn insert_conversation(&mut self, conversation: Conversation) -> Result<()> { @@ -37,25 +36,25 @@ impl<'a> Repository<'a> { diesel::replace_into(conversations) .values(&db_conversation) - .execute(&mut self.db.connection)?; + .execute(self.connection)?; diesel::replace_into(participants) .values(&db_participants) - .execute(&mut self.db.connection)?; + .execute(self.connection)?; // 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.connection)?; + .first::(self.connection)?; diesel::replace_into(conversation_participants) .values(( conversation_id.eq(&db_conversation.id), participant_id.eq(pid), )) - .execute(&mut self.db.connection)?; + .execute(self.connection)?; } Ok(()) @@ -67,14 +66,14 @@ impl<'a> Repository<'a> { let result = conversations .find(match_guid) - .first::(&mut self.db.connection) + .first::(self.connection) .optional()?; if let Some(conversation) = result { let db_participants = ConversationParticipant::belonging_to(&conversation) .inner_join(participants) .select(ParticipantRecord::as_select()) - .load::(&mut self.db.connection)?; + .load::(self.connection)?; let mut model_conversation: Conversation = conversation.into(); model_conversation.participants = db_participants.into_iter().map(|p| p.into()).collect(); @@ -90,14 +89,14 @@ impl<'a> Repository<'a> { use crate::schema::participants::dsl::*; let db_conversations = conversations - .load::(&mut self.db.connection)?; + .load::(self.connection)?; let mut result = Vec::new(); for db_conversation in db_conversations { let db_participants = ConversationParticipant::belonging_to(&db_conversation) .inner_join(participants) .select(ParticipantRecord::as_select()) - .load::(&mut self.db.connection)?; + .load::(self.connection)?; let mut model_conversation: Conversation = db_conversation.into(); model_conversation.participants = db_participants.into_iter().map(|p| p.into()).collect(); @@ -119,14 +118,14 @@ impl<'a> Repository<'a> { diesel::replace_into(messages) .values(&db_message) - .execute(&mut self.db.connection)?; + .execute(self.connection)?; diesel::replace_into(conversation_messages) .values(( conversation_id.eq(conversation_guid), message_id.eq(&db_message.id), )) - .execute(&mut self.db.connection)?; + .execute(self.connection)?; Ok(()) } @@ -141,7 +140,7 @@ impl<'a> Repository<'a> { .inner_join(messages) .select(MessageRecord::as_select()) .order_by(schema::messages::date.asc()) - .load::(&mut self.db.connection)?; + .load::(self.connection)?; let mut result = Vec::new(); for message_record in message_records { @@ -151,7 +150,7 @@ impl<'a> Repository<'a> { if let Some(pid) = message_record.sender_participant_id { let participant = participants .find(pid) - .first::(&mut self.db.connection)?; + .first::(self.connection)?; message.sender = participant.into(); } @@ -166,7 +165,7 @@ impl<'a> Repository<'a> { // Huge caveat with this is that it depends on whatever the last insert was, prevents concurrent inserts. fn last_insert_id(&mut self) -> Result { Ok(diesel::select(diesel::dsl::sql::("last_insert_rowid()")) - .get_result(&mut self.db.connection)?) + .get_result(self.connection)?) } fn get_or_create_participant(&mut self, participant: &Participant) -> Option { @@ -177,7 +176,7 @@ impl<'a> Repository<'a> { let existing_participant = participants .filter(display_name.eq(p_name)) - .first::(&mut self.db.connection) + .first::(self.connection) .optional() .unwrap(); @@ -192,7 +191,7 @@ impl<'a> Repository<'a> { diesel::insert_into(participants) .values(&participant_record) - .execute(&mut self.db.connection) + .execute(self.connection) .unwrap(); self.last_insert_id().ok() diff --git a/kordophone-db/src/settings.rs b/kordophone-db/src/settings.rs index ae6175a..4c14dcb 100644 --- a/kordophone-db/src/settings.rs +++ b/kordophone-db/src/settings.rs @@ -1,7 +1,7 @@ use diesel::*; use serde::{Serialize, de::DeserializeOwned}; use anyhow::Result; -use crate::database::Database; + #[derive(Insertable, Queryable, AsChangeset)] #[diesel(table_name = crate::schema::settings)] struct SettingsRow<'a> { @@ -10,12 +10,12 @@ struct SettingsRow<'a> { } pub struct Settings<'a> { - db: &'a mut Database, + connection: &'a mut SqliteConnection, } impl<'a> Settings<'a> { - pub fn new(db: &'a mut Database) -> Self { - Self { db } + pub fn new(connection: &'a mut SqliteConnection) -> Self { + Self { connection } } pub fn put( @@ -31,7 +31,7 @@ impl<'a> Settings<'a> { .on_conflict(key) .do_update() .set(value.eq(&bytes)) - .execute(&mut self.db.connection)?; + .execute(self.connection)?; Ok(()) } @@ -44,7 +44,7 @@ impl<'a> Settings<'a> { let blob: Option> = settings .select(value) .filter(key.eq(k)) - .first(&mut self.db.connection) + .first(self.connection) .optional()?; Ok(match blob { @@ -55,14 +55,14 @@ impl<'a> Settings<'a> { pub fn del(&mut self, k: &str) -> Result { use crate::schema::settings::dsl::*; - Ok(diesel::delete(settings.filter(key.eq(k))).execute(&mut self.db.connection)?) + Ok(diesel::delete(settings.filter(key.eq(k))).execute(self.connection)?) } pub fn list_keys(&mut self) -> Result> { use crate::schema::settings::dsl::*; let keys: Vec = settings .select(key) - .load(&mut self.db.connection)?; + .load(self.connection)?; Ok(keys) } diff --git a/kordophone-db/src/tests/mod.rs b/kordophone-db/src/tests/mod.rs index 961f486..535becc 100644 --- a/kordophone-db/src/tests/mod.rs +++ b/kordophone-db/src/tests/mod.rs @@ -28,222 +28,221 @@ fn participants_vec_equal_ignoring_id(a: &[Participant], b: &[Participant]) -> b #[test] fn test_database_init() { - let mut db = Database::new_in_memory().unwrap(); - let _ = Repository::new(&mut db); + let _ = Database::new_in_memory().unwrap(); } #[test] fn test_add_conversation() { let mut db = Database::new_in_memory().unwrap(); - let mut repository = db.get_repository(); + db.with_repository(|repository| { + let guid = "test"; + let test_conversation = Conversation::builder() + .guid(guid) + .unread_count(2) + .display_name("Test Conversation") + .build(); - let guid = "test"; - let test_conversation = Conversation::builder() - .guid(guid) - .unread_count(2) - .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 + let conversation = repository.get_conversation_by_guid(guid).unwrap().unwrap(); + assert_eq!(conversation.guid, "test"); - // 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() + .display_name("Modified Conversation") + .build(); - // Modify the conversation and update it - 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. + let all_conversations = repository.all_conversations().unwrap(); + assert_eq!(all_conversations.len(), 1); - // Make sure we still only have one conversation. - let all_conversations = repository.all_conversations().unwrap(); - assert_eq!(all_conversations.len(), 1); - - // 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"); + // 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"); + }); } #[test] fn test_conversation_participants() { let mut db = Database::new_in_memory().unwrap(); - let mut repository = db.get_repository(); + db.with_repository(|repository| { + let participants: Vec = vec!["one".into(), "two".into()]; - let participants: Vec = vec!["one".into(), "two".into()]; + let guid = uuid::Uuid::new_v4().to_string(); + let conversation = ConversationBuilder::new() + .guid(&guid) + .display_name("Test") + .participants(participants.clone()) + .build(); - let guid = uuid::Uuid::new_v4().to_string(); - let conversation = ConversationBuilder::new() - .guid(&guid) - .display_name("Test") - .participants(participants.clone()) - .build(); + repository.insert_conversation(conversation).unwrap(); - repository.insert_conversation(conversation).unwrap(); + let read_conversation = repository.get_conversation_by_guid(&guid).unwrap().unwrap(); + let read_participants = read_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() + .display_name("A Different Test") + .participants(participants.clone()) + .build(); - // Try making another conversation with the same participants - let conversation = ConversationBuilder::new() - .display_name("A Different Test") - .participants(participants.clone()) - .build(); + repository.insert_conversation(conversation).unwrap(); - repository.insert_conversation(conversation).unwrap(); + let read_conversation = repository.get_conversation_by_guid(&guid).unwrap().unwrap(); + let read_participants: Vec = read_conversation.participants; - let read_conversation = repository.get_conversation_by_guid(&guid).unwrap().unwrap(); - let read_participants: Vec = read_conversation.participants; - - assert!(participants_vec_equal_ignoring_id(&participants, &read_participants)); + assert!(participants_vec_equal_ignoring_id(&participants, &read_participants)); + }); } #[test] fn test_all_conversations_with_participants() { let mut db = Database::new_in_memory().unwrap(); - let mut repository = db.get_repository(); + db.with_repository(|repository| { + // Create two conversations with different participants + let participants1: Vec = vec!["one".into(), "two".into()]; + let participants2: Vec = vec!["three".into(), "four".into()]; - // Create two conversations with different participants - let participants1: Vec = vec!["one".into(), "two".into()]; - let participants2: Vec = vec!["three".into(), "four".into()]; + let guid1 = uuid::Uuid::new_v4().to_string(); + let conversation1 = ConversationBuilder::new() + .guid(&guid1) + .display_name("Test 1") + .participants(participants1.clone()) + .build(); - let guid1 = uuid::Uuid::new_v4().to_string(); - let conversation1 = ConversationBuilder::new() - .guid(&guid1) - .display_name("Test 1") - .participants(participants1.clone()) - .build(); + let guid2 = uuid::Uuid::new_v4().to_string(); + let conversation2 = ConversationBuilder::new() + .guid(&guid2) + .display_name("Test 2") + .participants(participants2.clone()) + .build(); - let guid2 = uuid::Uuid::new_v4().to_string(); - let conversation2 = ConversationBuilder::new() - .guid(&guid2) - .display_name("Test 2") - .participants(participants2.clone()) - .build(); + // Insert both conversations + repository.insert_conversation(conversation1).unwrap(); + repository.insert_conversation(conversation2).unwrap(); - // Insert both conversations - repository.insert_conversation(conversation1).unwrap(); - repository.insert_conversation(conversation2).unwrap(); + // Get all conversations and verify the results + let all_conversations = repository.all_conversations().unwrap(); + assert_eq!(all_conversations.len(), 2); - // Get all conversations and verify the results - let all_conversations = repository.all_conversations().unwrap(); - assert_eq!(all_conversations.len(), 2); + // Find and verify each conversation's participants + let conv1 = all_conversations.iter().find(|c| c.guid == guid1).unwrap(); + let conv2 = all_conversations.iter().find(|c| c.guid == guid2).unwrap(); - // Find and verify each conversation's 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)); + assert!(participants_vec_equal_ignoring_id(&conv1.participants, &participants1)); + assert!(participants_vec_equal_ignoring_id(&conv2.participants, &participants2)); + }); } #[test] fn test_messages() { let mut db = Database::new_in_memory().unwrap(); - let mut repository = db.get_repository(); + db.with_repository(|repository| { + // First create a conversation with participants + let participants = vec!["Alice".into(), "Bob".into()]; + let conversation = ConversationBuilder::new() + .display_name("Test Chat") + .participants(participants) + .build(); + let conversation_id = conversation.guid.clone(); - // First create a conversation with participants - let participants = vec!["Alice".into(), "Bob".into()]; - let conversation = ConversationBuilder::new() - .display_name("Test Chat") - .participants(participants) - .build(); - let conversation_id = conversation.guid.clone(); + repository.insert_conversation(conversation).unwrap(); - repository.insert_conversation(conversation).unwrap(); + // Create and insert a message from Me + let message1 = Message::builder() + .text("Hello everyone!".to_string()) + .build(); - // Create and insert a message from Me - let message1 = Message::builder() - .text("Hello everyone!".to_string()) - .build(); + // Create and insert a message from a remote participant + let message2 = Message::builder() + .text("Hi there!".to_string()) + .sender("Alice".into()) + .build(); - // Create and insert a message from a remote participant - let message2 = Message::builder() - .text("Hi there!".to_string()) - .sender("Alice".into()) - .build(); + // Insert both messages + repository.insert_message(&conversation_id, message1.clone()).unwrap(); + repository.insert_message(&conversation_id, message2.clone()).unwrap(); - // Insert both messages - 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(); + assert_eq!(messages.len(), 2); - // Retrieve messages - let messages = repository.get_messages_for_conversation(&conversation_id).unwrap(); - assert_eq!(messages.len(), 2); + // Verify first message (from Me) + let retrieved_message1 = messages.iter().find(|m| m.id == message1.id).unwrap(); + assert_eq!(retrieved_message1.text, "Hello everyone!"); + assert!(matches!(retrieved_message1.sender, Participant::Me)); - // Verify first message (from Me) - let retrieved_message1 = messages.iter().find(|m| m.id == message1.id).unwrap(); - assert_eq!(retrieved_message1.text, "Hello everyone!"); - assert!(matches!(retrieved_message1.sender, Participant::Me)); - - // Verify second message (from Alice) - let retrieved_message2 = messages.iter().find(|m| m.id == message2.id).unwrap(); - assert_eq!(retrieved_message2.text, "Hi there!"); - if let Participant::Remote { display_name, .. } = &retrieved_message2.sender { - assert_eq!(display_name, "Alice"); - } else { - panic!("Expected Remote participant. Got: {:?}", retrieved_message2.sender); - } + // Verify second message (from Alice) + let retrieved_message2 = messages.iter().find(|m| m.id == message2.id).unwrap(); + assert_eq!(retrieved_message2.text, "Hi there!"); + if let Participant::Remote { display_name, .. } = &retrieved_message2.sender { + assert_eq!(display_name, "Alice"); + } else { + panic!("Expected Remote participant. Got: {:?}", retrieved_message2.sender); + } + }); } #[test] fn test_message_ordering() { let mut db = Database::new_in_memory().unwrap(); - let mut repository = db.get_repository(); + db.with_repository(|repository| { + // Create a conversation + let conversation = ConversationBuilder::new() + .display_name("Test Chat") + .build(); + let conversation_id = conversation.guid.clone(); + repository.insert_conversation(conversation).unwrap(); - // Create a conversation - let conversation = ConversationBuilder::new() - .display_name("Test Chat") - .build(); - let conversation_id = conversation.guid.clone(); - repository.insert_conversation(conversation).unwrap(); + // Create messages with specific timestamps + let now = chrono::Utc::now().naive_utc(); + let message1 = Message::builder() + .text("First message".to_string()) + .date(now) + .build(); - // Create messages with specific timestamps - let now = chrono::Utc::now().naive_utc(); - let message1 = Message::builder() - .text("First message".to_string()) - .date(now) - .build(); + let message2 = Message::builder() + .text("Second message".to_string()) + .date(now + chrono::Duration::minutes(1)) + .build(); - let message2 = Message::builder() - .text("Second message".to_string()) - .date(now + chrono::Duration::minutes(1)) - .build(); + let message3 = Message::builder() + .text("Third message".to_string()) + .date(now + chrono::Duration::minutes(2)) + .build(); - let message3 = Message::builder() - .text("Third message".to_string()) - .date(now + chrono::Duration::minutes(2)) - .build(); + // Insert messages + repository.insert_message(&conversation_id, message1).unwrap(); + repository.insert_message(&conversation_id, message2).unwrap(); + repository.insert_message(&conversation_id, message3).unwrap(); - // Insert messages - 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(); + assert_eq!(messages.len(), 3); - // Retrieve messages and verify order - 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); - } + // Messages should be ordered by date + for i in 1..messages.len() { + assert!(messages[i].date > messages[i-1].date); + } + }); } #[test] fn test_settings() { let mut db = Database::new_in_memory().unwrap(); - let mut settings = db.get_settings(); + db.with_settings(|settings| { + settings.put("test", &"test".to_string()).unwrap(); + assert_eq!(settings.get::("test").unwrap().unwrap(), "test"); - settings.put("test", &"test".to_string()).unwrap(); - assert_eq!(settings.get::("test").unwrap().unwrap(), "test"); + settings.del("test").unwrap(); + assert!(settings.get::("test").unwrap().is_none()); - settings.del("test").unwrap(); - assert!(settings.get::("test").unwrap().is_none()); - - let keys = settings.list_keys().unwrap(); - assert_eq!(keys.len(), 0); + let keys = settings.list_keys().unwrap(); + assert_eq!(keys.len(), 0); + }); } diff --git a/kpcli/src/db/mod.rs b/kpcli/src/db/mod.rs index 73f5dc8..a183938 100644 --- a/kpcli/src/db/mod.rs +++ b/kpcli/src/db/mod.rs @@ -108,7 +108,9 @@ impl DbClient { } pub fn print_conversations(&mut self) -> Result<()> { - let all_conversations = self.database.get_repository().all_conversations()?; + let all_conversations = self.database.with_repository(|repository| { + repository.all_conversations() + })?; println!("{} Conversations: ", all_conversations.len()); for conversation in all_conversations { @@ -119,7 +121,10 @@ impl DbClient { } pub async fn print_messages(&mut self, conversation_id: &str) -> Result<()> { - let messages = self.database.get_repository().get_messages_for_conversation(conversation_id)?; + let messages = self.database.with_repository(|repository| { + repository.get_messages_for_conversation(conversation_id) + })?; + for message in messages { println!("{}", MessagePrinter::new(&message.into())); } @@ -133,10 +138,14 @@ impl DbClient { .map(|c| kordophone_db::models::Conversation::from(c)) .collect(); - let mut repository = self.database.get_repository(); + // Process each conversation for conversation in db_conversations { let conversation_id = conversation.guid.clone(); - repository.insert_conversation(conversation)?; + + // Insert the conversation + self.database.with_repository(|repository| { + repository.insert_conversation(conversation) + })?; // Fetch and sync messages for this conversation let messages = client.get_messages(&conversation_id).await?; @@ -144,59 +153,66 @@ impl DbClient { .map(|m| kordophone_db::models::Message::from(m)) .collect(); - for message in db_messages { - repository.insert_message(&conversation_id, message)?; - } + // Insert each message + self.database.with_repository(|repository| -> Result<()> { + for message in db_messages { + repository.insert_message(&conversation_id, message)?; + } + + Ok(()) + })?; } Ok(()) } pub fn get_setting(&mut self, key: Option) -> Result<()> { - let mut settings = self.database.get_settings(); - - match key { - Some(key) => { - // Get a specific setting - let value: Option = settings.get(&key)?; - match value { - Some(v) => println!("{} = {}", key, v), - None => println!("Setting '{}' not found", key), - } - }, - None => { - // List all settings - let keys = settings.list_keys()?; - if keys.is_empty() { - println!("No settings found"); - } else { - println!("Settings:"); - for key in keys { - let value: Option = settings.get(&key)?; - match value { - Some(v) => println!(" {} = {}", key, v), - None => println!(" {} = ", key), + self.database.with_settings(|settings| { + match key { + Some(key) => { + // Get a specific setting + let value: Option = settings.get(&key)?; + match value { + Some(v) => println!("{} = {}", key, v), + None => println!("Setting '{}' not found", key), + } + }, + None => { + // List all settings + let keys = settings.list_keys()?; + if keys.is_empty() { + println!("No settings found"); + } else { + println!("Settings:"); + for key in keys { + let value: Option = settings.get(&key)?; + match value { + Some(v) => println!(" {} = {}", key, v), + None => println!(" {} = ", key), + } } } } } - } - - Ok(()) + + Ok(()) + }) } pub fn put_setting(&mut self, key: String, value: String) -> Result<()> { - let mut settings = self.database.get_settings(); - settings.put(&key, &value)?; - Ok(()) + self.database.with_settings(|settings| { + settings.put(&key, &value)?; + Ok(()) + }) } pub fn delete_setting(&mut self, key: String) -> Result<()> { - let mut settings = self.database.get_settings(); - let count = settings.del(&key)?; - if count == 0 { - println!("Setting '{}' not found", key); - } - Ok(()) + self.database.with_settings(|settings| { + let count = settings.del(&key)?; + if count == 0 { + println!("Setting '{}' not found", key); + } + Ok(()) + }) } }