SQLite transaction - bank
examples/sqlite/bank/Cargo.toml
[package] name = "bank" version = "0.1.0" edition = "2021" [dependencies] clap = { version = "4.5.16", features = ["derive"] } sqlite = "0.36.1"
examples/sqlite/bank/src/main.rs
use sqlite::{Connection, State}; use clap::Parser; use clap::Subcommand; #[derive(Subcommand, Debug)] enum Action { Setup {}, Add { account: String, amount: i64, }, Transfer { from: String, to: String, amount: i64, #[arg(long)] panic: bool, #[arg(long)] transaction: bool, }, Show {}, } #[derive(Parser, Debug)] struct Cli { #[command(subcommand)] action: Action, } fn main() { let args = Cli::parse(); let filename = "bank.db"; let connection = sqlite::open(filename).unwrap(); match &args.action { Action::Setup {} => { setup_bank(&connection); } Action::Add { account, amount } => { println!("{:?} {:?}", account, amount); add(&connection, account, *amount); } Action::Transfer { from, to, amount, panic, transaction, } => { println!("{:?} {:?} {:?}", from, to, amount); transfer(&connection, from, to, *amount, *panic, *transaction) } Action::Show {} => { show(&connection); } } } fn setup_bank(connection: &Connection) { connection .execute( r#" CREATE TABLE bank ( name TEXT PRIMARY KEY, balance INTEGER NOT NULL ); "#, ) .unwrap(); } fn transfer( connection: &Connection, from: &str, to: &str, amount: i64, fail: bool, transaction: bool, ) { let sql = r#" UPDATE bank SET balance = ( SELECT balance FROM bank WHERE name = :name ) + :amount WHERE name = :name; "#; if transaction { connection.prepare("BEGIN").unwrap().next().unwrap(); } let mut statement = connection.prepare(sql).unwrap(); statement.bind((":name", from)).unwrap(); statement.bind((":amount", -amount)).unwrap(); statement.next().unwrap(); if fail { panic!("Problem"); } statement.reset().unwrap(); statement.bind((":name", to)).unwrap(); statement.bind((":amount", amount)).unwrap(); statement.next().unwrap(); if transaction { connection.prepare("COMMIT").unwrap().next().unwrap(); } } fn show(connection: &Connection) { let mut statement = connection.prepare("SELECT * FROM bank;").unwrap(); while let Ok(State::Row) = statement.next() { let name = statement.read::<String, _>("name").unwrap(); let balance = statement.read::<i64, _>("balance").unwrap(); println!("{name:5}: {:>4}", balance); } let mut statement = connection .prepare("SELECT SUM(balance) AS total FROM bank;") .unwrap(); if let Ok(State::Row) = statement.next() { let total = statement.read::<i64, _>("total").unwrap(); println!("Total: {:>4}", total); } println!("-----"); } fn add(connection: &Connection, name: &str, amount: i64) { let mut statement = connection .prepare("INSERT INTO bank (name, balance) VALUES (:name, :amount);") .unwrap(); statement.bind((":name", name)).unwrap(); statement.bind((":amount", amount)).unwrap(); statement.next().unwrap(); }