From 95f939cb07afea15230caaa71831ff23c136dc15 Mon Sep 17 00:00:00 2001 From: Elias Projahn Date: Sun, 11 Oct 2020 19:53:36 +0200 Subject: [PATCH] Use anyhow for backend errors --- Cargo.toml | 1 + src/backend.rs | 140 ++++---- src/database/database.rs | 514 +++++++++++++++-------------- src/dialogs/ensemble_selector.rs | 2 + src/dialogs/instrument_selector.rs | 2 + src/dialogs/person_selector.rs | 2 + src/dialogs/work_selector.rs | 4 +- src/window.rs | 11 +- 8 files changed, 336 insertions(+), 340 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 95aeaca..beb9fa2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2018" [dependencies] +anyhow = "1.0.33" diesel = { version = "1.4.5", features = ["sqlite"] } diesel_migrations = "1.4.0" gio = "0.9.1" diff --git a/src/backend.rs b/src/backend.rs index c3c1453..9dc1632 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -1,25 +1,26 @@ use super::database::*; +use anyhow::Result; use glib::Sender; enum BackendAction { - UpdatePerson(Person, Sender>), - GetPerson(i64, Sender>), - DeletePerson(i64, Sender>), - GetPersons(Sender>), - UpdateInstrument(Instrument, Sender>), - GetInstrument(i64, Sender>), - DeleteInstrument(i64, Sender>), - GetInstruments(Sender>), - UpdateWork(WorkInsertion, Sender>), - GetWorkDescriptions(i64, Sender>), - UpdateEnsemble(Ensemble, Sender>), - GetEnsemble(i64, Sender>), - DeleteEnsemble(i64, Sender>), - GetEnsembles(Sender>), - UpdateRecording(RecordingInsertion, Sender>), - GetRecordingsForPerson(i64, Sender>), - GetRecordingsForEnsemble(i64, Sender>), - GetRecordingsForWork(i64, Sender>), + UpdatePerson(Person, Sender>), + GetPerson(i64, Sender>), + DeletePerson(i64, Sender>), + GetPersons(Sender>>), + UpdateInstrument(Instrument, Sender>), + GetInstrument(i64, Sender>), + DeleteInstrument(i64, Sender>), + GetInstruments(Sender>>), + UpdateWork(WorkInsertion, Sender>), + GetWorkDescriptions(i64, Sender>>), + UpdateEnsemble(Ensemble, Sender>), + GetEnsemble(i64, Sender>), + DeleteEnsemble(i64, Sender>), + GetEnsembles(Sender>>), + UpdateRecording(RecordingInsertion, Sender>), + GetRecordingsForPerson(i64, Sender>>), + GetRecordingsForEnsemble(i64, Sender>>), + GetRecordingsForWork(i64, Sender>>), } use BackendAction::*; @@ -35,7 +36,7 @@ impl Backend { let (action_sender, action_receiver) = std::sync::mpsc::channel::(); std::thread::spawn(move || { - let db = Database::new(&url); + let db = Database::new(&url).expect("Failed to open database!"); for action in action_receiver { match action { @@ -156,13 +157,8 @@ impl Backend { } } - pub fn update_person) -> () + 'static>( - &self, - person: Person, - callback: F, - ) { - let (sender, receiver) = - glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + pub fn update_person) -> () + 'static>(&self, person: Person, callback: F) { + let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); receiver.attach(None, move |result| { callback(result); @@ -174,9 +170,8 @@ impl Backend { .expect("Failed to send action to database thread!"); } - pub fn get_person) -> () + 'static>(&self, id: i64, callback: F) { - let (sender, receiver) = - glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + pub fn get_person) -> () + 'static>(&self, id: i64, callback: F) { + let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); receiver.attach(None, move |result| { callback(result); @@ -188,9 +183,8 @@ impl Backend { .expect("Failed to send action to database thread!"); } - pub fn delete_person) -> () + 'static>(&self, id: i64, callback: F) { - let (sender, receiver) = - glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + pub fn delete_person) -> () + 'static>(&self, id: i64, callback: F) { + let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); receiver.attach(None, move |result| { callback(result); @@ -202,8 +196,8 @@ impl Backend { .expect("Failed to send action to database thread!"); } - pub fn get_persons) -> () + 'static>(&self, callback: F) { - let (sender, receiver) = glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + pub fn get_persons>) -> () + 'static>(&self, callback: F) { + let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); receiver.attach(None, move |result| { callback(result); @@ -215,13 +209,12 @@ impl Backend { .expect("Failed to send action to database thread!"); } - pub fn update_instrument) -> () + 'static>( + pub fn update_instrument) -> () + 'static>( &self, instrument: Instrument, callback: F, ) { - let (sender, receiver) = - glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); receiver.attach(None, move |result| { callback(result); @@ -233,9 +226,8 @@ impl Backend { .expect("Failed to send action to database thread!"); } - pub fn get_instrument) -> () + 'static>(&self, id: i64, callback: F) { - let (sender, receiver) = - glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + pub fn get_instrument) -> () + 'static>(&self, id: i64, callback: F) { + let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); receiver.attach(None, move |result| { callback(result); @@ -247,13 +239,8 @@ impl Backend { .expect("Failed to send action to database thread!"); } - pub fn delete_instrument) -> () + 'static>( - &self, - id: i64, - callback: F, - ) { - let (sender, receiver) = - glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + pub fn delete_instrument) -> () + 'static>(&self, id: i64, callback: F) { + let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); receiver.attach(None, move |result| { callback(result); @@ -265,9 +252,8 @@ impl Backend { .expect("Failed to send action to database thread!"); } - pub fn get_instruments) -> () + 'static>(&self, callback: F) { - let (sender, receiver) = - glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + pub fn get_instruments>) -> () + 'static>(&self, callback: F) { + let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); receiver.attach(None, move |result| { callback(result); @@ -279,13 +265,8 @@ impl Backend { .expect("Failed to send action to database thread!"); } - pub fn update_work) -> () + 'static>( - &self, - work: WorkInsertion, - callback: F, - ) { - let (sender, receiver) = - glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + pub fn update_work) -> () + 'static>(&self, work: WorkInsertion, callback: F) { + let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); receiver.attach(None, move |result| { callback(result); @@ -297,13 +278,12 @@ impl Backend { .expect("Failed to send action to database thread!"); } - pub fn get_work_descriptions) -> () + 'static>( + pub fn get_work_descriptions>) -> () + 'static>( &self, id: i64, callback: F, ) { - let (sender, receiver) = - glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); receiver.attach(None, move |result| { callback(result); @@ -315,13 +295,12 @@ impl Backend { .expect("Failed to send action to database thread!"); } - pub fn update_ensemble) -> () + 'static>( + pub fn update_ensemble) -> () + 'static>( &self, ensemble: Ensemble, callback: F, ) { - let (sender, receiver) = - glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); receiver.attach(None, move |result| { callback(result); @@ -333,9 +312,8 @@ impl Backend { .expect("Failed to send action to database thread!"); } - pub fn get_ensemble) -> () + 'static>(&self, id: i64, callback: F) { - let (sender, receiver) = - glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + pub fn get_ensemble) -> () + 'static>(&self, id: i64, callback: F) { + let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); receiver.attach(None, move |result| { callback(result); @@ -347,9 +325,8 @@ impl Backend { .expect("Failed to send action to database thread!"); } - pub fn delete_ensemble) -> () + 'static>(&self, id: i64, callback: F) { - let (sender, receiver) = - glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + pub fn delete_ensemble) -> () + 'static>(&self, id: i64, callback: F) { + let (sender, receiver) = glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); receiver.attach(None, move |result| { callback(result); @@ -361,9 +338,8 @@ impl Backend { .expect("Failed to send action to database thread!"); } - pub fn get_ensembles) -> () + 'static>(&self, callback: F) { - let (sender, receiver) = - glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + pub fn get_ensembles>) -> () + 'static>(&self, callback: F) { + let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); receiver.attach(None, move |result| { callback(result); @@ -375,13 +351,12 @@ impl Backend { .expect("Failed to send action to database thread!"); } - pub fn update_recording) -> () + 'static>( + pub fn update_recording) -> () + 'static>( &self, recording: RecordingInsertion, callback: F, ) { - let (sender, receiver) = - glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); receiver.attach(None, move |result| { callback(result); @@ -393,13 +368,12 @@ impl Backend { .expect("Failed to send action to database thread!"); } - pub fn get_recordings_for_person) -> () + 'static>( + pub fn get_recordings_for_person>) -> () + 'static>( &self, id: i64, callback: F, ) { - let (sender, receiver) = - glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); receiver.attach(None, move |result| { callback(result); @@ -411,13 +385,12 @@ impl Backend { .expect("Failed to send action to database thread!"); } - pub fn get_recordings_for_ensemble) -> () + 'static>( + pub fn get_recordings_for_ensemble>) -> () + 'static>( &self, id: i64, callback: F, ) { - let (sender, receiver) = - glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); receiver.attach(None, move |result| { callback(result); @@ -429,13 +402,12 @@ impl Backend { .expect("Failed to send action to database thread!"); } - pub fn get_recordings_for_work) -> () + 'static>( + pub fn get_recordings_for_work>) -> () + 'static>( &self, id: i64, callback: F, ) { - let (sender, receiver) = - glib::MainContext::channel::>(glib::PRIORITY_DEFAULT); + let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); receiver.attach(None, move |result| { callback(result); diff --git a/src/database/database.rs b/src/database/database.rs index 447e685..85ba0b8 100644 --- a/src/database/database.rs +++ b/src/database/database.rs @@ -1,6 +1,7 @@ use super::models::*; use super::schema::*; use super::tables::*; +use anyhow::{anyhow, Result}; use diesel::prelude::*; embed_migrations!(); @@ -10,385 +11,392 @@ pub struct Database { } impl Database { - pub fn new(path: &str) -> Database { - let c = SqliteConnection::establish(path) - .expect(&format!("Failed to connect to database at \"{}\"!", path)); + pub fn new(path: &str) -> Result { + let c = SqliteConnection::establish(path)?; - diesel::sql_query("PRAGMA foreign_keys = ON;") - .execute(&c) - .expect("Failed to activate foreign key support!"); + diesel::sql_query("PRAGMA foreign_keys = ON;").execute(&c)?; + embedded_migrations::run(&c)?; - embedded_migrations::run(&c).expect("Failed to run migrations!"); - - Database { c: c } + Ok(Database { c: c }) } - pub fn update_person(&self, person: Person) { + pub fn update_person(&self, person: Person) -> Result<()> { self.defer_foreign_keys(); - self.c - .transaction(|| { - diesel::replace_into(persons::table) - .values(person) - .execute(&self.c) - }) - .expect("Failed to insert person!"); + self.c.transaction(|| { + diesel::replace_into(persons::table) + .values(person) + .execute(&self.c) + })?; + + Ok(()) } - pub fn get_person(&self, id: i64) -> Option { + pub fn get_person(&self, id: i64) -> Result { persons::table .filter(persons::id.eq(id)) - .load::(&self.c) - .expect("Error loading person!") + .load::(&self.c)? .first() .cloned() + .ok_or(anyhow!("No person with ID: {}", id)) } - pub fn delete_person(&self, id: i64) { - diesel::delete(persons::table.filter(persons::id.eq(id))) - .execute(&self.c) - .expect("Failed to delete person!"); + pub fn delete_person(&self, id: i64) -> Result<()> { + diesel::delete(persons::table.filter(persons::id.eq(id))).execute(&self.c)?; + Ok(()) } - pub fn get_persons(&self) -> Vec { - persons::table - .load::(&self.c) - .expect("Error loading persons!") + pub fn get_persons(&self) -> Result> { + let persons = persons::table.load::(&self.c)?; + Ok(persons) } - pub fn update_instrument(&self, instrument: Instrument) { + pub fn update_instrument(&self, instrument: Instrument) -> Result<()> { self.defer_foreign_keys(); - self.c - .transaction(|| { - diesel::replace_into(instruments::table) - .values(instrument) - .execute(&self.c) - }) - .expect("Failed to insert instrument!"); + self.c.transaction(|| { + diesel::replace_into(instruments::table) + .values(instrument) + .execute(&self.c) + })?; + + Ok(()) } - pub fn get_instrument(&self, id: i64) -> Option { + pub fn get_instrument(&self, id: i64) -> Result { instruments::table .filter(instruments::id.eq(id)) - .load::(&self.c) - .expect("Error loading instrument!") + .load::(&self.c)? .first() .cloned() + .ok_or(anyhow!("No instrument with ID: {}", id)) } - pub fn delete_instrument(&self, id: i64) { - diesel::delete(instruments::table.filter(instruments::id.eq(id))) - .execute(&self.c) - .expect("Failed to delete instrument!"); + pub fn delete_instrument(&self, id: i64) -> Result<()> { + diesel::delete(instruments::table.filter(instruments::id.eq(id))).execute(&self.c)?; + Ok(()) } - pub fn get_instruments(&self) -> Vec { - instruments::table - .load::(&self.c) - .expect("Error loading instruments!") + pub fn get_instruments(&self) -> Result> { + let instruments = instruments::table.load::(&self.c)?; + Ok(instruments) } - pub fn update_work(&self, work_insertion: WorkInsertion) { + pub fn update_work(&self, work_insertion: WorkInsertion) -> Result<()> { let id = work_insertion.work.id; self.defer_foreign_keys(); - self.c - .transaction(|| { - self.delete_work(id); + self.c.transaction(|| { + self.delete_work(id); - diesel::insert_into(works::table) - .values(work_insertion.work) + diesel::insert_into(works::table) + .values(work_insertion.work) + .execute(&self.c)?; + + for instrument_id in work_insertion.instrument_ids { + diesel::insert_into(instrumentations::table) + .values(Instrumentation { + id: rand::random(), + work: id, + instrument: instrument_id, + }) + .execute(&self.c)?; + } + + for part_insertion in work_insertion.parts { + let part_id = part_insertion.part.id; + + diesel::insert_into(work_parts::table) + .values(part_insertion.part) .execute(&self.c)?; - for instrument_id in work_insertion.instrument_ids { - diesel::insert_into(instrumentations::table) - .values(Instrumentation { + for instrument_id in part_insertion.instrument_ids { + diesel::insert_into(part_instrumentations::table) + .values(PartInstrumentation { id: rand::random(), - work: id, + work_part: part_id, instrument: instrument_id, }) .execute(&self.c)?; } + } - for part_insertion in work_insertion.parts { - let part_id = part_insertion.part.id; + for section in work_insertion.sections { + diesel::insert_into(work_sections::table) + .values(section) + .execute(&self.c)?; + } - diesel::insert_into(work_parts::table) - .values(part_insertion.part) - .execute(&self.c)?; + diesel::result::QueryResult::Ok(()) + })?; - for instrument_id in part_insertion.instrument_ids { - diesel::insert_into(part_instrumentations::table) - .values(PartInstrumentation { - id: rand::random(), - work_part: part_id, - instrument: instrument_id, - }) - .execute(&self.c)?; - } - } - - for section in work_insertion.sections { - diesel::insert_into(work_sections::table) - .values(section) - .execute(&self.c)?; - } - - diesel::result::QueryResult::Ok(()) - }) - .expect("Failed to update work!"); + Ok(()) } - pub fn get_work(&self, id: i64) -> Option { + pub fn get_work(&self, id: i64) -> Result { works::table .filter(works::id.eq(id)) - .load::(&self.c) - .expect("Error loading work!") + .load::(&self.c)? .first() .cloned() + .ok_or(anyhow!("No work with ID: {}", id)) } - pub fn get_work_description_for_work(&self, work: &Work) -> WorkDescription { - WorkDescription { + pub fn get_work_description_for_work(&self, work: &Work) -> Result { + let mut instruments: Vec = Vec::new(); + + let instrumentations = instrumentations::table + .filter(instrumentations::work.eq(work.id)) + .load::(&self.c)?; + + for instrumentation in instrumentations { + instruments.push(self.get_instrument(instrumentation.instrument)?); + } + + let mut part_descriptions: Vec = Vec::new(); + + let work_parts = work_parts::table + .filter(work_parts::work.eq(work.id)) + .load::(&self.c)?; + + for work_part in work_parts { + let mut part_instruments: Vec = Vec::new(); + + let part_instrumentations = part_instrumentations::table + .filter(part_instrumentations::work_part.eq(work_part.id)) + .load::(&self.c)?; + + for part_instrumentation in part_instrumentations { + part_instruments.push(self.get_instrument(part_instrumentation.instrument)?); + } + + part_descriptions.push(WorkPartDescription { + composer: match work_part.composer { + Some(composer) => Some(self.get_person(composer)?), + None => None, + }, + title: work_part.title.clone(), + instruments: part_instruments, + }); + } + + let mut section_descriptions: Vec = Vec::new(); + + let sections = work_sections::table + .filter(work_sections::work.eq(work.id)) + .load::(&self.c)?; + + for section in sections { + section_descriptions.push(WorkSectionDescription { + title: section.title.clone(), + before_index: section.before_index, + }); + } + + let work_description = WorkDescription { id: work.id, - composer: self - .get_person(work.composer) - .expect("Could not find composer for work!"), + composer: self.get_person(work.composer)?, title: work.title.clone(), - instruments: instrumentations::table - .filter(instrumentations::work.eq(work.id)) - .load::(&self.c) - .expect("Failed to load instrumentations!") - .iter() - .map(|instrumentation| { - self.get_instrument(instrumentation.instrument) - .expect("Could not find instrument for instrumentation!") - }) - .collect(), - parts: work_parts::table - .filter(work_parts::work.eq(work.id)) - .load::(&self.c) - .expect("Failed to load work parts!") - .iter() - .map(|work_part| WorkPartDescription { - composer: match work_part.composer { - Some(composer) => Some( - self.get_person(composer) - .expect("Could not find composer for work part!"), - ), - None => None, - }, - title: work_part.title.clone(), - instruments: part_instrumentations::table - .filter(part_instrumentations::work_part.eq(work_part.id)) - .load::(&self.c) - .expect("Failed to load part instrumentations!") - .iter() - .map(|part_instrumentation| { - self.get_instrument(part_instrumentation.instrument) - .expect("Could not find instrument for part instrumentation!") - }) - .collect(), - }) - .collect(), - sections: work_sections::table - .filter(work_sections::work.eq(work.id)) - .load::(&self.c) - .expect("Failed to load work sections!") - .iter() - .map(|section| WorkSectionDescription { - title: section.title.clone(), - before_index: section.before_index, - }) - .collect(), - } + instruments: instruments, + parts: part_descriptions, + sections: section_descriptions, + }; + + Ok(work_description) } - pub fn get_work_description(&self, id: i64) -> Option { - match self.get_work(id) { - Some(work) => Some(self.get_work_description_for_work(&work)), - None => None, - } + pub fn get_work_description(&self, id: i64) -> Result { + let work = self.get_work(id)?; + let work_description = self.get_work_description_for_work(&work)?; + Ok(work_description) } - pub fn delete_work(&self, id: i64) { - diesel::delete(works::table.filter(works::id.eq(id))) - .execute(&self.c) - .expect("Failed to delete work!"); + pub fn delete_work(&self, id: i64) -> Result<()> { + diesel::delete(works::table.filter(works::id.eq(id))).execute(&self.c)?; + Ok(()) } - pub fn get_works(&self, composer_id: i64) -> Vec { - works::table + pub fn get_works(&self, composer_id: i64) -> Result> { + let works = works::table .filter(works::composer.eq(composer_id)) - .load::(&self.c) - .expect("Error loading works!") + .load::(&self.c)?; + + Ok(works) } - pub fn get_work_descriptions(&self, composer_id: i64) -> Vec { - self.get_works(composer_id) - .iter() - .map(|work| self.get_work_description_for_work(work)) - .collect() + pub fn get_work_descriptions(&self, composer_id: i64) -> Result> { + let mut work_descriptions: Vec = Vec::new(); + + let works = self.get_works(composer_id)?; + for work in works { + work_descriptions.push(self.get_work_description_for_work(&work)?); + } + + Ok(work_descriptions) } - pub fn update_ensemble(&self, ensemble: Ensemble) { + pub fn update_ensemble(&self, ensemble: Ensemble) -> Result<()> { self.defer_foreign_keys(); - self.c - .transaction(|| { - diesel::replace_into(ensembles::table) - .values(ensemble) - .execute(&self.c) - }) - .expect("Failed to insert ensemble!"); + self.c.transaction(|| { + diesel::replace_into(ensembles::table) + .values(ensemble) + .execute(&self.c) + })?; + + Ok(()) } - pub fn get_ensemble(&self, id: i64) -> Option { + pub fn get_ensemble(&self, id: i64) -> Result { ensembles::table .filter(ensembles::id.eq(id)) - .load::(&self.c) - .expect("Error loading ensemble!") + .load::(&self.c)? .first() .cloned() + .ok_or(anyhow!("No ensemble with ID: {}", id)) } - pub fn delete_ensemble(&self, id: i64) { - diesel::delete(ensembles::table.filter(ensembles::id.eq(id))) - .execute(&self.c) - .expect("Failed to delete ensemble!"); + pub fn delete_ensemble(&self, id: i64) -> Result<()> { + diesel::delete(ensembles::table.filter(ensembles::id.eq(id))).execute(&self.c)?; + Ok(()) } - pub fn get_ensembles(&self) -> Vec { - ensembles::table - .load::(&self.c) - .expect("Error loading ensembles!") + pub fn get_ensembles(&self) -> Result> { + let ensembles = ensembles::table.load::(&self.c)?; + Ok(ensembles) } - pub fn update_recording(&self, recording_insertion: RecordingInsertion) { + pub fn update_recording(&self, recording_insertion: RecordingInsertion) -> Result<()> { let id = recording_insertion.recording.id; self.defer_foreign_keys(); - self.c - .transaction(|| { - self.delete_recording(id); + self.c.transaction(|| { + self.delete_recording(id); - diesel::insert_into(recordings::table) - .values(recording_insertion.recording) + diesel::insert_into(recordings::table) + .values(recording_insertion.recording) + .execute(&self.c)?; + + for performance in recording_insertion.performances { + diesel::insert_into(performances::table) + .values(performance) .execute(&self.c)?; + } - for performance in recording_insertion.performances { - diesel::insert_into(performances::table) - .values(performance) - .execute(&self.c)?; - } + diesel::result::QueryResult::Ok(()) + })?; - diesel::result::QueryResult::Ok(()) - }) - .expect("Failed to insert performance!"); + Ok(()) } - pub fn get_recording(&self, id: i64) -> Option { + pub fn get_recording(&self, id: i64) -> Result { recordings::table .filter(recordings::id.eq(id)) - .load::(&self.c) - .expect("Error loading recording!") + .load::(&self.c)? .first() .cloned() + .ok_or(anyhow!("No recording with ID: {}", id)) } pub fn get_recording_description_for_recording( &self, - recording: Recording, - ) -> RecordingDescription { - RecordingDescription { + recording: &Recording, + ) -> Result { + let mut performance_descriptions: Vec = Vec::new(); + + let performances = performances::table + .filter(performances::recording.eq(recording.id)) + .load::(&self.c)?; + + for performance in performances { + performance_descriptions.push(PerformanceDescription { + person: match performance.person { + Some(id) => Some(self.get_person(id)?), + None => None, + }, + ensemble: match performance.ensemble { + Some(id) => Some(self.get_ensemble(id)?), + None => None, + }, + role: match performance.role { + Some(id) => Some(self.get_instrument(id)?), + None => None, + }, + }); + } + + Ok(RecordingDescription { id: recording.id, - work: self - .get_work_description(recording.work) - .expect("Could not find work for recording!"), - comment: recording.comment, - performances: performances::table - .filter(performances::recording.eq(recording.id)) - .load::(&self.c) - .expect("Failed to load performances!") - .iter() - .map(|performance| PerformanceDescription { - person: performance.person.map(|id| { - self.get_person(id) - .expect("Could not find person for performance!") - }), - ensemble: performance.ensemble.map(|id| { - self.get_ensemble(id) - .expect("Could not find ensemble for performance!") - }), - role: performance.role.map(|id| { - self.get_instrument(id) - .expect("Could not find role for performance!") - }), - }) - .collect(), - } + work: self.get_work_description(recording.work)?, + comment: recording.comment.clone(), + performances: performance_descriptions, + }) } - pub fn get_recording_description(&self, id: i64) -> Option { - match self.get_recording(id) { - Some(recording) => Some(self.get_recording_description_for_recording(recording)), - None => None, - } + pub fn get_recording_description(&self, id: i64) -> Result { + let recording = self.get_recording(id)?; + let recording_description = self.get_recording_description_for_recording(&recording)?; + Ok(recording_description) } - pub fn get_recordings_for_person(&self, id: i64) -> Vec { + pub fn get_recordings_for_person(&self, id: i64) -> Result> { + let mut recording_descriptions: Vec = Vec::new(); + let recordings = recordings::table .inner_join(performances::table.on(performances::recording.eq(recordings::id))) .inner_join(persons::table.on(persons::id.nullable().eq(performances::person))) .filter(persons::id.eq(id)) .select(recordings::table::all_columns()) - .load::(&self.c) - .expect("Error loading recordings for person!"); + .load::(&self.c)?; - recordings - .iter() - .map(|recording| self.get_recording_description_for_recording(recording.clone())) - .collect() + for recording in recordings { + recording_descriptions.push(self.get_recording_description_for_recording(&recording)?); + } + + Ok(recording_descriptions) } - pub fn get_recordings_for_ensemble(&self, id: i64) -> Vec { + pub fn get_recordings_for_ensemble(&self, id: i64) -> Result> { + let mut recording_descriptions: Vec = Vec::new(); + let recordings = recordings::table .inner_join(performances::table.on(performances::recording.eq(recordings::id))) .inner_join(ensembles::table.on(ensembles::id.nullable().eq(performances::ensemble))) .filter(ensembles::id.eq(id)) .select(recordings::table::all_columns()) - .load::(&self.c) - .expect("Error loading recordings for ensemble!"); + .load::(&self.c)?; - recordings - .iter() - .map(|recording| self.get_recording_description_for_recording(recording.clone())) - .collect() + for recording in recordings { + recording_descriptions.push(self.get_recording_description_for_recording(&recording)?); + } + + Ok(recording_descriptions) } - pub fn get_recordings_for_work(&self, id: i64) -> Vec { + pub fn get_recordings_for_work(&self, id: i64) -> Result> { + let mut recording_descriptions: Vec = Vec::new(); + let recordings = recordings::table .inner_join(works::table.on(works::id.eq(recordings::work))) .filter(works::id.eq(id)) .select(recordings::table::all_columns()) - .load::(&self.c) - .expect("Error loading recordings for work!"); + .load::(&self.c)?; - recordings - .iter() - .map(|recording| self.get_recording_description_for_recording(recording.clone())) - .collect() + for recording in recordings { + recording_descriptions.push(self.get_recording_description_for_recording(&recording)?); + } + + Ok(recording_descriptions) } - pub fn delete_recording(&self, id: i64) { - diesel::delete(recordings::table.filter(recordings::id.eq(id))) - .execute(&self.c) - .expect("Failed to delete recording!"); + pub fn delete_recording(&self, id: i64) -> Result<()> { + diesel::delete(recordings::table.filter(recordings::id.eq(id))).execute(&self.c)?; + Ok(()) } - pub fn get_recordings(&self, work_id: i64) -> Vec { - recordings::table + pub fn get_recordings(&self, work_id: i64) -> Result> { + let recordings = recordings::table .filter(recordings::work.eq(work_id)) - .load::(&self.c) - .expect("Error loading recordings!") + .load::(&self.c)?; + + Ok(recordings) } fn defer_foreign_keys(&self) { diff --git a/src/dialogs/ensemble_selector.rs b/src/dialogs/ensemble_selector.rs index 4ddb9ad..b399609 100644 --- a/src/dialogs/ensemble_selector.rs +++ b/src/dialogs/ensemble_selector.rs @@ -44,6 +44,8 @@ where result .backend .get_ensembles(clone!(@strong result => move |ensembles| { + let ensembles = ensembles.unwrap(); + for (index, ensemble) in ensembles.iter().enumerate() { let label = gtk::Label::new(Some(&ensemble.name)); label.set_halign(gtk::Align::Start); diff --git a/src/dialogs/instrument_selector.rs b/src/dialogs/instrument_selector.rs index a94109a..5d708eb 100644 --- a/src/dialogs/instrument_selector.rs +++ b/src/dialogs/instrument_selector.rs @@ -44,6 +44,8 @@ where result .backend .get_instruments(clone!(@strong result => move |instruments| { + let instruments = instruments.unwrap(); + for (index, instrument) in instruments.iter().enumerate() { let label = gtk::Label::new(Some(&instrument.name)); label.set_halign(gtk::Align::Start); diff --git a/src/dialogs/person_selector.rs b/src/dialogs/person_selector.rs index c095139..5575b3c 100644 --- a/src/dialogs/person_selector.rs +++ b/src/dialogs/person_selector.rs @@ -44,6 +44,8 @@ where result .backend .get_persons(clone!(@strong result => move |persons| { + let persons = persons.unwrap(); + for (index, person) in persons.iter().enumerate() { let label = gtk::Label::new(Some(&person.name_lf())); label.set_halign(gtk::Align::Start); diff --git a/src/dialogs/work_selector.rs b/src/dialogs/work_selector.rs index 70a1254..f3dd599 100644 --- a/src/dialogs/work_selector.rs +++ b/src/dialogs/work_selector.rs @@ -124,7 +124,7 @@ where Loading => { self.backend .get_persons(clone!(@strong self as self_ => move |persons| { - self_.clone().set_state(Persons(persons)); + self_.clone().set_state(Persons(persons.unwrap())); })); self.sidebar_stack.set_visible_child_name("loading"); @@ -184,7 +184,7 @@ where self.backend.get_work_descriptions( person.id, clone!(@strong self as self_ => move |works| { - self_.clone().set_state(Person(works)); + self_.clone().set_state(Person(works.unwrap())); }), ); diff --git a/src/window.rs b/src/window.rs index 24b157f..e8d15ea 100644 --- a/src/window.rs +++ b/src/window.rs @@ -300,7 +300,9 @@ impl Window { Loading => { self.backend .get_persons(clone!(@strong self as self_ => move |persons| { + let persons = persons.unwrap(); self_.backend.get_ensembles(clone!(@strong self_ => move |ensembles| { + let ensembles = ensembles.unwrap(); let mut poes: Vec = Vec::new(); for person in &persons { @@ -393,9 +395,11 @@ impl Window { self.backend.get_work_descriptions( person.id, clone!(@strong self as self_, @strong poe => move |works| { + let works = works.unwrap(); self_.backend.get_recordings_for_person( person.id, clone!(@strong self_, @strong poe => move |recordings| { + let recordings = recordings.unwrap(); self_.clone().set_state(OverviewScreen(poe.clone(), works.clone(), recordings, String::from(""))); }), ); @@ -426,6 +430,7 @@ impl Window { self.backend.get_recordings_for_ensemble( ensemble.id, clone!(@strong self as self_ => move |recordings| { + let recordings = recordings.unwrap(); self_.clone().set_state(OverviewScreen(poe.clone(), Vec::new(), recordings, String::from(""))); }), ); @@ -550,6 +555,7 @@ impl Window { self.backend.get_recordings_for_work( work.id, clone!(@strong self as self_ => move |recordings| { + let recordings = recordings.unwrap(); self_.clone().set_state(WorkScreen(poe.clone(), work.clone(), recordings, String::new())); }), ); @@ -592,7 +598,10 @@ impl Window { } } - match self.work_details_recording_list_row_activated_handler_id.take() { + match self + .work_details_recording_list_row_activated_handler_id + .take() + { Some(id) => self.work_details_recording_list.disconnect(id), None => (), }