Skip to content

Commit

Permalink
Merge pull request #30 from kanko-travel/idempotent_create
Browse files Browse the repository at this point in the history
Idempotent create
  • Loading branch information
umran authored Sep 8, 2024
2 parents 17e133e + 6af6812 commit 0137864
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 18 deletions.
37 changes: 30 additions & 7 deletions model/src/crud/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,26 @@ use sqlx::{postgres::PgRow, FromRow, PgConnection};
use crate::Error;
use crate::{crud::util::build_query, FieldValue, Model};

#[derive(Clone, Debug)]
use super::util::build_query_as;

#[derive(Debug)]
pub struct Create<'a, T: Model> {
value: &'a T,
value: &'a mut T,
idempotent: bool,
}

impl<'a, T> Create<'a, T>
where
T: Model + for<'b> FromRow<'b, PgRow> + Unpin + Sized + Send,
{
pub(crate) fn new(value: &'a T) -> Self {
Self { value }
pub(crate) fn new(value: &'a mut T) -> Self {
Self {
value,
idempotent: false,
}
}

pub async fn execute(&self, executor: &mut PgConnection) -> Result<(), Error> {
pub async fn execute(&mut self, executor: &mut PgConnection) -> Result<(), Error> {
let table_name = T::table_name();
let fields = self.value.fields()?;

Expand All @@ -33,13 +39,30 @@ where
.collect::<Vec<String>>()
.join(", ");

let var_bindings: Vec<FieldValue> = fields.into_iter().map(|(_, value)| value).collect();

if self.idempotent {
let primary_key_index = format!("{}_pkey", table_name);

let statement = format!(
"INSERT INTO {} ({}) VALUES ({}) ON CONFLICT ON CONSTRAINT {} DO NOTHING RETURNING *",
table_name, columns, placeholder_values, primary_key_index
);

let created: T = build_query_as(&statement, var_bindings)
.fetch_one(executor)
.await?;

*self.value = created;

return Ok(());
}

let statement = format!(
"INSERT INTO {} ({}) VALUES ({})",
table_name, columns, placeholder_values
);

let var_bindings: Vec<FieldValue> = fields.into_iter().map(|(_, value)| value).collect();

build_query(&statement, var_bindings)
.execute(executor)
.await?;
Expand Down
2 changes: 1 addition & 1 deletion model/src/crud/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ where
DeleteAssociation::new(self, relation_name, associated_id)
}

fn create<'a>(&'a self) -> Create<'a, Self> {
fn create<'a>(&'a mut self) -> Create<'a, Self> {
Create::new(self)
}

Expand Down
9 changes: 2 additions & 7 deletions model/src/sort_by/grammar.lalrpop
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
use std::str::FromStr;
use uuid::Uuid;
use rust_decimal::Decimal;
use chrono::{DateTime, NaiveDate};
use lalrpop_util::ParseError;
use crate::filter::ast::{Expr, LogicOp, CompOp, Var};
use crate::filter::util::apply_string_escapes;
use crate::{FieldType, FieldValue, ModelDef};
use crate::filter::ast::Var;
use crate::{ModelDef};

grammar(model_def: &ModelDef);

Expand Down
4 changes: 2 additions & 2 deletions model/tests/crud.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ async fn test_create() {

let mut records = records.into_iter();

let record = records.next().unwrap();
let mut record = records.next().unwrap();

record.create().execute(&mut tx).await.unwrap();

Expand Down Expand Up @@ -83,7 +83,7 @@ async fn test_upsert() {

let mut records = records.into_iter();

let record = records.next().unwrap();
let mut record = records.next().unwrap();

record.create().execute(&mut tx).await.unwrap();

Expand Down
2 changes: 1 addition & 1 deletion model/tests/pagination.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ async fn setup_tables(tx: &mut Transaction<'_, Postgres>) {
async fn insert_records(tx: &mut Transaction<'_, Postgres>) {
let records = read_records();

for record in records.into_iter() {
for mut record in records.into_iter() {
record.create().execute(tx).await.unwrap();
}
}
Expand Down

0 comments on commit 0137864

Please sign in to comment.