Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

insert order and line items in one atomic statement #12

Merged
merged 2 commits into from
Aug 21, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 26 additions & 53 deletions wasm-components/rust/orders-service/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,74 +53,46 @@ impl Guest for Component {
"orders-service",
"All requested products are in stock",
);
query("BEGIN;", &[]).expect("ORDER-SERVICE-CREATE-ORDER: Failed to begin transaction");

let mut ids: Vec<String> = vec![];

// create line items
for item in &items {
let params = vec![
PgValue::Integer(item.price),
PgValue::Integer(item.quantity),
PgValue::Text(item.sku.clone()),
];

let id = query(
indoc! {"
-- Create order line item
INSERT INTO orders.t_order_line_items (price, quantity, sku)
VALUES ($1, $2, $3) RETURNING id;
"},
&params,
let mut sql = String::from(indoc! {r#"
WITH order_id AS (
INSERT INTO orders.t_orders (order_number, total)
VALUES ($1, $2) RETURNING id
), item_ids AS (
INSERT INTO orders.t_order_line_items (price, quantity, sku)
VALUES $3 RETURNING id
), joins AS (
SELECT order_id.id as order_id, item_ids.id as item_id FROM order_id, item_ids
)
.expect("ORDER-SERVICE-CREATE-ORDER: Failed to insert order line item");
INSERT INTO orders.t_orders_order_line_items_list (order_id, order_line_items_list_id)
(SELECT order_id, item_id FROM joins);
"#});

if let PgValue::Int8(id) = id[0][0].value {
ids.push(id.to_string());
}
let mut value_strings = vec![];
for item in &items {
value_strings.push(format!("({},{},'{}')", item.price, item.quantity, item.sku));
}

sql = sql.replace("$3", &value_strings.join(","));

let total = &items
.iter()
.fold(0, |acc, item| acc + item.price * item.quantity);

let order_number = Uuid::new_v4().to_string();

let pg_response = query(
indoc! {"
-- Create order entry
INSERT INTO orders.t_orders (order_number, total)
VALUES ($1, $2) RETURNING id;
"},
query(
&sql,
&[
PgValue::Text(order_number.clone()),
PgValue::Integer(*total),
],
)
.expect("ORDER-SERVICE-CREATE-ORDER: Failed to insert order");

let order_id: String;

if let PgValue::Int8(id) = pg_response[0][0].value {
order_id = id.to_string();
} else {
panic!("RDER-SERVICE-CREATE-ORDER: Failed to get order id");
}

for id in ids {
query(
indoc! {"
-- Link order and line items
INSERT INTO orders.t_orders_order_line_items_list (order_id, order_line_items_list_id)
VALUES ($1, $2);
"},
&[PgValue::BigInt(order_id.parse().unwrap()), PgValue::BigInt(id.parse().unwrap())],
).expect("ORDER-SERVICE-CREATE-ORDER: Failed to link order and line items");
}

// TODO: make sure no idle transactions are left hanging if things go wrong here (rollback)
query("COMMIT;", &[])
.expect("ORDER-SERVICE-CREATE-ORDER: Failed to commit transaction");
.map_err(|e| {
let msg = format!("Failed to insert order: {:?}", e);
log(Level::Error, "orders-service", &msg);
Error::Internal(msg)
})?;

let notification = OrderNotification { order_number };

Expand Down Expand Up @@ -166,7 +138,8 @@ impl Guest for Component {
FROM
orders.t_order_line_items as line_items
JOIN orders.t_orders_order_line_items_list as order_lines ON "order_lines".order_line_items_list_id = "line_items".id
JOIN orders.t_orders as "order" ON "order".id = "order_lines".order_id;
JOIN orders.t_orders as "order" ON "order".id = "order_lines".order_id
LIMIT 10;
"#};

let rows =
Expand Down