mirror of
				https://github.com/johrpan/musicus.git
				synced 2025-10-26 19:57:25 +01:00 
			
		
		
		
	Properly sync associated items of recordings and works
This commit is contained in:
		
							parent
							
								
									bec0dfbf56
								
							
						
					
					
						commit
						37f21c582d
					
				
					 7 changed files with 103 additions and 89 deletions
				
			
		|  | @ -115,6 +115,34 @@ impl Database { | ||||||
|             let recording_id = &recording.id; |             let recording_id = &recording.id; | ||||||
|             self.delete_recording(recording_id)?; |             self.delete_recording(recording_id)?; | ||||||
| 
 | 
 | ||||||
|  |             // Add associated items from the server, if they don't already exist.
 | ||||||
|  | 
 | ||||||
|  |             if self.get_work(&recording.work.id)?.is_none() { | ||||||
|  |                 self.update_work(recording.work.clone())?; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             for performance in &recording.performances { | ||||||
|  |                 if let Some(person) = &performance.person { | ||||||
|  |                     if self.get_person(&person.id)?.is_none() { | ||||||
|  |                         self.update_person(person.clone())?; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 if let Some(ensemble) = &performance.ensemble { | ||||||
|  |                     if self.get_ensemble(&ensemble.id)?.is_none() { | ||||||
|  |                         self.update_ensemble(ensemble.clone())?; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 if let Some(role) = &performance.role { | ||||||
|  |                     if self.get_instrument(&role.id)?.is_none() { | ||||||
|  |                         self.update_instrument(role.clone())?; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // Add the actual recording.
 | ||||||
|  | 
 | ||||||
|             let row: RecordingRow = recording.clone().into(); |             let row: RecordingRow = recording.clone().into(); | ||||||
|             diesel::insert_into(recordings::table) |             diesel::insert_into(recordings::table) | ||||||
|                 .values(row) |                 .values(row) | ||||||
|  |  | ||||||
|  | @ -100,6 +100,28 @@ impl Database { | ||||||
|             let work_id = &work.id; |             let work_id = &work.id; | ||||||
|             self.delete_work(work_id)?; |             self.delete_work(work_id)?; | ||||||
| 
 | 
 | ||||||
|  |             // Add associated items from the server, if they don't already exist.
 | ||||||
|  | 
 | ||||||
|  |             if self.get_person(&work.composer.id)?.is_none() { | ||||||
|  |                 self.update_person(work.composer.clone())?; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             for instrument in &work.instruments { | ||||||
|  |                 if self.get_instrument(&instrument.id)?.is_none() { | ||||||
|  |                     self.update_instrument(instrument.clone())?; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             for part in &work.parts { | ||||||
|  |                 if let Some(person) = &part.composer { | ||||||
|  |                     if self.get_person(&person.id)?.is_none() { | ||||||
|  |                         self.update_person(person.clone())?; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // Add the actual work.
 | ||||||
|  | 
 | ||||||
|             let row: WorkRow = work.clone().into(); |             let row: WorkRow = work.clone().into(); | ||||||
|             diesel::insert_into(works::table) |             diesel::insert_into(works::table) | ||||||
|                 .values(row) |                 .values(row) | ||||||
|  |  | ||||||
|  | @ -89,7 +89,6 @@ sources = files( | ||||||
|   'widgets/list.rs', |   'widgets/list.rs', | ||||||
|   'widgets/mod.rs', |   'widgets/mod.rs', | ||||||
|   'widgets/navigator.rs', |   'widgets/navigator.rs', | ||||||
|   'widgets/person_list.rs', |  | ||||||
|   'widgets/player_bar.rs', |   'widgets/player_bar.rs', | ||||||
|   'widgets/poe_list.rs', |   'widgets/poe_list.rs', | ||||||
|   'widgets/selector_row.rs', |   'widgets/selector_row.rs', | ||||||
|  |  | ||||||
|  | @ -4,9 +4,6 @@ pub use list::*; | ||||||
| pub mod navigator; | pub mod navigator; | ||||||
| pub use navigator::*; | pub use navigator::*; | ||||||
| 
 | 
 | ||||||
| pub mod person_list; |  | ||||||
| pub use person_list::*; |  | ||||||
| 
 |  | ||||||
| pub mod player_bar; | pub mod player_bar; | ||||||
| pub use player_bar::*; | pub use player_bar::*; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,82 +0,0 @@ | ||||||
| use super::*; |  | ||||||
| use crate::backend::Backend; |  | ||||||
| use crate::database::*; |  | ||||||
| use gettextrs::gettext; |  | ||||||
| use glib::clone; |  | ||||||
| use gtk::prelude::*; |  | ||||||
| use gtk_macros::get_widget; |  | ||||||
| use std::rc::Rc; |  | ||||||
| 
 |  | ||||||
| pub struct PersonList { |  | ||||||
|     pub widget: gtk::Box, |  | ||||||
|     list: Rc<List<Person>>, |  | ||||||
|     backend: Rc<Backend>, |  | ||||||
|     stack: gtk::Stack, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl PersonList { |  | ||||||
|     pub fn new(backend: Rc<Backend>) -> Rc<Self> { |  | ||||||
|         let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/person_list.ui"); |  | ||||||
| 
 |  | ||||||
|         get_widget!(builder, gtk::Box, widget); |  | ||||||
|         get_widget!(builder, gtk::SearchEntry, search_entry); |  | ||||||
|         get_widget!(builder, gtk::Stack, stack); |  | ||||||
|         get_widget!(builder, gtk::ScrolledWindow, scrolled_window); |  | ||||||
| 
 |  | ||||||
|         let list = List::new(&gettext("No persons found.")); |  | ||||||
| 
 |  | ||||||
|         list.set_make_widget(|person: &Person| { |  | ||||||
|             let label = gtk::Label::new(Some(&person.name_lf())); |  | ||||||
|             label.set_halign(gtk::Align::Start); |  | ||||||
|             label.set_margin_start(6); |  | ||||||
|             label.set_margin_end(6); |  | ||||||
|             label.set_margin_top(6); |  | ||||||
|             label.set_margin_bottom(6); |  | ||||||
|             label.upcast() |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|         list.set_filter(clone!(@strong search_entry => move |person: &Person| { |  | ||||||
|             let search = search_entry.get_text().to_string().to_lowercase(); |  | ||||||
|             let name = person.name_fl().to_lowercase(); |  | ||||||
|             search.is_empty() || name.contains(&search) |  | ||||||
|         })); |  | ||||||
| 
 |  | ||||||
|         scrolled_window.add(&list.widget); |  | ||||||
| 
 |  | ||||||
|         let result = Rc::new(Self { |  | ||||||
|             widget, |  | ||||||
|             list, |  | ||||||
|             backend, |  | ||||||
|             stack, |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|         search_entry.connect_search_changed(clone!(@strong result => move |_| { |  | ||||||
|             result.list.invalidate_filter(); |  | ||||||
|         })); |  | ||||||
| 
 |  | ||||||
|         result.clone().reload(); |  | ||||||
| 
 |  | ||||||
|         result |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn set_selected<S>(&self, selected: S) |  | ||||||
|     where |  | ||||||
|         S: Fn(&Person) -> () + 'static, |  | ||||||
|     { |  | ||||||
|         self.list.set_selected(selected); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn reload(self: Rc<Self>) { |  | ||||||
|         self.stack.set_visible_child_name("loading"); |  | ||||||
| 
 |  | ||||||
|         let context = glib::MainContext::default(); |  | ||||||
|         let backend = self.backend.clone(); |  | ||||||
|         let list = self.list.clone(); |  | ||||||
| 
 |  | ||||||
|         context.spawn_local(async move { |  | ||||||
|             let persons = backend.db().get_persons().await.unwrap(); |  | ||||||
|             list.show_items(persons); |  | ||||||
|             self.stack.set_visible_child_name("content"); |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| use super::schema::{ensembles, performances, persons, recordings}; | use super::schema::{ensembles, performances, persons, recordings}; | ||||||
| use super::{get_ensemble, get_instrument, get_person, get_work}; | use super::{get_ensemble, get_instrument, get_person, get_work}; | ||||||
|  | use super::{update_ensemble, update_instrument, update_person, update_work}; | ||||||
| use super::{DbConn, Ensemble, Instrument, Person, User, Work}; | use super::{DbConn, Ensemble, Instrument, Person, User, Work}; | ||||||
| use crate::error::ServerError; | use crate::error::ServerError; | ||||||
| use anyhow::{anyhow, Error, Result}; | use anyhow::{anyhow, Error, Result}; | ||||||
|  | @ -48,7 +49,6 @@ struct PerformanceRow { | ||||||
| 
 | 
 | ||||||
| /// Update an existing recording or insert a new one. This will only work, if the provided user is
 | /// Update an existing recording or insert a new one. This will only work, if the provided user is
 | ||||||
| /// allowed to do that.
 | /// allowed to do that.
 | ||||||
| // TODO: Also add newly created associated items.
 |  | ||||||
| pub fn update_recording(conn: &DbConn, recording: &Recording, user: &User) -> Result<()> { | pub fn update_recording(conn: &DbConn, recording: &Recording, user: &User) -> Result<()> { | ||||||
|     conn.transaction::<(), Error, _>(|| { |     conn.transaction::<(), Error, _>(|| { | ||||||
|         let old_row = get_recording_row(conn, &recording.id)?; |         let old_row = get_recording_row(conn, &recording.id)?; | ||||||
|  | @ -66,6 +66,34 @@ pub fn update_recording(conn: &DbConn, recording: &Recording, user: &User) -> Re | ||||||
|                 .filter(recordings::id.eq(id)) |                 .filter(recordings::id.eq(id)) | ||||||
|                 .execute(conn)?; |                 .execute(conn)?; | ||||||
| 
 | 
 | ||||||
|  |             // Add associated items, if they don't already exist.
 | ||||||
|  | 
 | ||||||
|  |             if get_work(conn, &recording.work.id)?.is_none() { | ||||||
|  |                 update_work(conn, &recording.work, &user)?; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             for performance in &recording.performances { | ||||||
|  |                 if let Some(person) = &performance.person { | ||||||
|  |                     if get_person(conn, &person.id)?.is_none() { | ||||||
|  |                         update_person(conn, person, &user)?; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 if let Some(ensemble) = &performance.ensemble { | ||||||
|  |                     if get_ensemble(conn, &ensemble.id)?.is_none() { | ||||||
|  |                         update_ensemble(conn, ensemble, &user)?; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 if let Some(role) = &performance.role { | ||||||
|  |                     if get_instrument(conn, &role.id)?.is_none() { | ||||||
|  |                         update_instrument(conn, role, &user)?; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // Add the actual recording.
 | ||||||
|  | 
 | ||||||
|             let row = RecordingRow { |             let row = RecordingRow { | ||||||
|                 id: id.clone(), |                 id: id.clone(), | ||||||
|                 work: recording.work.id.clone(), |                 work: recording.work.id.clone(), | ||||||
|  |  | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| use super::schema::{instrumentations, work_parts, work_sections, works}; | use super::schema::{instrumentations, work_parts, work_sections, works}; | ||||||
| use super::{get_instrument, get_person, DbConn, Instrument, Person, User}; | use super::{get_instrument, get_person, update_instrument, update_person}; | ||||||
|  | use super::{DbConn, Instrument, Person, User}; | ||||||
| use crate::error::ServerError; | use crate::error::ServerError; | ||||||
| use anyhow::{anyhow, Error, Result}; | use anyhow::{anyhow, Error, Result}; | ||||||
| use diesel::prelude::*; | use diesel::prelude::*; | ||||||
|  | @ -76,7 +77,6 @@ struct WorkSectionRow { | ||||||
| 
 | 
 | ||||||
| /// Update an existing work or insert a new one. This will only succeed, if the user is allowed to
 | /// Update an existing work or insert a new one. This will only succeed, if the user is allowed to
 | ||||||
| /// do that.
 | /// do that.
 | ||||||
| // TODO: Also add newly created associated items.
 |  | ||||||
| pub fn update_work(conn: &DbConn, work: &Work, user: &User) -> Result<()> { | pub fn update_work(conn: &DbConn, work: &Work, user: &User) -> Result<()> { | ||||||
|     conn.transaction::<(), Error, _>(|| { |     conn.transaction::<(), Error, _>(|| { | ||||||
|         let old_row = get_work_row(conn, &work.id)?; |         let old_row = get_work_row(conn, &work.id)?; | ||||||
|  | @ -94,6 +94,28 @@ pub fn update_work(conn: &DbConn, work: &Work, user: &User) -> Result<()> { | ||||||
|                 .filter(works::id.eq(id)) |                 .filter(works::id.eq(id)) | ||||||
|                 .execute(conn)?; |                 .execute(conn)?; | ||||||
| 
 | 
 | ||||||
|  |             // Add associated items, if they don't already exist.
 | ||||||
|  | 
 | ||||||
|  |             if get_person(conn, &work.composer.id)?.is_none() { | ||||||
|  |                 update_person(conn, &work.composer, &user)?; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             for instrument in &work.instruments { | ||||||
|  |                 if get_instrument(conn, &instrument.id)?.is_none() { | ||||||
|  |                     update_instrument(conn, instrument, &user)?; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             for part in &work.parts { | ||||||
|  |                 if let Some(person) = &part.composer { | ||||||
|  |                     if get_person(conn, &person.id)?.is_none() { | ||||||
|  |                         update_person(conn, person, &user)?; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // Add the actual work.
 | ||||||
|  | 
 | ||||||
|             let row = WorkRow { |             let row = WorkRow { | ||||||
|                 id: id.clone(), |                 id: id.clone(), | ||||||
|                 composer: work.composer.id.clone(), |                 composer: work.composer.id.clone(), | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Elias Projahn
						Elias Projahn