server: Switch to strings for IDs

This commit is contained in:
Elias Projahn 2020-11-28 20:30:14 +01:00
parent 3b8ed4bdb1
commit 157bdb2917
8 changed files with 132 additions and 140 deletions

View file

@ -8,63 +8,63 @@ CREATE TABLE users (
); );
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,
created_by TEXT NOT NULL REFERENCES users(username) created_by TEXT NOT NULL REFERENCES users(username)
); );
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,
created_by TEXT NOT NULL REFERENCES users(username) created_by TEXT NOT NULL REFERENCES users(username)
); );
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,
created_by TEXT NOT NULL REFERENCES users(username) created_by TEXT NOT NULL REFERENCES users(username)
); );
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,
created_by TEXT NOT NULL REFERENCES users(username) created_by TEXT NOT NULL REFERENCES users(username)
); );
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,
created_by TEXT NOT NULL REFERENCES users(username) created_by TEXT NOT NULL REFERENCES users(username)
); );
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)
); );

View file

@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, 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,
} }
@ -17,7 +17,7 @@ pub struct Ensemble {
#[derive(Insertable, Queryable, AsChangeset, Debug, Clone)] #[derive(Insertable, Queryable, AsChangeset, Debug, Clone)]
#[table_name = "ensembles"] #[table_name = "ensembles"]
struct EnsembleRow { struct EnsembleRow {
pub id: i64, pub id: String,
pub name: String, pub name: String,
pub created_by: String, pub created_by: String,
} }
@ -25,7 +25,7 @@ struct EnsembleRow {
impl From<EnsembleRow> for Ensemble { impl From<EnsembleRow> for Ensemble {
fn from(row: EnsembleRow) -> Ensemble { fn from(row: EnsembleRow) -> Ensemble {
Ensemble { Ensemble {
id: row.id as u32, id: row.id,
name: row.name, name: row.name,
} }
} }
@ -34,7 +34,7 @@ impl From<EnsembleRow> for Ensemble {
/// Update an existing ensemble or insert a new one. This will only work, if the provided user is /// Update an existing ensemble or insert a new one. This will only work, if the provided user is
/// allowed to do that. /// allowed to do that.
pub fn update_ensemble(conn: &DbConn, ensemble: &Ensemble, user: &User) -> Result<()> { pub fn update_ensemble(conn: &DbConn, ensemble: &Ensemble, user: &User) -> Result<()> {
let old_row = get_ensemble_row(conn, ensemble.id)?; let old_row = get_ensemble_row(conn, &ensemble.id)?;
let allowed = match old_row { let allowed = match old_row {
Some(row) => user.may_edit(&row.created_by), Some(row) => user.may_edit(&row.created_by),
@ -43,7 +43,7 @@ pub fn update_ensemble(conn: &DbConn, ensemble: &Ensemble, user: &User) -> Resul
if allowed { if allowed {
let new_row = EnsembleRow { let new_row = EnsembleRow {
id: ensemble.id as i64, id: ensemble.id.clone(),
name: ensemble.name.clone(), name: ensemble.name.clone(),
created_by: user.username.clone(), created_by: user.username.clone(),
}; };
@ -62,7 +62,7 @@ pub fn update_ensemble(conn: &DbConn, ensemble: &Ensemble, user: &User) -> Resul
} }
/// Get an existing ensemble. /// Get an existing ensemble.
pub fn get_ensemble(conn: &DbConn, id: u32) -> Result<Option<Ensemble>> { pub fn get_ensemble(conn: &DbConn, id: &str) -> Result<Option<Ensemble>> {
let row = get_ensemble_row(conn, id)?; let row = get_ensemble_row(conn, id)?;
let ensemble = row.map(|row| row.into()); let ensemble = row.map(|row| row.into());
@ -70,9 +70,9 @@ pub fn get_ensemble(conn: &DbConn, id: u32) -> Result<Option<Ensemble>> {
} }
/// Delete an existing ensemble. This will only work if the provided user is allowed to do that. /// Delete an existing ensemble. This will only work if the provided user is allowed to do that.
pub fn delete_ensemble(conn: &DbConn, id: u32, user: &User) -> Result<()> { pub fn delete_ensemble(conn: &DbConn, id: &str, user: &User) -> Result<()> {
if user.may_delete() { if user.may_delete() {
diesel::delete(ensembles::table.filter(ensembles::id.eq(id as i64))).execute(conn)?; diesel::delete(ensembles::table.filter(ensembles::id.eq(id))).execute(conn)?;
Ok(()) Ok(())
} else { } else {
Err(Error::new(ServerError::Forbidden)) Err(Error::new(ServerError::Forbidden))
@ -88,9 +88,9 @@ pub fn get_ensembles(conn: &DbConn) -> Result<Vec<Ensemble>> {
} }
/// Get a ensemble row if it exists. /// Get a ensemble row if it exists.
fn get_ensemble_row(conn: &DbConn, id: u32) -> Result<Option<EnsembleRow>> { fn get_ensemble_row(conn: &DbConn, id: &str) -> Result<Option<EnsembleRow>> {
let row = ensembles::table let row = ensembles::table
.filter(ensembles::id.eq(id as i64)) .filter(ensembles::id.eq(id))
.load::<EnsembleRow>(conn)? .load::<EnsembleRow>(conn)?
.into_iter() .into_iter()
.next(); .next();

View file

@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, 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,
} }
@ -17,7 +17,7 @@ pub struct Instrument {
#[derive(Insertable, Queryable, AsChangeset, Debug, Clone)] #[derive(Insertable, Queryable, AsChangeset, Debug, Clone)]
#[table_name = "instruments"] #[table_name = "instruments"]
struct InstrumentRow { struct InstrumentRow {
pub id: i64, pub id: String,
pub name: String, pub name: String,
pub created_by: String, pub created_by: String,
} }
@ -25,7 +25,7 @@ struct InstrumentRow {
impl From<InstrumentRow> for Instrument { impl From<InstrumentRow> for Instrument {
fn from(row: InstrumentRow) -> Instrument { fn from(row: InstrumentRow) -> Instrument {
Instrument { Instrument {
id: row.id as u32, id: row.id,
name: row.name, name: row.name,
} }
} }
@ -34,7 +34,7 @@ impl From<InstrumentRow> for Instrument {
/// Update an existing instrument or insert a new one. This will only work, if the provided user is /// Update an existing instrument or insert a new one. This will only work, if the provided user is
/// allowed to do that. /// allowed to do that.
pub fn update_instrument(conn: &DbConn, instrument: &Instrument, user: &User) -> Result<()> { pub fn update_instrument(conn: &DbConn, instrument: &Instrument, user: &User) -> Result<()> {
let old_row = get_instrument_row(conn, instrument.id)?; let old_row = get_instrument_row(conn, &instrument.id)?;
let allowed = match old_row { let allowed = match old_row {
Some(row) => user.may_edit(&row.created_by), Some(row) => user.may_edit(&row.created_by),
@ -43,7 +43,7 @@ pub fn update_instrument(conn: &DbConn, instrument: &Instrument, user: &User) ->
if allowed { if allowed {
let new_row = InstrumentRow { let new_row = InstrumentRow {
id: instrument.id as i64, id: instrument.id.clone(),
name: instrument.name.clone(), name: instrument.name.clone(),
created_by: user.username.clone(), created_by: user.username.clone(),
}; };
@ -62,7 +62,7 @@ pub fn update_instrument(conn: &DbConn, instrument: &Instrument, user: &User) ->
} }
/// Get an existing instrument. /// Get an existing instrument.
pub fn get_instrument(conn: &DbConn, id: u32) -> Result<Option<Instrument>> { pub fn get_instrument(conn: &DbConn, id: &str) -> Result<Option<Instrument>> {
let row = get_instrument_row(conn, id)?; let row = get_instrument_row(conn, id)?;
let instrument = row.map(|row| row.into()); let instrument = row.map(|row| row.into());
@ -70,9 +70,9 @@ pub fn get_instrument(conn: &DbConn, id: u32) -> Result<Option<Instrument>> {
} }
/// Delete an existing instrument. This will only work if the provided user is allowed to do that. /// Delete an existing instrument. This will only work if the provided user is allowed to do that.
pub fn delete_instrument(conn: &DbConn, id: u32, user: &User) -> Result<()> { pub fn delete_instrument(conn: &DbConn, id: &str, user: &User) -> Result<()> {
if user.may_delete() { if user.may_delete() {
diesel::delete(instruments::table.filter(instruments::id.eq(id as i64))).execute(conn)?; diesel::delete(instruments::table.filter(instruments::id.eq(id))).execute(conn)?;
Ok(()) Ok(())
} else { } else {
Err(Error::new(ServerError::Forbidden)) Err(Error::new(ServerError::Forbidden))
@ -88,9 +88,9 @@ pub fn get_instruments(conn: &DbConn) -> Result<Vec<Instrument>> {
} }
/// Get a instrument row if it exists. /// Get a instrument row if it exists.
fn get_instrument_row(conn: &DbConn, id: u32) -> Result<Option<InstrumentRow>> { fn get_instrument_row(conn: &DbConn, id: &str) -> Result<Option<InstrumentRow>> {
let row = instruments::table let row = instruments::table
.filter(instruments::id.eq(id as i64)) .filter(instruments::id.eq(id))
.load::<InstrumentRow>(conn)? .load::<InstrumentRow>(conn)?
.into_iter() .into_iter()
.next(); .next();

View file

@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, 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,
} }
@ -18,7 +18,7 @@ pub struct Person {
#[derive(Insertable, Queryable, AsChangeset, Debug, Clone)] #[derive(Insertable, Queryable, AsChangeset, Debug, Clone)]
#[table_name = "persons"] #[table_name = "persons"]
struct PersonRow { struct PersonRow {
pub id: i64, pub id: String,
pub first_name: String, pub first_name: String,
pub last_name: String, pub last_name: String,
pub created_by: String, pub created_by: String,
@ -27,7 +27,7 @@ struct PersonRow {
impl From<PersonRow> for Person { impl From<PersonRow> for Person {
fn from(row: PersonRow) -> Person { fn from(row: PersonRow) -> Person {
Person { Person {
id: row.id as u32, id: row.id,
first_name: row.first_name, first_name: row.first_name,
last_name: row.last_name, last_name: row.last_name,
} }
@ -37,7 +37,7 @@ impl From<PersonRow> for Person {
/// Update an existing person or insert a new one. This will only work, if the provided user is /// Update an existing person or insert a new one. This will only work, if the provided user is
/// allowed to do that. /// allowed to do that.
pub fn update_person(conn: &DbConn, person: &Person, user: &User) -> Result<()> { pub fn update_person(conn: &DbConn, person: &Person, user: &User) -> Result<()> {
let old_row = get_person_row(conn, person.id)?; let old_row = get_person_row(conn, &person.id)?;
let allowed = match old_row { let allowed = match old_row {
Some(row) => user.may_edit(&row.created_by), Some(row) => user.may_edit(&row.created_by),
@ -46,7 +46,7 @@ pub fn update_person(conn: &DbConn, person: &Person, user: &User) -> Result<()>
if allowed { if allowed {
let new_row = PersonRow { let new_row = PersonRow {
id: person.id as i64, id: person.id.clone(),
first_name: person.first_name.clone(), first_name: person.first_name.clone(),
last_name: person.last_name.clone(), last_name: person.last_name.clone(),
created_by: user.username.clone(), created_by: user.username.clone(),
@ -66,7 +66,7 @@ pub fn update_person(conn: &DbConn, person: &Person, user: &User) -> Result<()>
} }
/// Get an existing person. /// Get an existing person.
pub fn get_person(conn: &DbConn, id: u32) -> Result<Option<Person>> { pub fn get_person(conn: &DbConn, id: &str) -> Result<Option<Person>> {
let row = get_person_row(conn, id)?; let row = get_person_row(conn, id)?;
let person = row.map(|row| row.into()); let person = row.map(|row| row.into());
@ -74,9 +74,9 @@ pub fn get_person(conn: &DbConn, id: u32) -> Result<Option<Person>> {
} }
/// Delete an existing person. This will only work if the provided user is allowed to do that. /// Delete an existing person. This will only work if the provided user is allowed to do that.
pub fn delete_person(conn: &DbConn, id: u32, user: &User) -> Result<()> { pub fn delete_person(conn: &DbConn, id: &str, user: &User) -> Result<()> {
if user.may_delete() { if user.may_delete() {
diesel::delete(persons::table.filter(persons::id.eq(id as i64))).execute(conn)?; diesel::delete(persons::table.filter(persons::id.eq(id))).execute(conn)?;
Ok(()) Ok(())
} else { } else {
Err(Error::new(ServerError::Forbidden)) Err(Error::new(ServerError::Forbidden))
@ -92,9 +92,9 @@ pub fn get_persons(conn: &DbConn) -> Result<Vec<Person>> {
} }
/// Get a person row if it exists. /// Get a person row if it exists.
fn get_person_row(conn: &DbConn, id: u32) -> Result<Option<PersonRow>> { fn get_person_row(conn: &DbConn, id: &str) -> Result<Option<PersonRow>> {
let row = persons::table let row = persons::table
.filter(persons::id.eq(id as i64)) .filter(persons::id.eq(id))
.load::<PersonRow>(conn)? .load::<PersonRow>(conn)?
.into_iter() .into_iter()
.next(); .next();

View file

@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize};
#[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>,
@ -29,8 +29,8 @@ pub struct Performance {
#[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,
pub created_by: String, pub created_by: String,
} }
@ -40,10 +40,10 @@ struct 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>,
} }
/// Update an existing recording or insert a new one. This will only work, if the provided user is /// Update an existing recording or insert a new one. This will only work, if the provided user is
@ -51,7 +51,7 @@ struct PerformanceRow {
// TODO: Also add newly created associated items. // TODO: Also add newly created associated items.
pub fn update_recording(conn: &DbConn, recording: &Recording, user: &User) -> Result<()> { pub fn update_recording(conn: &DbConn, recording: &Recording, user: &User) -> Result<()> {
conn.transaction::<(), Error, _>(|| { conn.transaction::<(), Error, _>(|| {
let old_row = get_recording_row(conn, recording.id)?; let old_row = get_recording_row(conn, &recording.id)?;
let allowed = match old_row { let allowed = match old_row {
Some(row) => user.may_edit(&row.created_by), Some(row) => user.may_edit(&row.created_by),
@ -59,7 +59,7 @@ pub fn update_recording(conn: &DbConn, recording: &Recording, user: &User) -> Re
}; };
if allowed { if allowed {
let id = recording.id as i64; let id = &recording.id;
// This will also delete the old performances. // This will also delete the old performances.
diesel::delete(recordings::table) diesel::delete(recordings::table)
@ -67,8 +67,8 @@ pub fn update_recording(conn: &DbConn, recording: &Recording, user: &User) -> Re
.execute(conn)?; .execute(conn)?;
let row = RecordingRow { let row = RecordingRow {
id, id: id.clone(),
work: recording.work.id as i64, work: recording.work.id.clone(),
comment: recording.comment.clone(), comment: recording.comment.clone(),
created_by: user.username.clone(), created_by: user.username.clone(),
}; };
@ -81,13 +81,13 @@ pub fn update_recording(conn: &DbConn, recording: &Recording, user: &User) -> Re
diesel::insert_into(performances::table) diesel::insert_into(performances::table)
.values(PerformanceRow { .values(PerformanceRow {
id: rand::random(), id: rand::random(),
recording: id, recording: id.clone(),
person: performance.person.as_ref().map(|person| person.id as i64), person: performance.person.as_ref().map(|person| person.id.clone()),
ensemble: performance ensemble: performance
.ensemble .ensemble
.as_ref() .as_ref()
.map(|ensemble| ensemble.id as i64), .map(|ensemble| ensemble.id.clone()),
role: performance.role.as_ref().map(|role| role.id as i64), role: performance.role.as_ref().map(|role| role.id.clone()),
}) })
.execute(conn)?; .execute(conn)?;
} }
@ -102,7 +102,7 @@ pub fn update_recording(conn: &DbConn, recording: &Recording, user: &User) -> Re
} }
/// Get an existing recording and all available information from related tables. /// Get an existing recording and all available information from related tables.
pub fn get_recording(conn: &DbConn, id: u32) -> Result<Option<Recording>> { pub fn get_recording(conn: &DbConn, id: &str) -> Result<Option<Recording>> {
let recording = match get_recording_row(conn, id)? { let recording = match get_recording_row(conn, id)? {
Some(row) => Some(get_description_for_recording_row(conn, &row)?), Some(row) => Some(get_description_for_recording_row(conn, &row)?),
None => None, None => None,
@ -112,13 +112,13 @@ pub fn get_recording(conn: &DbConn, id: u32) -> Result<Option<Recording>> {
} }
/// 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(conn: &DbConn, person_id: u32) -> Result<Vec<Recording>> { pub fn get_recordings_for_person(conn: &DbConn, 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>(conn)?; .load::<RecordingRow>(conn)?;
@ -130,13 +130,13 @@ pub fn get_recordings_for_person(conn: &DbConn, person_id: u32) -> Result<Vec<Re
} }
/// 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(conn: &DbConn, ensemble_id: u32) -> Result<Vec<Recording>> { pub fn get_recordings_for_ensemble(conn: &DbConn, 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>(conn)?; .load::<RecordingRow>(conn)?;
@ -148,11 +148,11 @@ pub fn get_recordings_for_ensemble(conn: &DbConn, ensemble_id: u32) -> Result<Ve
} }
/// Get allavailable information on all recordings of a work. /// Get allavailable information on all recordings of a work.
pub fn get_recordings_for_work(conn: &DbConn, work_id: u32) -> Result<Vec<Recording>> { pub fn get_recordings_for_work(conn: &DbConn, 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>(conn)?; .load::<RecordingRow>(conn)?;
for row in rows { for row in rows {
@ -165,9 +165,9 @@ pub fn get_recordings_for_work(conn: &DbConn, work_id: u32) -> Result<Vec<Record
/// 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. Also, the /// recording from other tables that are not directly part of the recording data. Also, the
/// provided user has to be allowed to delete the recording. /// provided user has to be allowed to delete the recording.
pub fn delete_recording(conn: &DbConn, id: u32, user: &User) -> Result<()> { pub fn delete_recording(conn: &DbConn, id: &str, user: &User) -> Result<()> {
if user.may_delete() { if user.may_delete() {
diesel::delete(recordings::table.filter(recordings::id.eq(id as i64))).execute(conn)?; diesel::delete(recordings::table.filter(recordings::id.eq(id))).execute(conn)?;
Ok(()) Ok(())
} else { } else {
Err(Error::new(ServerError::Forbidden)) Err(Error::new(ServerError::Forbidden))
@ -175,9 +175,9 @@ pub fn delete_recording(conn: &DbConn, id: u32, user: &User) -> Result<()> {
} }
/// Get an existing recording row. /// Get an existing recording row.
fn get_recording_row(conn: &DbConn, id: u32) -> Result<Option<RecordingRow>> { fn get_recording_row(conn: &DbConn, id: &str) -> Result<Option<RecordingRow>> {
Ok(recordings::table Ok(recordings::table
.filter(recordings::id.eq(id as i64)) .filter(recordings::id.eq(id))
.load::<RecordingRow>(conn)? .load::<RecordingRow>(conn)?
.into_iter() .into_iter()
.next()) .next())
@ -188,43 +188,36 @@ fn get_description_for_recording_row(conn: &DbConn, row: &RecordingRow) -> Resul
let mut performances: Vec<Performance> = Vec::new(); let mut performances: 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>(conn)?; .load::<PerformanceRow>(conn)?;
for row in performance_rows { for row in performance_rows {
performances.push(Performance { performances.push(Performance {
person: match row.person { person: match row.person {
Some(id) => { Some(id) => {
let id = id as u32; Some(get_person(conn, &id)?.ok_or(anyhow!("No person with ID: {}", id))?)
Some(get_person(conn, id)?.ok_or(anyhow!("No person with ID: {}", id))?)
} }
None => None, None => None,
}, },
ensemble: match row.ensemble { ensemble: match row.ensemble {
Some(id) => { Some(id) => {
let id = id as u32; Some(get_ensemble(conn, &id)?.ok_or(anyhow!("No ensemble with ID: {}", id))?)
Some(get_ensemble(conn, id)?.ok_or(anyhow!("No ensemble with ID: {}", id))?)
} }
None => None, None => None,
}, },
role: match row.role { role: match row.role {
Some(id) => { Some(id) => Some(
let id = id as u32; get_instrument(conn, &id)?.ok_or(anyhow!("No instrument with ID: {}", id))?,
Some( ),
get_instrument(conn, id)?
.ok_or(anyhow!("No instrument with ID: {}", id))?,
)
}
None => None, None => None,
}, },
}); });
} }
let id = row.work as u32; let work = get_work(conn, &row.work)?.ok_or(anyhow!("No work with ID: {}", &row.work))?;
let work = get_work(conn, id)?.ok_or(anyhow!("No work with ID: {}", id))?;
let recording = Recording { let recording = Recording {
id: row.id as u32, id: row.id.clone(),
work, work,
comment: row.comment.clone(), comment: row.comment.clone(),
performances, performances,

View file

@ -1,6 +1,6 @@
table! { table! {
ensembles (id) { ensembles (id) {
id -> Int8, id -> Text,
name -> Text, name -> Text,
created_by -> Text, created_by -> Text,
} }
@ -9,14 +9,14 @@ table! {
table! { table! {
instrumentations (id) { instrumentations (id) {
id -> Int8, id -> Int8,
work -> Int8, work -> Text,
instrument -> Int8, instrument -> Text,
} }
} }
table! { table! {
instruments (id) { instruments (id) {
id -> Int8, id -> Text,
name -> Text, name -> Text,
created_by -> Text, created_by -> Text,
} }
@ -25,16 +25,16 @@ table! {
table! { table! {
performances (id) { performances (id) {
id -> Int8, id -> Int8,
recording -> Int8, recording -> Text,
person -> Nullable<Int8>, person -> Nullable<Text>,
ensemble -> Nullable<Int8>, ensemble -> Nullable<Text>,
role -> Nullable<Int8>, role -> Nullable<Text>,
} }
} }
table! { table! {
persons (id) { persons (id) {
id -> Int8, id -> Text,
first_name -> Text, first_name -> Text,
last_name -> Text, last_name -> Text,
created_by -> Text, created_by -> Text,
@ -43,8 +43,8 @@ table! {
table! { table! {
recordings (id) { recordings (id) {
id -> Int8, id -> Text,
work -> Int8, work -> Text,
comment -> Text, comment -> Text,
created_by -> Text, created_by -> Text,
} }
@ -64,17 +64,17 @@ table! {
table! { table! {
work_parts (id) { work_parts (id) {
id -> Int8, id -> Int8,
work -> Int8, work -> Text,
part_index -> Int8, part_index -> Int8,
title -> Text, title -> Text,
composer -> Nullable<Int8>, composer -> Nullable<Text>,
} }
} }
table! { table! {
work_sections (id) { work_sections (id) {
id -> Int8, id -> Int8,
work -> Int8, work -> Text,
title -> Text, title -> Text,
before_index -> Int8, before_index -> Int8,
} }
@ -82,8 +82,8 @@ table! {
table! { table! {
works (id) { works (id) {
id -> Int8, id -> Text,
composer -> Int8, composer -> Text,
title -> Text, title -> Text,
created_by -> Text, created_by -> Text,
} }

View file

@ -10,7 +10,7 @@ use std::convert::TryInto;
#[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>,
@ -38,8 +38,8 @@ pub struct WorkSection {
#[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,
pub created_by: String, pub created_by: String,
} }
@ -49,8 +49,8 @@ struct 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 data for a work part. /// Table data for a work part.
@ -58,10 +58,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 data for a work section. /// Table data for a work section.
@ -69,7 +69,7 @@ struct WorkPartRow {
#[derive(Insertable, Queryable, Debug, Clone)] #[derive(Insertable, Queryable, Debug, Clone)]
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,
} }
@ -79,7 +79,7 @@ struct WorkSectionRow {
// TODO: Also add newly created associated items. // TODO: Also add newly created associated items.
pub fn update_work(conn: &DbConn, work: &Work, user: &User) -> Result<()> { pub fn update_work(conn: &DbConn, work: &Work, user: &User) -> Result<()> {
conn.transaction::<(), Error, _>(|| { conn.transaction::<(), Error, _>(|| {
let old_row = get_work_row(conn, work.id)?; let old_row = get_work_row(conn, &work.id)?;
let allowed = match old_row { let allowed = match old_row {
Some(row) => user.may_edit(&row.created_by), Some(row) => user.may_edit(&row.created_by),
@ -87,7 +87,7 @@ pub fn update_work(conn: &DbConn, work: &Work, user: &User) -> Result<()> {
}; };
if allowed { if allowed {
let id = work.id as i64; let id = &work.id;
// This will also delete rows from associated tables. // This will also delete rows from associated tables.
diesel::delete(works::table) diesel::delete(works::table)
@ -95,8 +95,8 @@ pub fn update_work(conn: &DbConn, work: &Work, user: &User) -> Result<()> {
.execute(conn)?; .execute(conn)?;
let row = WorkRow { let row = WorkRow {
id, id: id.clone(),
composer: work.composer.id as i64, composer: work.composer.id.clone(),
title: work.title.clone(), title: work.title.clone(),
created_by: user.username.clone(), created_by: user.username.clone(),
}; };
@ -109,8 +109,8 @@ pub fn update_work(conn: &DbConn, work: &Work, user: &User) -> Result<()> {
diesel::insert_into(instrumentations::table) diesel::insert_into(instrumentations::table)
.values(InstrumentationRow { .values(InstrumentationRow {
id: rand::random(), id: rand::random(),
work: id, work: id.clone(),
instrument: instrument.id as i64, instrument: instrument.id.clone(),
}) })
.execute(conn)?; .execute(conn)?;
} }
@ -118,10 +118,10 @@ pub fn update_work(conn: &DbConn, work: &Work, user: &User) -> Result<()> {
for (index, part) in work.parts.iter().enumerate() { for (index, part) in work.parts.iter().enumerate() {
let row = WorkPartRow { let row = WorkPartRow {
id: rand::random(), id: rand::random(),
work: id, work: id.clone(),
part_index: index.try_into()?, part_index: index.try_into()?,
title: part.title.clone(), title: part.title.clone(),
composer: part.composer.as_ref().map(|person| person.id as i64), composer: part.composer.as_ref().map(|person| person.id.clone()),
}; };
diesel::insert_into(work_parts::table) diesel::insert_into(work_parts::table)
@ -132,7 +132,7 @@ pub fn update_work(conn: &DbConn, work: &Work, user: &User) -> Result<()> {
for section in &work.sections { for section in &work.sections {
let row = WorkSectionRow { let row = WorkSectionRow {
id: rand::random(), id: rand::random(),
work: id, work: id.clone(),
title: section.title.clone(), title: section.title.clone(),
before_index: section.before_index, before_index: section.before_index,
}; };
@ -152,7 +152,7 @@ pub fn update_work(conn: &DbConn, work: &Work, user: &User) -> Result<()> {
} }
/// Get an existing work and all available information from related tables. /// Get an existing work and all available information from related tables.
pub fn get_work(conn: &DbConn, id: u32) -> Result<Option<Work>> { pub fn get_work(conn: &DbConn, id: &str) -> Result<Option<Work>> {
let work = match get_work_row(conn, id)? { let work = match get_work_row(conn, id)? {
Some(row) => Some(get_description_for_work_row(conn, &row)?), Some(row) => Some(get_description_for_work_row(conn, &row)?),
None => None, None => None,
@ -164,9 +164,9 @@ pub fn get_work(conn: &DbConn, id: u32) -> Result<Option<Work>> {
/// 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 itself. Also, /// this work except for the things that are part of the information on the work itself. Also,
/// this will only succeed, if the provided user is allowed to delete the work. /// this will only succeed, if the provided user is allowed to delete the work.
pub fn delete_work(conn: &DbConn, id: u32, user: &User) -> Result<()> { pub fn delete_work(conn: &DbConn, id: &str, user: &User) -> Result<()> {
if user.may_delete() { if user.may_delete() {
diesel::delete(works::table.filter(works::id.eq(id as i64))).execute(conn)?; diesel::delete(works::table.filter(works::id.eq(id))).execute(conn)?;
Ok(()) Ok(())
} else { } else {
Err(Error::new(ServerError::Forbidden)) Err(Error::new(ServerError::Forbidden))
@ -174,11 +174,11 @@ pub fn delete_work(conn: &DbConn, id: u32, user: &User) -> Result<()> {
} }
/// 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(conn: &DbConn, composer_id: u32) -> Result<Vec<Work>> { pub fn get_works(conn: &DbConn, 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>(conn)?; .load::<WorkRow>(conn)?;
for row in rows { for row in rows {
@ -189,9 +189,9 @@ pub fn get_works(conn: &DbConn, composer_id: u32) -> Result<Vec<Work>> {
} }
/// Get an already existing work without related rows from other tables. /// Get an already existing work without related rows from other tables.
fn get_work_row(conn: &DbConn, id: u32) -> Result<Option<WorkRow>> { fn get_work_row(conn: &DbConn, id: &str) -> Result<Option<WorkRow>> {
Ok(works::table Ok(works::table
.filter(works::id.eq(id as i64)) .filter(works::id.eq(id))
.load::<WorkRow>(conn)? .load::<WorkRow>(conn)?
.into_iter() .into_iter()
.next()) .next())
@ -202,19 +202,19 @@ fn get_description_for_work_row(conn: &DbConn, row: &WorkRow) -> Result<Work> {
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>(conn)?; .load::<InstrumentationRow>(conn)?;
for instrumentation in instrumentations { for instrumentation in instrumentations {
let id = instrumentation.instrument as u32; let id = instrumentation.instrument.clone();
instruments instruments
.push(get_instrument(conn, id)?.ok_or(anyhow!("No instrument with ID: {}", id))?); .push(get_instrument(conn, &id)?.ok_or(anyhow!("No instrument with ID: {}", id))?);
} }
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>(conn)?; .load::<WorkPartRow>(conn)?;
for part_row in part_rows { for part_row in part_rows {
@ -222,8 +222,7 @@ fn get_description_for_work_row(conn: &DbConn, row: &WorkRow) -> Result<Work> {
title: part_row.title, title: part_row.title,
composer: match part_row.composer { composer: match part_row.composer {
Some(id) => { Some(id) => {
let id = id as u32; Some(get_person(conn, &id)?.ok_or(anyhow!("No person with ID: {}", id))?)
Some(get_person(conn, id)?.ok_or(anyhow!("No person with ID: {}", id))?)
} }
None => None, None => None,
}, },
@ -233,7 +232,7 @@ fn get_description_for_work_row(conn: &DbConn, row: &WorkRow) -> Result<Work> {
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>(conn)?; .load::<WorkSectionRow>(conn)?;
for section in section_rows { for section in section_rows {
@ -243,11 +242,11 @@ fn get_description_for_work_row(conn: &DbConn, row: &WorkRow) -> Result<Work> {
}); });
} }
let id = row.composer as u32; let id = &row.composer;
let composer = get_person(conn, id)?.ok_or(anyhow!("No person with ID: {}", id))?; let composer = get_person(conn, id)?.ok_or(anyhow!("No person with ID: {}", id))?;
Ok(Work { Ok(Work {
id: row.id as u32, id: row.id.clone(),
composer, composer,
title: row.title.clone(), title: row.title.clone(),
instruments, instruments,

View file

@ -9,11 +9,11 @@ use actix_web_httpauth::extractors::bearer::BearerAuth;
#[get("/persons/{id}")] #[get("/persons/{id}")]
pub async fn get_person( pub async fn get_person(
db: web::Data<DbPool>, db: web::Data<DbPool>,
id: web::Path<u32>, id: web::Path<String>,
) -> Result<HttpResponse, ServerError> { ) -> Result<HttpResponse, ServerError> {
let data = web::block(move || { let data = web::block(move || {
let conn = db.into_inner().get()?; let conn = db.into_inner().get()?;
database::get_person(&conn, id.into_inner())?.ok_or(ServerError::NotFound) database::get_person(&conn, &id.into_inner())?.ok_or(ServerError::NotFound)
}) })
.await?; .await?;
@ -55,13 +55,13 @@ pub async fn get_persons(db: web::Data<DbPool>) -> Result<HttpResponse, ServerEr
pub async fn delete_person( pub async fn delete_person(
auth: BearerAuth, auth: BearerAuth,
db: web::Data<DbPool>, db: web::Data<DbPool>,
id: web::Path<u32>, id: web::Path<String>,
) -> Result<HttpResponse, ServerError> { ) -> Result<HttpResponse, ServerError> {
web::block(move || { web::block(move || {
let conn = db.into_inner().get()?; let conn = db.into_inner().get()?;
let user = authenticate(&conn, auth.token()).or(Err(ServerError::Unauthorized))?; let user = authenticate(&conn, auth.token()).or(Err(ServerError::Unauthorized))?;
database::delete_person(&conn, id.into_inner(), &user)?; database::delete_person(&conn, &id.into_inner(), &user)?;
Ok(()) Ok(())
}) })