diff options
Diffstat (limited to 'rust/src')
-rw-r--r-- | rust/src/api_helpers.rs | 5 | ||||
-rw-r--r-- | rust/src/api_server.rs | 93 | ||||
-rw-r--r-- | rust/src/database_entity_crud.rs | 442 | ||||
-rw-r--r-- | rust/src/database_models.rs | 29 | ||||
-rw-r--r-- | rust/src/lib.rs | 2 |
5 files changed, 364 insertions, 207 deletions
diff --git a/rust/src/api_helpers.rs b/rust/src/api_helpers.rs index 6c9a4e5f..fd0ad9e7 100644 --- a/rust/src/api_helpers.rs +++ b/rust/src/api_helpers.rs @@ -5,10 +5,11 @@ use diesel; use diesel::prelude::*; use errors::*; use regex::Regex; -use uuid::Uuid; use std::str::FromStr; +use uuid::Uuid; -pub type DbConn = diesel::r2d2::PooledConnection<diesel::r2d2::ConnectionManager<diesel::PgConnection>>; +pub type DbConn = + diesel::r2d2::PooledConnection<diesel::r2d2::ConnectionManager<diesel::PgConnection>>; /// This function should always be run within a transaction pub fn get_or_create_editgroup(editor_id: Uuid, conn: &PgConnection) -> Result<Uuid> { diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index 602fbfb7..0e68777b 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -2,6 +2,7 @@ use api_helpers::*; use chrono; +use database_entity_crud::{EditContext, EntityCrud}; use database_models::*; use database_schema::{ abstracts, changelog, container_edit, container_ident, container_rev, creator_edit, @@ -15,10 +16,9 @@ use errors::*; use fatcat_api::models; use fatcat_api::models::*; use sha1::Sha1; +use std::str::FromStr; use uuid::Uuid; use ConnectionPool; -use database_entity_crud::{EntityCrud, EditContext}; -use std::str::FromStr; macro_rules! entity_batch_handler { ($post_batch_handler:ident, $model:ident) => { @@ -125,7 +125,6 @@ impl Server { _expand: Option<String>, conn: &DbConn, ) -> Result<CreatorEntity> { - CreatorEntity::db_get(conn, FatCatId::from_uuid(id)) } @@ -195,7 +194,6 @@ impl Server { expand: Option<String>, conn: &DbConn, ) -> Result<ReleaseEntity> { - let mut release = ReleaseEntity::db_get(conn, FatCatId::from_uuid(id))?; // For now, if there is any expand param we do them all @@ -226,7 +224,6 @@ impl Server { } pub fn get_release_files_handler(&self, id: &str, conn: &DbConn) -> Result<Vec<FileEntity>> { - let ident = FatCatId::from_str(id)?; let rows: Vec<(FileRevRow, FileIdentRow, FileReleaseRow)> = file_rev::table @@ -286,7 +283,12 @@ impl Server { let edit = entity.db_update(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() } - pub fn delete_container_handler(&self, id: &Uuid, editgroup_id: Option<Uuid>, conn: &DbConn) -> Result<EntityEdit> { + pub fn delete_container_handler( + &self, + id: &Uuid, + editgroup_id: Option<Uuid>, + conn: &DbConn, + ) -> Result<EntityEdit> { let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)))?; let edit = ContainerEntity::db_delete(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() @@ -300,7 +302,6 @@ impl Server { let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?)?; let edit = entity.db_create(conn, &edit_context)?; edit.into_model() - } pub fn update_creator_handler( @@ -313,7 +314,12 @@ impl Server { let edit = entity.db_update(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() } - pub fn delete_creator_handler(&self, id: &Uuid, editgroup_id: Option<Uuid>, conn: &DbConn) -> Result<EntityEdit> { + pub fn delete_creator_handler( + &self, + id: &Uuid, + editgroup_id: Option<Uuid>, + conn: &DbConn, + ) -> Result<EntityEdit> { let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)))?; let edit = CreatorEntity::db_delete(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() @@ -339,7 +345,12 @@ impl Server { let edit = entity.db_update(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() } - pub fn delete_file_handler(&self, id: &Uuid, editgroup_id: Option<Uuid>, conn: &DbConn) -> Result<EntityEdit> { + pub fn delete_file_handler( + &self, + id: &Uuid, + editgroup_id: Option<Uuid>, + conn: &DbConn, + ) -> Result<EntityEdit> { let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)))?; let edit = FileEntity::db_delete(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() @@ -365,7 +376,12 @@ impl Server { let edit = entity.db_update(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() } - pub fn delete_release_handler(&self, id: &Uuid, editgroup_id: Option<Uuid>, conn: &DbConn) -> Result<EntityEdit> { + pub fn delete_release_handler( + &self, + id: &Uuid, + editgroup_id: Option<Uuid>, + conn: &DbConn, + ) -> Result<EntityEdit> { let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)))?; let edit = ReleaseEntity::db_delete(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() @@ -392,7 +408,12 @@ impl Server { edit.into_model() } - pub fn delete_work_handler(&self, id: &Uuid, editgroup_id: Option<Uuid>, conn: &DbConn) -> Result<EntityEdit> { + pub fn delete_work_handler( + &self, + id: &Uuid, + editgroup_id: Option<Uuid>, + conn: &DbConn, + ) -> Result<EntityEdit> { let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)))?; let edit = WorkEntity::db_delete(conn, &edit_context, FatCatId::from_uuid(id))?; @@ -627,34 +648,50 @@ impl Server { Ok(StatsResponse { extra: Some(val) }) } - entity_batch_handler!( - create_container_batch_handler, - ContainerEntity - ); - entity_batch_handler!( - create_creator_batch_handler, - CreatorEntity - ); + entity_batch_handler!(create_container_batch_handler, ContainerEntity); + entity_batch_handler!(create_creator_batch_handler, CreatorEntity); entity_batch_handler!(create_file_batch_handler, FileEntity); - entity_batch_handler!( - create_release_batch_handler, - ReleaseEntity - ); + entity_batch_handler!(create_release_batch_handler, ReleaseEntity); entity_batch_handler!(create_work_batch_handler, WorkEntity); - pub fn get_container_history_handler(&self, id: &Uuid, limit: Option<i64>, conn: &DbConn,) -> Result<Vec<EntityHistoryEntry>> { + pub fn get_container_history_handler( + &self, + id: &Uuid, + limit: Option<i64>, + conn: &DbConn, + ) -> Result<Vec<EntityHistoryEntry>> { ContainerEntity::db_get_history(conn, FatCatId::from_uuid(id), limit) } - pub fn get_creator_history_handler(&self, id: &Uuid, limit: Option<i64>, conn: &DbConn,) -> Result<Vec<EntityHistoryEntry>> { + pub fn get_creator_history_handler( + &self, + id: &Uuid, + limit: Option<i64>, + conn: &DbConn, + ) -> Result<Vec<EntityHistoryEntry>> { CreatorEntity::db_get_history(conn, FatCatId::from_uuid(id), limit) } - pub fn get_file_history_handler(&self, id: &Uuid, limit: Option<i64>, conn: &DbConn,) -> Result<Vec<EntityHistoryEntry>> { + pub fn get_file_history_handler( + &self, + id: &Uuid, + limit: Option<i64>, + conn: &DbConn, + ) -> Result<Vec<EntityHistoryEntry>> { FileEntity::db_get_history(conn, FatCatId::from_uuid(id), limit) } - pub fn get_release_history_handler(&self, id: &Uuid, limit: Option<i64>, conn: &DbConn,) -> Result<Vec<EntityHistoryEntry>> { + pub fn get_release_history_handler( + &self, + id: &Uuid, + limit: Option<i64>, + conn: &DbConn, + ) -> Result<Vec<EntityHistoryEntry>> { ReleaseEntity::db_get_history(conn, FatCatId::from_uuid(id), limit) } - pub fn get_work_history_handler(&self, id: &Uuid, limit: Option<i64>, conn: &DbConn,) -> Result<Vec<EntityHistoryEntry>> { + pub fn get_work_history_handler( + &self, + id: &Uuid, + limit: Option<i64>, + conn: &DbConn, + ) -> Result<Vec<EntityHistoryEntry>> { WorkEntity::db_get_history(conn, FatCatId::from_uuid(id), limit) } } diff --git a/rust/src/database_entity_crud.rs b/rust/src/database_entity_crud.rs index 0f5c5f9d..3f13a27d 100644 --- a/rust/src/database_entity_crud.rs +++ b/rust/src/database_entity_crud.rs @@ -1,17 +1,16 @@ - -use sha1::Sha1; +use api_helpers::*; use chrono; +use database_models::*; +use database_schema::*; use diesel::prelude::*; use diesel::{self, insert_into}; -use database_schema::*; -use database_models::*; use errors::*; use fatcat_api::models::*; -use api_helpers::*; -use uuid::Uuid; +use serde_json; +use sha1::Sha1; use std::marker::Sized; use std::str::FromStr; -use serde_json; +use uuid::Uuid; pub struct EditContext { pub editor_id: FatCatId, @@ -37,7 +36,10 @@ pub struct EditContext { */ // Associated Type, not parametric -pub trait EntityCrud where Self: Sized { +pub trait EntityCrud +where + Self: Sized, +{ // TODO: could these be generic structs? Or do they need to be bound to a specific table? type EditRow; // EntityEditRow type EditNewRow; @@ -51,13 +53,34 @@ pub trait EntityCrud where Self: Sized { fn db_get(conn: &DbConn, ident: FatCatId) -> Result<Self>; fn db_get_rev(conn: &DbConn, rev_id: Uuid) -> Result<Self>; fn db_create(&self, conn: &DbConn, edit_context: &EditContext) -> Result<Self::EditRow>; - fn db_create_batch(conn: &DbConn, edit_context: &EditContext, models: &[&Self]) -> Result<Vec<Self::EditRow>>; - fn db_update(&self, conn: &DbConn, edit_context: &EditContext, ident: FatCatId) -> Result<Self::EditRow>; - fn db_delete(conn: &DbConn, edit_context: &EditContext, ident: FatCatId) -> Result<Self::EditRow>; - fn db_get_history(conn: &DbConn, ident: FatCatId, limit: Option<i64>) -> Result<Vec<EntityHistoryEntry>>; + fn db_create_batch( + conn: &DbConn, + edit_context: &EditContext, + models: &[&Self], + ) -> Result<Vec<Self::EditRow>>; + fn db_update( + &self, + conn: &DbConn, + edit_context: &EditContext, + ident: FatCatId, + ) -> Result<Self::EditRow>; + fn db_delete( + conn: &DbConn, + edit_context: &EditContext, + ident: FatCatId, + ) -> Result<Self::EditRow>; + fn db_get_history( + conn: &DbConn, + ident: FatCatId, + limit: Option<i64>, + ) -> Result<Vec<EntityHistoryEntry>>; // Entity-specific Methods - fn db_from_row(conn: &DbConn, rev_row: Self::RevRow, ident_row: Option<Self::IdentRow>) -> Result<Self>; + fn db_from_row( + conn: &DbConn, + rev_row: Self::RevRow, + ident_row: Option<Self::IdentRow>, + ) -> Result<Self>; fn db_insert_rev(&self, conn: &DbConn) -> Result<Uuid>; fn db_insert_revs(conn: &DbConn, models: &[&Self]) -> Result<Vec<Uuid>>; } @@ -75,7 +98,7 @@ macro_rules! generic_parse_editgroup_id{ } macro_rules! generic_db_get { - ($ident_table: ident, $rev_table: ident) => { + ($ident_table:ident, $rev_table:ident) => { fn db_get(conn: &DbConn, ident: FatCatId) -> Result<Self> { let (ident, rev): (Self::IdentRow, Self::RevRow) = $ident_table::table .find(ident.to_uuid()) @@ -84,19 +107,17 @@ macro_rules! generic_db_get { Self::db_from_row(conn, rev, Some(ident)) } - } + }; } macro_rules! generic_db_get_rev { - ($rev_table: ident) => { + ($rev_table:ident) => { fn db_get_rev(conn: &DbConn, rev_id: Uuid) -> Result<Self> { - let rev = $rev_table::table - .find(rev_id) - .first(conn)?; - + let rev = $rev_table::table.find(rev_id).first(conn)?; + Self::db_from_row(conn, rev, None) } - } + }; } macro_rules! generic_db_create { @@ -121,34 +142,45 @@ macro_rules! generic_db_create { } macro_rules! generic_db_create_batch { - ($ident_table: ident, $edit_table: ident) => { - fn db_create_batch(conn: &DbConn, edit_context: &EditContext, models: &[&Self]) -> Result<Vec<Self::EditRow>> { + ($ident_table:ident, $edit_table:ident) => { + fn db_create_batch( + conn: &DbConn, + edit_context: &EditContext, + models: &[&Self], + ) -> Result<Vec<Self::EditRow>> { let rev_ids: Vec<Uuid> = Self::db_insert_revs(conn, models)?; let ident_ids: Vec<Uuid> = insert_into($ident_table::table) - .values(rev_ids.iter() - .map(|rev_id| Self::IdentNewRow { - rev_id: Some(rev_id.clone()), - is_live: edit_context.autoapprove, - redirect_id: None, - }) - .collect::<Vec<Self::IdentNewRow>>()) + .values( + rev_ids + .iter() + .map(|rev_id| Self::IdentNewRow { + rev_id: Some(rev_id.clone()), + is_live: edit_context.autoapprove, + redirect_id: None, + }) + .collect::<Vec<Self::IdentNewRow>>(), + ) .returning($ident_table::id) .get_results(conn)?; let edits: Vec<Self::EditRow> = insert_into($edit_table::table) - .values(rev_ids.into_iter().zip(ident_ids.into_iter()) - .map(|(rev_id, ident_id)| Self::EditNewRow { - editgroup_id: edit_context.editgroup_id.to_uuid(), - rev_id: Some(rev_id), - ident_id: ident_id, - redirect_id: None, - prev_rev: None, - extra_json: edit_context.extra_json.clone(), - }) - .collect::<Vec<Self::EditNewRow>>()) + .values( + rev_ids + .into_iter() + .zip(ident_ids.into_iter()) + .map(|(rev_id, ident_id)| Self::EditNewRow { + editgroup_id: edit_context.editgroup_id.to_uuid(), + rev_id: Some(rev_id), + ident_id: ident_id, + redirect_id: None, + prev_rev: None, + extra_json: edit_context.extra_json.clone(), + }) + .collect::<Vec<Self::EditNewRow>>(), + ) .get_results(conn)?; Ok(edits) } - } + }; } macro_rules! generic_db_update { @@ -181,9 +213,12 @@ macro_rules! generic_db_update { } macro_rules! generic_db_delete { - ($ident_table: ident, $edit_table:ident) => { - fn db_delete(conn: &DbConn, edit_context: &EditContext, ident: FatCatId) -> Result<Self::EditRow> { - + ($ident_table:ident, $edit_table:ident) => { + fn db_delete( + conn: &DbConn, + edit_context: &EditContext, + ident: FatCatId, + ) -> Result<Self::EditRow> { let current: Self::IdentRow = $ident_table::table.find(ident.to_uuid()).first(conn)?; if current.is_live != true { // TODO: what if isn't live? 4xx not 5xx @@ -206,12 +241,16 @@ macro_rules! generic_db_delete { Ok(edit) } - } + }; } macro_rules! generic_db_get_history { ($edit_table:ident) => { - fn db_get_history(conn: &DbConn, ident: FatCatId, limit: Option<i64>) -> Result<Vec<EntityHistoryEntry>> { + fn db_get_history( + conn: &DbConn, + ident: FatCatId, + limit: Option<i64>, + ) -> Result<Vec<EntityHistoryEntry>> { let limit = limit.unwrap_or(50); // TODO: make a static let rows: Vec<(EditgroupRow, ChangelogRow, Self::EditRow)> = editgroup::table @@ -223,15 +262,17 @@ macro_rules! generic_db_get_history { .get_results(conn)?; let history: Result<Vec<EntityHistoryEntry>> = rows.into_iter() - .map(|(eg_row, cl_row, e_row)| Ok(EntityHistoryEntry { - edit: e_row.into_model()?, - editgroup: eg_row.into_model_partial(), - changelog_entry: cl_row.into_model(), - })) + .map(|(eg_row, cl_row, e_row)| { + Ok(EntityHistoryEntry { + edit: e_row.into_model()?, + editgroup: eg_row.into_model_partial(), + changelog_entry: cl_row.into_model(), + }) + }) .collect(); history } - } + }; } macro_rules! generic_db_insert_rev { @@ -259,8 +300,11 @@ impl EntityCrud for ContainerEntity { generic_db_get_history!(container_edit); generic_db_insert_rev!(); - fn db_from_row(_conn: &DbConn, rev_row: Self::RevRow, ident_row: Option<Self::IdentRow>) -> Result<Self> { - + fn db_from_row( + _conn: &DbConn, + rev_row: Self::RevRow, + ident_row: Option<Self::IdentRow>, + ) -> Result<Self> { let (state, ident_id, redirect_id) = match ident_row { Some(i) => ( Some(i.state().unwrap().shortname()), @@ -287,7 +331,6 @@ impl EntityCrud for ContainerEntity { } fn db_insert_revs(conn: &DbConn, models: &[&Self]) -> Result<Vec<Uuid>> { - // first verify external identifier syntax for entity in models { if let Some(ref extid) = entity.wikidata_qid { @@ -299,17 +342,20 @@ impl EntityCrud for ContainerEntity { } let rev_ids: Vec<Uuid> = insert_into(container_rev::table) - .values(models.iter() - .map(|model| ContainerRevNewRow { - name: model.name.clone(), - publisher: model.publisher.clone(), - issnl: model.issnl.clone(), - wikidata_qid: model.wikidata_qid.clone(), - abbrev: model.abbrev.clone(), - coden: model.coden.clone(), - extra_json: model.extra.clone() - }) - .collect::<Vec<ContainerRevNewRow>>()) + .values( + models + .iter() + .map(|model| ContainerRevNewRow { + name: model.name.clone(), + publisher: model.publisher.clone(), + issnl: model.issnl.clone(), + wikidata_qid: model.wikidata_qid.clone(), + abbrev: model.abbrev.clone(), + coden: model.coden.clone(), + extra_json: model.extra.clone(), + }) + .collect::<Vec<ContainerRevNewRow>>(), + ) .returning(container_rev::id) .get_results(conn)?; Ok(rev_ids) @@ -333,7 +379,11 @@ impl EntityCrud for CreatorEntity { generic_db_get_history!(creator_edit); generic_db_insert_rev!(); - fn db_from_row(_conn: &DbConn, rev_row: Self::RevRow, ident_row: Option<Self::IdentRow>) -> Result<Self> { + fn db_from_row( + _conn: &DbConn, + rev_row: Self::RevRow, + ident_row: Option<Self::IdentRow>, + ) -> Result<Self> { let (state, ident_id, redirect_id) = match ident_row { Some(i) => ( Some(i.state().unwrap().shortname()), @@ -358,7 +408,6 @@ impl EntityCrud for CreatorEntity { } fn db_insert_revs(conn: &DbConn, models: &[&Self]) -> Result<Vec<Uuid>> { - // first verify external identifier syntax for entity in models { if let Some(ref extid) = entity.orcid { @@ -370,16 +419,19 @@ impl EntityCrud for CreatorEntity { } let rev_ids: Vec<Uuid> = insert_into(creator_rev::table) - .values(models.iter() - .map(|model| CreatorRevNewRow { - display_name: model.display_name.clone(), - given_name: model.given_name.clone(), - surname: model.surname.clone(), - orcid: model.orcid.clone(), - wikidata_qid: model.wikidata_qid.clone(), - extra_json: model.extra.clone() - }) - .collect::<Vec<CreatorRevNewRow>>()) + .values( + models + .iter() + .map(|model| CreatorRevNewRow { + display_name: model.display_name.clone(), + given_name: model.given_name.clone(), + surname: model.surname.clone(), + orcid: model.orcid.clone(), + wikidata_qid: model.wikidata_qid.clone(), + extra_json: model.extra.clone(), + }) + .collect::<Vec<CreatorRevNewRow>>(), + ) .returning(creator_rev::id) .get_results(conn)?; Ok(rev_ids) @@ -403,7 +455,11 @@ impl EntityCrud for FileEntity { generic_db_get_history!(file_edit); generic_db_insert_rev!(); - fn db_from_row(conn: &DbConn, rev_row: Self::RevRow, ident_row: Option<Self::IdentRow>) -> Result<Self> { + fn db_from_row( + conn: &DbConn, + rev_row: Self::RevRow, + ident_row: Option<Self::IdentRow>, + ) -> Result<Self> { let (state, ident_id, redirect_id) = match ident_row { Some(i) => ( Some(i.state().unwrap().shortname()), @@ -448,18 +504,20 @@ impl EntityCrud for FileEntity { } fn db_insert_revs(conn: &DbConn, models: &[&Self]) -> Result<Vec<Uuid>> { - let rev_ids: Vec<Uuid> = insert_into(file_rev::table) - .values(models.iter() - .map(|model| FileRevNewRow { - size: model.size, - sha1: model.sha1.clone(), - sha256: model.sha256.clone(), - md5: model.md5.clone(), - mimetype: model.mimetype.clone(), - extra_json: model.extra.clone() - }) - .collect::<Vec<FileRevNewRow>>()) + .values( + models + .iter() + .map(|model| FileRevNewRow { + size: model.size, + sha1: model.sha1.clone(), + sha256: model.sha256.clone(), + md5: model.md5.clone(), + mimetype: model.mimetype.clone(), + extra_json: model.extra.clone(), + }) + .collect::<Vec<FileRevNewRow>>(), + ) .returning(file_rev::id) .get_results(conn)?; @@ -472,10 +530,12 @@ impl EntityCrud for FileEntity { Some(release_list) => { let these_release_rows: Result<Vec<FileReleaseRow>> = release_list .iter() - .map(|r| Ok(FileReleaseRow { - file_rev: rev_id.clone(), - target_release_ident_id: FatCatId::from_str(r)?.to_uuid(), - })) + .map(|r| { + Ok(FileReleaseRow { + file_rev: rev_id.clone(), + target_release_ident_id: FatCatId::from_str(r)?.to_uuid(), + }) + }) .collect(); file_release_rows.extend(these_release_rows?); } @@ -537,7 +597,11 @@ impl EntityCrud for ReleaseEntity { Ok(edits.pop().unwrap()) } - fn db_create_batch(conn: &DbConn, edit_context: &EditContext, models: &[&Self]) -> Result<Vec<Self::EditRow>> { + fn db_create_batch( + conn: &DbConn, + edit_context: &EditContext, + models: &[&Self], + ) -> Result<Vec<Self::EditRow>> { // This isn't the generic implementation because we need to create Work entities for each // of the release entities passed (at least in the common case) @@ -558,49 +622,65 @@ impl EntityCrud for ReleaseEntity { } // create the works, then pluck the list of idents from the result - let new_work_edits = WorkEntity::db_create_batch(conn, edit_context, new_work_models.as_slice())?; + let new_work_edits = + WorkEntity::db_create_batch(conn, edit_context, new_work_models.as_slice())?; let mut new_work_ids: Vec<Uuid> = new_work_edits.iter().map(|edit| edit.ident_id).collect(); // Copy all the release models, and ensure that each has work_id set, using the new work // idents. There should be one new work ident for each release missing one. - let models_with_work_ids: Vec<Self> = models.iter().map(|model| { - let mut model = (*model).clone(); - if model.work_id.is_none() { - model.work_id = Some(FatCatId::from_uuid(&new_work_ids.pop().unwrap()).to_string()) - } - model - }).collect(); + let models_with_work_ids: Vec<Self> = models + .iter() + .map(|model| { + let mut model = (*model).clone(); + if model.work_id.is_none() { + model.work_id = + Some(FatCatId::from_uuid(&new_work_ids.pop().unwrap()).to_string()) + } + model + }) + .collect(); let model_refs: Vec<&Self> = models_with_work_ids.iter().map(|s| s).collect(); let models = model_refs.as_slice(); // The rest here is copy/pasta from the generic (how to avoid copypasta?) let rev_ids: Vec<Uuid> = Self::db_insert_revs(conn, models)?; let ident_ids: Vec<Uuid> = insert_into(release_ident::table) - .values(rev_ids.iter() - .map(|rev_id| Self::IdentNewRow { - rev_id: Some(rev_id.clone()), - is_live: edit_context.autoapprove, - redirect_id: None, - }) - .collect::<Vec<Self::IdentNewRow>>()) + .values( + rev_ids + .iter() + .map(|rev_id| Self::IdentNewRow { + rev_id: Some(rev_id.clone()), + is_live: edit_context.autoapprove, + redirect_id: None, + }) + .collect::<Vec<Self::IdentNewRow>>(), + ) .returning(release_ident::id) .get_results(conn)?; let edits: Vec<Self::EditRow> = insert_into(release_edit::table) - .values(rev_ids.into_iter().zip(ident_ids.into_iter()) - .map(|(rev_id, ident_id)| Self::EditNewRow { - editgroup_id: edit_context.editgroup_id.to_uuid(), - rev_id: Some(rev_id), - ident_id: ident_id, - redirect_id: None, - prev_rev: None, - extra_json: edit_context.extra_json.clone(), - }) - .collect::<Vec<Self::EditNewRow>>()) + .values( + rev_ids + .into_iter() + .zip(ident_ids.into_iter()) + .map(|(rev_id, ident_id)| Self::EditNewRow { + editgroup_id: edit_context.editgroup_id.to_uuid(), + rev_id: Some(rev_id), + ident_id: ident_id, + redirect_id: None, + prev_rev: None, + extra_json: edit_context.extra_json.clone(), + }) + .collect::<Vec<Self::EditNewRow>>(), + ) .get_results(conn)?; Ok(edits) } - fn db_from_row(conn: &DbConn, rev_row: Self::RevRow, ident_row: Option<Self::IdentRow>) -> Result<Self> { + fn db_from_row( + conn: &DbConn, + rev_row: Self::RevRow, + ident_row: Option<Self::IdentRow>, + ) -> Result<Self> { let (state, ident_id, redirect_id) = match ident_row { Some(i) => ( Some(i.state().unwrap().shortname()), @@ -623,7 +703,8 @@ impl EntityCrud for ReleaseEntity { year: r.year, title: r.title, locator: r.locator, - target_release_id: r.target_release_ident_id.map(|v| FatCatId::from_uuid(&v).to_string()), + target_release_id: r.target_release_ident_id + .map(|v| FatCatId::from_uuid(&v).to_string()), }) .collect(); @@ -640,7 +721,8 @@ impl EntityCrud for ReleaseEntity { raw_name: c.raw_name, role: c.role, extra: c.extra_json, - creator_id: c.creator_ident_id.map(|v| FatCatId::from_uuid(&v).to_string()), + creator_id: c.creator_ident_id + .map(|v| FatCatId::from_uuid(&v).to_string()), creator: None, }) .collect(); @@ -664,7 +746,8 @@ impl EntityCrud for ReleaseEntity { title: rev_row.title, release_type: rev_row.release_type, release_status: rev_row.release_status, - release_date: rev_row.release_date + release_date: rev_row + .release_date .map(|v| chrono::DateTime::from_utc(v.and_hms(0, 0, 0), chrono::Utc)), doi: rev_row.doi, pmid: rev_row.pmid, @@ -677,7 +760,9 @@ impl EntityCrud for ReleaseEntity { pages: rev_row.pages, files: None, container: None, - container_id: rev_row.container_ident_id.map(|u| FatCatId::from_uuid(&u).to_string()), + container_id: rev_row + .container_ident_id + .map(|u| FatCatId::from_uuid(&u).to_string()), publisher: rev_row.publisher, language: rev_row.language, work_id: Some(FatCatId::from_uuid(&rev_row.work_ident_id).to_string()), @@ -694,7 +779,6 @@ impl EntityCrud for ReleaseEntity { } fn db_insert_revs(conn: &DbConn, models: &[&Self]) -> Result<Vec<Uuid>> { - // first verify external identifier syntax for entity in models { if let Some(ref extid) = entity.doi { @@ -712,8 +796,10 @@ impl EntityCrud for ReleaseEntity { } let rev_ids: Vec<Uuid> = insert_into(release_rev::table) - .values(models.iter() - .map(|model| Ok(ReleaseRevNewRow { + .values(models + .iter() + .map(|model| { + Ok(ReleaseRevNewRow { title: model.title.clone(), release_type: model.release_type.clone(), release_status: model.release_status.clone(), @@ -738,7 +824,8 @@ impl EntityCrud for ReleaseEntity { publisher: model.publisher.clone(), language: model.language.clone(), extra_json: model.extra.clone() - })) + }) + }) .collect::<Result<Vec<ReleaseRevNewRow>>>()?) .returning(release_rev::id) .get_results(conn)?; @@ -752,20 +839,22 @@ impl EntityCrud for ReleaseEntity { Some(ref_list) => { let these_ref_rows: Vec<ReleaseRefNewRow> = ref_list .iter() - .map(|r| Ok(ReleaseRefNewRow { - release_rev: rev_id.clone(), - target_release_ident_id: match r.target_release_id.clone() { - None => None, - Some(v) => Some(FatCatId::from_str(&v)?.to_uuid()), - }, - index_val: r.index, - key: r.key.clone(), - container_title: r.container_title.clone(), - year: r.year, - title: r.title.clone(), - locator: r.locator.clone(), - extra_json: r.extra.clone(), - })) + .map(|r| { + Ok(ReleaseRefNewRow { + release_rev: rev_id.clone(), + target_release_ident_id: match r.target_release_id.clone() { + None => None, + Some(v) => Some(FatCatId::from_str(&v)?.to_uuid()), + }, + index_val: r.index, + key: r.key.clone(), + container_title: r.container_title.clone(), + year: r.year, + title: r.title.clone(), + locator: r.locator.clone(), + extra_json: r.extra.clone(), + }) + }) .collect::<Result<Vec<ReleaseRefNewRow>>>()?; release_ref_rows.extend(these_ref_rows); } @@ -776,17 +865,19 @@ impl EntityCrud for ReleaseEntity { Some(contrib_list) => { let these_contrib_rows: Vec<ReleaseContribNewRow> = contrib_list .iter() - .map(|c| Ok(ReleaseContribNewRow { - release_rev: rev_id.clone(), - creator_ident_id: match c.creator_id.clone() { - None => None, - Some(v) => Some(FatCatId::from_str(&v)?.to_uuid()), - }, - raw_name: c.raw_name.clone(), - index_val: c.index, - role: c.role.clone(), - extra_json: c.extra.clone(), - })) + .map(|c| { + Ok(ReleaseContribNewRow { + release_rev: rev_id.clone(), + creator_ident_id: match c.creator_id.clone() { + None => None, + Some(v) => Some(FatCatId::from_str(&v)?.to_uuid()), + }, + raw_name: c.raw_name.clone(), + index_val: c.index, + role: c.role.clone(), + extra_json: c.extra.clone(), + }) + }) .collect::<Result<Vec<ReleaseContribNewRow>>>()?; release_contrib_rows.extend(these_contrib_rows); } @@ -814,18 +905,20 @@ impl EntityCrud for ReleaseEntity { } let release_abstract_rows: Vec<ReleaseRevAbstractNewRow> = abstract_list .into_iter() - .map(|c| Ok(ReleaseRevAbstractNewRow { - release_rev: rev_id.clone(), - abstract_sha1: match c.content { - Some(ref content) => Sha1::from(content).hexdigest(), - None => match c.sha1.clone() { - Some(v) => v, - None => { bail!("either abstract_sha1 or content is required") } + .map(|c| { + Ok(ReleaseRevAbstractNewRow { + release_rev: rev_id.clone(), + abstract_sha1: match c.content { + Some(ref content) => Sha1::from(content).hexdigest(), + None => match c.sha1.clone() { + Some(v) => v, + None => bail!("either abstract_sha1 or content is required"), + }, }, - }, - lang: c.lang.clone(), - mimetype: c.mimetype.clone(), - })) + lang: c.lang.clone(), + mimetype: c.mimetype.clone(), + }) + }) .collect::<Result<Vec<ReleaseRevAbstractNewRow>>>()?; insert_into(release_rev_abstract::table) .values(release_abstract_rows) @@ -866,8 +959,11 @@ impl EntityCrud for WorkEntity { generic_db_get_history!(work_edit); generic_db_insert_rev!(); - fn db_from_row(_conn: &DbConn, rev_row: Self::RevRow, ident_row: Option<Self::IdentRow>) -> Result<Self> { - + fn db_from_row( + _conn: &DbConn, + rev_row: Self::RevRow, + ident_row: Option<Self::IdentRow>, + ) -> Result<Self> { let (state, ident_id, redirect_id) = match ident_row { Some(i) => ( Some(i.state().unwrap().shortname()), @@ -889,12 +985,16 @@ impl EntityCrud for WorkEntity { fn db_insert_revs(conn: &DbConn, models: &[&Self]) -> Result<Vec<Uuid>> { let rev_ids: Vec<Uuid> = insert_into(work_rev::table) - .values(models.iter() - .map(|model| WorkRevNewRow { extra_json: model.extra.clone() } ) - .collect::<Vec<WorkRevNewRow>>()) + .values( + models + .iter() + .map(|model| WorkRevNewRow { + extra_json: model.extra.clone(), + }) + .collect::<Vec<WorkRevNewRow>>(), + ) .returning(work_rev::id) .get_results(conn)?; Ok(rev_ids) } } - diff --git a/rust/src/database_models.rs b/rust/src/database_models.rs index 2d6788eb..93e6a0fe 100644 --- a/rust/src/database_models.rs +++ b/rust/src/database_models.rs @@ -37,9 +37,14 @@ pub trait EntityEditRow { // Helper for constructing tables macro_rules! entity_structs { - ($edit_table:expr, $edit_struct:ident, $edit_new_struct:ident, $ident_table:expr, - $ident_struct:ident, $ident_new_struct:ident) => { - + ( + $edit_table:expr, + $edit_struct:ident, + $edit_new_struct:ident, + $ident_table:expr, + $ident_struct:ident, + $ident_new_struct:ident + ) => { #[derive(Debug, Queryable, Identifiable, Associations, AsChangeset, QueryableByName)] #[table_name = $edit_table] pub struct $edit_struct { @@ -218,7 +223,14 @@ pub struct FileRevNewRow { pub mimetype: Option<String>, } -entity_structs!("file_edit", FileEditRow, FileEditNewRow, "file_ident", FileIdentRow, FileIdentNewRow); +entity_structs!( + "file_edit", + FileEditRow, + FileEditNewRow, + "file_ident", + FileIdentRow, + FileIdentNewRow +); #[derive(Debug, Queryable, Identifiable, Associations, AsChangeset)] #[table_name = "release_rev"] @@ -289,7 +301,14 @@ pub struct WorkRevNewRow { pub extra_json: Option<serde_json::Value>, } -entity_structs!("work_edit", WorkEditRow, WorkEditNewRow, "work_ident", WorkIdentRow, WorkIdentNewRow); +entity_structs!( + "work_edit", + WorkEditRow, + WorkEditNewRow, + "work_ident", + WorkIdentRow, + WorkIdentNewRow +); #[derive(Debug, Queryable, Identifiable, Associations, AsChangeset)] #[table_name = "release_rev_abstract"] diff --git a/rust/src/lib.rs b/rust/src/lib.rs index a938486b..38f9b343 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -25,9 +25,9 @@ extern crate sha1; pub mod api_helpers; pub mod api_server; pub mod api_wrappers; +pub mod database_entity_crud; pub mod database_models; pub mod database_schema; -pub mod database_entity_crud; mod errors { // Create the Error, ErrorKind, ResultExt, and Result types |