aboutsummaryrefslogtreecommitdiffstats
path: root/rust/src
diff options
context:
space:
mode:
Diffstat (limited to 'rust/src')
-rw-r--r--rust/src/api_entity_crud.rs (renamed from rust/src/database_entity_crud.rs)92
-rw-r--r--rust/src/api_helpers.rs58
-rw-r--r--rust/src/api_server.rs309
-rw-r--r--rust/src/api_wrappers.rs206
-rw-r--r--rust/src/lib.rs2
5 files changed, 204 insertions, 463 deletions
diff --git a/rust/src/database_entity_crud.rs b/rust/src/api_entity_crud.rs
index 8b29ff28..2d5ea93d 100644
--- a/rust/src/database_entity_crud.rs
+++ b/rust/src/api_entity_crud.rs
@@ -6,19 +6,11 @@ use diesel::prelude::*;
use diesel::{self, insert_into};
use errors::*;
use fatcat_api::models::*;
-use serde_json;
use sha1::Sha1;
use std::marker::Sized;
use std::str::FromStr;
use uuid::Uuid;
-pub struct EditContext {
- pub editor_id: FatCatId,
- pub editgroup_id: FatCatId,
- pub extra_json: Option<serde_json::Value>,
- pub autoaccept: bool,
-}
-
/* One goal here is to abstract the non-entity-specific bits into generic traits or functions,
* instead of macros.
*
@@ -51,19 +43,9 @@ where
fn parse_editgroup_id(&self) -> Result<Option<FatCatId>>;
// Generic Methods
- 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_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,
@@ -85,10 +67,7 @@ where
ident: FatCatId,
limit: Option<i64>,
) -> Result<Vec<EntityHistoryEntry>>;
- fn db_accept_edits(
- conn: &DbConn,
- editgroup_id: FatCatId
- ) -> Result<u64>;
+ fn db_accept_edits(conn: &DbConn, editgroup_id: FatCatId) -> Result<u64>;
// Entity-specific Methods
fn db_from_row(
@@ -96,14 +75,8 @@ where
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>>;
+ fn db_insert_rev(&self, conn: &DbConn) -> Result<Uuid>;
+ fn db_insert_revs(conn: &DbConn, models: &[&Self]) -> Result<Vec<Uuid>>;
}
// TODO: this could be a separate trait on all entities
@@ -333,13 +306,10 @@ macro_rules! generic_db_get_history {
// UPDATE FROM version: single query for many rows
// Works with Postgres, not Cockroach
+#[allow(unused_macros)]
macro_rules! generic_db_accept_edits_batch {
($entity_name_str:expr) => {
- fn db_accept_edits(
- conn: &DbConn,
- editgroup_id: FatCatId,
- ) -> Result<u64> {
-
+ fn db_accept_edits(conn: &DbConn, editgroup_id: FatCatId) -> Result<u64> {
let count = diesel::sql_query(format!(
"
UPDATE {entity}_ident
@@ -351,23 +321,20 @@ macro_rules! generic_db_accept_edits_batch {
WHERE
{entity}_ident.id = {entity}_edit.ident_id
AND {entity}_edit.editgroup_id = $1",
- entity = $entity_name_str
+ entity = $entity_name_str
)).bind::<diesel::sql_types::Uuid, _>(editgroup_id.to_uuid())
.execute(conn)?;
Ok(count as u64)
}
- }
+ };
}
// UPDATE ROW version: single query per row
// CockroachDB version (slow, single query per row)
+#[allow(unused_macros)]
macro_rules! generic_db_accept_edits_each {
($ident_table:ident, $edit_table:ident) => {
- fn db_accept_edits(
- conn: &DbConn,
- editgroup_id: FatCatId,
- ) -> Result<u64> {
-
+ fn db_accept_edits(conn: &DbConn, editgroup_id: FatCatId) -> Result<u64> {
// 1. select edit rows (in sql)
let edit_rows: Vec<Self::EditRow> = $edit_table::table
.filter($edit_table::editgroup_id.eq(&editgroup_id.to_uuid()))
@@ -375,31 +342,26 @@ macro_rules! generic_db_accept_edits_each {
// 2. create ident rows (in rust)
let ident_rows: Vec<Self::IdentRow> = edit_rows
.iter()
- .map(|edit|
- Self::IdentRow {
- id: edit.ident_id,
- is_live: true,
- rev_id: edit.rev_id,
- redirect_id: edit.redirect_id,
-
- }
- )
+ .map(|edit| Self::IdentRow {
+ id: edit.ident_id,
+ is_live: true,
+ rev_id: edit.rev_id,
+ redirect_id: edit.redirect_id,
+ })
.collect();
/*
- // 3. upsert ident rows (in sql)
- let count: u64 = diesel::insert_into($ident_table::table)
- .values(ident_rows)
- .on_conflict()
- .do_update()
- .set(ident_rows)
- .execute(conn)?;
- */
+ // 3. upsert ident rows (in sql)
+ let count: u64 = diesel::insert_into($ident_table::table)
+ .values(ident_rows)
+ .on_conflict()
+ .do_update()
+ .set(ident_rows)
+ .execute(conn)?;
+ */
// 3. update every row individually
let count = ident_rows.len() as u64;
for row in ident_rows {
- diesel::update(&row)
- .set(&row)
- .execute(conn)?;
+ diesel::update(&row).set(&row).execute(conn)?;
}
Ok(count)
}
diff --git a/rust/src/api_helpers.rs b/rust/src/api_helpers.rs
index 8ab9dcb3..6c214223 100644
--- a/rust/src/api_helpers.rs
+++ b/rust/src/api_helpers.rs
@@ -1,18 +1,51 @@
+use api_entity_crud::EntityCrud;
use data_encoding::BASE32_NOPAD;
use database_models::*;
use database_schema::*;
-use fatcat_api::models::*;
use diesel;
use diesel::prelude::*;
use errors::*;
+use fatcat_api::models::*;
use regex::Regex;
+use serde_json;
use std::str::FromStr;
use uuid::Uuid;
-use database_entity_crud::EntityCrud;
pub type DbConn =
diesel::r2d2::PooledConnection<diesel::r2d2::ConnectionManager<diesel::PgConnection>>;
+pub struct EditContext {
+ pub editor_id: FatCatId,
+ pub editgroup_id: FatCatId,
+ pub extra_json: Option<serde_json::Value>,
+ pub autoaccept: bool,
+}
+
+pub fn make_edit_context(
+ conn: &DbConn,
+ editgroup_id: Option<FatCatId>,
+ autoaccept: bool,
+) -> Result<EditContext> {
+ let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth
+ let editgroup_id: FatCatId = match (editgroup_id, autoaccept) {
+ (Some(eg), _) => eg,
+ // If autoaccept and no editgroup_id passed, always create a new one for this transaction
+ (None, true) => {
+ let eg_row: EditgroupRow = diesel::insert_into(editgroup::table)
+ .values((editgroup::editor_id.eq(editor_id),))
+ .get_result(conn)?;
+ FatCatId::from_uuid(&eg_row.id)
+ }
+ (None, false) => FatCatId::from_uuid(&get_or_create_editgroup(editor_id, conn)?),
+ };
+ Ok(EditContext {
+ editor_id: FatCatId::from_uuid(&editor_id),
+ editgroup_id: editgroup_id,
+ extra_json: None,
+ autoaccept: autoaccept,
+ })
+}
+
/// This function should always be run within a transaction
pub fn get_or_create_editgroup(editor_id: Uuid, conn: &DbConn) -> Result<Uuid> {
// check for current active
@@ -32,34 +65,33 @@ pub fn get_or_create_editgroup(editor_id: Uuid, conn: &DbConn) -> Result<Uuid> {
}
/// This function should always be run within a transaction
-pub fn accept_editgroup(editgroup_id: Uuid, conn: &DbConn) -> Result<ChangelogRow> {
+pub fn accept_editgroup(editgroup_id: FatCatId, conn: &DbConn) -> Result<ChangelogRow> {
// 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))
+ .filter(changelog::editgroup_id.eq(editgroup_id.to_uuid()))
.count()
.get_result(conn)?;
if count > 0 {
- return Err(ErrorKind::EditgroupAlreadyAccepted(uuid2fcid(&editgroup_id)).into());
+ return Err(ErrorKind::EditgroupAlreadyAccepted(editgroup_id.to_string()).into());
}
// copy edit columns to ident table
- let eg_id = FatCatId::from_uuid(&editgroup_id);
- ContainerEntity::db_accept_edits(conn, eg_id)?;
- CreatorEntity::db_accept_edits(conn, eg_id)?;
- FileEntity::db_accept_edits(conn, eg_id)?;
- ReleaseEntity::db_accept_edits(conn, eg_id)?;
- WorkEntity::db_accept_edits(conn, eg_id)?;
+ ContainerEntity::db_accept_edits(conn, editgroup_id)?;
+ CreatorEntity::db_accept_edits(conn, editgroup_id)?;
+ FileEntity::db_accept_edits(conn, editgroup_id)?;
+ ReleaseEntity::db_accept_edits(conn, editgroup_id)?;
+ WorkEntity::db_accept_edits(conn, editgroup_id)?;
// append log/changelog row
let entry: ChangelogRow = diesel::insert_into(changelog::table)
- .values((changelog::editgroup_id.eq(editgroup_id),))
+ .values((changelog::editgroup_id.eq(editgroup_id.to_uuid()),))
.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))
+ .filter(editor::active_editgroup_id.eq(editgroup_id.to_uuid()))
.set(editor::active_editgroup_id.eq(no_active))
.execute(conn)?;
Ok(entry)
diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs
index 5fce8e64..076bc085 100644
--- a/rust/src/api_server.rs
+++ b/rust/src/api_server.rs
@@ -1,8 +1,8 @@
//! API endpoint handlers
+use api_entity_crud::EntityCrud;
use api_helpers::*;
use chrono;
-use database_entity_crud::{EditContext, EntityCrud};
use database_models::*;
use database_schema::*;
use diesel::prelude::*;
@@ -11,7 +11,6 @@ use errors::*;
use fatcat_api::models;
use fatcat_api::models::*;
use std::str::FromStr;
-use uuid::Uuid;
use ConnectionPool;
macro_rules! entity_batch_handler {
@@ -53,27 +52,6 @@ macro_rules! count_entity {
}};
}
-fn make_edit_context(conn: &DbConn, editgroup_id: Option<FatCatId>, autoaccept: bool) -> Result<EditContext> {
- let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth
- let editgroup_id: FatCatId = match (editgroup_id, autoaccept) {
- (Some(eg), _) => eg,
- // If autoaccept and no editgroup_id passed, always create a new one for this transaction
- (None, true) => {
- let eg_row: EditgroupRow = diesel::insert_into(editgroup::table)
- .values((editgroup::editor_id.eq(editor_id),))
- .get_result(conn)?;
- FatCatId::from_uuid(&eg_row.id)
- },
- (None, false) => FatCatId::from_uuid(&get_or_create_editgroup(editor_id, conn)?),
- };
- Ok(EditContext {
- editor_id: FatCatId::from_uuid(&editor_id),
- editgroup_id: editgroup_id,
- extra_json: None,
- autoaccept: autoaccept,
- })
-}
-
#[derive(Clone)]
pub struct Server {
pub db_pool: ConnectionPool,
@@ -82,11 +60,11 @@ pub struct Server {
impl Server {
pub fn get_container_handler(
&self,
- id: &Uuid,
+ id: FatCatId,
_expand: Option<String>,
conn: &DbConn,
) -> Result<ContainerEntity> {
- ContainerEntity::db_get(conn, FatCatId::from_uuid(id))
+ ContainerEntity::db_get(conn, id)
}
pub fn lookup_container_handler(&self, issnl: &str, conn: &DbConn) -> Result<ContainerEntity> {
@@ -106,11 +84,11 @@ impl Server {
pub fn get_creator_handler(
&self,
- id: &Uuid,
+ id: FatCatId,
_expand: Option<String>,
conn: &DbConn,
) -> Result<CreatorEntity> {
- CreatorEntity::db_get(conn, FatCatId::from_uuid(id))
+ CreatorEntity::db_get(conn, id)
}
pub fn lookup_creator_handler(&self, orcid: &str, conn: &DbConn) -> Result<CreatorEntity> {
@@ -130,16 +108,14 @@ impl Server {
pub fn get_creator_releases_handler(
&self,
- id: &str,
+ id: FatCatId,
conn: &DbConn,
) -> Result<Vec<ReleaseEntity>> {
- let id = fcid2uuid(&id)?;
-
// TODO: some kind of unique or group-by?
let rows: Vec<(ReleaseRevRow, ReleaseIdentRow, ReleaseContribRow)> = release_rev::table
.inner_join(release_ident::table)
.inner_join(release_contrib::table)
- .filter(release_contrib::creator_ident_id.eq(&id))
+ .filter(release_contrib::creator_ident_id.eq(&id.to_uuid()))
.filter(release_ident::is_live.eq(true))
.filter(release_ident::redirect_id.is_null())
.load(conn)?;
@@ -152,11 +128,11 @@ impl Server {
pub fn get_file_handler(
&self,
- id: &Uuid,
+ id: FatCatId,
_expand: Option<String>,
conn: &DbConn,
) -> Result<FileEntity> {
- FileEntity::db_get(conn, FatCatId::from_uuid(id))
+ FileEntity::db_get(conn, id)
}
pub fn lookup_file_handler(&self, sha1: &str, conn: &DbConn) -> Result<FileEntity> {
@@ -175,19 +151,18 @@ impl Server {
pub fn get_release_handler(
&self,
- id: &Uuid,
+ id: FatCatId,
expand: Option<String>,
conn: &DbConn,
) -> Result<ReleaseEntity> {
- let mut release = ReleaseEntity::db_get(conn, FatCatId::from_uuid(id))?;
+ let mut release = ReleaseEntity::db_get(conn, id)?;
// For now, if there is any expand param we do them all
if expand.is_some() {
- release.files =
- Some(self.get_release_files_handler(&release.ident.clone().unwrap(), conn)?);
+ release.files = Some(self.get_release_files_handler(id, conn)?);
if let Some(ref cid) = release.container_id {
release.container =
- Some(self.get_container_handler(&fcid2uuid(&cid)?, None, conn)?);
+ Some(self.get_container_handler(FatCatId::from_str(&cid)?, None, conn)?);
}
}
Ok(release)
@@ -208,13 +183,15 @@ impl Server {
ReleaseEntity::db_from_row(conn, rev, Some(ident))
}
- pub fn get_release_files_handler(&self, id: &str, conn: &DbConn) -> Result<Vec<FileEntity>> {
- let ident = FatCatId::from_str(id)?;
-
+ pub fn get_release_files_handler(
+ &self,
+ id: FatCatId,
+ conn: &DbConn,
+ ) -> Result<Vec<FileEntity>> {
let rows: Vec<(FileRevRow, FileIdentRow, FileReleaseRow)> = file_rev::table
.inner_join(file_ident::table)
.inner_join(file_release::table)
- .filter(file_release::target_release_ident_id.eq(&ident.to_uuid()))
+ .filter(file_release::target_release_ident_id.eq(&id.to_uuid()))
.filter(file_ident::is_live.eq(true))
.filter(file_ident::redirect_id.is_null())
.load(conn)?;
@@ -226,19 +203,21 @@ impl Server {
pub fn get_work_handler(
&self,
- id: &Uuid,
+ id: FatCatId,
_expand: Option<String>,
conn: &DbConn,
) -> Result<WorkEntity> {
- WorkEntity::db_get(conn, FatCatId::from_uuid(id))
+ WorkEntity::db_get(conn, id)
}
- pub fn get_work_releases_handler(&self, id: &str, conn: &DbConn) -> Result<Vec<ReleaseEntity>> {
- let id = fcid2uuid(&id)?;
-
+ pub fn get_work_releases_handler(
+ &self,
+ id: FatCatId,
+ conn: &DbConn,
+ ) -> Result<Vec<ReleaseEntity>> {
let rows: Vec<(ReleaseRevRow, ReleaseIdentRow)> = release_rev::table
.inner_join(release_ident::table)
- .filter(release_rev::work_ident_id.eq(&id))
+ .filter(release_rev::work_ident_id.eq(&id.to_uuid()))
.filter(release_ident::is_live.eq(true))
.filter(release_ident::redirect_id.is_null())
.load(conn)?;
@@ -248,165 +227,8 @@ impl Server {
.collect()
}
- pub fn create_container_handler(
- &self,
- entity: models::ContainerEntity,
- conn: &DbConn,
- ) -> Result<EntityEdit> {
- let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?, false)?;
- let edit = entity.db_create(conn, &edit_context)?;
- edit.into_model()
- }
-
- pub fn update_container_handler(
- &self,
- id: &Uuid,
- entity: models::ContainerEntity,
- conn: &DbConn,
- ) -> Result<EntityEdit> {
- let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?, false)?;
- 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> {
- let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)), false)?;
- let edit = ContainerEntity::db_delete(conn, &edit_context, FatCatId::from_uuid(id))?;
- edit.into_model()
- }
-
- pub fn create_creator_handler(
- &self,
- entity: models::CreatorEntity,
- conn: &DbConn,
- ) -> Result<EntityEdit> {
- let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?, false)?;
- let edit = entity.db_create(conn, &edit_context)?;
- edit.into_model()
- }
-
- pub fn update_creator_handler(
- &self,
- id: &Uuid,
- entity: models::CreatorEntity,
- conn: &DbConn,
- ) -> Result<EntityEdit> {
- let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?, false)?;
- 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> {
- let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)), false)?;
- let edit = CreatorEntity::db_delete(conn, &edit_context, FatCatId::from_uuid(id))?;
- edit.into_model()
- }
-
- pub fn create_file_handler(
- &self,
- entity: models::FileEntity,
- conn: &DbConn,
- ) -> Result<EntityEdit> {
- let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?, false)?;
- let edit = entity.db_create(conn, &edit_context)?;
- edit.into_model()
- }
-
- pub fn update_file_handler(
- &self,
- id: &Uuid,
- entity: models::FileEntity,
- conn: &DbConn,
- ) -> Result<EntityEdit> {
- let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?, false)?;
- 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> {
- let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)), false)?;
- let edit = FileEntity::db_delete(conn, &edit_context, FatCatId::from_uuid(id))?;
- edit.into_model()
- }
-
- pub fn create_release_handler(
- &self,
- entity: models::ReleaseEntity,
- conn: &DbConn,
- ) -> Result<EntityEdit> {
- let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?, false)?;
- let edit = entity.db_create(conn, &edit_context)?;
- edit.into_model()
- }
-
- pub fn update_release_handler(
- &self,
- id: &Uuid,
- entity: models::ReleaseEntity,
- conn: &DbConn,
- ) -> Result<EntityEdit> {
- let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?, false)?;
- 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> {
- let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)), false)?;
- let edit = ReleaseEntity::db_delete(conn, &edit_context, FatCatId::from_uuid(id))?;
- edit.into_model()
- }
-
- pub fn create_work_handler(
- &self,
- entity: models::WorkEntity,
- conn: &DbConn,
- ) -> Result<EntityEdit> {
- let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?, false)?;
- let edit = entity.db_create(conn, &edit_context)?;
- edit.into_model()
- }
-
- pub fn update_work_handler(
- &self,
- id: &Uuid,
- entity: models::WorkEntity,
- conn: &DbConn,
- ) -> Result<EntityEdit> {
- let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?, false)?;
- let edit = entity.db_update(conn, &edit_context, FatCatId::from_uuid(id))?;
- edit.into_model()
- }
-
- 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)), false)?;
- let edit = WorkEntity::db_delete(conn, &edit_context, FatCatId::from_uuid(id))?;
-
- edit.into_model()
- }
-
- pub fn accept_editgroup_handler(&self, id: &str, conn: &DbConn) -> Result<()> {
- accept_editgroup(fcid2uuid(id)?, conn)?;
+ pub fn accept_editgroup_handler(&self, id: FatCatId, conn: &DbConn) -> Result<()> {
+ accept_editgroup(id, conn)?;
Ok(())
}
@@ -417,7 +239,7 @@ impl Server {
) -> Result<Editgroup> {
let row: EditgroupRow = insert_into(editgroup::table)
.values((
- editgroup::editor_id.eq(fcid2uuid(&entity.editor_id)?),
+ editgroup::editor_id.eq(FatCatId::from_str(&entity.editor_id)?.to_uuid()),
editgroup::description.eq(entity.description),
editgroup::extra_json.eq(entity.extra),
))
@@ -432,14 +254,13 @@ impl Server {
})
}
- 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)?;
+ pub fn get_editgroup_handler(&self, id: FatCatId, conn: &DbConn) -> Result<Editgroup> {
+ let row: EditgroupRow = editgroup::table.find(id.to_uuid()).first(conn)?;
let edits = EditgroupEdits {
containers: Some(
container_edit::table
- .filter(container_edit::editgroup_id.eq(id))
+ .filter(container_edit::editgroup_id.eq(id.to_uuid()))
.get_results(conn)?
.into_iter()
.map(|e: ContainerEditRow| e.into_model().unwrap())
@@ -447,7 +268,7 @@ impl Server {
),
creators: Some(
creator_edit::table
- .filter(creator_edit::editgroup_id.eq(id))
+ .filter(creator_edit::editgroup_id.eq(id.to_uuid()))
.get_results(conn)?
.into_iter()
.map(|e: CreatorEditRow| e.into_model().unwrap())
@@ -455,7 +276,7 @@ impl Server {
),
files: Some(
file_edit::table
- .filter(file_edit::editgroup_id.eq(id))
+ .filter(file_edit::editgroup_id.eq(id.to_uuid()))
.get_results(conn)?
.into_iter()
.map(|e: FileEditRow| e.into_model().unwrap())
@@ -463,7 +284,7 @@ impl Server {
),
releases: Some(
release_edit::table
- .filter(release_edit::editgroup_id.eq(id))
+ .filter(release_edit::editgroup_id.eq(id.to_uuid()))
.get_results(conn)?
.into_iter()
.map(|e: ReleaseEditRow| e.into_model().unwrap())
@@ -471,7 +292,7 @@ impl Server {
),
works: Some(
work_edit::table
- .filter(work_edit::editgroup_id.eq(id))
+ .filter(work_edit::editgroup_id.eq(id.to_uuid()))
.get_results(conn)?
.into_iter()
.map(|e: WorkEditRow| e.into_model().unwrap())
@@ -489,9 +310,8 @@ impl Server {
Ok(eg)
}
- 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)?;
+ pub fn get_editor_handler(&self, id: FatCatId, conn: &DbConn) -> Result<Editor> {
+ let row: EditorRow = editor::table.find(id.to_uuid()).first(conn)?;
let ed = Editor {
id: Some(uuid2fcid(&row.id)),
@@ -500,14 +320,13 @@ impl Server {
Ok(ed)
}
- pub fn editor_changelog_get_handler(
+ pub fn get_editor_changelog_handler(
&self,
- id: &str,
+ id: FatCatId,
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.to_uuid()).first(conn)?;
let changes: Vec<(ChangelogRow, EditgroupRow)> = changelog::table
.inner_join(editgroup::table)
.filter(editgroup::editor_id.eq(editor.id))
@@ -552,7 +371,8 @@ impl Server {
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), conn)?;
+ let editgroup =
+ self.get_editgroup_handler(FatCatId::from_uuid(&cl_row.editgroup_id), conn)?;
let mut entry = cl_row.into_model();
entry.editgroup = Some(editgroup);
@@ -638,45 +458,4 @@ impl Server {
entity_batch_handler!(create_file_batch_handler, FileEntity);
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>> {
- 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>> {
- 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>> {
- 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>> {
- 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>> {
- WorkEntity::db_get_history(conn, FatCatId::from_uuid(id), limit)
- }
}
diff --git a/rust/src/api_wrappers.rs b/rust/src/api_wrappers.rs
index faafe984..f6425c8c 100644
--- a/rust/src/api_wrappers.rs
+++ b/rust/src/api_wrappers.rs
@@ -1,13 +1,16 @@
//! API endpoint handlers
-use api_helpers::fcid2uuid;
+use api_entity_crud::EntityCrud;
+use api_helpers::*;
use api_server::Server;
+use database_models::EntityEditRow;
use diesel::Connection;
use errors::*;
use fatcat_api::models;
use fatcat_api::models::*;
use fatcat_api::*;
use futures::{self, Future};
+use std::str::FromStr;
/// 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<>
@@ -17,11 +20,11 @@ macro_rules! wrap_entity_handlers {
// stable doesn't have a mechanism to "concat" or generate new identifiers in macros, at least
// in the context of defining new functions.
// The only stable approach I know of would be: https://github.com/dtolnay/mashup
- ($get_fn:ident, $get_handler:ident, $get_resp:ident, $post_fn:ident, $post_handler:ident,
+ ($get_fn:ident, $get_handler:ident, $get_resp:ident, $post_fn:ident,
$post_resp:ident, $post_batch_fn:ident, $post_batch_handler:ident,
- $post_batch_resp:ident, $update_fn:ident, $update_handler:ident, $update_resp:ident,
- $delete_fn:ident, $delete_handler:ident, $delete_resp:ident, $get_history_fn:ident,
- $get_history_handler:ident, $get_history_resp:ident, $model:ident) => {
+ $post_batch_resp:ident, $update_fn:ident, $update_resp:ident,
+ $delete_fn:ident, $delete_resp:ident, $get_history_fn:ident,
+ $get_history_resp:ident, $model:ident) => {
fn $get_fn(
&self,
@@ -29,13 +32,12 @@ macro_rules! wrap_entity_handlers {
expand: Option<String>,
_context: &Context,
) -> Box<Future<Item = $get_resp, Error = ApiError> + Send> {
- let id = if let Ok(parsed) = fcid2uuid(&id) { parsed } else {
- return Box::new(futures::done(Ok($get_resp::BadRequest(ErrorResponse {
- message: ErrorKind::InvalidFatcatId(id).to_string() }))));
- };
let conn = self.db_pool.get().expect("db_pool error");
// No transaction for GET
- let ret = match self.$get_handler(&id, expand, &conn) {
+ let ret = match conn.transaction(|| {
+ let entity_id = FatCatId::from_str(&id)?;
+ self.$get_handler(entity_id, expand, &conn)
+ }) {
Ok(entity) =>
$get_resp::FoundEntity(entity),
Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) =>
@@ -61,7 +63,10 @@ macro_rules! wrap_entity_handlers {
_context: &Context,
) -> Box<Future<Item = $post_resp, Error = ApiError> + Send> {
let conn = self.db_pool.get().expect("db_pool error");
- let ret = match conn.transaction(|| self.$post_handler(entity, &conn)) {
+ let ret = match conn.transaction(|| {
+ let edit_context = make_edit_context(&conn, entity.parse_editgroup_id()?, false)?;
+ Ok(entity.db_create(&conn, &edit_context)?.into_model()?)
+ }) {
Ok(edit) =>
$post_resp::CreatedEntity(edit),
Err(Error(ErrorKind::Diesel(e), _)) =>
@@ -115,12 +120,12 @@ macro_rules! wrap_entity_handlers {
entity: models::$model,
_context: &Context,
) -> Box<Future<Item = $update_resp, Error = ApiError> + Send> {
- let id = if let Ok(parsed) = fcid2uuid(&id) { parsed } else {
- return Box::new(futures::done(Ok($update_resp::BadRequest(ErrorResponse {
- message: ErrorKind::InvalidFatcatId(id).to_string() }))));
- };
let conn = self.db_pool.get().expect("db_pool error");
- let ret = match conn.transaction(|| self.$update_handler(&id, entity, &conn)) {
+ let ret = match conn.transaction(|| {
+ let entity_id = FatCatId::from_str(&id)?;
+ let edit_context = make_edit_context(&conn, entity.parse_editgroup_id()?, false)?;
+ Ok(entity.db_update(&conn, &edit_context, entity_id)?.into_model()?)
+ }) {
Ok(edit) =>
$update_resp::UpdatedEntity(edit),
Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) =>
@@ -148,19 +153,16 @@ macro_rules! wrap_entity_handlers {
editgroup_id: Option<String>,
_context: &Context,
) -> Box<Future<Item = $delete_resp, Error = ApiError> + Send> {
- let id = if let Ok(parsed) = fcid2uuid(&id) { parsed } else {
- return Box::new(futures::done(Ok($delete_resp::BadRequest(ErrorResponse {
- message: ErrorKind::InvalidFatcatId(id).to_string() }))));
- };
- let editgroup_id = match editgroup_id {
- Some(raw) => if let Ok(parsed) = fcid2uuid(&raw) { Some(parsed) } else {
- return Box::new(futures::done(Ok($delete_resp::BadRequest(ErrorResponse {
- message: ErrorKind::InvalidFatcatId(raw).to_string() }))))
- }
- None => None
- };
let conn = self.db_pool.get().expect("db_pool error");
- let ret = match conn.transaction(|| self.$delete_handler(&id, editgroup_id, &conn)) {
+ let ret = match conn.transaction(|| {
+ let entity_id = FatCatId::from_str(&id)?;
+ let editgroup_id: Option<FatCatId> = match editgroup_id {
+ Some(s) => Some(FatCatId::from_str(&s)?),
+ None => None,
+ };
+ let edit_context = make_edit_context(&conn, editgroup_id, false)?;
+ Ok($model::db_delete(&conn, &edit_context, entity_id)?.into_model()?)
+ }) {
Ok(edit) =>
$delete_resp::DeletedEntity(edit),
Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) =>
@@ -188,13 +190,12 @@ macro_rules! wrap_entity_handlers {
limit: Option<i64>,
_context: &Context,
) -> Box<Future<Item = $get_history_resp, Error = ApiError> + Send> {
- let id = if let Ok(parsed) = fcid2uuid(&id) { parsed } else {
- return Box::new(futures::done(Ok($get_history_resp::BadRequest(ErrorResponse {
- message: ErrorKind::InvalidFatcatId(id).to_string() }))));
- };
let conn = self.db_pool.get().expect("db_pool error");
// No transaction for GET
- let ret = match self.$get_history_handler(&id, limit, &conn) {
+ let ret = match conn.transaction(|| {
+ let entity_id = FatCatId::from_str(&id)?;
+ Ok($model::db_get_history(&conn, entity_id, limit)?)
+ }) {
Ok(history) =>
$get_history_resp::FoundEntityHistory(history),
Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) =>
@@ -240,25 +241,50 @@ macro_rules! wrap_lookup_handler {
}
}
+macro_rules! wrap_fcid_handler {
+ ($get_fn:ident, $get_handler:ident, $get_resp:ident) => {
+ fn $get_fn(
+ &self,
+ id: String,
+ _context: &Context,
+ ) -> Box<Future<Item = $get_resp, Error = ApiError> + Send> {
+ let conn = self.db_pool.get().expect("db_pool error");
+ // No transaction for GET
+ let ret = match (|| {
+ let fcid = FatCatId::from_str(&id)?;
+ self.$get_handler(fcid, &conn)
+ })() {
+ Ok(entity) =>
+ $get_resp::Found(entity),
+ Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) =>
+ $get_resp::NotFound(ErrorResponse { message: format!("Not found: {}", id) }),
+ Err(Error(ErrorKind::MalformedExternalId(e), _)) =>
+ $get_resp::BadRequest(ErrorResponse { message: e.to_string() }),
+ Err(e) => {
+ error!("{}", e);
+ $get_resp::BadRequest(ErrorResponse { message: e.to_string() })
+ },
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+ }
+}
+
impl Api for Server {
wrap_entity_handlers!(
get_container,
get_container_handler,
GetContainerResponse,
create_container,
- create_container_handler,
CreateContainerResponse,
create_container_batch,
create_container_batch_handler,
CreateContainerBatchResponse,
update_container,
- update_container_handler,
UpdateContainerResponse,
delete_container,
- delete_container_handler,
DeleteContainerResponse,
get_container_history,
- get_container_history_handler,
GetContainerHistoryResponse,
ContainerEntity
);
@@ -268,19 +294,15 @@ impl Api for Server {
get_creator_handler,
GetCreatorResponse,
create_creator,
- create_creator_handler,
CreateCreatorResponse,
create_creator_batch,
create_creator_batch_handler,
CreateCreatorBatchResponse,
update_creator,
- update_creator_handler,
UpdateCreatorResponse,
delete_creator,
- delete_creator_handler,
DeleteCreatorResponse,
get_creator_history,
- get_creator_history_handler,
GetCreatorHistoryResponse,
CreatorEntity
);
@@ -289,19 +311,15 @@ impl Api for Server {
get_file_handler,
GetFileResponse,
create_file,
- create_file_handler,
CreateFileResponse,
create_file_batch,
create_file_batch_handler,
CreateFileBatchResponse,
update_file,
- update_file_handler,
UpdateFileResponse,
delete_file,
- delete_file_handler,
DeleteFileResponse,
get_file_history,
- get_file_history_handler,
GetFileHistoryResponse,
FileEntity
);
@@ -310,19 +328,15 @@ impl Api for Server {
get_release_handler,
GetReleaseResponse,
create_release,
- create_release_handler,
CreateReleaseResponse,
create_release_batch,
create_release_batch_handler,
CreateReleaseBatchResponse,
update_release,
- update_release_handler,
UpdateReleaseResponse,
delete_release,
- delete_release_handler,
DeleteReleaseResponse,
get_release_history,
- get_release_history_handler,
GetReleaseHistoryResponse,
ReleaseEntity
);
@@ -331,19 +345,15 @@ impl Api for Server {
get_work_handler,
GetWorkResponse,
create_work,
- create_work_handler,
CreateWorkResponse,
create_work_batch,
create_work_batch_handler,
CreateWorkBatchResponse,
update_work,
- update_work_handler,
UpdateWorkResponse,
delete_work,
- delete_work_handler,
DeleteWorkResponse,
get_work_history,
- get_work_history_handler,
GetWorkHistoryResponse,
WorkEntity
);
@@ -377,26 +387,26 @@ impl Api for Server {
String
);
- wrap_lookup_handler!(
+ wrap_fcid_handler!(
get_release_files,
get_release_files_handler,
- GetReleaseFilesResponse,
- id,
- String
+ GetReleaseFilesResponse
);
- wrap_lookup_handler!(
+ wrap_fcid_handler!(
get_work_releases,
get_work_releases_handler,
- GetWorkReleasesResponse,
- id,
- String
+ GetWorkReleasesResponse
);
- wrap_lookup_handler!(
+ wrap_fcid_handler!(
get_creator_releases,
get_creator_releases_handler,
- GetCreatorReleasesResponse,
- id,
- String
+ GetCreatorReleasesResponse
+ );
+ wrap_fcid_handler!(get_editor, get_editor_handler, GetEditorResponse);
+ wrap_fcid_handler!(
+ get_editor_changelog,
+ get_editor_changelog_handler,
+ GetEditorChangelogResponse
);
fn accept_editgroup(
@@ -405,7 +415,10 @@ impl Api for Server {
_context: &Context,
) -> Box<Future<Item = AcceptEditgroupResponse, Error = ApiError> + Send> {
let conn = self.db_pool.get().expect("db_pool error");
- let ret = match conn.transaction(|| self.accept_editgroup_handler(&id, &conn)) {
+ let ret = match conn.transaction(|| {
+ let id = FatCatId::from_str(&id)?;
+ self.accept_editgroup_handler(id, &conn)
+ }) {
Ok(()) => AcceptEditgroupResponse::MergedSuccessfully(Success {
message: "horray!".to_string(),
}),
@@ -432,9 +445,12 @@ impl Api for Server {
_context: &Context,
) -> Box<Future<Item = GetEditgroupResponse, Error = ApiError> + Send> {
let conn = self.db_pool.get().expect("db_pool error");
- let ret = match conn.transaction(|| self.get_editgroup_handler(&id, &conn)) {
+ let ret = match conn.transaction(|| {
+ let id = FatCatId::from_str(&id)?;
+ self.get_editgroup_handler(id, &conn)
+ }) {
Ok(entity) =>
- GetEditgroupResponse::FoundEntity(entity),
+ GetEditgroupResponse::Found(entity),
Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) =>
GetEditgroupResponse::NotFound(
ErrorResponse { message: format!("No such editgroup: {}", id) }),
@@ -452,7 +468,9 @@ impl Api for Server {
_context: &Context,
) -> Box<Future<Item = CreateEditgroupResponse, Error = ApiError> + Send> {
let conn = self.db_pool.get().expect("db_pool error");
- let ret = match conn.transaction(|| self.create_editgroup_handler(entity, &conn)) {
+ let ret = match conn.transaction(||
+ self.create_editgroup_handler(entity, &conn)
+ ) {
Ok(eg) =>
CreateEditgroupResponse::SuccessfullyCreated(eg),
Err(e) =>
@@ -463,56 +481,6 @@ impl Api for Server {
Box::new(futures::done(Ok(ret)))
}
- fn get_editor_changelog(
- &self,
- username: String,
- _context: &Context,
- ) -> Box<Future<Item = GetEditorChangelogResponse, Error = ApiError> + Send> {
- 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 {
- message: format!("No such editor: {}", username.clone()),
- })
- }
- Err(e) => {
- // TODO: dig in to error type here
- error!("{}", e);
- GetEditorChangelogResponse::GenericError(ErrorResponse {
- message: e.to_string(),
- })
- }
- };
- Box::new(futures::done(Ok(ret)))
- }
-
- fn get_editor(
- &self,
- username: String,
- _context: &Context,
- ) -> Box<Future<Item = GetEditorResponse, Error = ApiError> + Send> {
- 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 {
- message: format!("No such editor: {}", username.clone()),
- })
- }
- Err(e) => {
- // TODO: dig in to error type here
- error!("{}", e);
- GetEditorResponse::GenericError(ErrorResponse {
- message: e.to_string(),
- })
- }
- };
- Box::new(futures::done(Ok(ret)))
- }
-
fn get_changelog(
&self,
limit: Option<i64>,
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index 2236d602..b4b9e3c7 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -22,10 +22,10 @@ extern crate regex;
extern crate lazy_static;
extern crate sha1;
+pub mod api_entity_crud;
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;