diff options
| author | Bryan Newbold <bnewbold@robocracy.org> | 2018-09-07 16:00:54 -0700 | 
|---|---|---|
| committer | Bryan Newbold <bnewbold@robocracy.org> | 2018-09-07 16:00:54 -0700 | 
| commit | e73b56f9354596c556cfbb2d45584a6bb86ad60e (patch) | |
| tree | 06ac6520d13552974d66e3631548f4d101e63f6b /rust | |
| parent | cdf46b6a5246b8d750bb7aba60acebca11507540 (diff) | |
| download | fatcat-e73b56f9354596c556cfbb2d45584a6bb86ad60e.tar.gz fatcat-e73b56f9354596c556cfbb2d45584a6bb86ad60e.zip | |
batch inserts by default
Diffstat (limited to 'rust')
| -rw-r--r-- | rust/src/api_server.rs | 1 | ||||
| -rw-r--r-- | rust/src/database_entity_crud.rs | 76 | ||||
| -rw-r--r-- | rust/src/database_models.rs | 45 | 
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"] | 
