diff options
-rw-r--r-- | rust/src/api_helpers.rs | 140 | ||||
-rw-r--r-- | rust/src/api_server.rs | 237 | ||||
-rw-r--r-- | rust/src/api_wrappers.rs | 48 |
3 files changed, 189 insertions, 236 deletions
diff --git a/rust/src/api_helpers.rs b/rust/src/api_helpers.rs index 91c6200d..489631b3 100644 --- a/rust/src/api_helpers.rs +++ b/rust/src/api_helpers.rs @@ -7,6 +7,7 @@ use errors::*; use regex::Regex; use uuid::Uuid; +/// This function should always be run within a transaction pub fn get_or_create_editgroup(editor_id: Uuid, conn: &PgConnection) -> Result<Uuid> { // check for current active let ed_row: EditorRow = editor::table.find(editor_id).first(conn)?; @@ -15,81 +16,78 @@ pub fn get_or_create_editgroup(editor_id: Uuid, conn: &PgConnection) -> Result<U } // need to insert and update - conn.build_transaction().run(|| { - let eg_row: EditgroupRow = diesel::insert_into(editgroup::table) - .values((editgroup::editor_id.eq(ed_row.id),)) - .get_result(conn)?; - diesel::update(editor::table.find(ed_row.id)) - .set(editor::active_editgroup_id.eq(eg_row.id)) - .execute(conn)?; - Ok(eg_row.id) - }) + let eg_row: EditgroupRow = diesel::insert_into(editgroup::table) + .values((editgroup::editor_id.eq(ed_row.id),)) + .get_result(conn)?; + diesel::update(editor::table.find(ed_row.id)) + .set(editor::active_editgroup_id.eq(eg_row.id)) + .execute(conn)?; + Ok(eg_row.id) } +/// This function should always be run within a transaction pub fn accept_editgroup(editgroup_id: Uuid, conn: &PgConnection) -> Result<ChangelogRow> { - conn.build_transaction().run(|| { - // check that we haven't accepted already (in changelog) - // NB: could leave this to a UNIQUE constraint - let count: i64 = changelog::table - .filter(changelog::editgroup_id.eq(editgroup_id)) - .count() - .get_result(conn)?; - if count > 0 { - bail!( - "editgroup {} has already been accepted", - editgroup_id.to_string() - ); - } - - // for each entity type... - //for entity in (container_edit, creator_edit, file_edit, release_edit, work_edit) { - /* - // This would be the clean and efficient way, but see: - // https://github.com/diesel-rs/diesel/issues/1478 - diesel::update(container_ident::table) - .inner_join(container_edit::table.on( - container_ident::id.eq(container_edit::ident_id) - )) - .filter(container_edit::editgroup_id.eq(editgroup_id)) - .values(( - container_ident::is_live.eq(true), - container_ident::rev_id.eq(container_edit::rev_id), - container_ident::redirect_id.eq(container_edit::redirect_id), - )) - .execute()?; - */ - - // Sketchy... but fast? Only a few queries per accept. - for entity in &["container", "creator", "file", "work", "release"] { - diesel::sql_query(format!( - " - UPDATE {entity}_ident - SET - is_live = true, - rev_id = {entity}_edit.rev_id, - redirect_id = {entity}_edit.redirect_id - FROM {entity}_edit - WHERE - {entity}_ident.id = {entity}_edit.ident_id - AND {entity}_edit.editgroup_id = $1", - entity = entity - )).bind::<diesel::sql_types::Uuid, _>(editgroup_id) - .execute(conn)?; - } - - // append log/changelog row - let entry: ChangelogRow = diesel::insert_into(changelog::table) - .values((changelog::editgroup_id.eq(editgroup_id),)) - .get_result(conn)?; - - // update any editor's active editgroup - let no_active: Option<Uuid> = None; - diesel::update(editor::table) - .filter(editor::active_editgroup_id.eq(editgroup_id)) - .set(editor::active_editgroup_id.eq(no_active)) + // check that we haven't accepted already (in changelog) + // NB: could leave this to a UNIQUE constraint + let count: i64 = changelog::table + .filter(changelog::editgroup_id.eq(editgroup_id)) + .count() + .get_result(conn)?; + if count > 0 { + bail!( + "editgroup {} has already been accepted", + editgroup_id.to_string() + ); + } + + // for each entity type... + //for entity in (container_edit, creator_edit, file_edit, release_edit, work_edit) { + /* + // This would be the clean and efficient way, but see: + // https://github.com/diesel-rs/diesel/issues/1478 + diesel::update(container_ident::table) + .inner_join(container_edit::table.on( + container_ident::id.eq(container_edit::ident_id) + )) + .filter(container_edit::editgroup_id.eq(editgroup_id)) + .values(( + container_ident::is_live.eq(true), + container_ident::rev_id.eq(container_edit::rev_id), + container_ident::redirect_id.eq(container_edit::redirect_id), + )) + .execute()?; + */ + + // Sketchy... but fast? Only a few queries per accept. + for entity in &["container", "creator", "file", "work", "release"] { + diesel::sql_query(format!( + " + UPDATE {entity}_ident + SET + is_live = true, + rev_id = {entity}_edit.rev_id, + redirect_id = {entity}_edit.redirect_id + FROM {entity}_edit + WHERE + {entity}_ident.id = {entity}_edit.ident_id + AND {entity}_edit.editgroup_id = $1", + entity = entity + )).bind::<diesel::sql_types::Uuid, _>(editgroup_id) .execute(conn)?; - Ok(entry) - }) + } + + // append log/changelog row + let entry: ChangelogRow = diesel::insert_into(changelog::table) + .values((changelog::editgroup_id.eq(editgroup_id),)) + .get_result(conn)?; + + // update any editor's active editgroup + let no_active: Option<Uuid> = None; + diesel::update(editor::table) + .filter(editor::active_editgroup_id.eq(editgroup_id)) + .set(editor::active_editgroup_id.eq(no_active)) + .execute(conn)?; + Ok(entry) } /// Convert fatcat IDs (base32 strings) to UUID diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index 902b0934..bd13ebb6 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -22,13 +22,14 @@ type DbConn = diesel::r2d2::PooledConnection<diesel::r2d2::ConnectionManager<die macro_rules! entity_batch_handler { ($post_handler:ident, $post_batch_handler:ident, $model:ident) => { - pub fn $post_batch_handler(&self, entity_list: &[models::$model]) -> - Result<Vec<EntityEdit>> { - let conn = self.db_pool.get().expect("db_pool error"); - // TODO: start a transaction + pub fn $post_batch_handler( + &self, + entity_list: &[models::$model], + conn: &DbConn, + ) -> Result<Vec<EntityEdit>> { let mut ret: Vec<EntityEdit> = vec![]; for entity in entity_list { - ret.push(self.$post_handler(entity.clone(), Some(&conn))?); + ret.push(self.$post_handler(entity.clone(), conn)?); } Ok(ret) } @@ -41,8 +42,8 @@ macro_rules! entity_history_handler { &self, id: &str, limit: Option<i64>, + conn: &DbConn, ) -> Result<Vec<EntityHistoryEntry>> { - let conn = self.db_pool.get().expect("db_pool error"); let id = fcid2uuid(id)?; let limit = limit.unwrap_or(50); @@ -52,7 +53,7 @@ macro_rules! entity_history_handler { .filter($edit_table::ident_id.eq(id)) .order(changelog::id.desc()) .limit(limit) - .get_results(&conn)?; + .get_results(conn)?; let history: Vec<EntityHistoryEntry> = rows.into_iter() .map(|(eg_row, cl_row, e_row)| EntityHistoryEntry { @@ -294,21 +295,19 @@ fn work_row2entity(ident: Option<WorkIdentRow>, rev: WorkRevRow) -> Result<WorkE } impl Server { - pub fn get_container_handler(&self, id: &str) -> Result<ContainerEntity> { - let conn = self.db_pool.get().expect("db_pool error"); + pub fn get_container_handler(&self, id: &str, conn: &DbConn) -> Result<ContainerEntity> { let id = fcid2uuid(id)?; // TODO: handle Deletions let (ident, rev): (ContainerIdentRow, ContainerRevRow) = container_ident::table .find(id) .inner_join(container_rev::table) - .first(&conn)?; + .first(conn)?; container_row2entity(Some(ident), rev) } - pub fn lookup_container_handler(&self, issnl: &str) -> Result<ContainerEntity> { - let conn = self.db_pool.get().expect("db_pool error"); + pub fn lookup_container_handler(&self, issnl: &str, conn: &DbConn) -> Result<ContainerEntity> { check_issn(issnl)?; let (ident, rev): (ContainerIdentRow, ContainerRevRow) = container_ident::table @@ -316,25 +315,23 @@ impl Server { .filter(container_rev::issnl.eq(issnl)) .filter(container_ident::is_live.eq(true)) .filter(container_ident::redirect_id.is_null()) - .first(&conn)?; + .first(conn)?; container_row2entity(Some(ident), rev) } - pub fn get_creator_handler(&self, id: &str) -> Result<CreatorEntity> { - let conn = self.db_pool.get().expect("db_pool error"); + pub fn get_creator_handler(&self, id: &str, conn: &DbConn) -> Result<CreatorEntity> { let id = fcid2uuid(id)?; let (ident, rev): (CreatorIdentRow, CreatorRevRow) = creator_ident::table .find(id) .inner_join(creator_rev::table) - .first(&conn)?; + .first(conn)?; creator_row2entity(Some(ident), rev) } - pub fn lookup_creator_handler(&self, orcid: &str) -> Result<CreatorEntity> { - let conn = self.db_pool.get().expect("db_pool error"); + pub fn lookup_creator_handler(&self, orcid: &str, conn: &DbConn) -> Result<CreatorEntity> { check_orcid(orcid)?; let (ident, rev): (CreatorIdentRow, CreatorRevRow) = creator_ident::table @@ -342,13 +339,13 @@ impl Server { .filter(creator_rev::orcid.eq(orcid)) .filter(creator_ident::is_live.eq(true)) .filter(creator_ident::redirect_id.is_null()) - .first(&conn)?; + .first(conn)?; creator_row2entity(Some(ident), rev) } - pub fn get_creator_releases_handler(&self, id: &str) -> Result<Vec<ReleaseEntity>> { - let conn = self.db_pool.get().expect("db_pool error"); + pub fn get_creator_releases_handler(&self, id: &str, conn: &DbConn) -> Result<Vec<ReleaseEntity>> { + let id = fcid2uuid(id)?; // TODO: some kind of unique or group-by? @@ -358,52 +355,51 @@ impl Server { .filter(release_contrib::creator_ident_id.eq(&id)) .filter(release_ident::is_live.eq(true)) .filter(release_ident::redirect_id.is_null()) - .load(&conn)?; + .load(conn)?; rows.into_iter() - .map(|(rev, ident, _)| release_row2entity(Some(ident), rev, &conn)) + .map(|(rev, ident, _)| release_row2entity(Some(ident), rev, conn)) .collect() } - pub fn get_file_handler(&self, id: &str) -> Result<FileEntity> { - let conn = self.db_pool.get().expect("db_pool error"); + pub fn get_file_handler(&self, id: &str, conn: &DbConn) -> Result<FileEntity> { + let id = fcid2uuid(id)?; let (ident, rev): (FileIdentRow, FileRevRow) = file_ident::table .find(id) .inner_join(file_rev::table) - .first(&conn)?; + .first(conn)?; - file_row2entity(Some(ident), rev, &conn) + file_row2entity(Some(ident), rev, conn) } - pub fn lookup_file_handler(&self, sha1: &str) -> Result<FileEntity> { - let conn = self.db_pool.get().expect("db_pool error"); + pub fn lookup_file_handler(&self, sha1: &str, conn: &DbConn) -> Result<FileEntity> { + let (ident, rev): (FileIdentRow, FileRevRow) = file_ident::table .inner_join(file_rev::table) .filter(file_rev::sha1.eq(sha1)) .filter(file_ident::is_live.eq(true)) .filter(file_ident::redirect_id.is_null()) - .first(&conn)?; + .first(conn)?; - file_row2entity(Some(ident), rev, &conn) + file_row2entity(Some(ident), rev, conn) } - pub fn get_release_handler(&self, id: &str) -> Result<ReleaseEntity> { - let conn = self.db_pool.get().expect("db_pool error"); + pub fn get_release_handler(&self, id: &str, conn: &DbConn) -> Result<ReleaseEntity> { + let id = fcid2uuid(id)?; let (ident, rev): (ReleaseIdentRow, ReleaseRevRow) = release_ident::table .find(id) .inner_join(release_rev::table) - .first(&conn)?; + .first(conn)?; - release_row2entity(Some(ident), rev, &conn) + release_row2entity(Some(ident), rev, conn) } - pub fn lookup_release_handler(&self, doi: &str) -> Result<ReleaseEntity> { - let conn = self.db_pool.get().expect("db_pool error"); + pub fn lookup_release_handler(&self, doi: &str, conn: &DbConn) -> Result<ReleaseEntity> { check_doi(doi)?; let (ident, rev): (ReleaseIdentRow, ReleaseRevRow) = release_ident::table @@ -411,13 +407,13 @@ impl Server { .filter(release_rev::doi.eq(doi)) .filter(release_ident::is_live.eq(true)) .filter(release_ident::redirect_id.is_null()) - .first(&conn)?; + .first(conn)?; - release_row2entity(Some(ident), rev, &conn) + release_row2entity(Some(ident), rev, conn) } - pub fn get_release_files_handler(&self, id: &str) -> Result<Vec<FileEntity>> { - let conn = self.db_pool.get().expect("db_pool error"); + pub fn get_release_files_handler(&self, id: &str, conn: &DbConn) -> Result<Vec<FileEntity>> { + let id = fcid2uuid(id)?; let rows: Vec<(FileRevRow, FileIdentRow, FileReleaseRow)> = file_rev::table @@ -426,27 +422,27 @@ impl Server { .filter(file_release::target_release_ident_id.eq(&id)) .filter(file_ident::is_live.eq(true)) .filter(file_ident::redirect_id.is_null()) - .load(&conn)?; + .load(conn)?; rows.into_iter() - .map(|(rev, ident, _)| file_row2entity(Some(ident), rev, &conn)) + .map(|(rev, ident, _)| file_row2entity(Some(ident), rev, conn)) .collect() } - pub fn get_work_handler(&self, id: &str) -> Result<WorkEntity> { - let conn = self.db_pool.get().expect("db_pool error"); + pub fn get_work_handler(&self, id: &str, conn: &DbConn) -> Result<WorkEntity> { + let id = fcid2uuid(id)?; let (ident, rev): (WorkIdentRow, WorkRevRow) = work_ident::table .find(id) .inner_join(work_rev::table) - .first(&conn)?; + .first(conn)?; work_row2entity(Some(ident), rev) } - pub fn get_work_releases_handler(&self, id: &str) -> Result<Vec<ReleaseEntity>> { - let conn = self.db_pool.get().expect("db_pool error"); + pub fn get_work_releases_handler(&self, id: &str, conn: &DbConn) -> Result<Vec<ReleaseEntity>> { + let id = fcid2uuid(id)?; let rows: Vec<(ReleaseRevRow, ReleaseIdentRow)> = release_rev::table @@ -454,31 +450,21 @@ impl Server { .filter(release_rev::work_ident_id.eq(&id)) .filter(release_ident::is_live.eq(true)) .filter(release_ident::redirect_id.is_null()) - .load(&conn)?; + .load(conn)?; rows.into_iter() - .map(|(rev, ident)| release_row2entity(Some(ident), rev, &conn)) + .map(|(rev, ident)| release_row2entity(Some(ident), rev, conn)) .collect() } pub fn create_container_handler( &self, entity: models::ContainerEntity, - conn: Option<&DbConn>, + conn: &DbConn, ) -> Result<EntityEdit> { - // TODO: still can't cast for some reason - // There mut be a cleaner way to manage the lifetime here - let real_conn = match conn { - Some(_) => None, - None => Some(self.db_pool.get().expect("database pool")), - }; - let conn = match real_conn { - Some(ref c) => c, - None => conn.unwrap(), - }; let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth let editgroup_id: Uuid = match entity.editgroup_id { - None => get_or_create_editgroup(editor_id, &conn)?, + None => get_or_create_editgroup(editor_id, conn)?, Some(param) => fcid2uuid(¶m)?, }; if let Some(ref extid) = entity.wikidata_qid { @@ -514,20 +500,11 @@ impl Server { pub fn create_creator_handler( &self, entity: models::CreatorEntity, - conn: Option<&DbConn>, + conn: &DbConn, ) -> Result<EntityEdit> { - // There mut be a cleaner way to manage the lifetime here - let real_conn = match conn { - Some(_) => None, - None => Some(self.db_pool.get().expect("database pool")), - }; - let conn = match real_conn { - Some(ref c) => c, - None => conn.unwrap(), - }; let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth let editgroup_id = match entity.editgroup_id { - None => get_or_create_editgroup(editor_id, &conn).expect("current editgroup"), + None => get_or_create_editgroup(editor_id, conn).expect("current editgroup"), Some(param) => fcid2uuid(¶m)?, }; if let Some(ref extid) = entity.orcid { @@ -562,20 +539,11 @@ impl Server { pub fn create_file_handler( &self, entity: models::FileEntity, - conn: Option<&DbConn>, + conn: &DbConn, ) -> Result<EntityEdit> { - // There mut be a cleaner way to manage the lifetime here - let real_conn = match conn { - Some(_) => None, - None => Some(self.db_pool.get().expect("database pool")), - }; - let conn = match real_conn { - Some(ref c) => c, - None => conn.unwrap(), - }; let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth let editgroup_id = match entity.editgroup_id { - None => get_or_create_editgroup(editor_id, &conn).expect("current editgroup"), + None => get_or_create_editgroup(editor_id, conn).expect("current editgroup"), Some(param) => fcid2uuid(¶m)?, }; @@ -651,20 +619,11 @@ impl Server { pub fn create_release_handler( &self, entity: models::ReleaseEntity, - conn: Option<&DbConn>, + conn: &DbConn, ) -> Result<EntityEdit> { - // There mut be a cleaner way to manage the lifetime here - let real_conn = match conn { - Some(_) => None, - None => Some(self.db_pool.get().expect("database pool")), - }; - let conn = match real_conn { - Some(ref c) => c, - None => conn.unwrap(), - }; let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth let editgroup_id = match entity.editgroup_id { - None => get_or_create_editgroup(editor_id, &conn).expect("current editgroup"), + None => get_or_create_editgroup(editor_id, conn).expect("current editgroup"), Some(param) => fcid2uuid(¶m)?, }; if let Some(ref extid) = entity.doi { @@ -692,7 +651,7 @@ impl Server { editgroup_id: Some(uuid2fcid(&editgroup_id)), extra: None, }; - let new_entity = self.create_work_handler(work_model, Some(&conn))?; + let new_entity = self.create_work_handler(work_model, conn)?; fcid2uuid(&new_entity.ident)? } }; @@ -835,21 +794,12 @@ impl Server { pub fn create_work_handler( &self, entity: models::WorkEntity, - conn: Option<&DbConn>, + conn: &DbConn, ) -> Result<EntityEdit> { - // There mut be a cleaner way to manage the lifetime here - let real_conn = match conn { - Some(_) => None, - None => Some(self.db_pool.get().expect("database pool")), - }; - let conn = match real_conn { - Some(ref c) => c, - None => conn.unwrap(), - }; let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth let editgroup_id = match entity.editgroup_id { - None => get_or_create_editgroup(editor_id, &conn).expect("current editgroup"), + None => get_or_create_editgroup(editor_id, conn).expect("current editgroup"), Some(param) => fcid2uuid(¶m)?, }; @@ -871,22 +821,19 @@ impl Server { edit.into_model() } - pub fn accept_editgroup_handler(&self, id: &str) -> Result<()> { - let conn = self.db_pool.get().expect("db_pool error"); - accept_editgroup(fcid2uuid(id)?, &conn)?; + pub fn accept_editgroup_handler(&self, id: &str, conn: &DbConn) -> Result<()> { + accept_editgroup(fcid2uuid(id)?, conn)?; Ok(()) } - pub fn create_editgroup_handler(&self, entity: models::Editgroup) -> Result<Editgroup> { - let conn = self.db_pool.get().expect("db_pool error"); - + pub fn create_editgroup_handler(&self, entity: models::Editgroup, conn: &DbConn) -> Result<Editgroup> { let row: EditgroupRow = insert_into(editgroup::table) .values(( editgroup::editor_id.eq(fcid2uuid(&entity.editor_id)?), editgroup::description.eq(entity.description), editgroup::extra_json.eq(entity.extra), )) - .get_result(&conn) + .get_result(conn) .expect("error creating edit group"); Ok(Editgroup { @@ -898,17 +845,7 @@ impl Server { }) } - pub fn get_editgroup_handler(&self, id: &str, conn: Option<&DbConn>) -> Result<Editgroup> { - // TODO: still can't cast for some reason - // There mut be a cleaner way to manage the lifetime here - let real_conn = match conn { - Some(_) => None, - None => Some(self.db_pool.get().expect("database pool")), - }; - let conn = match real_conn { - Some(ref c) => c, - None => conn.unwrap(), - }; + pub fn get_editgroup_handler(&self, id: &str, conn: &DbConn) -> Result<Editgroup> { let id = fcid2uuid(id)?; let row: EditgroupRow = editgroup::table.find(id).first(conn)?; @@ -966,11 +903,10 @@ impl Server { Ok(eg) } - pub fn get_editor_handler(&self, id: &str) -> Result<Editor> { - let conn = self.db_pool.get().expect("db_pool error"); + pub fn get_editor_handler(&self, id: &str, conn: &DbConn) -> Result<Editor> { let id = fcid2uuid(id)?; - let row: EditorRow = editor::table.find(id).first(&conn)?; + let row: EditorRow = editor::table.find(id).first(conn)?; let ed = Editor { id: Some(uuid2fcid(&row.id)), @@ -979,16 +915,15 @@ impl Server { Ok(ed) } - pub fn editor_changelog_get_handler(&self, id: &str) -> Result<Vec<ChangelogEntry>> { - let conn = self.db_pool.get().expect("db_pool error"); + pub fn editor_changelog_get_handler(&self, id: &str, conn: &DbConn) -> Result<Vec<ChangelogEntry>> { let id = fcid2uuid(id)?; // TODO: single query - let editor: EditorRow = editor::table.find(id).first(&conn)?; + let editor: EditorRow = editor::table.find(id).first(conn)?; let changes: Vec<(ChangelogRow, EditgroupRow)> = changelog::table .inner_join(editgroup::table) .filter(editgroup::editor_id.eq(editor.id)) - .load(&conn)?; + .load(conn)?; let entries = changes .into_iter() @@ -1002,15 +937,15 @@ impl Server { Ok(entries) } - pub fn get_changelog_handler(&self, limit: Option<i64>) -> Result<Vec<ChangelogEntry>> { - let conn = self.db_pool.get().expect("db_pool error"); + pub fn get_changelog_handler(&self, limit: Option<i64>, conn: &DbConn) -> Result<Vec<ChangelogEntry>> { + let limit = limit.unwrap_or(50); let changes: Vec<(ChangelogRow, EditgroupRow)> = changelog::table .inner_join(editgroup::table) .order(changelog::id.desc()) .limit(limit) - .load(&conn)?; + .load(conn)?; let entries = changes .into_iter() @@ -1024,44 +959,42 @@ impl Server { Ok(entries) } - pub fn get_changelog_entry_handler(&self, id: i64) -> Result<ChangelogEntry> { - let conn = self.db_pool.get().expect("db_pool error"); + pub fn get_changelog_entry_handler(&self, id: i64, conn: &DbConn) -> Result<ChangelogEntry> { - let cl_row: ChangelogRow = changelog::table.find(id).first(&conn)?; - let editgroup = self.get_editgroup_handler(&uuid2fcid(&cl_row.editgroup_id), Some(&conn))?; + let cl_row: ChangelogRow = changelog::table.find(id).first(conn)?; + let editgroup = self.get_editgroup_handler(&uuid2fcid(&cl_row.editgroup_id), conn)?; let mut entry = cl_row.into_model(); entry.editgroup = Some(editgroup); Ok(entry) } - pub fn get_stats_handler(&self, more: &Option<String>) -> Result<StatsResponse> { - let conn = self.db_pool.get().expect("db_pool error"); + pub fn get_stats_handler(&self, more: &Option<String>, conn: &DbConn) -> Result<StatsResponse> { let merged_editgroups: i64 = changelog::table .select(diesel::dsl::count_star()) - .first(&conn)?; + .first(conn)?; let releases_with_dois: i64 = release_rev::table .inner_join(release_ident::table) .filter(release_rev::doi.is_not_null()) .filter(release_ident::is_live.eq(true)) .filter(release_ident::redirect_id.is_null()) .select(diesel::dsl::count_star()) - .first(&conn)?; + .first(conn)?; let creators_with_orcids: i64 = creator_rev::table .inner_join(creator_ident::table) .filter(creator_rev::orcid.is_not_null()) .filter(creator_ident::is_live.eq(true)) .filter(creator_ident::redirect_id.is_null()) .select(diesel::dsl::count_star()) - .first(&conn)?; + .first(conn)?; let containers_with_issnls: i64 = container_rev::table .inner_join(container_ident::table) .filter(container_rev::issnl.is_not_null()) .filter(container_ident::is_live.eq(true)) .filter(container_ident::redirect_id.is_null()) .count() - .first(&conn)?; + .first(conn)?; let files_with_releases: Option<i64> = if more.is_some() { // this query is slightly inaccurate and over-counts: it includes files that have release @@ -1074,7 +1007,7 @@ impl Server { .select(file_ident::id) .distinct() .count() - .first(&conn)?) + .first(conn)?) } else { None }; @@ -1088,18 +1021,18 @@ impl Server { .select(file_release::target_release_ident_id) .distinct() .count() - .first(&conn)?) + .first(conn)?) } else { None }; let val = json!({ "entity_counts": { - "container": count_entity!(container_ident, &conn), - "creator": count_entity!(creator_ident, &conn), - "file": count_entity!(file_ident, &conn), - "release": count_entity!(release_ident, &conn), - "work": count_entity!(work_ident, &conn), + "container": count_entity!(container_ident, conn), + "creator": count_entity!(creator_ident, conn), + "file": count_entity!(file_ident, conn), + "release": count_entity!(release_ident, conn), + "work": count_entity!(work_ident, conn), }, "merged_editgroups": merged_editgroups, "releases_with_dois": releases_with_dois, diff --git a/rust/src/api_wrappers.rs b/rust/src/api_wrappers.rs index df066694..e0112149 100644 --- a/rust/src/api_wrappers.rs +++ b/rust/src/api_wrappers.rs @@ -6,6 +6,7 @@ use fatcat_api::models; use fatcat_api::models::*; use fatcat_api::*; use futures::{self, Future}; +use diesel::Connection; /// Helper for generating wrappers (which return "Box::new(futures::done(Ok(BLAH)))" like the /// codegen fatcat-api code wants) that call through to actual helpers (which have simple Result<> @@ -25,7 +26,9 @@ macro_rules! wrap_entity_handlers { id: String, _context: &Context, ) -> Box<Future<Item = $get_resp, Error = ApiError> + Send> { - let ret = match self.$get_handler(&id) { + let conn = self.db_pool.get().expect("db_pool error"); + // No transaction for GET + let ret = match self.$get_handler(&id, &conn) { Ok(entity) => $get_resp::FoundEntity(entity), Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => @@ -50,7 +53,8 @@ macro_rules! wrap_entity_handlers { entity: models::$model, _context: &Context, ) -> Box<Future<Item = $post_resp, Error = ApiError> + Send> { - let ret = match self.$post_handler(entity, None) { + let conn = self.db_pool.get().expect("db_pool error"); + let ret = match conn.transaction(|| self.$post_handler(entity, &conn)) { Ok(edit) => $post_resp::CreatedEntity(edit), Err(Error(ErrorKind::Diesel(e), _)) => @@ -75,7 +79,8 @@ macro_rules! wrap_entity_handlers { entity_list: &Vec<models::$model>, _context: &Context, ) -> Box<Future<Item = $post_batch_resp, Error = ApiError> + Send> { - let ret = match self.$post_batch_handler(entity_list) { + let conn = self.db_pool.get().expect("db_pool error"); + let ret = match conn.transaction(|| self.$post_batch_handler(entity_list, &conn)) { Ok(edit) => $post_batch_resp::CreatedEntities(edit), Err(Error(ErrorKind::Diesel(e), _)) => @@ -101,7 +106,9 @@ macro_rules! wrap_entity_handlers { limit: Option<i64>, _context: &Context, ) -> Box<Future<Item = $get_history_resp, Error = ApiError> + Send> { - let ret = match self.$get_history_handler(&id, limit) { + let conn = self.db_pool.get().expect("db_pool error"); + // No transaction for GET + let ret = match self.$get_history_handler(&id, limit, &conn) { Ok(history) => $get_history_resp::FoundEntityHistory(history), Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => @@ -128,7 +135,9 @@ macro_rules! wrap_lookup_handler { $idname: $idtype, _context: &Context, ) -> Box<Future<Item = $get_resp, Error = ApiError> + Send> { - let ret = match self.$get_handler(&$idname) { + let conn = self.db_pool.get().expect("db_pool error"); + // No transaction for GET + let ret = match self.$get_handler(&$idname, &conn) { Ok(entity) => $get_resp::FoundEntity(entity), Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => @@ -279,7 +288,8 @@ impl Api for Server { id: String, _context: &Context, ) -> Box<Future<Item = AcceptEditgroupResponse, Error = ApiError> + Send> { - let ret = match self.accept_editgroup_handler(&id) { + let conn = self.db_pool.get().expect("db_pool error"); + let ret = match conn.transaction(|| self.accept_editgroup_handler(&id, &conn)) { Ok(()) => AcceptEditgroupResponse::MergedSuccessfully(Success { message: "horray!".to_string(), }), @@ -300,7 +310,8 @@ impl Api for Server { id: String, _context: &Context, ) -> Box<Future<Item = GetEditgroupResponse, Error = ApiError> + Send> { - let ret = match self.get_editgroup_handler(&id, None) { + let conn = self.db_pool.get().expect("db_pool error"); + let ret = match conn.transaction(|| self.get_editgroup_handler(&id, &conn)) { Ok(entity) => GetEditgroupResponse::FoundEntity(entity), Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => @@ -319,7 +330,8 @@ impl Api for Server { entity: models::Editgroup, _context: &Context, ) -> Box<Future<Item = CreateEditgroupResponse, Error = ApiError> + Send> { - let ret = match self.create_editgroup_handler(entity) { + let conn = self.db_pool.get().expect("db_pool error"); + let ret = match conn.transaction(|| self.create_editgroup_handler(entity, &conn)) { Ok(eg) => CreateEditgroupResponse::SuccessfullyCreated(eg), Err(e) => @@ -335,7 +347,9 @@ impl Api for Server { username: String, _context: &Context, ) -> Box<Future<Item = GetEditorChangelogResponse, Error = ApiError> + Send> { - let ret = match self.editor_changelog_get_handler(&username) { + let conn = self.db_pool.get().expect("db_pool error"); + // No transaction for GET + let ret = match self.editor_changelog_get_handler(&username, &conn) { Ok(entries) => GetEditorChangelogResponse::FoundMergedChanges(entries), Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => { GetEditorChangelogResponse::NotFound(ErrorResponse { @@ -358,7 +372,9 @@ impl Api for Server { username: String, _context: &Context, ) -> Box<Future<Item = GetEditorResponse, Error = ApiError> + Send> { - let ret = match self.get_editor_handler(&username) { + let conn = self.db_pool.get().expect("db_pool error"); + // No transaction for GET + let ret = match self.get_editor_handler(&username, &conn) { Ok(entity) => GetEditorResponse::FoundEditor(entity), Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => { GetEditorResponse::NotFound(ErrorResponse { @@ -381,7 +397,9 @@ impl Api for Server { limit: Option<i64>, _context: &Context, ) -> Box<Future<Item = GetChangelogResponse, Error = ApiError> + Send> { - let ret = match self.get_changelog_handler(limit) { + let conn = self.db_pool.get().expect("db_pool error"); + // No transaction for GET + let ret = match self.get_changelog_handler(limit, &conn) { Ok(changelog) => GetChangelogResponse::Success(changelog), Err(e) => { error!("{}", e); @@ -398,7 +416,9 @@ impl Api for Server { id: i64, _context: &Context, ) -> Box<Future<Item = GetChangelogEntryResponse, Error = ApiError> + Send> { - let ret = match self.get_changelog_entry_handler(id) { + let conn = self.db_pool.get().expect("db_pool error"); + // No transaction for GET + let ret = match self.get_changelog_entry_handler(id, &conn) { Ok(entry) => GetChangelogEntryResponse::FoundChangelogEntry(entry), Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => { GetChangelogEntryResponse::NotFound(ErrorResponse { @@ -420,7 +440,9 @@ impl Api for Server { more: Option<String>, _context: &Context, ) -> Box<Future<Item = GetStatsResponse, Error = ApiError> + Send> { - let ret = match self.get_stats_handler(&more) { + let conn = self.db_pool.get().expect("db_pool error"); + // No transaction for GET + let ret = match self.get_stats_handler(&more, &conn) { Ok(stats) => GetStatsResponse::Success(stats), Err(e) => { error!("{}", e); |