aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBryan Newbold <bnewbold@robocracy.org>2018-09-07 16:00:54 -0700
committerBryan Newbold <bnewbold@robocracy.org>2018-09-07 16:00:54 -0700
commite73b56f9354596c556cfbb2d45584a6bb86ad60e (patch)
tree06ac6520d13552974d66e3631548f4d101e63f6b
parentcdf46b6a5246b8d750bb7aba60acebca11507540 (diff)
downloadfatcat-e73b56f9354596c556cfbb2d45584a6bb86ad60e.tar.gz
fatcat-e73b56f9354596c556cfbb2d45584a6bb86ad60e.zip
batch inserts by default
-rw-r--r--rust/src/api_server.rs1
-rw-r--r--rust/src/database_entity_crud.rs76
-rw-r--r--rust/src/database_models.rs45
3 files changed, 95 insertions, 27 deletions
diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs
index 20f71c7a..5060ba0f 100644
--- a/rust/src/api_server.rs
+++ b/rust/src/api_server.rs
@@ -87,6 +87,7 @@ fn make_edit_context(conn: &DbConn, editgroup_id: Option<FatCatId>) -> Result<Ed
editor_id: FatCatId::from_uuid(&editor_id),
editgroup_id: editgroup_id,
extra_json: None,
+ autoapprove: false,
})
}
diff --git a/rust/src/database_entity_crud.rs b/rust/src/database_entity_crud.rs
index 24d5277c..e97e134b 100644
--- a/rust/src/database_entity_crud.rs
+++ b/rust/src/database_entity_crud.rs
@@ -15,6 +15,7 @@ pub struct EditContext {
pub editor_id: FatCatId,
pub editgroup_id: FatCatId,
pub extra_json: Option<serde_json::Value>,
+ pub autoapprove: bool,
}
/* One goal here is to abstract the non-entity-specific bits into generic traits or functions,
@@ -35,8 +36,11 @@ pub struct EditContext {
// Associated Type, not parametric
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;
type IdentRow; // EntityIdentRow
+ type IdentNewRow;
type RevRow;
fn parse_editgroup_id(&self) -> Result<Option<FatCatId>>;
@@ -45,14 +49,15 @@ 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_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 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>>;
}
// TODO: this could be a separate trait on all entities?
@@ -75,7 +80,7 @@ macro_rules! generic_db_get {
.inner_join($rev_table::table)
.first(conn)?;
- Self::db_from_row(conn, rev, Some(ident))
+ Self::from_row(conn, rev, Some(ident))
}
}
}
@@ -87,7 +92,7 @@ macro_rules! generic_db_get_rev {
.find(rev_id)
.first(conn)?;
- Self::db_from_row(conn, rev, None)
+ Self::from_row(conn, rev, None)
}
}
}
@@ -113,13 +118,32 @@ macro_rules! generic_db_create {
}
macro_rules! generic_db_create_batch {
- () => {
- fn db_create_batch(conn: &DbConn, edit_context: &EditContext, models: &[Self]) -> Result<Vec<Self::EditRow>> {
- let mut ret: Vec<Self::EditRow> = vec![];
- for entity in models {
- ret.push(entity.db_create(conn, edit_context)?);
- }
- Ok(ret)
+ ($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<WorkIdentNewRow>>())
+ .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<WorkEditNewRow>>())
+ .get_results(conn)?;
+ Ok(edits)
}
}
}
@@ -183,7 +207,6 @@ macro_rules! generic_db_delete {
}
macro_rules! generic_db_get_history {
- // TODO: only actually need edit table? and maybe not that?
($edit_table:ident) => {
fn db_get_history(conn: &DbConn, ident: FatCatId, limit: Option<i64>) -> Result<Vec<EntityHistoryEntry>> {
let limit = limit.unwrap_or(50); // XXX: make a static
@@ -208,21 +231,32 @@ macro_rules! generic_db_get_history {
}
}
+macro_rules! generic_db_insert_rev {
+ () => {
+ fn db_insert_rev(&self, conn: &DbConn) -> Result<Uuid> {
+ Self::db_insert_revs(conn, &vec![self]).map(|id_list| id_list[0])
+ }
+ }
+}
+
impl EntityCrud for WorkEntity {
type EditRow = WorkEditRow;
+ type EditNewRow = WorkEditNewRow;
type IdentRow = WorkIdentRow;
+ type IdentNewRow = WorkIdentNewRow;
type RevRow = WorkRevRow;
generic_parse_editgroup_id!();
generic_db_get!(work_ident, work_rev);
generic_db_get_rev!(work_rev);
generic_db_create!(work_ident, work_edit);
- generic_db_create_batch!();
+ generic_db_create_batch!(work_ident, work_edit);
generic_db_update!(work_ident, work_edit);
generic_db_delete!(work_ident, work_edit);
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 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) => (
@@ -243,14 +277,14 @@ impl EntityCrud for WorkEntity {
})
}
- fn db_insert_rev(&self, conn: &DbConn) -> Result<Uuid> {
- let rev_row: Uuid = insert_into(work_rev::table)
- .values((
- work_rev::extra_json.eq(&self.extra)
- ))
+ 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>>())
.returning(work_rev::id)
- .get_result(conn)?;
- Ok(rev_row)
+ .get_results(conn)?;
+ Ok(rev_ids)
}
}
diff --git a/rust/src/database_models.rs b/rust/src/database_models.rs
index 47e00bcf..14215a3c 100644
--- a/rust/src/database_models.rs
+++ b/rust/src/database_models.rs
@@ -37,7 +37,9 @@ pub trait EntityEditRow {
// Helper for constructing tables
macro_rules! entity_structs {
- ($edit_table:expr, $edit_struct:ident, $ident_table:expr, $ident_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 {
@@ -51,6 +53,17 @@ macro_rules! entity_structs {
pub extra_json: Option<serde_json::Value>,
}
+ #[derive(Debug, Associations, AsChangeset, QueryableByName, Insertable)]
+ #[table_name = $edit_table]
+ pub struct $edit_new_struct {
+ pub editgroup_id: Uuid,
+ pub ident_id: Uuid,
+ pub rev_id: Option<Uuid>,
+ pub redirect_id: Option<Uuid>,
+ pub prev_rev: Option<Uuid>,
+ pub extra_json: Option<serde_json::Value>,
+ }
+
impl EntityEditRow for $edit_struct {
/// Go from a row (SQL model) to an API model
fn into_model(self) -> Result<EntityEdit> {
@@ -75,6 +88,14 @@ macro_rules! entity_structs {
pub redirect_id: Option<Uuid>,
}
+ #[derive(Debug, Associations, AsChangeset, Insertable)]
+ #[table_name = $ident_table]
+ pub struct $ident_new_struct {
+ pub is_live: bool,
+ pub rev_id: Option<Uuid>,
+ pub redirect_id: Option<Uuid>,
+ }
+
impl EntityIdentRow for $ident_struct {
fn state(&self) -> Result<EntityState> {
if !self.is_live {
@@ -107,8 +128,10 @@ pub struct ContainerRevRow {
entity_structs!(
"container_edit",
ContainerEditRow,
+ ContainerEditNewRow,
"container_ident",
- ContainerIdentRow
+ ContainerIdentRow,
+ ContainerIdentNewRow
);
#[derive(Debug, Queryable, Identifiable, Associations, AsChangeset)]
@@ -126,8 +149,10 @@ pub struct CreatorRevRow {
entity_structs!(
"creator_edit",
CreatorEditRow,
+ CreatorEditNewRow,
"creator_ident",
- CreatorIdentRow
+ CreatorIdentRow,
+ CreatorIdentNewRow
);
#[derive(Debug, Queryable, Identifiable, Associations, AsChangeset)]
@@ -159,7 +184,7 @@ pub struct FileRevRow {
pub mimetype: Option<String>,
}
-entity_structs!("file_edit", FileEditRow, "file_ident", FileIdentRow);
+entity_structs!("file_edit", FileEditRow, FileEditNewRow, "file_ident", FileIdentRow, FileIdentNewRow);
#[derive(Debug, Queryable, Identifiable, Associations, AsChangeset)]
#[table_name = "release_rev"]
@@ -188,8 +213,10 @@ pub struct ReleaseRevRow {
entity_structs!(
"release_edit",
ReleaseEditRow,
+ ReleaseEditNewRow,
"release_ident",
- ReleaseIdentRow
+ ReleaseIdentRow,
+ ReleaseIdentNewRow
);
#[derive(Debug, Queryable, Identifiable, Associations, AsChangeset)]
@@ -199,7 +226,13 @@ pub struct WorkRevRow {
pub extra_json: Option<serde_json::Value>,
}
-entity_structs!("work_edit", WorkEditRow, "work_ident", WorkIdentRow);
+#[derive(Debug, Associations, AsChangeset, Insertable)]
+#[table_name = "work_rev"]
+pub struct WorkRevNewRow {
+ pub extra_json: Option<serde_json::Value>,
+}
+
+entity_structs!("work_edit", WorkEditRow, WorkEditNewRow, "work_ident", WorkIdentRow, WorkIdentNewRow);
#[derive(Debug, Queryable, Identifiable, Associations, AsChangeset)]
#[table_name = "release_rev_abstract"]