Finalized member migration
This commit is contained in:
parent
9cf9e5752f
commit
26f5195069
@ -1,5 +1,5 @@
|
|||||||
use rand::distr::{Alphanumeric, SampleString};
|
use rand::distr::{Alphanumeric, SampleString};
|
||||||
use sqlx::{Postgres, QueryBuilder};
|
use sqlx::{PgPool, Postgres, QueryBuilder};
|
||||||
use validator::Validate;
|
use validator::Validate;
|
||||||
|
|
||||||
#[derive(Debug, Validate)]
|
#[derive(Debug, Validate)]
|
||||||
@ -15,10 +15,26 @@ pub struct Member {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Member {
|
impl Member {
|
||||||
pub async fn insert_multiple(
|
pub async fn get_many(transaction: &PgPool, members: Vec<Self>) -> Result<(), sqlx::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_all(pool: &PgPool) -> Result<Vec<Self>, sqlx::Error> {
|
||||||
|
let members = sqlx::query_as!(Member, "SELECT * FROM members;",)
|
||||||
|
.fetch_all(pool)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(members)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn insert_many(
|
||||||
transaction: &mut sqlx::Transaction<'_, Postgres>,
|
transaction: &mut sqlx::Transaction<'_, Postgres>,
|
||||||
members: Vec<Self>,
|
members: Vec<Self>,
|
||||||
) -> Result<(), sqlx::Error> {
|
) -> Result<(), sqlx::Error> {
|
||||||
|
if members.len() == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let mut query_builder = QueryBuilder::new(
|
let mut query_builder = QueryBuilder::new(
|
||||||
"INSERT INTO members(id, first_name, full_name, registration_token, diploma, hours, groups) "
|
"INSERT INTO members(id, first_name, full_name, registration_token, diploma, hours, groups) "
|
||||||
);
|
);
|
||||||
@ -41,14 +57,34 @@ impl Member {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_multiple(
|
pub async fn update_many(
|
||||||
transaction: &mut sqlx::Transaction<'_, Postgres>,
|
transaction: &mut sqlx::Transaction<'_, Postgres>,
|
||||||
members: Vec<Self>,
|
members: Vec<Self>,
|
||||||
) -> Result<(), sqlx::Error> {
|
) -> Result<(), sqlx::Error> {
|
||||||
|
if members.len() == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
for member in members {
|
for member in members {
|
||||||
sqlx::query!("UPDATE ONLY members SET first_name = $1, full_name = $2, diploma = $3, hours = $4, groups = $5 WHERE id = $6", member.first_name, member.full_name, member.diploma, &member.hours, &member.groups, member.id).execute(&mut **transaction).await?;
|
sqlx::query!("UPDATE ONLY members SET first_name = $1, full_name = $2, diploma = $3, hours = $4, groups = $5 WHERE id = $6", member.first_name, member.full_name, member.diploma, &member.hours, &member.groups, member.id).execute(&mut **transaction).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn remove_many(
|
||||||
|
transaction: &mut sqlx::Transaction<'_, Postgres>,
|
||||||
|
member_ids: &Vec<String>,
|
||||||
|
) -> Result<(), sqlx::Error> {
|
||||||
|
sqlx::query!(
|
||||||
|
"
|
||||||
|
DELETE FROM members WHERE id = ANY($1)
|
||||||
|
",
|
||||||
|
member_ids
|
||||||
|
)
|
||||||
|
.execute(&mut **transaction)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
#[derive(Clone, serde::Serialize)]
|
#[derive(Debug, Clone, serde::Serialize)]
|
||||||
pub struct Name {
|
pub struct Name {
|
||||||
pub first: String,
|
pub first: String,
|
||||||
pub full: String,
|
pub full: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, serde::Serialize)]
|
#[derive(Debug, Clone, serde::Serialize)]
|
||||||
pub struct Member {
|
pub struct Member {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub name: Name,
|
pub name: Name,
|
||||||
|
@ -21,14 +21,15 @@ pub async fn migrate_request<'a>(
|
|||||||
return Err(AuthError::NoPermssions.into());
|
return Err(AuthError::NoPermssions.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tracing::info!("Migration is requested");
|
||||||
|
|
||||||
// Convert the input CSV to a vector of members
|
// Convert the input CSV to a vector of members
|
||||||
let members_new: Vec<Member> = Row::from_csv_multiple(&body)?
|
let members_new: Vec<Member> = Row::from_csv_many(&body)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|m| m.into())
|
.map(|m| m.into())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// TODO: Write function to get members from database
|
let members_old = convert_vec(DbMember::get_all(&state.pool).await?);
|
||||||
let members_old: Vec<Member> = Vec::new();
|
|
||||||
|
|
||||||
let members_diff = generate_diff(members_new, members_old);
|
let members_diff = generate_diff(members_new, members_old);
|
||||||
|
|
||||||
@ -50,6 +51,8 @@ pub async fn migrate_confirm<'a>(
|
|||||||
return Err(AuthError::NoPermssions.into());
|
return Err(AuthError::NoPermssions.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tracing::info!("Migration is confirmed");
|
||||||
|
|
||||||
// TODO: Implement better error naming
|
// TODO: Implement better error naming
|
||||||
let count = match body.trim().parse::<u32>() {
|
let count = match body.trim().parse::<u32>() {
|
||||||
Ok(c) => c,
|
Ok(c) => c,
|
||||||
@ -63,16 +66,30 @@ pub async fn migrate_confirm<'a>(
|
|||||||
None => return Err(crate::Error::NotFound),
|
None => return Err(crate::Error::NotFound),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let inserted_len = members_diff.insert.len();
|
||||||
|
let update_len = members_diff.update.len();
|
||||||
|
let remove_len = members_diff.remove.len();
|
||||||
|
|
||||||
migrate_transaction(&state.pool, members_diff).await?;
|
migrate_transaction(&state.pool, members_diff).await?;
|
||||||
|
|
||||||
|
tracing::info!(
|
||||||
|
"Migration is successfully executed. Inserted: {}, updated: {}, removed: {}",
|
||||||
|
inserted_len,
|
||||||
|
update_len,
|
||||||
|
remove_len
|
||||||
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn migrate_transaction(pool: &PgPool, members_diff: MembersDiff) -> Result<(), sqlx::Error> {
|
async fn migrate_transaction(pool: &PgPool, members_diff: MembersDiff) -> Result<(), sqlx::Error> {
|
||||||
let mut transaction = pool.begin().await?;
|
let mut transaction = pool.begin().await?;
|
||||||
|
|
||||||
// DbMember::insert_multiple(&mut transaction, convert_vec(members_diff.insert)).await?;
|
DbMember::insert_many(&mut transaction, convert_vec(members_diff.insert)).await?;
|
||||||
DbMember::update_multiple(&mut transaction, convert_vec(members_diff.update)).await?;
|
DbMember::update_many(&mut transaction, convert_vec(members_diff.update)).await?;
|
||||||
|
|
||||||
|
let members_remove_ids: Vec<String> = members_diff.remove.into_iter().map(|m| m.id).collect();
|
||||||
|
DbMember::remove_many(&mut transaction, &members_remove_ids).await?;
|
||||||
|
|
||||||
transaction.commit().await?;
|
transaction.commit().await?;
|
||||||
|
|
||||||
@ -98,7 +115,7 @@ struct Row {
|
|||||||
diploma: Option<String>,
|
diploma: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct MembersDiff {
|
pub struct MembersDiff {
|
||||||
insert: Vec<Member>,
|
insert: Vec<Member>,
|
||||||
update: Vec<Member>,
|
update: Vec<Member>,
|
||||||
@ -128,7 +145,7 @@ impl Default for MigrationStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Row {
|
impl Row {
|
||||||
fn from_csv_multiple(input: &str) -> Result<Vec<Self>, csv::Error> {
|
fn from_csv_many(input: &str) -> Result<Vec<Self>, csv::Error> {
|
||||||
let mut rdr = csv::ReaderBuilder::new()
|
let mut rdr = csv::ReaderBuilder::new()
|
||||||
.delimiter(b';')
|
.delimiter(b';')
|
||||||
.from_reader(input.as_bytes());
|
.from_reader(input.as_bytes());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user