|
| 1 | +use anyhow::Result; |
| 2 | +use libsql_client::{params, Connection, QueryResult, ResultSet, Statement}; |
| 3 | +use rand::prelude::SliceRandom; |
| 4 | + |
| 5 | +fn result_to_string(query_result: QueryResult) -> Result<String> { |
| 6 | + let mut ret = String::new(); |
| 7 | + let ResultSet { columns, rows } = query_result.into_result_set()?; |
| 8 | + for column in &columns { |
| 9 | + ret += &format!("| {column:16} |"); |
| 10 | + } |
| 11 | + ret += "\n| -------------------------------------------------------- |\n"; |
| 12 | + for row in rows { |
| 13 | + for column in &columns { |
| 14 | + ret += &format!("| {:16} |", row.cells[column].to_string()); |
| 15 | + } |
| 16 | + ret += "\n"; |
| 17 | + } |
| 18 | + Ok(ret) |
| 19 | +} |
| 20 | + |
| 21 | +// Bumps a counter for one of the geographic locations picked at random. |
| 22 | +async fn bump_counter(db: impl Connection) -> Result<String> { |
| 23 | + // Recreate the tables if they do not exist yet |
| 24 | + db.batch([ |
| 25 | + "CREATE TABLE IF NOT EXISTS counter(country TEXT, city TEXT, value, PRIMARY KEY(country, city)) WITHOUT ROWID", |
| 26 | + "CREATE TABLE IF NOT EXISTS coordinates(lat INT, long INT, airport TEXT, PRIMARY KEY (lat, long))" |
| 27 | + ]).await?; |
| 28 | + |
| 29 | + // For demo purposes, let's pick a pseudorandom location |
| 30 | + const FAKE_LOCATIONS: &[(&str, &str, &str, f64, f64)] = &[ |
| 31 | + ("WAW", "PL", "Warsaw", 52.22959, 21.0067), |
| 32 | + ("EWR", "US", "Newark", 42.99259, -81.3321), |
| 33 | + ("HAM", "DE", "Hamburg", 50.118801, 7.684300), |
| 34 | + ("HEL", "FI", "Helsinki", 60.3183, 24.9497), |
| 35 | + ("NSW", "AU", "Sydney", -33.9500, 151.1819), |
| 36 | + ]; |
| 37 | + |
| 38 | + let (airport, country, city, latitude, longitude) = |
| 39 | + *FAKE_LOCATIONS.choose(&mut rand::thread_rng()).unwrap(); |
| 40 | + |
| 41 | + db.transaction([ |
| 42 | + Statement::with_params( |
| 43 | + "INSERT OR IGNORE INTO counter VALUES (?, ?, 0)", |
| 44 | + // Parameters that have a single type can be passed as a regular slice |
| 45 | + &[country, city], |
| 46 | + ), |
| 47 | + Statement::with_params( |
| 48 | + "UPDATE counter SET value = value + 1 WHERE country = ? AND city = ?", |
| 49 | + &[country, city], |
| 50 | + ), |
| 51 | + Statement::with_params( |
| 52 | + "INSERT OR IGNORE INTO coordinates VALUES (?, ?, ?)", |
| 53 | + // Parameters with different types can be passed to a convenience macro - params!() |
| 54 | + params!(latitude, longitude, airport), |
| 55 | + ), |
| 56 | + ]) |
| 57 | + .await?; |
| 58 | + |
| 59 | + let counter_response = db.execute("SELECT * FROM counter").await?; |
| 60 | + let scoreboard = result_to_string(counter_response)?; |
| 61 | + let html = format!("Scoreboard:\n{scoreboard}"); |
| 62 | + Ok(html) |
| 63 | +} |
| 64 | + |
| 65 | +#[tokio::main] |
| 66 | +async fn main() { |
| 67 | + match libsql_client::reqwest::Connection::connect_from_env() { |
| 68 | + Ok(remote_db) => { |
| 69 | + match bump_counter(remote_db).await { |
| 70 | + Ok(response) => println!("Remote:\n{response}"), |
| 71 | + Err(e) => println!("Remote database query failed: {e}"), |
| 72 | + }; |
| 73 | + } |
| 74 | + Err(e) => println!("Failed to fetch from a remote database: {e}"), |
| 75 | + } |
| 76 | + |
| 77 | + let mut path_buf = std::env::temp_dir(); |
| 78 | + path_buf.push("libsql_client_test_db.db"); |
| 79 | + let local_db = libsql_client::local::Connection::connect(path_buf.as_path()).unwrap(); |
| 80 | + match bump_counter(local_db).await { |
| 81 | + Ok(response) => println!("Local:\n{response}"), |
| 82 | + Err(e) => println!("Local database query failed: {e}"), |
| 83 | + }; |
| 84 | +} |
0 commit comments