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