mirror of
				https://github.com/johrpan/musicus.git
				synced 2025-10-26 19:57:25 +01:00 
			
		
		
		
	client: Switch to string IDs
This commit is contained in:
		
							parent
							
								
									157bdb2917
								
							
						
					
					
						commit
						5c3377e246
					
				
					 24 changed files with 249 additions and 363 deletions
				
			
		|  | @ -25,3 +25,4 @@ rand = "0.7.3" | ||||||
| secret-service = "1.1.1" | secret-service = "1.1.1" | ||||||
| serde = { version = "1.0.117", features = ["derive"] } | serde = { version = "1.0.117", features = ["derive"] } | ||||||
| serde_json = "1.0.59" | serde_json = "1.0.59" | ||||||
|  | uuid = { version = "0.8", features = ["v4"] } | ||||||
|  |  | ||||||
|  | @ -1,64 +1,64 @@ | ||||||
| CREATE TABLE persons ( | CREATE TABLE persons ( | ||||||
|     id BIGINT NOT NULL PRIMARY KEY, |     id TEXT NOT NULL PRIMARY KEY, | ||||||
|     first_name TEXT NOT NULL, |     first_name TEXT NOT NULL, | ||||||
|     last_name TEXT NOT NULL |     last_name TEXT NOT NULL | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| CREATE TABLE instruments ( | CREATE TABLE instruments ( | ||||||
|     id BIGINT NOT NULL PRIMARY KEY, |     id TEXT NOT NULL PRIMARY KEY, | ||||||
|     name TEXT NOT NULL |     name TEXT NOT NULL | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| CREATE TABLE works ( | CREATE TABLE works ( | ||||||
|     id BIGINT NOT NULL PRIMARY KEY, |     id TEXT NOT NULL PRIMARY KEY, | ||||||
|     composer BIGINT NOT NULL REFERENCES persons(id), |     composer TEXT NOT NULL REFERENCES persons(id), | ||||||
|     title TEXT NOT NULL |     title TEXT NOT NULL | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| CREATE TABLE instrumentations ( | CREATE TABLE instrumentations ( | ||||||
|     id BIGINT NOT NULL PRIMARY KEY, |     id BIGINT NOT NULL PRIMARY KEY, | ||||||
|     work BIGINT NOT NULL REFERENCES works(id) ON DELETE CASCADE, |     work TEXT NOT NULL REFERENCES works(id) ON DELETE CASCADE, | ||||||
|     instrument BIGINT NOT NULL REFERENCES instruments(id) ON DELETE CASCADE |     instrument TEXT NOT NULL REFERENCES instruments(id) ON DELETE CASCADE | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| CREATE TABLE work_parts ( | CREATE TABLE work_parts ( | ||||||
|     id BIGINT NOT NULL PRIMARY KEY, |     id BIGINT NOT NULL PRIMARY KEY, | ||||||
|     work BIGINT NOT NULL REFERENCES works(id) ON DELETE CASCADE, |     work TEXT NOT NULL REFERENCES works(id) ON DELETE CASCADE, | ||||||
|     part_index BIGINT NOT NULL, |     part_index BIGINT NOT NULL, | ||||||
|     title TEXT NOT NULL, |     title TEXT NOT NULL, | ||||||
|     composer BIGINT REFERENCES persons(id) |     composer TEXT REFERENCES persons(id) | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| CREATE TABLE work_sections ( | CREATE TABLE work_sections ( | ||||||
|     id BIGINT NOT NULL PRIMARY KEY, |     id BIGINT NOT NULL PRIMARY KEY, | ||||||
|     work BIGINT NOT NULL REFERENCES works(id) ON DELETE CASCADE, |     work TEXT NOT NULL REFERENCES works(id) ON DELETE CASCADE, | ||||||
|     title TEXT NOT NULL, |     title TEXT NOT NULL, | ||||||
|     before_index BIGINT NOT NULL |     before_index BIGINT NOT NULL | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| CREATE TABLE ensembles ( | CREATE TABLE ensembles ( | ||||||
|     id BIGINT NOT NULL PRIMARY KEY, |     id TEXT NOT NULL PRIMARY KEY, | ||||||
|     name TEXT NOT NULL |     name TEXT NOT NULL | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| CREATE TABLE recordings ( | CREATE TABLE recordings ( | ||||||
|     id BIGINT NOT NULL PRIMARY KEY, |     id TEXT NOT NULL PRIMARY KEY, | ||||||
|     work BIGINT NOT NULL REFERENCES works(id), |     work TEXT NOT NULL REFERENCES works(id), | ||||||
|     comment TEXT NOT NULL |     comment TEXT NOT NULL | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| CREATE TABLE performances ( | CREATE TABLE performances ( | ||||||
|     id BIGINT NOT NULL PRIMARY KEY, |     id BIGINT NOT NULL PRIMARY KEY, | ||||||
|     recording BIGINT NOT NULL REFERENCES recordings(id) ON DELETE CASCADE, |     recording TEXT NOT NULL REFERENCES recordings(id) ON DELETE CASCADE, | ||||||
|     person BIGINT REFERENCES persons(id), |     person TEXT REFERENCES persons(id), | ||||||
|     ensemble BIGINT REFERENCES ensembles(id), |     ensemble TEXT REFERENCES ensembles(id), | ||||||
|     role BIGINT REFERENCES instruments(id) |     role TEXT REFERENCES instruments(id) | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| CREATE TABLE tracks ( | CREATE TABLE tracks ( | ||||||
|     id BIGINT NOT NULL PRIMARY KEY, |     id BIGINT NOT NULL PRIMARY KEY, | ||||||
|     file_name TEXT NOT NULL, |     file_name TEXT NOT NULL, | ||||||
|     recording BIGINT NOT NULL REFERENCES recordings(id), |     recording TEXT NOT NULL REFERENCES recordings(id), | ||||||
|     track_index INTEGER NOT NULL, |     track_index INTEGER NOT NULL, | ||||||
|     work_parts TEXT NOT NULL |     work_parts TEXT NOT NULL | ||||||
| ); | ); | ||||||
|  | @ -1,57 +1,25 @@ | ||||||
| use super::schema::ensembles; | use super::schema::ensembles; | ||||||
| use super::Database; | use super::Database; | ||||||
| use anyhow::{Error, Result}; | use anyhow::Result; | ||||||
| use diesel::prelude::*; | use diesel::prelude::*; | ||||||
| use diesel::{Insertable, Queryable}; |  | ||||||
| use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||||
| use std::convert::{TryFrom, TryInto}; |  | ||||||
| 
 |  | ||||||
| /// Database table data for an ensemble.
 |  | ||||||
| #[derive(Insertable, Queryable, Debug, Clone)] |  | ||||||
| #[table_name = "ensembles"] |  | ||||||
| struct EnsembleRow { |  | ||||||
|     pub id: i64, |  | ||||||
|     pub name: String, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl From<Ensemble> for EnsembleRow { |  | ||||||
|     fn from(ensemble: Ensemble) -> Self { |  | ||||||
|         EnsembleRow { |  | ||||||
|             id: ensemble.id as i64, |  | ||||||
|             name: ensemble.name, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| /// An ensemble that takes part in recordings.
 | /// An ensemble that takes part in recordings.
 | ||||||
| #[derive(Serialize, Deserialize, Debug, Clone)] | #[derive(Serialize, Deserialize, Insertable, Queryable, Debug, Clone)] | ||||||
| #[serde(rename_all = "camelCase")] | #[serde(rename_all = "camelCase")] | ||||||
| pub struct Ensemble { | pub struct Ensemble { | ||||||
|     pub id: u32, |     pub id: String, | ||||||
|     pub name: String, |     pub name: String, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl TryFrom<EnsembleRow> for Ensemble { |  | ||||||
|     type Error = Error; |  | ||||||
|     fn try_from(row: EnsembleRow) -> Result<Self> { |  | ||||||
|         let ensemble = Ensemble { |  | ||||||
|             id: row.id.try_into()?, |  | ||||||
|             name: row.name, |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         Ok(ensemble) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Database { | impl Database { | ||||||
|     /// Update an existing ensemble or insert a new one.
 |     /// Update an existing ensemble or insert a new one.
 | ||||||
|     pub fn update_ensemble(&self, ensemble: Ensemble) -> Result<()> { |     pub fn update_ensemble(&self, ensemble: Ensemble) -> Result<()> { | ||||||
|         self.defer_foreign_keys()?; |         self.defer_foreign_keys()?; | ||||||
| 
 | 
 | ||||||
|         self.connection.transaction(|| { |         self.connection.transaction(|| { | ||||||
|             let row: EnsembleRow = ensemble.into(); |  | ||||||
|             diesel::replace_into(ensembles::table) |             diesel::replace_into(ensembles::table) | ||||||
|                 .values(row) |                 .values(ensemble) | ||||||
|                 .execute(&self.connection) |                 .execute(&self.connection) | ||||||
|         })?; |         })?; | ||||||
| 
 | 
 | ||||||
|  | @ -59,37 +27,26 @@ impl Database { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Get an existing ensemble.
 |     /// Get an existing ensemble.
 | ||||||
|     pub fn get_ensemble(&self, id: u32) -> Result<Option<Ensemble>> { |     pub fn get_ensemble(&self, id: &str) -> Result<Option<Ensemble>> { | ||||||
|         let row = ensembles::table |         let ensemble = ensembles::table | ||||||
|             .filter(ensembles::id.eq(id as i64)) |             .filter(ensembles::id.eq(id)) | ||||||
|             .load::<EnsembleRow>(&self.connection)? |             .load::<Ensemble>(&self.connection)? | ||||||
|             .first() |             .into_iter() | ||||||
|             .cloned(); |             .next(); | ||||||
| 
 |  | ||||||
|         let ensemble = match row { |  | ||||||
|             Some(row) => Some(row.try_into()?), |  | ||||||
|             None => None, |  | ||||||
|         }; |  | ||||||
| 
 | 
 | ||||||
|         Ok(ensemble) |         Ok(ensemble) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Delete an existing ensemble.
 |     /// Delete an existing ensemble.
 | ||||||
|     pub fn delete_ensemble(&self, id: u32) -> Result<()> { |     pub fn delete_ensemble(&self, id: &str) -> Result<()> { | ||||||
|         diesel::delete(ensembles::table.filter(ensembles::id.eq(id as i64))) |         diesel::delete(ensembles::table.filter(ensembles::id.eq(id))).execute(&self.connection)?; | ||||||
|             .execute(&self.connection)?; |  | ||||||
| 
 | 
 | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Get all existing ensembles.
 |     /// Get all existing ensembles.
 | ||||||
|     pub fn get_ensembles(&self) -> Result<Vec<Ensemble>> { |     pub fn get_ensembles(&self) -> Result<Vec<Ensemble>> { | ||||||
|         let mut ensembles = Vec::<Ensemble>::new(); |         let ensembles = ensembles::table.load::<Ensemble>(&self.connection)?; | ||||||
| 
 |  | ||||||
|         let rows = ensembles::table.load::<EnsembleRow>(&self.connection)?; |  | ||||||
|         for row in rows { |  | ||||||
|             ensembles.push(row.try_into()?); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         Ok(ensembles) |         Ok(ensembles) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -1,57 +1,25 @@ | ||||||
| use super::schema::instruments; | use super::schema::instruments; | ||||||
| use super::Database; | use super::Database; | ||||||
| use anyhow::{Error, Result}; | use anyhow::Result; | ||||||
| use diesel::prelude::*; | use diesel::prelude::*; | ||||||
| use diesel::{Insertable, Queryable}; |  | ||||||
| use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||||
| use std::convert::{TryFrom, TryInto}; |  | ||||||
| 
 |  | ||||||
| /// Table row data for an instrument.
 |  | ||||||
| #[derive(Insertable, Queryable, Debug, Clone)] |  | ||||||
| #[table_name = "instruments"] |  | ||||||
| struct InstrumentRow { |  | ||||||
|     pub id: i64, |  | ||||||
|     pub name: String, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl From<Instrument> for InstrumentRow { |  | ||||||
|     fn from(instrument: Instrument) -> Self { |  | ||||||
|         InstrumentRow { |  | ||||||
|             id: instrument.id as i64, |  | ||||||
|             name: instrument.name, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| /// An instrument or any other possible role within a recording.
 | /// An instrument or any other possible role within a recording.
 | ||||||
| #[derive(Serialize, Deserialize, Debug, Clone)] | #[derive(Serialize, Deserialize, Insertable, Queryable, Debug, Clone)] | ||||||
| #[serde(rename_all = "camelCase")] | #[serde(rename_all = "camelCase")] | ||||||
| pub struct Instrument { | pub struct Instrument { | ||||||
|     pub id: u32, |     pub id: String, | ||||||
|     pub name: String, |     pub name: String, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl TryFrom<InstrumentRow> for Instrument { |  | ||||||
|     type Error = Error; |  | ||||||
|     fn try_from(row: InstrumentRow) -> Result<Self> { |  | ||||||
|         let instrument = Instrument { |  | ||||||
|             id: row.id.try_into()?, |  | ||||||
|             name: row.name, |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         Ok(instrument) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Database { | impl Database { | ||||||
|     /// Update an existing instrument or insert a new one.
 |     /// Update an existing instrument or insert a new one.
 | ||||||
|     pub fn update_instrument(&self, instrument: Instrument) -> Result<()> { |     pub fn update_instrument(&self, instrument: Instrument) -> Result<()> { | ||||||
|         self.defer_foreign_keys()?; |         self.defer_foreign_keys()?; | ||||||
| 
 | 
 | ||||||
|         self.connection.transaction(|| { |         self.connection.transaction(|| { | ||||||
|             let row: InstrumentRow = instrument.into(); |  | ||||||
|             diesel::replace_into(instruments::table) |             diesel::replace_into(instruments::table) | ||||||
|                 .values(row) |                 .values(instrument) | ||||||
|                 .execute(&self.connection) |                 .execute(&self.connection) | ||||||
|         })?; |         })?; | ||||||
| 
 | 
 | ||||||
|  | @ -59,24 +27,19 @@ impl Database { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Get an existing instrument.
 |     /// Get an existing instrument.
 | ||||||
|     pub fn get_instrument(&self, id: u32) -> Result<Option<Instrument>> { |     pub fn get_instrument(&self, id: &str) -> Result<Option<Instrument>> { | ||||||
|         let row = instruments::table |         let instrument = instruments::table | ||||||
|             .filter(instruments::id.eq(id as i64)) |             .filter(instruments::id.eq(id)) | ||||||
|             .load::<InstrumentRow>(&self.connection)? |             .load::<Instrument>(&self.connection)? | ||||||
|             .first() |             .into_iter() | ||||||
|             .cloned(); |             .next(); | ||||||
| 
 |  | ||||||
|         let instrument = match row { |  | ||||||
|             Some(row) => Some(row.try_into()?), |  | ||||||
|             None => None, |  | ||||||
|         }; |  | ||||||
| 
 | 
 | ||||||
|         Ok(instrument) |         Ok(instrument) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Delete an existing instrument.
 |     /// Delete an existing instrument.
 | ||||||
|     pub fn delete_instrument(&self, id: u32) -> Result<()> { |     pub fn delete_instrument(&self, id: &str) -> Result<()> { | ||||||
|         diesel::delete(instruments::table.filter(instruments::id.eq(id as i64))) |         diesel::delete(instruments::table.filter(instruments::id.eq(id))) | ||||||
|             .execute(&self.connection)?; |             .execute(&self.connection)?; | ||||||
| 
 | 
 | ||||||
|         Ok(()) |         Ok(()) | ||||||
|  | @ -84,12 +47,7 @@ impl Database { | ||||||
| 
 | 
 | ||||||
|     /// Get all existing instruments.
 |     /// Get all existing instruments.
 | ||||||
|     pub fn get_instruments(&self) -> Result<Vec<Instrument>> { |     pub fn get_instruments(&self) -> Result<Vec<Instrument>> { | ||||||
|         let mut instruments = Vec::<Instrument>::new(); |         let instruments = instruments::table.load::<Instrument>(&self.connection)?; | ||||||
| 
 |  | ||||||
|         let rows = instruments::table.load::<InstrumentRow>(&self.connection)?; |  | ||||||
|         for row in rows { |  | ||||||
|             instruments.push(row.try_into()?); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         Ok(instruments) |         Ok(instruments) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -27,6 +27,14 @@ mod schema; | ||||||
| // This makes the SQL migration scripts accessible from the code.
 | // This makes the SQL migration scripts accessible from the code.
 | ||||||
| embed_migrations!(); | embed_migrations!(); | ||||||
| 
 | 
 | ||||||
|  | /// Generate a random string suitable as an item ID.
 | ||||||
|  | pub fn generate_id() -> String { | ||||||
|  |     let mut buffer = uuid::Uuid::encode_buffer(); | ||||||
|  |     let id = uuid::Uuid::new_v4().to_simple().encode_lower(&mut buffer); | ||||||
|  | 
 | ||||||
|  |     id.to_string() | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /// Interface to a Musicus database.
 | /// Interface to a Musicus database.
 | ||||||
| pub struct Database { | pub struct Database { | ||||||
|     connection: SqliteConnection, |     connection: SqliteConnection, | ||||||
|  |  | ||||||
|  | @ -1,52 +1,18 @@ | ||||||
| use super::schema::persons; | use super::schema::persons; | ||||||
| use super::Database; | use super::Database; | ||||||
| use anyhow::{Error, Result}; | use anyhow::Result; | ||||||
| use diesel::prelude::*; | use diesel::prelude::*; | ||||||
| use diesel::{Insertable, Queryable}; |  | ||||||
| use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||||
| use std::convert::{TryFrom, TryInto}; |  | ||||||
| 
 |  | ||||||
| /// Database table data for a person.
 |  | ||||||
| #[derive(Insertable, Queryable, Debug, Clone)] |  | ||||||
| #[table_name = "persons"] |  | ||||||
| struct PersonRow { |  | ||||||
|     pub id: i64, |  | ||||||
|     pub first_name: String, |  | ||||||
|     pub last_name: String, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl From<Person> for PersonRow { |  | ||||||
|     fn from(person: Person) -> Self { |  | ||||||
|         PersonRow { |  | ||||||
|             id: person.id as i64, |  | ||||||
|             first_name: person.first_name, |  | ||||||
|             last_name: person.last_name, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| /// A person that is a composer, an interpret or both.
 | /// A person that is a composer, an interpret or both.
 | ||||||
| #[derive(Serialize, Deserialize, Debug, Clone)] | #[derive(Serialize, Deserialize, Insertable, Queryable, Debug, Clone)] | ||||||
| #[serde(rename_all = "camelCase")] | #[serde(rename_all = "camelCase")] | ||||||
| pub struct Person { | pub struct Person { | ||||||
|     pub id: u32, |     pub id: String, | ||||||
|     pub first_name: String, |     pub first_name: String, | ||||||
|     pub last_name: String, |     pub last_name: String, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl TryFrom<PersonRow> for Person { |  | ||||||
|     type Error = Error; |  | ||||||
|     fn try_from(row: PersonRow) -> Result<Self> { |  | ||||||
|         let person = Person { |  | ||||||
|             id: row.id.try_into()?, |  | ||||||
|             first_name: row.first_name, |  | ||||||
|             last_name: row.last_name, |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         Ok(person) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Person { | impl Person { | ||||||
|     /// Get the full name in the form "First Last".
 |     /// Get the full name in the form "First Last".
 | ||||||
|     pub fn name_fl(&self) -> String { |     pub fn name_fl(&self) -> String { | ||||||
|  | @ -65,9 +31,8 @@ impl Database { | ||||||
|         self.defer_foreign_keys()?; |         self.defer_foreign_keys()?; | ||||||
| 
 | 
 | ||||||
|         self.connection.transaction(|| { |         self.connection.transaction(|| { | ||||||
|             let row: PersonRow = person.into(); |  | ||||||
|             diesel::replace_into(persons::table) |             diesel::replace_into(persons::table) | ||||||
|                 .values(row) |                 .values(person) | ||||||
|                 .execute(&self.connection) |                 .execute(&self.connection) | ||||||
|         })?; |         })?; | ||||||
| 
 | 
 | ||||||
|  | @ -75,36 +40,26 @@ impl Database { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Get an existing person.
 |     /// Get an existing person.
 | ||||||
|     pub fn get_person(&self, id: u32) -> Result<Option<Person>> { |     pub fn get_person(&self, id: &str) -> Result<Option<Person>> { | ||||||
|         let row = persons::table |         let person = persons::table | ||||||
|             .filter(persons::id.eq(id as i64)) |             .filter(persons::id.eq(id)) | ||||||
|             .load::<PersonRow>(&self.connection)? |             .load::<Person>(&self.connection)? | ||||||
|             .first() |             .into_iter() | ||||||
|             .cloned(); |             .next(); | ||||||
| 
 |  | ||||||
|         let person = match row { |  | ||||||
|             Some(row) => Some(row.try_into()?), |  | ||||||
|             None => None, |  | ||||||
|         }; |  | ||||||
| 
 | 
 | ||||||
|         Ok(person) |         Ok(person) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Delete an existing person.
 |     /// Delete an existing person.
 | ||||||
|     pub fn delete_person(&self, id: u32) -> Result<()> { |     pub fn delete_person(&self, id: &str) -> Result<()> { | ||||||
|         diesel::delete(persons::table.filter(persons::id.eq(id as i64))) |         diesel::delete(persons::table.filter(persons::id.eq(id))).execute(&self.connection)?; | ||||||
|             .execute(&self.connection)?; | 
 | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Get all existing persons.
 |     /// Get all existing persons.
 | ||||||
|     pub fn get_persons(&self) -> Result<Vec<Person>> { |     pub fn get_persons(&self) -> Result<Vec<Person>> { | ||||||
|         let mut persons = Vec::<Person>::new(); |         let persons = persons::table.load::<Person>(&self.connection)?; | ||||||
| 
 |  | ||||||
|         let rows = persons::table.load::<PersonRow>(&self.connection)?; |  | ||||||
|         for row in rows { |  | ||||||
|             persons.push(row.try_into()?); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         Ok(persons) |         Ok(persons) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -10,16 +10,16 @@ use std::convert::TryInto; | ||||||
| #[derive(Insertable, Queryable, Debug, Clone)] | #[derive(Insertable, Queryable, Debug, Clone)] | ||||||
| #[table_name = "recordings"] | #[table_name = "recordings"] | ||||||
| struct RecordingRow { | struct RecordingRow { | ||||||
|     pub id: i64, |     pub id: String, | ||||||
|     pub work: i64, |     pub work: String, | ||||||
|     pub comment: String, |     pub comment: String, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl From<Recording> for RecordingRow { | impl From<Recording> for RecordingRow { | ||||||
|     fn from(recording: Recording) -> Self { |     fn from(recording: Recording) -> Self { | ||||||
|         RecordingRow { |         RecordingRow { | ||||||
|             id: recording.id as i64, |             id: recording.id, | ||||||
|             work: recording.work.id as i64, |             work: recording.work.id, | ||||||
|             comment: recording.comment, |             comment: recording.comment, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -30,10 +30,10 @@ impl From<Recording> for RecordingRow { | ||||||
| #[table_name = "performances"] | #[table_name = "performances"] | ||||||
| struct PerformanceRow { | struct PerformanceRow { | ||||||
|     pub id: i64, |     pub id: i64, | ||||||
|     pub recording: i64, |     pub recording: String, | ||||||
|     pub person: Option<i64>, |     pub person: Option<String>, | ||||||
|     pub ensemble: Option<i64>, |     pub ensemble: Option<String>, | ||||||
|     pub role: Option<i64>, |     pub role: Option<String>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// How a person or ensemble was involved in a recording.
 | /// How a person or ensemble was involved in a recording.
 | ||||||
|  | @ -88,7 +88,7 @@ impl Performance { | ||||||
| #[derive(Serialize, Deserialize, Debug, Clone)] | #[derive(Serialize, Deserialize, Debug, Clone)] | ||||||
| #[serde(rename_all = "camelCase")] | #[serde(rename_all = "camelCase")] | ||||||
| pub struct Recording { | pub struct Recording { | ||||||
|     pub id: u32, |     pub id: String, | ||||||
|     pub work: Work, |     pub work: Work, | ||||||
|     pub comment: String, |     pub comment: String, | ||||||
|     pub performances: Vec<Performance>, |     pub performances: Vec<Performance>, | ||||||
|  | @ -114,9 +114,9 @@ impl Database { | ||||||
|     pub fn update_recording(&self, recording: Recording) -> Result<()> { |     pub fn update_recording(&self, recording: Recording) -> Result<()> { | ||||||
|         self.defer_foreign_keys()?; |         self.defer_foreign_keys()?; | ||||||
|         self.connection.transaction::<(), Error, _>(|| { |         self.connection.transaction::<(), Error, _>(|| { | ||||||
|             self.delete_recording(recording.id)?; |             let recording_id = &recording.id; | ||||||
|  |             self.delete_recording(recording_id)?; | ||||||
| 
 | 
 | ||||||
|             let recording_id = recording.id as i64; |  | ||||||
|             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) | ||||||
|  | @ -125,10 +125,10 @@ impl Database { | ||||||
|             for performance in recording.performances { |             for performance in recording.performances { | ||||||
|                 let row = PerformanceRow { |                 let row = PerformanceRow { | ||||||
|                     id: rand::random(), |                     id: rand::random(), | ||||||
|                     recording: recording_id, |                     recording: recording_id.to_string(), | ||||||
|                     person: performance.person.map(|person| person.id as i64), |                     person: performance.person.map(|person| person.id), | ||||||
|                     ensemble: performance.ensemble.map(|ensemble| ensemble.id as i64), |                     ensemble: performance.ensemble.map(|ensemble| ensemble.id), | ||||||
|                     role: performance.role.map(|role| role.id as i64), |                     role: performance.role.map(|role| role.id), | ||||||
|                 }; |                 }; | ||||||
| 
 | 
 | ||||||
|                 diesel::insert_into(performances::table) |                 diesel::insert_into(performances::table) | ||||||
|  | @ -147,28 +147,28 @@ impl Database { | ||||||
|         let mut performance_descriptions: Vec<Performance> = Vec::new(); |         let mut performance_descriptions: Vec<Performance> = Vec::new(); | ||||||
| 
 | 
 | ||||||
|         let performance_rows = performances::table |         let performance_rows = performances::table | ||||||
|             .filter(performances::recording.eq(row.id)) |             .filter(performances::recording.eq(&row.id)) | ||||||
|             .load::<PerformanceRow>(&self.connection)?; |             .load::<PerformanceRow>(&self.connection)?; | ||||||
| 
 | 
 | ||||||
|         for row in performance_rows { |         for row in performance_rows { | ||||||
|             performance_descriptions.push(Performance { |             performance_descriptions.push(Performance { | ||||||
|                 person: match row.person { |                 person: match row.person { | ||||||
|                     Some(id) => Some( |                     Some(id) => Some( | ||||||
|                         self.get_person(id.try_into()?)? |                         self.get_person(&id)? | ||||||
|                             .ok_or(anyhow!("No person with ID: {}", id))?, |                             .ok_or(anyhow!("No person with ID: {}", id))?, | ||||||
|                     ), |                     ), | ||||||
|                     None => None, |                     None => None, | ||||||
|                 }, |                 }, | ||||||
|                 ensemble: match row.ensemble { |                 ensemble: match row.ensemble { | ||||||
|                     Some(id) => Some( |                     Some(id) => Some( | ||||||
|                         self.get_ensemble(id.try_into()?)? |                         self.get_ensemble(&id)? | ||||||
|                             .ok_or(anyhow!("No ensemble with ID: {}", id))?, |                             .ok_or(anyhow!("No ensemble with ID: {}", id))?, | ||||||
|                     ), |                     ), | ||||||
|                     None => None, |                     None => None, | ||||||
|                 }, |                 }, | ||||||
|                 role: match row.role { |                 role: match row.role { | ||||||
|                     Some(id) => Some( |                     Some(id) => Some( | ||||||
|                         self.get_instrument(id.try_into()?)? |                         self.get_instrument(&id)? | ||||||
|                             .ok_or(anyhow!("No instrument with ID: {}", id))?, |                             .ok_or(anyhow!("No instrument with ID: {}", id))?, | ||||||
|                     ), |                     ), | ||||||
|                     None => None, |                     None => None, | ||||||
|  | @ -176,13 +176,13 @@ impl Database { | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let work_id: u32 = row.work.try_into()?; |         let work_id = &row.work; | ||||||
|         let work = self |         let work = self | ||||||
|             .get_work(work_id)? |             .get_work(work_id)? | ||||||
|             .ok_or(anyhow!("Work doesn't exist: {}", work_id))?; |             .ok_or(anyhow!("Work doesn't exist: {}", work_id))?; | ||||||
| 
 | 
 | ||||||
|         let recording_description = Recording { |         let recording_description = Recording { | ||||||
|             id: row.id.try_into()?, |             id: row.id, | ||||||
|             work, |             work, | ||||||
|             comment: row.comment.clone(), |             comment: row.comment.clone(), | ||||||
|             performances: performance_descriptions, |             performances: performance_descriptions, | ||||||
|  | @ -192,13 +192,13 @@ impl Database { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Get all available information on all recordings where a person is performing.
 |     /// Get all available information on all recordings where a person is performing.
 | ||||||
|     pub fn get_recordings_for_person(&self, person_id: u32) -> Result<Vec<Recording>> { |     pub fn get_recordings_for_person(&self, person_id: &str) -> Result<Vec<Recording>> { | ||||||
|         let mut recordings: Vec<Recording> = Vec::new(); |         let mut recordings: Vec<Recording> = Vec::new(); | ||||||
| 
 | 
 | ||||||
|         let rows = recordings::table |         let rows = recordings::table | ||||||
|             .inner_join(performances::table.on(performances::recording.eq(recordings::id))) |             .inner_join(performances::table.on(performances::recording.eq(recordings::id))) | ||||||
|             .inner_join(persons::table.on(persons::id.nullable().eq(performances::person))) |             .inner_join(persons::table.on(persons::id.nullable().eq(performances::person))) | ||||||
|             .filter(persons::id.eq(person_id as i64)) |             .filter(persons::id.eq(person_id)) | ||||||
|             .select(recordings::table::all_columns()) |             .select(recordings::table::all_columns()) | ||||||
|             .load::<RecordingRow>(&self.connection)?; |             .load::<RecordingRow>(&self.connection)?; | ||||||
| 
 | 
 | ||||||
|  | @ -210,13 +210,13 @@ impl Database { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Get all available information on all recordings where an ensemble is performing.
 |     /// Get all available information on all recordings where an ensemble is performing.
 | ||||||
|     pub fn get_recordings_for_ensemble(&self, ensemble_id: u32) -> Result<Vec<Recording>> { |     pub fn get_recordings_for_ensemble(&self, ensemble_id: &str) -> Result<Vec<Recording>> { | ||||||
|         let mut recordings: Vec<Recording> = Vec::new(); |         let mut recordings: Vec<Recording> = Vec::new(); | ||||||
| 
 | 
 | ||||||
|         let rows = recordings::table |         let rows = recordings::table | ||||||
|             .inner_join(performances::table.on(performances::recording.eq(recordings::id))) |             .inner_join(performances::table.on(performances::recording.eq(recordings::id))) | ||||||
|             .inner_join(ensembles::table.on(ensembles::id.nullable().eq(performances::ensemble))) |             .inner_join(ensembles::table.on(ensembles::id.nullable().eq(performances::ensemble))) | ||||||
|             .filter(ensembles::id.eq(ensemble_id as i64)) |             .filter(ensembles::id.eq(ensemble_id)) | ||||||
|             .select(recordings::table::all_columns()) |             .select(recordings::table::all_columns()) | ||||||
|             .load::<RecordingRow>(&self.connection)?; |             .load::<RecordingRow>(&self.connection)?; | ||||||
| 
 | 
 | ||||||
|  | @ -228,11 +228,11 @@ impl Database { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Get allavailable information on all recordings of a work.
 |     /// Get allavailable information on all recordings of a work.
 | ||||||
|     pub fn get_recordings_for_work(&self, work_id: u32) -> Result<Vec<Recording>> { |     pub fn get_recordings_for_work(&self, work_id: &str) -> Result<Vec<Recording>> { | ||||||
|         let mut recordings: Vec<Recording> = Vec::new(); |         let mut recordings: Vec<Recording> = Vec::new(); | ||||||
| 
 | 
 | ||||||
|         let rows = recordings::table |         let rows = recordings::table | ||||||
|             .filter(recordings::work.eq(work_id as i64)) |             .filter(recordings::work.eq(work_id)) | ||||||
|             .load::<RecordingRow>(&self.connection)?; |             .load::<RecordingRow>(&self.connection)?; | ||||||
| 
 | 
 | ||||||
|         for row in rows { |         for row in rows { | ||||||
|  | @ -244,8 +244,8 @@ impl Database { | ||||||
| 
 | 
 | ||||||
|     /// Delete an existing recording. This will fail if there are still references to this
 |     /// Delete an existing recording. This will fail if there are still references to this
 | ||||||
|     /// recording from other tables that are not directly part of the recording data.
 |     /// recording from other tables that are not directly part of the recording data.
 | ||||||
|     pub fn delete_recording(&self, id: u32) -> Result<()> { |     pub fn delete_recording(&self, id: &str) -> Result<()> { | ||||||
|         diesel::delete(recordings::table.filter(recordings::id.eq(id as i64))) |         diesel::delete(recordings::table.filter(recordings::id.eq(id))) | ||||||
|             .execute(&self.connection)?; |             .execute(&self.connection)?; | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| table! { | table! { | ||||||
|     ensembles (id) { |     ensembles (id) { | ||||||
|         id -> BigInt, |         id -> Text, | ||||||
|         name -> Text, |         name -> Text, | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -8,14 +8,14 @@ table! { | ||||||
| table! { | table! { | ||||||
|     instrumentations (id) { |     instrumentations (id) { | ||||||
|         id -> BigInt, |         id -> BigInt, | ||||||
|         work -> BigInt, |         work -> Text, | ||||||
|         instrument -> BigInt, |         instrument -> Text, | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| table! { | table! { | ||||||
|     instruments (id) { |     instruments (id) { | ||||||
|         id -> BigInt, |         id -> Text, | ||||||
|         name -> Text, |         name -> Text, | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -23,16 +23,16 @@ table! { | ||||||
| table! { | table! { | ||||||
|     performances (id) { |     performances (id) { | ||||||
|         id -> BigInt, |         id -> BigInt, | ||||||
|         recording -> BigInt, |         recording -> Text, | ||||||
|         person -> Nullable<BigInt>, |         person -> Nullable<Text>, | ||||||
|         ensemble -> Nullable<BigInt>, |         ensemble -> Nullable<Text>, | ||||||
|         role -> Nullable<BigInt>, |         role -> Nullable<Text>, | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| table! { | table! { | ||||||
|     persons (id) { |     persons (id) { | ||||||
|         id -> BigInt, |         id -> Text, | ||||||
|         first_name -> Text, |         first_name -> Text, | ||||||
|         last_name -> Text, |         last_name -> Text, | ||||||
|     } |     } | ||||||
|  | @ -40,8 +40,8 @@ table! { | ||||||
| 
 | 
 | ||||||
| table! { | table! { | ||||||
|     recordings (id) { |     recordings (id) { | ||||||
|         id -> BigInt, |         id -> Text, | ||||||
|         work -> BigInt, |         work -> Text, | ||||||
|         comment -> Text, |         comment -> Text, | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -50,7 +50,7 @@ table! { | ||||||
|     tracks (id) { |     tracks (id) { | ||||||
|         id -> BigInt, |         id -> BigInt, | ||||||
|         file_name -> Text, |         file_name -> Text, | ||||||
|         recording -> BigInt, |         recording -> Text, | ||||||
|         track_index -> Integer, |         track_index -> Integer, | ||||||
|         work_parts -> Text, |         work_parts -> Text, | ||||||
|     } |     } | ||||||
|  | @ -59,17 +59,17 @@ table! { | ||||||
| table! { | table! { | ||||||
|     work_parts (id) { |     work_parts (id) { | ||||||
|         id -> BigInt, |         id -> BigInt, | ||||||
|         work -> BigInt, |         work -> Text, | ||||||
|         part_index -> BigInt, |         part_index -> BigInt, | ||||||
|         title -> Text, |         title -> Text, | ||||||
|         composer -> Nullable<BigInt>, |         composer -> Nullable<Text>, | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| table! { | table! { | ||||||
|     work_sections (id) { |     work_sections (id) { | ||||||
|         id -> BigInt, |         id -> BigInt, | ||||||
|         work -> BigInt, |         work -> Text, | ||||||
|         title -> Text, |         title -> Text, | ||||||
|         before_index -> BigInt, |         before_index -> BigInt, | ||||||
|     } |     } | ||||||
|  | @ -77,8 +77,8 @@ table! { | ||||||
| 
 | 
 | ||||||
| table! { | table! { | ||||||
|     works (id) { |     works (id) { | ||||||
|         id -> BigInt, |         id -> Text, | ||||||
|         composer -> BigInt, |         composer -> Text, | ||||||
|         title -> Text, |         title -> Text, | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -8,28 +8,28 @@ use std::thread; | ||||||
| /// An action the database thread can perform.
 | /// An action the database thread can perform.
 | ||||||
| enum Action { | enum Action { | ||||||
|     UpdatePerson(Person, Sender<Result<()>>), |     UpdatePerson(Person, Sender<Result<()>>), | ||||||
|     GetPerson(u32, Sender<Result<Option<Person>>>), |     GetPerson(String, Sender<Result<Option<Person>>>), | ||||||
|     DeletePerson(u32, Sender<Result<()>>), |     DeletePerson(String, Sender<Result<()>>), | ||||||
|     GetPersons(Sender<Result<Vec<Person>>>), |     GetPersons(Sender<Result<Vec<Person>>>), | ||||||
|     UpdateInstrument(Instrument, Sender<Result<()>>), |     UpdateInstrument(Instrument, Sender<Result<()>>), | ||||||
|     GetInstrument(u32, Sender<Result<Option<Instrument>>>), |     GetInstrument(String, Sender<Result<Option<Instrument>>>), | ||||||
|     DeleteInstrument(u32, Sender<Result<()>>), |     DeleteInstrument(String, Sender<Result<()>>), | ||||||
|     GetInstruments(Sender<Result<Vec<Instrument>>>), |     GetInstruments(Sender<Result<Vec<Instrument>>>), | ||||||
|     UpdateWork(Work, Sender<Result<()>>), |     UpdateWork(Work, Sender<Result<()>>), | ||||||
|     DeleteWork(u32, Sender<Result<()>>), |     DeleteWork(String, Sender<Result<()>>), | ||||||
|     GetWorks(u32, Sender<Result<Vec<Work>>>), |     GetWorks(String, Sender<Result<Vec<Work>>>), | ||||||
|     UpdateEnsemble(Ensemble, Sender<Result<()>>), |     UpdateEnsemble(Ensemble, Sender<Result<()>>), | ||||||
|     GetEnsemble(u32, Sender<Result<Option<Ensemble>>>), |     GetEnsemble(String, Sender<Result<Option<Ensemble>>>), | ||||||
|     DeleteEnsemble(u32, Sender<Result<()>>), |     DeleteEnsemble(String, Sender<Result<()>>), | ||||||
|     GetEnsembles(Sender<Result<Vec<Ensemble>>>), |     GetEnsembles(Sender<Result<Vec<Ensemble>>>), | ||||||
|     UpdateRecording(Recording, Sender<Result<()>>), |     UpdateRecording(Recording, Sender<Result<()>>), | ||||||
|     DeleteRecording(u32, Sender<Result<()>>), |     DeleteRecording(String, Sender<Result<()>>), | ||||||
|     GetRecordingsForPerson(u32, Sender<Result<Vec<Recording>>>), |     GetRecordingsForPerson(String, Sender<Result<Vec<Recording>>>), | ||||||
|     GetRecordingsForEnsemble(u32, Sender<Result<Vec<Recording>>>), |     GetRecordingsForEnsemble(String, Sender<Result<Vec<Recording>>>), | ||||||
|     GetRecordingsForWork(u32, Sender<Result<Vec<Recording>>>), |     GetRecordingsForWork(String, Sender<Result<Vec<Recording>>>), | ||||||
|     UpdateTracks(u32, Vec<Track>, Sender<Result<()>>), |     UpdateTracks(String, Vec<Track>, Sender<Result<()>>), | ||||||
|     DeleteTracks(u32, Sender<Result<()>>), |     DeleteTracks(String, Sender<Result<()>>), | ||||||
|     GetTracks(u32, Sender<Result<Vec<Track>>>), |     GetTracks(String, Sender<Result<Vec<Track>>>), | ||||||
|     Stop(Sender<()>), |     Stop(Sender<()>), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -64,10 +64,10 @@ impl DbThread { | ||||||
|                         sender.send(db.update_person(person)).unwrap(); |                         sender.send(db.update_person(person)).unwrap(); | ||||||
|                     } |                     } | ||||||
|                     GetPerson(id, sender) => { |                     GetPerson(id, sender) => { | ||||||
|                         sender.send(db.get_person(id)).unwrap(); |                         sender.send(db.get_person(&id)).unwrap(); | ||||||
|                     } |                     } | ||||||
|                     DeletePerson(id, sender) => { |                     DeletePerson(id, sender) => { | ||||||
|                         sender.send(db.delete_person(id)).unwrap(); |                         sender.send(db.delete_person(&id)).unwrap(); | ||||||
|                     } |                     } | ||||||
|                     GetPersons(sender) => { |                     GetPersons(sender) => { | ||||||
|                         sender.send(db.get_persons()).unwrap(); |                         sender.send(db.get_persons()).unwrap(); | ||||||
|  | @ -76,10 +76,10 @@ impl DbThread { | ||||||
|                         sender.send(db.update_instrument(instrument)).unwrap(); |                         sender.send(db.update_instrument(instrument)).unwrap(); | ||||||
|                     } |                     } | ||||||
|                     GetInstrument(id, sender) => { |                     GetInstrument(id, sender) => { | ||||||
|                         sender.send(db.get_instrument(id)).unwrap(); |                         sender.send(db.get_instrument(&id)).unwrap(); | ||||||
|                     } |                     } | ||||||
|                     DeleteInstrument(id, sender) => { |                     DeleteInstrument(id, sender) => { | ||||||
|                         sender.send(db.delete_instrument(id)).unwrap(); |                         sender.send(db.delete_instrument(&id)).unwrap(); | ||||||
|                     } |                     } | ||||||
|                     GetInstruments(sender) => { |                     GetInstruments(sender) => { | ||||||
|                         sender.send(db.get_instruments()).unwrap(); |                         sender.send(db.get_instruments()).unwrap(); | ||||||
|  | @ -88,19 +88,19 @@ impl DbThread { | ||||||
|                         sender.send(db.update_work(work)).unwrap(); |                         sender.send(db.update_work(work)).unwrap(); | ||||||
|                     } |                     } | ||||||
|                     DeleteWork(id, sender) => { |                     DeleteWork(id, sender) => { | ||||||
|                         sender.send(db.delete_work(id)).unwrap(); |                         sender.send(db.delete_work(&id)).unwrap(); | ||||||
|                     } |                     } | ||||||
|                     GetWorks(id, sender) => { |                     GetWorks(id, sender) => { | ||||||
|                         sender.send(db.get_works(id)).unwrap(); |                         sender.send(db.get_works(&id)).unwrap(); | ||||||
|                     } |                     } | ||||||
|                     UpdateEnsemble(ensemble, sender) => { |                     UpdateEnsemble(ensemble, sender) => { | ||||||
|                         sender.send(db.update_ensemble(ensemble)).unwrap(); |                         sender.send(db.update_ensemble(ensemble)).unwrap(); | ||||||
|                     } |                     } | ||||||
|                     GetEnsemble(id, sender) => { |                     GetEnsemble(id, sender) => { | ||||||
|                         sender.send(db.get_ensemble(id)).unwrap(); |                         sender.send(db.get_ensemble(&id)).unwrap(); | ||||||
|                     } |                     } | ||||||
|                     DeleteEnsemble(id, sender) => { |                     DeleteEnsemble(id, sender) => { | ||||||
|                         sender.send(db.delete_ensemble(id)).unwrap(); |                         sender.send(db.delete_ensemble(&id)).unwrap(); | ||||||
|                     } |                     } | ||||||
|                     GetEnsembles(sender) => { |                     GetEnsembles(sender) => { | ||||||
|                         sender.send(db.get_ensembles()).unwrap(); |                         sender.send(db.get_ensembles()).unwrap(); | ||||||
|  | @ -109,25 +109,27 @@ impl DbThread { | ||||||
|                         sender.send(db.update_recording(recording)).unwrap(); |                         sender.send(db.update_recording(recording)).unwrap(); | ||||||
|                     } |                     } | ||||||
|                     DeleteRecording(id, sender) => { |                     DeleteRecording(id, sender) => { | ||||||
|                         sender.send(db.delete_recording(id)).unwrap(); |                         sender.send(db.delete_recording(&id)).unwrap(); | ||||||
|                     } |                     } | ||||||
|                     GetRecordingsForPerson(id, sender) => { |                     GetRecordingsForPerson(id, sender) => { | ||||||
|                         sender.send(db.get_recordings_for_person(id)).unwrap(); |                         sender.send(db.get_recordings_for_person(&id)).unwrap(); | ||||||
|                     } |                     } | ||||||
|                     GetRecordingsForEnsemble(id, sender) => { |                     GetRecordingsForEnsemble(id, sender) => { | ||||||
|                         sender.send(db.get_recordings_for_ensemble(id)).unwrap(); |                         sender.send(db.get_recordings_for_ensemble(&id)).unwrap(); | ||||||
|                     } |                     } | ||||||
|                     GetRecordingsForWork(id, sender) => { |                     GetRecordingsForWork(id, sender) => { | ||||||
|                         sender.send(db.get_recordings_for_work(id)).unwrap(); |                         sender.send(db.get_recordings_for_work(&id)).unwrap(); | ||||||
|                     } |                     } | ||||||
|                     UpdateTracks(recording_id, tracks, sender) => { |                     UpdateTracks(recording_id, tracks, sender) => { | ||||||
|                         sender.send(db.update_tracks(recording_id, tracks)).unwrap(); |                         sender | ||||||
|  |                             .send(db.update_tracks(&recording_id, tracks)) | ||||||
|  |                             .unwrap(); | ||||||
|                     } |                     } | ||||||
|                     DeleteTracks(recording_id, sender) => { |                     DeleteTracks(recording_id, sender) => { | ||||||
|                         sender.send(db.delete_tracks(recording_id)).unwrap(); |                         sender.send(db.delete_tracks(&recording_id)).unwrap(); | ||||||
|                     } |                     } | ||||||
|                     GetTracks(recording_id, sender) => { |                     GetTracks(recording_id, sender) => { | ||||||
|                         sender.send(db.get_tracks(recording_id)).unwrap(); |                         sender.send(db.get_tracks(&recording_id)).unwrap(); | ||||||
|                     } |                     } | ||||||
|                     Stop(sender) => { |                     Stop(sender) => { | ||||||
|                         sender.send(()).unwrap(); |                         sender.send(()).unwrap(); | ||||||
|  | @ -149,17 +151,18 @@ impl DbThread { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Get an existing person.
 |     /// Get an existing person.
 | ||||||
|     pub async fn get_person(&self, id: u32) -> Result<Option<Person>> { |     pub async fn get_person(&self, id: &str) -> Result<Option<Person>> { | ||||||
|         let (sender, receiver) = oneshot::channel(); |         let (sender, receiver) = oneshot::channel(); | ||||||
|         self.action_sender.send(GetPerson(id, sender))?; |         self.action_sender.send(GetPerson(id.to_string(), sender))?; | ||||||
|         receiver.await? |         receiver.await? | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Delete an existing person. This will fail, if there are still other items referencing
 |     /// Delete an existing person. This will fail, if there are still other items referencing
 | ||||||
|     /// this person.
 |     /// this person.
 | ||||||
|     pub async fn delete_person(&self, id: u32) -> Result<()> { |     pub async fn delete_person(&self, id: &str) -> Result<()> { | ||||||
|         let (sender, receiver) = oneshot::channel(); |         let (sender, receiver) = oneshot::channel(); | ||||||
|         self.action_sender.send(DeletePerson(id, sender))?; |         self.action_sender | ||||||
|  |             .send(DeletePerson(id.to_string(), sender))?; | ||||||
|         receiver.await? |         receiver.await? | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -179,17 +182,19 @@ impl DbThread { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Get an existing instrument.
 |     /// Get an existing instrument.
 | ||||||
|     pub async fn get_instrument(&self, id: u32) -> Result<Option<Instrument>> { |     pub async fn get_instrument(&self, id: &str) -> Result<Option<Instrument>> { | ||||||
|         let (sender, receiver) = oneshot::channel(); |         let (sender, receiver) = oneshot::channel(); | ||||||
|         self.action_sender.send(GetInstrument(id, sender))?; |         self.action_sender | ||||||
|  |             .send(GetInstrument(id.to_string(), sender))?; | ||||||
|         receiver.await? |         receiver.await? | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Delete an existing instrument. This will fail, if there are still other items referencing
 |     /// Delete an existing instrument. This will fail, if there are still other items referencing
 | ||||||
|     /// this instrument.
 |     /// this instrument.
 | ||||||
|     pub async fn delete_instrument(&self, id: u32) -> Result<()> { |     pub async fn delete_instrument(&self, id: &str) -> Result<()> { | ||||||
|         let (sender, receiver) = oneshot::channel(); |         let (sender, receiver) = oneshot::channel(); | ||||||
|         self.action_sender.send(DeleteInstrument(id, sender))?; |         self.action_sender | ||||||
|  |             .send(DeleteInstrument(id.to_string(), sender))?; | ||||||
|         receiver.await? |         receiver.await? | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -209,16 +214,18 @@ impl DbThread { | ||||||
| 
 | 
 | ||||||
|     /// Delete an existing work. This will fail, if there are still other items referencing
 |     /// Delete an existing work. This will fail, if there are still other items referencing
 | ||||||
|     /// this work.
 |     /// this work.
 | ||||||
|     pub async fn delete_work(&self, id: u32) -> Result<()> { |     pub async fn delete_work(&self, id: &str) -> Result<()> { | ||||||
|         let (sender, receiver) = oneshot::channel(); |         let (sender, receiver) = oneshot::channel(); | ||||||
|         self.action_sender.send(DeleteWork(id, sender))?; |         self.action_sender | ||||||
|  |             .send(DeleteWork(id.to_string(), sender))?; | ||||||
|         receiver.await? |         receiver.await? | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Get information on all existing works by a composer.
 |     /// Get information on all existing works by a composer.
 | ||||||
|     pub async fn get_works(&self, person_id: u32) -> Result<Vec<Work>> { |     pub async fn get_works(&self, person_id: &str) -> Result<Vec<Work>> { | ||||||
|         let (sender, receiver) = oneshot::channel(); |         let (sender, receiver) = oneshot::channel(); | ||||||
|         self.action_sender.send(GetWorks(person_id, sender))?; |         self.action_sender | ||||||
|  |             .send(GetWorks(person_id.to_string(), sender))?; | ||||||
|         receiver.await? |         receiver.await? | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -230,17 +237,19 @@ impl DbThread { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Get an existing ensemble.
 |     /// Get an existing ensemble.
 | ||||||
|     pub async fn get_ensemble(&self, id: u32) -> Result<Option<Ensemble>> { |     pub async fn get_ensemble(&self, id: &str) -> Result<Option<Ensemble>> { | ||||||
|         let (sender, receiver) = oneshot::channel(); |         let (sender, receiver) = oneshot::channel(); | ||||||
|         self.action_sender.send(GetEnsemble(id, sender))?; |         self.action_sender | ||||||
|  |             .send(GetEnsemble(id.to_string(), sender))?; | ||||||
|         receiver.await? |         receiver.await? | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Delete an existing ensemble. This will fail, if there are still other items referencing
 |     /// Delete an existing ensemble. This will fail, if there are still other items referencing
 | ||||||
|     /// this ensemble.
 |     /// this ensemble.
 | ||||||
|     pub async fn delete_ensemble(&self, id: u32) -> Result<()> { |     pub async fn delete_ensemble(&self, id: &str) -> Result<()> { | ||||||
|         let (sender, receiver) = oneshot::channel(); |         let (sender, receiver) = oneshot::channel(); | ||||||
|         self.action_sender.send(DeleteEnsemble(id, sender))?; |         self.action_sender | ||||||
|  |             .send(DeleteEnsemble(id.to_string(), sender))?; | ||||||
|         receiver.await? |         receiver.await? | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -260,61 +269,59 @@ impl DbThread { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Delete an existing recording.
 |     /// Delete an existing recording.
 | ||||||
|     pub async fn delete_recording(&self, id: u32) -> Result<()> { |     pub async fn delete_recording(&self, id: &str) -> Result<()> { | ||||||
|         let (sender, receiver) = oneshot::channel(); |         let (sender, receiver) = oneshot::channel(); | ||||||
|         self.action_sender.send(DeleteRecording(id, sender))?; |         self.action_sender | ||||||
|  |             .send(DeleteRecording(id.to_string(), sender))?; | ||||||
|         receiver.await? |         receiver.await? | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Get information on all recordings in which a person performs.
 |     /// Get information on all recordings in which a person performs.
 | ||||||
|     pub async fn get_recordings_for_person(&self, person_id: u32) -> Result<Vec<Recording>> { |     pub async fn get_recordings_for_person(&self, person_id: &str) -> Result<Vec<Recording>> { | ||||||
|         let (sender, receiver) = oneshot::channel(); |         let (sender, receiver) = oneshot::channel(); | ||||||
|         self.action_sender |         self.action_sender | ||||||
|             .send(GetRecordingsForPerson(person_id, sender))?; |             .send(GetRecordingsForPerson(person_id.to_string(), sender))?; | ||||||
|         receiver.await? |         receiver.await? | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Get information on all recordings in which an ensemble performs.
 |     /// Get information on all recordings in which an ensemble performs.
 | ||||||
|     pub async fn get_recordings_for_ensemble(&self, ensemble_id: u32) -> Result<Vec<Recording>> { |     pub async fn get_recordings_for_ensemble(&self, ensemble_id: &str) -> Result<Vec<Recording>> { | ||||||
|         let (sender, receiver) = oneshot::channel(); |         let (sender, receiver) = oneshot::channel(); | ||||||
|         self.action_sender |         self.action_sender | ||||||
|             .send(GetRecordingsForEnsemble(ensemble_id, sender))?; |             .send(GetRecordingsForEnsemble(ensemble_id.to_string(), sender))?; | ||||||
|         receiver.await? |         receiver.await? | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Get information on all recordings of a work.
 |     /// Get information on all recordings of a work.
 | ||||||
|     pub async fn get_recordings_for_work(&self, work_id: u32) -> Result<Vec<Recording>> { |     pub async fn get_recordings_for_work(&self, work_id: &str) -> Result<Vec<Recording>> { | ||||||
|         let (sender, receiver) = oneshot::channel(); |         let (sender, receiver) = oneshot::channel(); | ||||||
|         self.action_sender |         self.action_sender | ||||||
|             .send(GetRecordingsForWork(work_id, sender))?; |             .send(GetRecordingsForWork(work_id.to_string(), sender))?; | ||||||
|         receiver.await? |         receiver.await? | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Add or change the tracks associated with a recording. This will fail, if there are still
 |     /// Add or change the tracks associated with a recording. This will fail, if there are still
 | ||||||
|     /// other items referencing this recording.
 |     /// other items referencing this recording.
 | ||||||
|     pub async fn update_tracks( |     pub async fn update_tracks(&self, recording_id: &str, tracks: Vec<Track>) -> Result<()> { | ||||||
|         &self, |  | ||||||
|         recording_id: u32, |  | ||||||
|         tracks: Vec<Track>, |  | ||||||
|     ) -> Result<()> { |  | ||||||
|         let (sender, receiver) = oneshot::channel(); |         let (sender, receiver) = oneshot::channel(); | ||||||
|         self.action_sender |         self.action_sender | ||||||
|             .send(UpdateTracks(recording_id, tracks, sender))?; |             .send(UpdateTracks(recording_id.to_string(), tracks, sender))?; | ||||||
|         receiver.await? |         receiver.await? | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Delete all tracks associated with a recording.
 |     /// Delete all tracks associated with a recording.
 | ||||||
|     pub async fn delete_tracks(&self, recording_id: u32) -> Result<()> { |     pub async fn delete_tracks(&self, recording_id: &str) -> Result<()> { | ||||||
|         let (sender, receiver) = oneshot::channel(); |         let (sender, receiver) = oneshot::channel(); | ||||||
|         self.action_sender |         self.action_sender | ||||||
|             .send(DeleteTracks(recording_id, sender))?; |             .send(DeleteTracks(recording_id.to_string(), sender))?; | ||||||
|         receiver.await? |         receiver.await? | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Get all tracks associated with a recording.
 |     /// Get all tracks associated with a recording.
 | ||||||
|     pub async fn get_tracks(&self, recording_id: u32) -> Result<Vec<Track>> { |     pub async fn get_tracks(&self, recording_id: &str) -> Result<Vec<Track>> { | ||||||
|         let (sender, receiver) = oneshot::channel(); |         let (sender, receiver) = oneshot::channel(); | ||||||
|         self.action_sender.send(GetTracks(recording_id, sender))?; |         self.action_sender | ||||||
|  |             .send(GetTracks(recording_id.to_string(), sender))?; | ||||||
|         receiver.await? |         receiver.await? | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -10,7 +10,7 @@ use std::convert::{TryFrom, TryInto}; | ||||||
| struct TrackRow { | struct TrackRow { | ||||||
|     pub id: i64, |     pub id: i64, | ||||||
|     pub file_name: String, |     pub file_name: String, | ||||||
|     pub recording: i64, |     pub recording: String, | ||||||
|     pub track_index: i32, |     pub track_index: i32, | ||||||
|     pub work_parts: String, |     pub work_parts: String, | ||||||
| } | } | ||||||
|  | @ -43,14 +43,14 @@ impl TryFrom<TrackRow> for Track { | ||||||
| 
 | 
 | ||||||
| impl Database { | impl Database { | ||||||
|     /// Insert or update tracks for the specified recording.
 |     /// Insert or update tracks for the specified recording.
 | ||||||
|     pub fn update_tracks(&self, recording_id: u32, tracks: Vec<Track>) -> Result<()> { |     pub fn update_tracks(&self, recording_id: &str, tracks: Vec<Track>) -> Result<()> { | ||||||
|         self.delete_tracks(recording_id)?; |         self.delete_tracks(recording_id)?; | ||||||
| 
 | 
 | ||||||
|         for (index, track) in tracks.iter().enumerate() { |         for (index, track) in tracks.iter().enumerate() { | ||||||
|             let row = TrackRow { |             let row = TrackRow { | ||||||
|                 id: rand::random(), |                 id: rand::random(), | ||||||
|                 file_name: track.file_name.clone(), |                 file_name: track.file_name.clone(), | ||||||
|                 recording: recording_id as i64, |                 recording: recording_id.to_string(), | ||||||
|                 track_index: index.try_into()?, |                 track_index: index.try_into()?, | ||||||
|                 work_parts: track |                 work_parts: track | ||||||
|                     .work_parts |                     .work_parts | ||||||
|  | @ -69,19 +69,19 @@ impl Database { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Delete all tracks for the specified recording.
 |     /// Delete all tracks for the specified recording.
 | ||||||
|     pub fn delete_tracks(&self, recording_id: u32) -> Result<()> { |     pub fn delete_tracks(&self, recording_id: &str) -> Result<()> { | ||||||
|         diesel::delete(tracks::table.filter(tracks::recording.eq(recording_id as i64))) |         diesel::delete(tracks::table.filter(tracks::recording.eq(recording_id))) | ||||||
|             .execute(&self.connection)?; |             .execute(&self.connection)?; | ||||||
| 
 | 
 | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Get all tracks of the specified recording.
 |     /// Get all tracks of the specified recording.
 | ||||||
|     pub fn get_tracks(&self, recording_id: u32) -> Result<Vec<Track>> { |     pub fn get_tracks(&self, recording_id: &str) -> Result<Vec<Track>> { | ||||||
|         let mut tracks = Vec::<Track>::new(); |         let mut tracks = Vec::<Track>::new(); | ||||||
| 
 | 
 | ||||||
|         let rows = tracks::table |         let rows = tracks::table | ||||||
|             .filter(tracks::recording.eq(recording_id as i64)) |             .filter(tracks::recording.eq(recording_id)) | ||||||
|             .order_by(tracks::track_index) |             .order_by(tracks::track_index) | ||||||
|             .load::<TrackRow>(&self.connection)?; |             .load::<TrackRow>(&self.connection)?; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -10,16 +10,16 @@ use std::convert::TryInto; | ||||||
| #[derive(Insertable, Queryable, Debug, Clone)] | #[derive(Insertable, Queryable, Debug, Clone)] | ||||||
| #[table_name = "works"] | #[table_name = "works"] | ||||||
| struct WorkRow { | struct WorkRow { | ||||||
|     pub id: i64, |     pub id: String, | ||||||
|     pub composer: i64, |     pub composer: String, | ||||||
|     pub title: String, |     pub title: String, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl From<Work> for WorkRow { | impl From<Work> for WorkRow { | ||||||
|     fn from(work: Work) -> Self { |     fn from(work: Work) -> Self { | ||||||
|         WorkRow { |         WorkRow { | ||||||
|             id: work.id as i64, |             id: work.id, | ||||||
|             composer: work.composer.id as i64, |             composer: work.composer.id, | ||||||
|             title: work.title, |             title: work.title, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -30,8 +30,8 @@ impl From<Work> for WorkRow { | ||||||
| #[table_name = "instrumentations"] | #[table_name = "instrumentations"] | ||||||
| struct InstrumentationRow { | struct InstrumentationRow { | ||||||
|     pub id: i64, |     pub id: i64, | ||||||
|     pub work: i64, |     pub work: String, | ||||||
|     pub instrument: i64, |     pub instrument: String, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Table row data for a work part.
 | /// Table row data for a work part.
 | ||||||
|  | @ -39,10 +39,10 @@ struct InstrumentationRow { | ||||||
| #[table_name = "work_parts"] | #[table_name = "work_parts"] | ||||||
| struct WorkPartRow { | struct WorkPartRow { | ||||||
|     pub id: i64, |     pub id: i64, | ||||||
|     pub work: i64, |     pub work: String, | ||||||
|     pub part_index: i64, |     pub part_index: i64, | ||||||
|     pub title: String, |     pub title: String, | ||||||
|     pub composer: Option<i64>, |     pub composer: Option<String>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Table row data for a work section.
 | /// Table row data for a work section.
 | ||||||
|  | @ -50,7 +50,7 @@ struct WorkPartRow { | ||||||
| #[table_name = "work_sections"] | #[table_name = "work_sections"] | ||||||
| struct WorkSectionRow { | struct WorkSectionRow { | ||||||
|     pub id: i64, |     pub id: i64, | ||||||
|     pub work: i64, |     pub work: String, | ||||||
|     pub title: String, |     pub title: String, | ||||||
|     pub before_index: i64, |     pub before_index: i64, | ||||||
| } | } | ||||||
|  | @ -74,7 +74,7 @@ pub struct WorkSection { | ||||||
| #[derive(Serialize, Deserialize, Debug, Clone)] | #[derive(Serialize, Deserialize, Debug, Clone)] | ||||||
| #[serde(rename_all = "camelCase")] | #[serde(rename_all = "camelCase")] | ||||||
| pub struct Work { | pub struct Work { | ||||||
|     pub id: u32, |     pub id: String, | ||||||
|     pub title: String, |     pub title: String, | ||||||
|     pub composer: Person, |     pub composer: Person, | ||||||
|     pub instruments: Vec<Instrument>, |     pub instruments: Vec<Instrument>, | ||||||
|  | @ -97,9 +97,9 @@ impl Database { | ||||||
|         self.defer_foreign_keys()?; |         self.defer_foreign_keys()?; | ||||||
| 
 | 
 | ||||||
|         self.connection.transaction::<(), Error, _>(|| { |         self.connection.transaction::<(), Error, _>(|| { | ||||||
|             self.delete_work(work.id)?; |             let work_id = &work.id; | ||||||
|  |             self.delete_work(work_id)?; | ||||||
| 
 | 
 | ||||||
|             let work_id = work.id as i64; |  | ||||||
|             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) | ||||||
|  | @ -115,8 +115,8 @@ impl Database { | ||||||
|                     for instrument in instruments { |                     for instrument in instruments { | ||||||
|                         let row = InstrumentationRow { |                         let row = InstrumentationRow { | ||||||
|                             id: rand::random(), |                             id: rand::random(), | ||||||
|                             work: work_id, |                             work: work_id.to_string(), | ||||||
|                             instrument: instrument.id as i64, |                             instrument: instrument.id, | ||||||
|                         }; |                         }; | ||||||
| 
 | 
 | ||||||
|                         diesel::insert_into(instrumentations::table) |                         diesel::insert_into(instrumentations::table) | ||||||
|  | @ -127,10 +127,10 @@ impl Database { | ||||||
|                     for (index, part) in parts.into_iter().enumerate() { |                     for (index, part) in parts.into_iter().enumerate() { | ||||||
|                         let row = WorkPartRow { |                         let row = WorkPartRow { | ||||||
|                             id: rand::random(), |                             id: rand::random(), | ||||||
|                             work: work_id, |                             work: work_id.to_string(), | ||||||
|                             part_index: index.try_into()?, |                             part_index: index.try_into()?, | ||||||
|                             title: part.title, |                             title: part.title, | ||||||
|                             composer: part.composer.map(|person| person.id as i64), |                             composer: part.composer.map(|person| person.id), | ||||||
|                         }; |                         }; | ||||||
| 
 | 
 | ||||||
|                         diesel::insert_into(work_parts::table) |                         diesel::insert_into(work_parts::table) | ||||||
|  | @ -141,7 +141,7 @@ impl Database { | ||||||
|                     for section in sections { |                     for section in sections { | ||||||
|                         let row = WorkSectionRow { |                         let row = WorkSectionRow { | ||||||
|                             id: rand::random(), |                             id: rand::random(), | ||||||
|                             work: work_id, |                             work: work_id.to_string(), | ||||||
|                             title: section.title, |                             title: section.title, | ||||||
|                             before_index: section.before_index.try_into()?, |                             before_index: section.before_index.try_into()?, | ||||||
|                         }; |                         }; | ||||||
|  | @ -160,9 +160,9 @@ impl Database { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Get an existing work.
 |     /// Get an existing work.
 | ||||||
|     pub fn get_work(&self, id: u32) -> Result<Option<Work>> { |     pub fn get_work(&self, id: &str) -> Result<Option<Work>> { | ||||||
|         let row = works::table |         let row = works::table | ||||||
|             .filter(works::id.eq(id as i64)) |             .filter(works::id.eq(id)) | ||||||
|             .load::<WorkRow>(&self.connection)? |             .load::<WorkRow>(&self.connection)? | ||||||
|             .first() |             .first() | ||||||
|             .cloned(); |             .cloned(); | ||||||
|  | @ -180,11 +180,11 @@ impl Database { | ||||||
|         let mut instruments: Vec<Instrument> = Vec::new(); |         let mut instruments: Vec<Instrument> = Vec::new(); | ||||||
| 
 | 
 | ||||||
|         let instrumentations = instrumentations::table |         let instrumentations = instrumentations::table | ||||||
|             .filter(instrumentations::work.eq(row.id)) |             .filter(instrumentations::work.eq(&row.id)) | ||||||
|             .load::<InstrumentationRow>(&self.connection)?; |             .load::<InstrumentationRow>(&self.connection)?; | ||||||
| 
 | 
 | ||||||
|         for instrumentation in instrumentations { |         for instrumentation in instrumentations { | ||||||
|             let id: u32 = instrumentation.instrument.try_into()?; |             let id = &instrumentation.instrument; | ||||||
|             instruments.push( |             instruments.push( | ||||||
|                 self.get_instrument(id)? |                 self.get_instrument(id)? | ||||||
|                     .ok_or(anyhow!("No instrument with ID: {}", id))?, |                     .ok_or(anyhow!("No instrument with ID: {}", id))?, | ||||||
|  | @ -194,7 +194,7 @@ impl Database { | ||||||
|         let mut parts: Vec<WorkPart> = Vec::new(); |         let mut parts: Vec<WorkPart> = Vec::new(); | ||||||
| 
 | 
 | ||||||
|         let part_rows = work_parts::table |         let part_rows = work_parts::table | ||||||
|             .filter(work_parts::work.eq(row.id)) |             .filter(work_parts::work.eq(&row.id)) | ||||||
|             .load::<WorkPartRow>(&self.connection)?; |             .load::<WorkPartRow>(&self.connection)?; | ||||||
| 
 | 
 | ||||||
|         for part_row in part_rows { |         for part_row in part_rows { | ||||||
|  | @ -202,7 +202,7 @@ impl Database { | ||||||
|                 title: part_row.title, |                 title: part_row.title, | ||||||
|                 composer: match part_row.composer { |                 composer: match part_row.composer { | ||||||
|                     Some(composer) => Some( |                     Some(composer) => Some( | ||||||
|                         self.get_person(composer.try_into()?)? |                         self.get_person(&composer)? | ||||||
|                             .ok_or(anyhow!("No person with ID: {}", composer))?, |                             .ok_or(anyhow!("No person with ID: {}", composer))?, | ||||||
|                     ), |                     ), | ||||||
|                     None => None, |                     None => None, | ||||||
|  | @ -213,7 +213,7 @@ impl Database { | ||||||
|         let mut sections: Vec<WorkSection> = Vec::new(); |         let mut sections: Vec<WorkSection> = Vec::new(); | ||||||
| 
 | 
 | ||||||
|         let section_rows = work_sections::table |         let section_rows = work_sections::table | ||||||
|             .filter(work_sections::work.eq(row.id)) |             .filter(work_sections::work.eq(&row.id)) | ||||||
|             .load::<WorkSectionRow>(&self.connection)?; |             .load::<WorkSectionRow>(&self.connection)?; | ||||||
| 
 | 
 | ||||||
|         for section_row in section_rows { |         for section_row in section_rows { | ||||||
|  | @ -223,13 +223,13 @@ impl Database { | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let person_id = row.composer.try_into()?; |         let person_id = &row.composer; | ||||||
|         let person = self |         let person = self | ||||||
|             .get_person(person_id)? |             .get_person(person_id)? | ||||||
|             .ok_or(anyhow!("Person doesn't exist: {}", person_id))?; |             .ok_or(anyhow!("Person doesn't exist: {}", person_id))?; | ||||||
| 
 | 
 | ||||||
|         Ok(Work { |         Ok(Work { | ||||||
|             id: row.id.try_into()?, |             id: row.id, | ||||||
|             composer: person, |             composer: person, | ||||||
|             title: row.title, |             title: row.title, | ||||||
|             instruments, |             instruments, | ||||||
|  | @ -240,17 +240,17 @@ impl Database { | ||||||
| 
 | 
 | ||||||
|     /// Delete an existing work. This will fail if there are still other tables that relate to
 |     /// Delete an existing work. This will fail if there are still other tables that relate to
 | ||||||
|     /// this work except for the things that are part of the information on the work it
 |     /// this work except for the things that are part of the information on the work it
 | ||||||
|     pub fn delete_work(&self, id: u32) -> Result<()> { |     pub fn delete_work(&self, id: &str) -> Result<()> { | ||||||
|         diesel::delete(works::table.filter(works::id.eq(id as i64))).execute(&self.connection)?; |         diesel::delete(works::table.filter(works::id.eq(id))).execute(&self.connection)?; | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Get all existing works by a composer and related information from other tables.
 |     /// Get all existing works by a composer and related information from other tables.
 | ||||||
|     pub fn get_works(&self, composer_id: u32) -> Result<Vec<Work>> { |     pub fn get_works(&self, composer_id: &str) -> Result<Vec<Work>> { | ||||||
|         let mut works: Vec<Work> = Vec::new(); |         let mut works: Vec<Work> = Vec::new(); | ||||||
| 
 | 
 | ||||||
|         let rows = works::table |         let rows = works::table | ||||||
|             .filter(works::composer.eq(composer_id as i64)) |             .filter(works::composer.eq(composer_id)) | ||||||
|             .load::<WorkRow>(&self.connection)?; |             .load::<WorkRow>(&self.connection)?; | ||||||
| 
 | 
 | ||||||
|         for row in rows { |         for row in rows { | ||||||
|  |  | ||||||
|  | @ -12,7 +12,7 @@ where | ||||||
|     backend: Rc<Backend>, |     backend: Rc<Backend>, | ||||||
|     window: libhandy::Window, |     window: libhandy::Window, | ||||||
|     callback: F, |     callback: F, | ||||||
|     id: u32, |     id: String, | ||||||
|     name_entry: gtk::Entry, |     name_entry: gtk::Entry, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -38,7 +38,7 @@ where | ||||||
|                 name_entry.set_text(&ensemble.name); |                 name_entry.set_text(&ensemble.name); | ||||||
|                 ensemble.id |                 ensemble.id | ||||||
|             } |             } | ||||||
|             None => rand::random::<u32>().into(), |             None => generate_id(), | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         let result = Rc::new(EnsembleEditor { |         let result = Rc::new(EnsembleEditor { | ||||||
|  | @ -55,7 +55,7 @@ where | ||||||
| 
 | 
 | ||||||
|         save_button.connect_clicked(clone!(@strong result => move |_| { |         save_button.connect_clicked(clone!(@strong result => move |_| { | ||||||
|             let ensemble = Ensemble { |             let ensemble = Ensemble { | ||||||
|                 id: result.id, |                 id: result.id.clone(), | ||||||
|                 name: result.name_entry.get_text().to_string(), |                 name: result.name_entry.get_text().to_string(), | ||||||
|             }; |             }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -12,7 +12,7 @@ where | ||||||
|     backend: Rc<Backend>, |     backend: Rc<Backend>, | ||||||
|     window: libhandy::Window, |     window: libhandy::Window, | ||||||
|     callback: F, |     callback: F, | ||||||
|     id: u32, |     id: String, | ||||||
|     name_entry: gtk::Entry, |     name_entry: gtk::Entry, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -26,8 +26,7 @@ where | ||||||
|         instrument: Option<Instrument>, |         instrument: Option<Instrument>, | ||||||
|         callback: F, |         callback: F, | ||||||
|     ) -> Rc<Self> { |     ) -> Rc<Self> { | ||||||
|         let builder = |         let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/instrument_editor.ui"); | ||||||
|             gtk::Builder::from_resource("/de/johrpan/musicus/ui/instrument_editor.ui"); |  | ||||||
| 
 | 
 | ||||||
|         get_widget!(builder, libhandy::Window, window); |         get_widget!(builder, libhandy::Window, window); | ||||||
|         get_widget!(builder, gtk::Button, cancel_button); |         get_widget!(builder, gtk::Button, cancel_button); | ||||||
|  | @ -39,7 +38,7 @@ where | ||||||
|                 name_entry.set_text(&instrument.name); |                 name_entry.set_text(&instrument.name); | ||||||
|                 instrument.id |                 instrument.id | ||||||
|             } |             } | ||||||
|             None => rand::random::<u32>().into(), |             None => generate_id(), | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         let result = Rc::new(InstrumentEditor { |         let result = Rc::new(InstrumentEditor { | ||||||
|  | @ -56,7 +55,7 @@ where | ||||||
| 
 | 
 | ||||||
|         save_button.connect_clicked(clone!(@strong result => move |_| { |         save_button.connect_clicked(clone!(@strong result => move |_| { | ||||||
|             let instrument = Instrument { |             let instrument = Instrument { | ||||||
|                 id: result.id, |                 id: result.id.clone(), | ||||||
|                 name: result.name_entry.get_text().to_string(), |                 name: result.name_entry.get_text().to_string(), | ||||||
|             }; |             }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ where | ||||||
|     F: Fn(Person) -> () + 'static, |     F: Fn(Person) -> () + 'static, | ||||||
| { | { | ||||||
|     backend: Rc<Backend>, |     backend: Rc<Backend>, | ||||||
|  |     id: String, | ||||||
|     window: libhandy::Window, |     window: libhandy::Window, | ||||||
|     callback: F, |     callback: F, | ||||||
|     id: u32, |     id: u32, | ||||||
|  |  | ||||||
|  | @ -20,7 +20,7 @@ pub struct RecordingEditor { | ||||||
|     work_label: gtk::Label, |     work_label: gtk::Label, | ||||||
|     comment_entry: gtk::Entry, |     comment_entry: gtk::Entry, | ||||||
|     performance_list: Rc<List<Performance>>, |     performance_list: Rc<List<Performance>>, | ||||||
|     id: u32, |     id: String, | ||||||
|     work: RefCell<Option<Work>>, |     work: RefCell<Option<Work>>, | ||||||
|     performances: RefCell<Vec<Performance>>, |     performances: RefCell<Vec<Performance>>, | ||||||
|     selected_cb: RefCell<Option<Box<dyn Fn(Recording) -> ()>>>, |     selected_cb: RefCell<Option<Box<dyn Fn(Recording) -> ()>>>, | ||||||
|  | @ -59,7 +59,7 @@ impl RecordingEditor { | ||||||
|                 comment_entry.set_text(&recording.comment); |                 comment_entry.set_text(&recording.comment); | ||||||
|                 (recording.id, Some(recording.work), recording.performances) |                 (recording.id, Some(recording.work), recording.performances) | ||||||
|             } |             } | ||||||
|             None => (rand::random::<u32>().into(), None, Vec::new()), |             None => (generate_id(), None, Vec::new()), | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         let this = Rc::new(RecordingEditor { |         let this = Rc::new(RecordingEditor { | ||||||
|  | @ -88,7 +88,7 @@ impl RecordingEditor { | ||||||
|         this.save_button |         this.save_button | ||||||
|             .connect_clicked(clone!(@strong this => move |_| { |             .connect_clicked(clone!(@strong this => move |_| { | ||||||
|                 let recording = Recording { |                 let recording = Recording { | ||||||
|                     id: this.id, |                     id: this.id.clone(), | ||||||
|                     work: this.work.borrow().clone().expect("Tried to create recording without work!"), |                     work: this.work.borrow().clone().expect("Tried to create recording without work!"), | ||||||
|                     comment: this.comment_entry.get_text().to_string(), |                     comment: this.comment_entry.get_text().to_string(), | ||||||
|                     performances: this.performances.borrow().clone(), |                     performances: this.performances.borrow().clone(), | ||||||
|  |  | ||||||
|  | @ -92,7 +92,7 @@ impl RecordingSelectorPersonScreen { | ||||||
|         let context = glib::MainContext::default(); |         let context = glib::MainContext::default(); | ||||||
|         let clone = this.clone(); |         let clone = this.clone(); | ||||||
|         context.spawn_local(async move { |         context.spawn_local(async move { | ||||||
|             let works = clone.backend.db().get_works(person.id).await.unwrap(); |             let works = clone.backend.db().get_works(&person.id).await.unwrap(); | ||||||
| 
 | 
 | ||||||
|             clone.work_list.show_items(works); |             clone.work_list.show_items(works); | ||||||
|             clone.stack.set_visible_child_name("content"); |             clone.stack.set_visible_child_name("content"); | ||||||
|  |  | ||||||
|  | @ -90,7 +90,7 @@ impl RecordingSelectorWorkScreen { | ||||||
|             let recordings = clone |             let recordings = clone | ||||||
|                 .backend |                 .backend | ||||||
|                 .db() |                 .db() | ||||||
|                 .get_recordings_for_work(work.id) |                 .get_recordings_for_work(&work.id) | ||||||
|                 .await |                 .await | ||||||
|                 .unwrap(); |                 .unwrap(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -81,7 +81,7 @@ impl TracksEditor { | ||||||
|                 let this = this.clone(); |                 let this = this.clone(); | ||||||
|                 context.spawn_local(async move { |                 context.spawn_local(async move { | ||||||
|                     this.backend.db().update_tracks( |                     this.backend.db().update_tracks( | ||||||
|                         this.recording.borrow().as_ref().unwrap().id as u32, |                         &this.recording.borrow().as_ref().unwrap().id, | ||||||
|                         this.tracks.borrow().clone(), |                         this.tracks.borrow().clone(), | ||||||
|                     ).await.unwrap(); |                     ).await.unwrap(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -29,7 +29,7 @@ pub struct WorkEditor { | ||||||
|     composer_label: gtk::Label, |     composer_label: gtk::Label, | ||||||
|     instrument_list: Rc<List<Instrument>>, |     instrument_list: Rc<List<Instrument>>, | ||||||
|     part_list: Rc<List<PartOrSection>>, |     part_list: Rc<List<PartOrSection>>, | ||||||
|     id: u32, |     id: String, | ||||||
|     composer: RefCell<Option<Person>>, |     composer: RefCell<Option<Person>>, | ||||||
|     instruments: RefCell<Vec<Instrument>>, |     instruments: RefCell<Vec<Instrument>>, | ||||||
|     structure: RefCell<Vec<PartOrSection>>, |     structure: RefCell<Vec<PartOrSection>>, | ||||||
|  | @ -91,7 +91,7 @@ impl WorkEditor { | ||||||
| 
 | 
 | ||||||
|                 (work.id, Some(work.composer), work.instruments, structure) |                 (work.id, Some(work.composer), work.instruments, structure) | ||||||
|             } |             } | ||||||
|             None => (rand::random::<u32>().into(), None, Vec::new(), Vec::new()), |             None => (generate_id(), None, Vec::new(), Vec::new()), | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         let this = Rc::new(Self { |         let this = Rc::new(Self { | ||||||
|  | @ -137,7 +137,7 @@ impl WorkEditor { | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             let work = Work { |             let work = Work { | ||||||
|                 id: this.id, |                 id: this.id.clone(), | ||||||
|                 title: this.title_entry.get_text().to_string(), |                 title: this.title_entry.get_text().to_string(), | ||||||
|                 composer: this.composer.borrow().clone().expect("Tried to create work without composer!"), |                 composer: this.composer.borrow().clone().expect("Tried to create work without composer!"), | ||||||
|                 instruments: this.instruments.borrow().clone(), |                 instruments: this.instruments.borrow().clone(), | ||||||
|  |  | ||||||
|  | @ -80,7 +80,7 @@ impl WorkSelectorPersonScreen { | ||||||
|         let context = glib::MainContext::default(); |         let context = glib::MainContext::default(); | ||||||
|         let clone = this.clone(); |         let clone = this.clone(); | ||||||
|         context.spawn_local(async move { |         context.spawn_local(async move { | ||||||
|             let works = clone.backend.db().get_works(person.id).await.unwrap(); |             let works = clone.backend.db().get_works(&person.id).await.unwrap(); | ||||||
| 
 | 
 | ||||||
|             clone.work_list.show_items(works); |             clone.work_list.show_items(works); | ||||||
|             clone.stack.set_visible_child_name("content"); |             clone.stack.set_visible_child_name("content"); | ||||||
|  |  | ||||||
|  | @ -116,7 +116,7 @@ impl EnsembleScreen { | ||||||
|             let context = glib::MainContext::default(); |             let context = glib::MainContext::default(); | ||||||
|             let clone = result.clone(); |             let clone = result.clone(); | ||||||
|             context.spawn_local(async move { |             context.spawn_local(async move { | ||||||
|                 clone.backend.db().delete_ensemble(clone.ensemble.id).await.unwrap(); |                 clone.backend.db().delete_ensemble(&clone.ensemble.id).await.unwrap(); | ||||||
|             }); |             }); | ||||||
|         })); |         })); | ||||||
| 
 | 
 | ||||||
|  | @ -126,7 +126,7 @@ impl EnsembleScreen { | ||||||
|             let recordings = clone |             let recordings = clone | ||||||
|                 .backend |                 .backend | ||||||
|                 .db() |                 .db() | ||||||
|                 .get_recordings_for_ensemble(clone.ensemble.id) |                 .get_recordings_for_ensemble(&clone.ensemble.id) | ||||||
|                 .await |                 .await | ||||||
|                 .unwrap(); |                 .unwrap(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -145,14 +145,14 @@ impl PersonScreen { | ||||||
|             })); |             })); | ||||||
| 
 | 
 | ||||||
|         edit_action.connect_activate(clone!(@strong result => move |_, _| { |         edit_action.connect_activate(clone!(@strong result => move |_, _| { | ||||||
|             PersonEditor::new(result.backend.clone(), &result.window, Some(result.person.clone()), |_| {}).show(); |             PersonEditor::new(result.backend.clone(), &result.window, Some(result.person.clone())).show(); | ||||||
|         })); |         })); | ||||||
| 
 | 
 | ||||||
|         delete_action.connect_activate(clone!(@strong result => move |_, _| { |         delete_action.connect_activate(clone!(@strong result => move |_, _| { | ||||||
|             let context = glib::MainContext::default(); |             let context = glib::MainContext::default(); | ||||||
|             let clone = result.clone(); |             let clone = result.clone(); | ||||||
|             context.spawn_local(async move { |             context.spawn_local(async move { | ||||||
|                 clone.backend.db().delete_person(clone.person.id).await.unwrap(); |                 clone.backend.db().delete_person(&clone.person.id).await.unwrap(); | ||||||
|             }); |             }); | ||||||
|         })); |         })); | ||||||
| 
 | 
 | ||||||
|  | @ -162,13 +162,13 @@ impl PersonScreen { | ||||||
|             let works = clone |             let works = clone | ||||||
|                 .backend |                 .backend | ||||||
|                 .db() |                 .db() | ||||||
|                 .get_works(clone.person.id as u32) |                 .get_works(&clone.person.id) | ||||||
|                 .await |                 .await | ||||||
|                 .unwrap(); |                 .unwrap(); | ||||||
|             let recordings = clone |             let recordings = clone | ||||||
|                 .backend |                 .backend | ||||||
|                 .db() |                 .db() | ||||||
|                 .get_recordings_for_person(clone.person.id as u32) |                 .get_recordings_for_person(&clone.person.id) | ||||||
|                 .await |                 .await | ||||||
|                 .unwrap(); |                 .unwrap(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -118,7 +118,7 @@ impl RecordingScreen { | ||||||
|             let context = glib::MainContext::default(); |             let context = glib::MainContext::default(); | ||||||
|             let clone = result.clone(); |             let clone = result.clone(); | ||||||
|             context.spawn_local(async move { |             context.spawn_local(async move { | ||||||
|                 clone.backend.db().delete_recording(clone.recording.id).await.unwrap(); |                 clone.backend.db().delete_recording(&clone.recording.id).await.unwrap(); | ||||||
|             }); |             }); | ||||||
|         })); |         })); | ||||||
| 
 | 
 | ||||||
|  | @ -130,7 +130,7 @@ impl RecordingScreen { | ||||||
|             let context = glib::MainContext::default(); |             let context = glib::MainContext::default(); | ||||||
|             let clone = result.clone(); |             let clone = result.clone(); | ||||||
|             context.spawn_local(async move { |             context.spawn_local(async move { | ||||||
|                 clone.backend.db().delete_tracks(clone.recording.id).await.unwrap(); |                 clone.backend.db().delete_tracks(&clone.recording.id).await.unwrap(); | ||||||
|             }); |             }); | ||||||
|         })); |         })); | ||||||
| 
 | 
 | ||||||
|  | @ -140,7 +140,7 @@ impl RecordingScreen { | ||||||
|             let tracks = clone |             let tracks = clone | ||||||
|                 .backend |                 .backend | ||||||
|                 .db() |                 .db() | ||||||
|                 .get_tracks(clone.recording.id) |                 .get_tracks(&clone.recording.id) | ||||||
|                 .await |                 .await | ||||||
|                 .unwrap(); |                 .unwrap(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -115,7 +115,7 @@ impl WorkScreen { | ||||||
|             let context = glib::MainContext::default(); |             let context = glib::MainContext::default(); | ||||||
|             let clone = result.clone(); |             let clone = result.clone(); | ||||||
|             context.spawn_local(async move { |             context.spawn_local(async move { | ||||||
|                 clone.backend.db().delete_work(clone.work.id).await.unwrap(); |                 clone.backend.db().delete_work(&clone.work.id).await.unwrap(); | ||||||
|             }); |             }); | ||||||
|         })); |         })); | ||||||
| 
 | 
 | ||||||
|  | @ -125,7 +125,7 @@ impl WorkScreen { | ||||||
|             let recordings = clone |             let recordings = clone | ||||||
|                 .backend |                 .backend | ||||||
|                 .db() |                 .db() | ||||||
|                 .get_recordings_for_work(clone.work.id as u32) |                 .get_recordings_for_work(&clone.work.id) | ||||||
|                 .await |                 .await | ||||||
|                 .unwrap(); |                 .unwrap(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Elias Projahn
						Elias Projahn