client: Switch to string IDs

This commit is contained in:
Elias Projahn 2020-11-28 21:45:22 +01:00
parent 157bdb2917
commit 5c3377e246
24 changed files with 249 additions and 363 deletions

View file

@ -25,3 +25,4 @@ rand = "0.7.3"
secret-service = "1.1.1"
serde = { version = "1.0.117", features = ["derive"] }
serde_json = "1.0.59"
uuid = { version = "0.8", features = ["v4"] }

View file

@ -1,64 +1,64 @@
CREATE TABLE persons (
id BIGINT NOT NULL PRIMARY KEY,
id TEXT NOT NULL PRIMARY KEY,
first_name TEXT NOT NULL,
last_name TEXT NOT NULL
);
CREATE TABLE instruments (
id BIGINT NOT NULL PRIMARY KEY,
id TEXT NOT NULL PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE works (
id BIGINT NOT NULL PRIMARY KEY,
composer BIGINT NOT NULL REFERENCES persons(id),
id TEXT NOT NULL PRIMARY KEY,
composer TEXT NOT NULL REFERENCES persons(id),
title TEXT NOT NULL
);
CREATE TABLE instrumentations (
id BIGINT NOT NULL PRIMARY KEY,
work BIGINT NOT NULL REFERENCES works(id) ON DELETE CASCADE,
instrument BIGINT NOT NULL REFERENCES instruments(id) ON DELETE CASCADE
work TEXT NOT NULL REFERENCES works(id) ON DELETE CASCADE,
instrument TEXT NOT NULL REFERENCES instruments(id) ON DELETE CASCADE
);
CREATE TABLE work_parts (
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,
title TEXT NOT NULL,
composer BIGINT REFERENCES persons(id)
composer TEXT REFERENCES persons(id)
);
CREATE TABLE work_sections (
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,
before_index BIGINT NOT NULL
);
CREATE TABLE ensembles (
id BIGINT NOT NULL PRIMARY KEY,
id TEXT NOT NULL PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE recordings (
id BIGINT NOT NULL PRIMARY KEY,
work BIGINT NOT NULL REFERENCES works(id),
id TEXT NOT NULL PRIMARY KEY,
work TEXT NOT NULL REFERENCES works(id),
comment TEXT NOT NULL
);
CREATE TABLE performances (
id BIGINT NOT NULL PRIMARY KEY,
recording BIGINT NOT NULL REFERENCES recordings(id) ON DELETE CASCADE,
person BIGINT REFERENCES persons(id),
ensemble BIGINT REFERENCES ensembles(id),
role BIGINT REFERENCES instruments(id)
recording TEXT NOT NULL REFERENCES recordings(id) ON DELETE CASCADE,
person TEXT REFERENCES persons(id),
ensemble TEXT REFERENCES ensembles(id),
role TEXT REFERENCES instruments(id)
);
CREATE TABLE tracks (
id BIGINT NOT NULL PRIMARY KEY,
file_name TEXT NOT NULL,
recording BIGINT NOT NULL REFERENCES recordings(id),
recording TEXT NOT NULL REFERENCES recordings(id),
track_index INTEGER NOT NULL,
work_parts TEXT NOT NULL
);

View file

@ -1,57 +1,25 @@
use super::schema::ensembles;
use super::Database;
use anyhow::{Error, Result};
use anyhow::Result;
use diesel::prelude::*;
use diesel::{Insertable, Queryable};
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.
#[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Serialize, Deserialize, Insertable, Queryable, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Ensemble {
pub id: u32,
pub id: 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 {
/// Update an existing ensemble or insert a new one.
pub fn update_ensemble(&self, ensemble: Ensemble) -> Result<()> {
self.defer_foreign_keys()?;
self.connection.transaction(|| {
let row: EnsembleRow = ensemble.into();
diesel::replace_into(ensembles::table)
.values(row)
.values(ensemble)
.execute(&self.connection)
})?;
@ -59,37 +27,26 @@ impl Database {
}
/// Get an existing ensemble.
pub fn get_ensemble(&self, id: u32) -> Result<Option<Ensemble>> {
let row = ensembles::table
.filter(ensembles::id.eq(id as i64))
.load::<EnsembleRow>(&self.connection)?
.first()
.cloned();
let ensemble = match row {
Some(row) => Some(row.try_into()?),
None => None,
};
pub fn get_ensemble(&self, id: &str) -> Result<Option<Ensemble>> {
let ensemble = ensembles::table
.filter(ensembles::id.eq(id))
.load::<Ensemble>(&self.connection)?
.into_iter()
.next();
Ok(ensemble)
}
/// Delete an existing ensemble.
pub fn delete_ensemble(&self, id: u32) -> Result<()> {
diesel::delete(ensembles::table.filter(ensembles::id.eq(id as i64)))
.execute(&self.connection)?;
pub fn delete_ensemble(&self, id: &str) -> Result<()> {
diesel::delete(ensembles::table.filter(ensembles::id.eq(id))).execute(&self.connection)?;
Ok(())
}
/// Get all existing ensembles.
pub fn get_ensembles(&self) -> Result<Vec<Ensemble>> {
let mut ensembles = Vec::<Ensemble>::new();
let rows = ensembles::table.load::<EnsembleRow>(&self.connection)?;
for row in rows {
ensembles.push(row.try_into()?);
}
let ensembles = ensembles::table.load::<Ensemble>(&self.connection)?;
Ok(ensembles)
}

View file

@ -1,57 +1,25 @@
use super::schema::instruments;
use super::Database;
use anyhow::{Error, Result};
use anyhow::Result;
use diesel::prelude::*;
use diesel::{Insertable, Queryable};
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.
#[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Serialize, Deserialize, Insertable, Queryable, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Instrument {
pub id: u32,
pub id: 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 {
/// Update an existing instrument or insert a new one.
pub fn update_instrument(&self, instrument: Instrument) -> Result<()> {
self.defer_foreign_keys()?;
self.connection.transaction(|| {
let row: InstrumentRow = instrument.into();
diesel::replace_into(instruments::table)
.values(row)
.values(instrument)
.execute(&self.connection)
})?;
@ -59,24 +27,19 @@ impl Database {
}
/// Get an existing instrument.
pub fn get_instrument(&self, id: u32) -> Result<Option<Instrument>> {
let row = instruments::table
.filter(instruments::id.eq(id as i64))
.load::<InstrumentRow>(&self.connection)?
.first()
.cloned();
let instrument = match row {
Some(row) => Some(row.try_into()?),
None => None,
};
pub fn get_instrument(&self, id: &str) -> Result<Option<Instrument>> {
let instrument = instruments::table
.filter(instruments::id.eq(id))
.load::<Instrument>(&self.connection)?
.into_iter()
.next();
Ok(instrument)
}
/// Delete an existing instrument.
pub fn delete_instrument(&self, id: u32) -> Result<()> {
diesel::delete(instruments::table.filter(instruments::id.eq(id as i64)))
pub fn delete_instrument(&self, id: &str) -> Result<()> {
diesel::delete(instruments::table.filter(instruments::id.eq(id)))
.execute(&self.connection)?;
Ok(())
@ -84,12 +47,7 @@ impl Database {
/// Get all existing instruments.
pub fn get_instruments(&self) -> Result<Vec<Instrument>> {
let mut instruments = Vec::<Instrument>::new();
let rows = instruments::table.load::<InstrumentRow>(&self.connection)?;
for row in rows {
instruments.push(row.try_into()?);
}
let instruments = instruments::table.load::<Instrument>(&self.connection)?;
Ok(instruments)
}

View file

@ -27,6 +27,14 @@ mod schema;
// This makes the SQL migration scripts accessible from the code.
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.
pub struct Database {
connection: SqliteConnection,

View file

@ -1,52 +1,18 @@
use super::schema::persons;
use super::Database;
use anyhow::{Error, Result};
use anyhow::Result;
use diesel::prelude::*;
use diesel::{Insertable, Queryable};
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.
#[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Serialize, Deserialize, Insertable, Queryable, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Person {
pub id: u32,
pub id: String,
pub first_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 {
/// Get the full name in the form "First Last".
pub fn name_fl(&self) -> String {
@ -65,9 +31,8 @@ impl Database {
self.defer_foreign_keys()?;
self.connection.transaction(|| {
let row: PersonRow = person.into();
diesel::replace_into(persons::table)
.values(row)
.values(person)
.execute(&self.connection)
})?;
@ -75,36 +40,26 @@ impl Database {
}
/// Get an existing person.
pub fn get_person(&self, id: u32) -> Result<Option<Person>> {
let row = persons::table
.filter(persons::id.eq(id as i64))
.load::<PersonRow>(&self.connection)?
.first()
.cloned();
let person = match row {
Some(row) => Some(row.try_into()?),
None => None,
};
pub fn get_person(&self, id: &str) -> Result<Option<Person>> {
let person = persons::table
.filter(persons::id.eq(id))
.load::<Person>(&self.connection)?
.into_iter()
.next();
Ok(person)
}
/// Delete an existing person.
pub fn delete_person(&self, id: u32) -> Result<()> {
diesel::delete(persons::table.filter(persons::id.eq(id as i64)))
.execute(&self.connection)?;
pub fn delete_person(&self, id: &str) -> Result<()> {
diesel::delete(persons::table.filter(persons::id.eq(id))).execute(&self.connection)?;
Ok(())
}
/// Get all existing persons.
pub fn get_persons(&self) -> Result<Vec<Person>> {
let mut persons = Vec::<Person>::new();
let rows = persons::table.load::<PersonRow>(&self.connection)?;
for row in rows {
persons.push(row.try_into()?);
}
let persons = persons::table.load::<Person>(&self.connection)?;
Ok(persons)
}

View file

@ -10,16 +10,16 @@ use std::convert::TryInto;
#[derive(Insertable, Queryable, Debug, Clone)]
#[table_name = "recordings"]
struct RecordingRow {
pub id: i64,
pub work: i64,
pub id: String,
pub work: String,
pub comment: String,
}
impl From<Recording> for RecordingRow {
fn from(recording: Recording) -> Self {
RecordingRow {
id: recording.id as i64,
work: recording.work.id as i64,
id: recording.id,
work: recording.work.id,
comment: recording.comment,
}
}
@ -30,10 +30,10 @@ impl From<Recording> for RecordingRow {
#[table_name = "performances"]
struct PerformanceRow {
pub id: i64,
pub recording: i64,
pub person: Option<i64>,
pub ensemble: Option<i64>,
pub role: Option<i64>,
pub recording: String,
pub person: Option<String>,
pub ensemble: Option<String>,
pub role: Option<String>,
}
/// How a person or ensemble was involved in a recording.
@ -88,7 +88,7 @@ impl Performance {
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Recording {
pub id: u32,
pub id: String,
pub work: Work,
pub comment: String,
pub performances: Vec<Performance>,
@ -114,9 +114,9 @@ impl Database {
pub fn update_recording(&self, recording: Recording) -> Result<()> {
self.defer_foreign_keys()?;
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();
diesel::insert_into(recordings::table)
.values(row)
@ -125,10 +125,10 @@ impl Database {
for performance in recording.performances {
let row = PerformanceRow {
id: rand::random(),
recording: recording_id,
person: performance.person.map(|person| person.id as i64),
ensemble: performance.ensemble.map(|ensemble| ensemble.id as i64),
role: performance.role.map(|role| role.id as i64),
recording: recording_id.to_string(),
person: performance.person.map(|person| person.id),
ensemble: performance.ensemble.map(|ensemble| ensemble.id),
role: performance.role.map(|role| role.id),
};
diesel::insert_into(performances::table)
@ -147,28 +147,28 @@ impl Database {
let mut performance_descriptions: Vec<Performance> = Vec::new();
let performance_rows = performances::table
.filter(performances::recording.eq(row.id))
.filter(performances::recording.eq(&row.id))
.load::<PerformanceRow>(&self.connection)?;
for row in performance_rows {
performance_descriptions.push(Performance {
person: match row.person {
Some(id) => Some(
self.get_person(id.try_into()?)?
self.get_person(&id)?
.ok_or(anyhow!("No person with ID: {}", id))?,
),
None => None,
},
ensemble: match row.ensemble {
Some(id) => Some(
self.get_ensemble(id.try_into()?)?
self.get_ensemble(&id)?
.ok_or(anyhow!("No ensemble with ID: {}", id))?,
),
None => None,
},
role: match row.role {
Some(id) => Some(
self.get_instrument(id.try_into()?)?
self.get_instrument(&id)?
.ok_or(anyhow!("No instrument with ID: {}", id))?,
),
None => None,
@ -176,13 +176,13 @@ impl Database {
});
}
let work_id: u32 = row.work.try_into()?;
let work_id = &row.work;
let work = self
.get_work(work_id)?
.ok_or(anyhow!("Work doesn't exist: {}", work_id))?;
let recording_description = Recording {
id: row.id.try_into()?,
id: row.id,
work,
comment: row.comment.clone(),
performances: performance_descriptions,
@ -192,13 +192,13 @@ impl Database {
}
/// 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 rows = recordings::table
.inner_join(performances::table.on(performances::recording.eq(recordings::id)))
.inner_join(persons::table.on(persons::id.nullable().eq(performances::person)))
.filter(persons::id.eq(person_id as i64))
.filter(persons::id.eq(person_id))
.select(recordings::table::all_columns())
.load::<RecordingRow>(&self.connection)?;
@ -210,13 +210,13 @@ impl Database {
}
/// 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 rows = recordings::table
.inner_join(performances::table.on(performances::recording.eq(recordings::id)))
.inner_join(ensembles::table.on(ensembles::id.nullable().eq(performances::ensemble)))
.filter(ensembles::id.eq(ensemble_id as i64))
.filter(ensembles::id.eq(ensemble_id))
.select(recordings::table::all_columns())
.load::<RecordingRow>(&self.connection)?;
@ -228,11 +228,11 @@ impl Database {
}
/// 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 rows = recordings::table
.filter(recordings::work.eq(work_id as i64))
.filter(recordings::work.eq(work_id))
.load::<RecordingRow>(&self.connection)?;
for row in rows {
@ -244,8 +244,8 @@ impl Database {
/// 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.
pub fn delete_recording(&self, id: u32) -> Result<()> {
diesel::delete(recordings::table.filter(recordings::id.eq(id as i64)))
pub fn delete_recording(&self, id: &str) -> Result<()> {
diesel::delete(recordings::table.filter(recordings::id.eq(id)))
.execute(&self.connection)?;
Ok(())
}

View file

@ -1,6 +1,6 @@
table! {
ensembles (id) {
id -> BigInt,
id -> Text,
name -> Text,
}
}
@ -8,14 +8,14 @@ table! {
table! {
instrumentations (id) {
id -> BigInt,
work -> BigInt,
instrument -> BigInt,
work -> Text,
instrument -> Text,
}
}
table! {
instruments (id) {
id -> BigInt,
id -> Text,
name -> Text,
}
}
@ -23,16 +23,16 @@ table! {
table! {
performances (id) {
id -> BigInt,
recording -> BigInt,
person -> Nullable<BigInt>,
ensemble -> Nullable<BigInt>,
role -> Nullable<BigInt>,
recording -> Text,
person -> Nullable<Text>,
ensemble -> Nullable<Text>,
role -> Nullable<Text>,
}
}
table! {
persons (id) {
id -> BigInt,
id -> Text,
first_name -> Text,
last_name -> Text,
}
@ -40,8 +40,8 @@ table! {
table! {
recordings (id) {
id -> BigInt,
work -> BigInt,
id -> Text,
work -> Text,
comment -> Text,
}
}
@ -50,7 +50,7 @@ table! {
tracks (id) {
id -> BigInt,
file_name -> Text,
recording -> BigInt,
recording -> Text,
track_index -> Integer,
work_parts -> Text,
}
@ -59,17 +59,17 @@ table! {
table! {
work_parts (id) {
id -> BigInt,
work -> BigInt,
work -> Text,
part_index -> BigInt,
title -> Text,
composer -> Nullable<BigInt>,
composer -> Nullable<Text>,
}
}
table! {
work_sections (id) {
id -> BigInt,
work -> BigInt,
work -> Text,
title -> Text,
before_index -> BigInt,
}
@ -77,8 +77,8 @@ table! {
table! {
works (id) {
id -> BigInt,
composer -> BigInt,
id -> Text,
composer -> Text,
title -> Text,
}
}

View file

@ -8,28 +8,28 @@ use std::thread;
/// An action the database thread can perform.
enum Action {
UpdatePerson(Person, Sender<Result<()>>),
GetPerson(u32, Sender<Result<Option<Person>>>),
DeletePerson(u32, Sender<Result<()>>),
GetPerson(String, Sender<Result<Option<Person>>>),
DeletePerson(String, Sender<Result<()>>),
GetPersons(Sender<Result<Vec<Person>>>),
UpdateInstrument(Instrument, Sender<Result<()>>),
GetInstrument(u32, Sender<Result<Option<Instrument>>>),
DeleteInstrument(u32, Sender<Result<()>>),
GetInstrument(String, Sender<Result<Option<Instrument>>>),
DeleteInstrument(String, Sender<Result<()>>),
GetInstruments(Sender<Result<Vec<Instrument>>>),
UpdateWork(Work, Sender<Result<()>>),
DeleteWork(u32, Sender<Result<()>>),
GetWorks(u32, Sender<Result<Vec<Work>>>),
DeleteWork(String, Sender<Result<()>>),
GetWorks(String, Sender<Result<Vec<Work>>>),
UpdateEnsemble(Ensemble, Sender<Result<()>>),
GetEnsemble(u32, Sender<Result<Option<Ensemble>>>),
DeleteEnsemble(u32, Sender<Result<()>>),
GetEnsemble(String, Sender<Result<Option<Ensemble>>>),
DeleteEnsemble(String, Sender<Result<()>>),
GetEnsembles(Sender<Result<Vec<Ensemble>>>),
UpdateRecording(Recording, Sender<Result<()>>),
DeleteRecording(u32, Sender<Result<()>>),
GetRecordingsForPerson(u32, Sender<Result<Vec<Recording>>>),
GetRecordingsForEnsemble(u32, Sender<Result<Vec<Recording>>>),
GetRecordingsForWork(u32, Sender<Result<Vec<Recording>>>),
UpdateTracks(u32, Vec<Track>, Sender<Result<()>>),
DeleteTracks(u32, Sender<Result<()>>),
GetTracks(u32, Sender<Result<Vec<Track>>>),
DeleteRecording(String, Sender<Result<()>>),
GetRecordingsForPerson(String, Sender<Result<Vec<Recording>>>),
GetRecordingsForEnsemble(String, Sender<Result<Vec<Recording>>>),
GetRecordingsForWork(String, Sender<Result<Vec<Recording>>>),
UpdateTracks(String, Vec<Track>, Sender<Result<()>>),
DeleteTracks(String, Sender<Result<()>>),
GetTracks(String, Sender<Result<Vec<Track>>>),
Stop(Sender<()>),
}
@ -64,10 +64,10 @@ impl DbThread {
sender.send(db.update_person(person)).unwrap();
}
GetPerson(id, sender) => {
sender.send(db.get_person(id)).unwrap();
sender.send(db.get_person(&id)).unwrap();
}
DeletePerson(id, sender) => {
sender.send(db.delete_person(id)).unwrap();
sender.send(db.delete_person(&id)).unwrap();
}
GetPersons(sender) => {
sender.send(db.get_persons()).unwrap();
@ -76,10 +76,10 @@ impl DbThread {
sender.send(db.update_instrument(instrument)).unwrap();
}
GetInstrument(id, sender) => {
sender.send(db.get_instrument(id)).unwrap();
sender.send(db.get_instrument(&id)).unwrap();
}
DeleteInstrument(id, sender) => {
sender.send(db.delete_instrument(id)).unwrap();
sender.send(db.delete_instrument(&id)).unwrap();
}
GetInstruments(sender) => {
sender.send(db.get_instruments()).unwrap();
@ -88,19 +88,19 @@ impl DbThread {
sender.send(db.update_work(work)).unwrap();
}
DeleteWork(id, sender) => {
sender.send(db.delete_work(id)).unwrap();
sender.send(db.delete_work(&id)).unwrap();
}
GetWorks(id, sender) => {
sender.send(db.get_works(id)).unwrap();
sender.send(db.get_works(&id)).unwrap();
}
UpdateEnsemble(ensemble, sender) => {
sender.send(db.update_ensemble(ensemble)).unwrap();
}
GetEnsemble(id, sender) => {
sender.send(db.get_ensemble(id)).unwrap();
sender.send(db.get_ensemble(&id)).unwrap();
}
DeleteEnsemble(id, sender) => {
sender.send(db.delete_ensemble(id)).unwrap();
sender.send(db.delete_ensemble(&id)).unwrap();
}
GetEnsembles(sender) => {
sender.send(db.get_ensembles()).unwrap();
@ -109,25 +109,27 @@ impl DbThread {
sender.send(db.update_recording(recording)).unwrap();
}
DeleteRecording(id, sender) => {
sender.send(db.delete_recording(id)).unwrap();
sender.send(db.delete_recording(&id)).unwrap();
}
GetRecordingsForPerson(id, sender) => {
sender.send(db.get_recordings_for_person(id)).unwrap();
sender.send(db.get_recordings_for_person(&id)).unwrap();
}
GetRecordingsForEnsemble(id, sender) => {
sender.send(db.get_recordings_for_ensemble(id)).unwrap();
sender.send(db.get_recordings_for_ensemble(&id)).unwrap();
}
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) => {
sender.send(db.update_tracks(recording_id, tracks)).unwrap();
sender
.send(db.update_tracks(&recording_id, tracks))
.unwrap();
}
DeleteTracks(recording_id, sender) => {
sender.send(db.delete_tracks(recording_id)).unwrap();
sender.send(db.delete_tracks(&recording_id)).unwrap();
}
GetTracks(recording_id, sender) => {
sender.send(db.get_tracks(recording_id)).unwrap();
sender.send(db.get_tracks(&recording_id)).unwrap();
}
Stop(sender) => {
sender.send(()).unwrap();
@ -149,17 +151,18 @@ impl DbThread {
}
/// 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();
self.action_sender.send(GetPerson(id, sender))?;
self.action_sender.send(GetPerson(id.to_string(), sender))?;
receiver.await?
}
/// Delete an existing person. This will fail, if there are still other items referencing
/// 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();
self.action_sender.send(DeletePerson(id, sender))?;
self.action_sender
.send(DeletePerson(id.to_string(), sender))?;
receiver.await?
}
@ -179,17 +182,19 @@ impl DbThread {
}
/// 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();
self.action_sender.send(GetInstrument(id, sender))?;
self.action_sender
.send(GetInstrument(id.to_string(), sender))?;
receiver.await?
}
/// Delete an existing instrument. This will fail, if there are still other items referencing
/// 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();
self.action_sender.send(DeleteInstrument(id, sender))?;
self.action_sender
.send(DeleteInstrument(id.to_string(), sender))?;
receiver.await?
}
@ -209,16 +214,18 @@ impl DbThread {
/// Delete an existing work. This will fail, if there are still other items referencing
/// 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();
self.action_sender.send(DeleteWork(id, sender))?;
self.action_sender
.send(DeleteWork(id.to_string(), sender))?;
receiver.await?
}
/// 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();
self.action_sender.send(GetWorks(person_id, sender))?;
self.action_sender
.send(GetWorks(person_id.to_string(), sender))?;
receiver.await?
}
@ -230,17 +237,19 @@ impl DbThread {
}
/// 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();
self.action_sender.send(GetEnsemble(id, sender))?;
self.action_sender
.send(GetEnsemble(id.to_string(), sender))?;
receiver.await?
}
/// Delete an existing ensemble. This will fail, if there are still other items referencing
/// 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();
self.action_sender.send(DeleteEnsemble(id, sender))?;
self.action_sender
.send(DeleteEnsemble(id.to_string(), sender))?;
receiver.await?
}
@ -260,61 +269,59 @@ impl DbThread {
}
/// 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();
self.action_sender.send(DeleteRecording(id, sender))?;
self.action_sender
.send(DeleteRecording(id.to_string(), sender))?;
receiver.await?
}
/// 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();
self.action_sender
.send(GetRecordingsForPerson(person_id, sender))?;
.send(GetRecordingsForPerson(person_id.to_string(), sender))?;
receiver.await?
}
/// 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();
self.action_sender
.send(GetRecordingsForEnsemble(ensemble_id, sender))?;
.send(GetRecordingsForEnsemble(ensemble_id.to_string(), sender))?;
receiver.await?
}
/// 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();
self.action_sender
.send(GetRecordingsForWork(work_id, sender))?;
.send(GetRecordingsForWork(work_id.to_string(), sender))?;
receiver.await?
}
/// Add or change the tracks associated with a recording. This will fail, if there are still
/// other items referencing this recording.
pub async fn update_tracks(
&self,
recording_id: u32,
tracks: Vec<Track>,
) -> Result<()> {
pub async fn update_tracks(&self, recording_id: &str, tracks: Vec<Track>) -> Result<()> {
let (sender, receiver) = oneshot::channel();
self.action_sender
.send(UpdateTracks(recording_id, tracks, sender))?;
.send(UpdateTracks(recording_id.to_string(), tracks, sender))?;
receiver.await?
}
/// 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();
self.action_sender
.send(DeleteTracks(recording_id, sender))?;
.send(DeleteTracks(recording_id.to_string(), sender))?;
receiver.await?
}
/// 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();
self.action_sender.send(GetTracks(recording_id, sender))?;
self.action_sender
.send(GetTracks(recording_id.to_string(), sender))?;
receiver.await?
}

View file

@ -10,7 +10,7 @@ use std::convert::{TryFrom, TryInto};
struct TrackRow {
pub id: i64,
pub file_name: String,
pub recording: i64,
pub recording: String,
pub track_index: i32,
pub work_parts: String,
}
@ -43,14 +43,14 @@ impl TryFrom<TrackRow> for Track {
impl Database {
/// 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)?;
for (index, track) in tracks.iter().enumerate() {
let row = TrackRow {
id: rand::random(),
file_name: track.file_name.clone(),
recording: recording_id as i64,
recording: recording_id.to_string(),
track_index: index.try_into()?,
work_parts: track
.work_parts
@ -69,19 +69,19 @@ impl Database {
}
/// Delete all tracks for the specified recording.
pub fn delete_tracks(&self, recording_id: u32) -> Result<()> {
diesel::delete(tracks::table.filter(tracks::recording.eq(recording_id as i64)))
pub fn delete_tracks(&self, recording_id: &str) -> Result<()> {
diesel::delete(tracks::table.filter(tracks::recording.eq(recording_id)))
.execute(&self.connection)?;
Ok(())
}
/// 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 rows = tracks::table
.filter(tracks::recording.eq(recording_id as i64))
.filter(tracks::recording.eq(recording_id))
.order_by(tracks::track_index)
.load::<TrackRow>(&self.connection)?;

View file

@ -10,16 +10,16 @@ use std::convert::TryInto;
#[derive(Insertable, Queryable, Debug, Clone)]
#[table_name = "works"]
struct WorkRow {
pub id: i64,
pub composer: i64,
pub id: String,
pub composer: String,
pub title: String,
}
impl From<Work> for WorkRow {
fn from(work: Work) -> Self {
WorkRow {
id: work.id as i64,
composer: work.composer.id as i64,
id: work.id,
composer: work.composer.id,
title: work.title,
}
}
@ -30,8 +30,8 @@ impl From<Work> for WorkRow {
#[table_name = "instrumentations"]
struct InstrumentationRow {
pub id: i64,
pub work: i64,
pub instrument: i64,
pub work: String,
pub instrument: String,
}
/// Table row data for a work part.
@ -39,10 +39,10 @@ struct InstrumentationRow {
#[table_name = "work_parts"]
struct WorkPartRow {
pub id: i64,
pub work: i64,
pub work: String,
pub part_index: i64,
pub title: String,
pub composer: Option<i64>,
pub composer: Option<String>,
}
/// Table row data for a work section.
@ -50,7 +50,7 @@ struct WorkPartRow {
#[table_name = "work_sections"]
struct WorkSectionRow {
pub id: i64,
pub work: i64,
pub work: String,
pub title: String,
pub before_index: i64,
}
@ -74,7 +74,7 @@ pub struct WorkSection {
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Work {
pub id: u32,
pub id: String,
pub title: String,
pub composer: Person,
pub instruments: Vec<Instrument>,
@ -97,9 +97,9 @@ impl Database {
self.defer_foreign_keys()?;
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();
diesel::insert_into(works::table)
.values(row)
@ -115,8 +115,8 @@ impl Database {
for instrument in instruments {
let row = InstrumentationRow {
id: rand::random(),
work: work_id,
instrument: instrument.id as i64,
work: work_id.to_string(),
instrument: instrument.id,
};
diesel::insert_into(instrumentations::table)
@ -127,10 +127,10 @@ impl Database {
for (index, part) in parts.into_iter().enumerate() {
let row = WorkPartRow {
id: rand::random(),
work: work_id,
work: work_id.to_string(),
part_index: index.try_into()?,
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)
@ -141,7 +141,7 @@ impl Database {
for section in sections {
let row = WorkSectionRow {
id: rand::random(),
work: work_id,
work: work_id.to_string(),
title: section.title,
before_index: section.before_index.try_into()?,
};
@ -160,9 +160,9 @@ impl Database {
}
/// 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
.filter(works::id.eq(id as i64))
.filter(works::id.eq(id))
.load::<WorkRow>(&self.connection)?
.first()
.cloned();
@ -180,11 +180,11 @@ impl Database {
let mut instruments: Vec<Instrument> = Vec::new();
let instrumentations = instrumentations::table
.filter(instrumentations::work.eq(row.id))
.filter(instrumentations::work.eq(&row.id))
.load::<InstrumentationRow>(&self.connection)?;
for instrumentation in instrumentations {
let id: u32 = instrumentation.instrument.try_into()?;
let id = &instrumentation.instrument;
instruments.push(
self.get_instrument(id)?
.ok_or(anyhow!("No instrument with ID: {}", id))?,
@ -194,7 +194,7 @@ impl Database {
let mut parts: Vec<WorkPart> = Vec::new();
let part_rows = work_parts::table
.filter(work_parts::work.eq(row.id))
.filter(work_parts::work.eq(&row.id))
.load::<WorkPartRow>(&self.connection)?;
for part_row in part_rows {
@ -202,7 +202,7 @@ impl Database {
title: part_row.title,
composer: match part_row.composer {
Some(composer) => Some(
self.get_person(composer.try_into()?)?
self.get_person(&composer)?
.ok_or(anyhow!("No person with ID: {}", composer))?,
),
None => None,
@ -213,7 +213,7 @@ impl Database {
let mut sections: Vec<WorkSection> = Vec::new();
let section_rows = work_sections::table
.filter(work_sections::work.eq(row.id))
.filter(work_sections::work.eq(&row.id))
.load::<WorkSectionRow>(&self.connection)?;
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
.get_person(person_id)?
.ok_or(anyhow!("Person doesn't exist: {}", person_id))?;
Ok(Work {
id: row.id.try_into()?,
id: row.id,
composer: person,
title: row.title,
instruments,
@ -240,17 +240,17 @@ impl Database {
/// 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
pub fn delete_work(&self, id: u32) -> Result<()> {
diesel::delete(works::table.filter(works::id.eq(id as i64))).execute(&self.connection)?;
pub fn delete_work(&self, id: &str) -> Result<()> {
diesel::delete(works::table.filter(works::id.eq(id))).execute(&self.connection)?;
Ok(())
}
/// 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 rows = works::table
.filter(works::composer.eq(composer_id as i64))
.filter(works::composer.eq(composer_id))
.load::<WorkRow>(&self.connection)?;
for row in rows {

View file

@ -12,7 +12,7 @@ where
backend: Rc<Backend>,
window: libhandy::Window,
callback: F,
id: u32,
id: String,
name_entry: gtk::Entry,
}
@ -38,7 +38,7 @@ where
name_entry.set_text(&ensemble.name);
ensemble.id
}
None => rand::random::<u32>().into(),
None => generate_id(),
};
let result = Rc::new(EnsembleEditor {
@ -55,7 +55,7 @@ where
save_button.connect_clicked(clone!(@strong result => move |_| {
let ensemble = Ensemble {
id: result.id,
id: result.id.clone(),
name: result.name_entry.get_text().to_string(),
};

View file

@ -12,7 +12,7 @@ where
backend: Rc<Backend>,
window: libhandy::Window,
callback: F,
id: u32,
id: String,
name_entry: gtk::Entry,
}
@ -26,8 +26,7 @@ where
instrument: Option<Instrument>,
callback: F,
) -> Rc<Self> {
let builder =
gtk::Builder::from_resource("/de/johrpan/musicus/ui/instrument_editor.ui");
let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/instrument_editor.ui");
get_widget!(builder, libhandy::Window, window);
get_widget!(builder, gtk::Button, cancel_button);
@ -39,7 +38,7 @@ where
name_entry.set_text(&instrument.name);
instrument.id
}
None => rand::random::<u32>().into(),
None => generate_id(),
};
let result = Rc::new(InstrumentEditor {
@ -56,7 +55,7 @@ where
save_button.connect_clicked(clone!(@strong result => move |_| {
let instrument = Instrument {
id: result.id,
id: result.id.clone(),
name: result.name_entry.get_text().to_string(),
};

View file

@ -10,6 +10,7 @@ where
F: Fn(Person) -> () + 'static,
{
backend: Rc<Backend>,
id: String,
window: libhandy::Window,
callback: F,
id: u32,

View file

@ -20,7 +20,7 @@ pub struct RecordingEditor {
work_label: gtk::Label,
comment_entry: gtk::Entry,
performance_list: Rc<List<Performance>>,
id: u32,
id: String,
work: RefCell<Option<Work>>,
performances: RefCell<Vec<Performance>>,
selected_cb: RefCell<Option<Box<dyn Fn(Recording) -> ()>>>,
@ -59,7 +59,7 @@ impl RecordingEditor {
comment_entry.set_text(&recording.comment);
(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 {
@ -88,7 +88,7 @@ impl RecordingEditor {
this.save_button
.connect_clicked(clone!(@strong this => move |_| {
let recording = Recording {
id: this.id,
id: this.id.clone(),
work: this.work.borrow().clone().expect("Tried to create recording without work!"),
comment: this.comment_entry.get_text().to_string(),
performances: this.performances.borrow().clone(),

View file

@ -92,7 +92,7 @@ impl RecordingSelectorPersonScreen {
let context = glib::MainContext::default();
let clone = this.clone();
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.stack.set_visible_child_name("content");

View file

@ -90,7 +90,7 @@ impl RecordingSelectorWorkScreen {
let recordings = clone
.backend
.db()
.get_recordings_for_work(work.id)
.get_recordings_for_work(&work.id)
.await
.unwrap();

View file

@ -81,7 +81,7 @@ impl TracksEditor {
let this = this.clone();
context.spawn_local(async move {
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(),
).await.unwrap();

View file

@ -29,7 +29,7 @@ pub struct WorkEditor {
composer_label: gtk::Label,
instrument_list: Rc<List<Instrument>>,
part_list: Rc<List<PartOrSection>>,
id: u32,
id: String,
composer: RefCell<Option<Person>>,
instruments: RefCell<Vec<Instrument>>,
structure: RefCell<Vec<PartOrSection>>,
@ -91,7 +91,7 @@ impl WorkEditor {
(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 {
@ -137,7 +137,7 @@ impl WorkEditor {
}
let work = Work {
id: this.id,
id: this.id.clone(),
title: this.title_entry.get_text().to_string(),
composer: this.composer.borrow().clone().expect("Tried to create work without composer!"),
instruments: this.instruments.borrow().clone(),

View file

@ -80,7 +80,7 @@ impl WorkSelectorPersonScreen {
let context = glib::MainContext::default();
let clone = this.clone();
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.stack.set_visible_child_name("content");

View file

@ -116,7 +116,7 @@ impl EnsembleScreen {
let context = glib::MainContext::default();
let clone = result.clone();
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
.backend
.db()
.get_recordings_for_ensemble(clone.ensemble.id)
.get_recordings_for_ensemble(&clone.ensemble.id)
.await
.unwrap();

View file

@ -145,14 +145,14 @@ impl PersonScreen {
}));
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 |_, _| {
let context = glib::MainContext::default();
let clone = result.clone();
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
.backend
.db()
.get_works(clone.person.id as u32)
.get_works(&clone.person.id)
.await
.unwrap();
let recordings = clone
.backend
.db()
.get_recordings_for_person(clone.person.id as u32)
.get_recordings_for_person(&clone.person.id)
.await
.unwrap();

View file

@ -118,7 +118,7 @@ impl RecordingScreen {
let context = glib::MainContext::default();
let clone = result.clone();
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 clone = result.clone();
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
.backend
.db()
.get_tracks(clone.recording.id)
.get_tracks(&clone.recording.id)
.await
.unwrap();

View file

@ -115,7 +115,7 @@ impl WorkScreen {
let context = glib::MainContext::default();
let clone = result.clone();
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
.backend
.db()
.get_recordings_for_work(clone.work.id as u32)
.get_recordings_for_work(&clone.work.id)
.await
.unwrap();