Transaction Examples
This guide demonstrates ACID transaction patterns in PocketDB.
Setup
rust
use pocketdb::{Database, doc, filter, PocketValue};
use pocketdb::query::UpdateExpression;
fn main() -> pocketdb::Result<()> {
let db = Database::open("transactions_example.pdb")?;
// ... examples ...
Ok(())
}Basic Transaction
rust
let mut tx = db.begin_transaction()?;
// Perform operations within the transaction
{
let mut users = tx.collection("users")?;
users.insert(doc! { "name" => "Alice", "balance" => 1000 })?;
users.insert(doc! { "name" => "Bob", "balance" => 500 })?;
}
// Commit all changes atomically
tx.commit()?;Money Transfer
Transfer money between accounts atomically:
rust
fn transfer(
db: &Database,
from: &str,
to: &str,
amount: i64,
) -> pocketdb::Result<()> {
let mut tx = db.begin_transaction()?;
// Debit sender
{
let mut accounts = tx.collection("accounts")?;
accounts.update_one(
&filter! { "name" => == from },
UpdateExpression::new().inc("balance", PocketValue::Int(-amount)),
)?;
}
// Credit receiver
{
let mut accounts = tx.collection("accounts")?;
accounts.update_one(
&filter! { "name" => == to },
UpdateExpression::new().inc("balance", PocketValue::Int(amount)),
)?;
}
// Log the transfer
{
let mut logs = tx.collection("transfer_logs")?;
logs.insert(doc! {
"from" => from,
"to" => to,
"amount" => amount,
"timestamp" => std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_millis() as u64
})?;
}
tx.commit()?;
Ok(())
}
// Usage
transfer(&db, "Alice", "Bob", 200)?;Rollback on Error
rust
let result = (|| -> pocketdb::Result<()> {
let mut tx = db.begin_transaction()?;
{
let mut orders = tx.collection("orders")?;
orders.insert(doc! { "item" => "Widget", "qty" => 5 })?;
}
// Simulate an error
let _forced_error = Err::<(), _>(pocketdb::PocketError::Other("Simulated failure".to_string()));
// This code is unreachable in this example
tx.commit()?;
Ok(())
})();
if let Err(e) = result {
eprintln!("Transaction failed: {}", e);
// Changes are automatically discarded on rollback
}Multi-Collection Transaction
rust
let mut tx = db.begin_transaction()?;
// Create order
{
let mut orders = tx.collection("orders")?;
orders.insert(doc! {
"customer_id" => "cust_123",
"items" => ["Widget", "Gadget"],
"total" => 150
})?;
}
// Update inventory
{
let mut inventory = tx.collection("inventory")?;
inventory.update_one(
&filter! { "item" => == "Widget" },
UpdateExpression::new().inc("stock", PocketValue::Int(-3)),
)?;
inventory.update_one(
&filter! { "item" => == "Gadget" },
UpdateExpression::new().inc("stock", PocketValue::Int(-1)),
)?;
}
// Update customer stats
{
let mut customers = tx.collection("customers")?;
customers.update_one(
&filter! { "_id" => == PocketValue::String("cust_123".to_string()) },
UpdateExpression::new()
.inc("order_count", PocketValue::Int(1))
.inc("total_spent", PocketValue::Int(150)),
)?;
}
tx.commit()?;Transaction with Query
Read data within a transaction:
rust
let mut tx = db.begin_transaction()?;
// Read current balance
let balance = {
let accounts = tx.collection("accounts")?;
let account = accounts.find_one(&filter! { "name" => == "Alice" });
account
.and_then(|d| d.get("balance"))
.and_then(|v| v.as_i64())
.unwrap_or(0)
};
println!("Alice's balance: {}", balance);
// Conditionally update
if balance >= 100 {
let mut accounts = tx.collection("accounts")?;
accounts.update_one(
&filter! { "name" => == "Alice" },
UpdateExpression::new().inc("balance", PocketValue::Int(-100)),
)?;
tx.commit()?;
println!("Deducted $100 from Alice's account");
} else {
tx.rollback()?;
println!("Insufficient funds");
}Batch Processing
rust
fn process_batch(db: &Database, items: Vec<(&str, i64)>) -> pocketdb::Result<()> {
let mut tx = db.begin_transaction()?;
for (name, amount) in items {
let mut accounts = tx.collection("accounts")?;
accounts.update_one(
&filter! { "name" => == name },
UpdateExpression::new().inc("balance", PocketValue::Int(amount)),
)?;
}
tx.commit()?;
Ok(())
}
let batch = vec![
("Alice", 100),
("Bob", -50),
("Charlie", 200),
];
process_batch(&db, batch)?;Error Handling Patterns
Check Commit Result
rust
let mut tx = db.begin_transaction()?;
{
let mut col = tx.collection("users")?;
col.insert(doc! { "name" => "Alice" })?;
}
match tx.commit() {
Ok(()) => println!("Transaction committed successfully"),
Err(e) => eprintln!("Commit failed: {}", e),
}Conditional Operations
rust
let mut tx = db.begin_transaction()?;
let mut success = true;
{
let mut accounts = tx.collection("accounts")?;
// Check balance before transfer
let balance = accounts.find_one(&filter! { "name" => == "Alice" })
.and_then(|d| d.get("balance"))
.and_then(|v| v.as_i64())
.unwrap_or(0);
if balance < 100 {
success = false;
} else {
accounts.update_one(
&filter! { "name" => == "Alice" },
UpdateExpression::new().inc("balance", PocketValue::Int(-100)),
)?;
}
}
if success {
tx.commit()?;
} else {
tx.rollback()?;
println!("Insufficient funds — transaction rolled back");
}