The standard library offers the std::fs module for filesystem manipulation, which we explored in Chapter 11, Exploring the Standard Library.
- If you have to work with Comma Separated Values (csv) files, use one of the available crates such as csv, quick_csv, simple_csv, or xsv. The article on 24 days, http://zsiciarz.github.io/24daysofrust/book/vol1/day3.html, can get you started.
- For working with JSON files, use a crate such as json, simple_json, serde_json, or json_macros; start with reading http://zsiciarz.github.io/24daysofrust/book/vol1/day6.html.
- For XML format, there are also plenty of possibilities, such as the xml-rs or quick-xml crates.
For databases, there are many crates available for working with:
- sqlite3 (crates rusqlite or sqlite)
- PostgreSQL (crates postgres and tokio-postgres); get started by using http://zsiciarz.github.io/24daysofrust/book/vol1/day11.html
- Mysql (crate mysql or mysql_async):
Here is some code (mysql.rs) that connects to a local Mysql database, creates a payment table, and does some insert operations, and then finally reads back from that table:
#[macro_use] extern crate mysql; #[derive(Debug, PartialEq, Eq)] struct Payment { customer_id: i32, amount: i32, account_name: Option<String>, } fn main() { let pool = mysql::Pool::new("mysql://root:password@localhost:3307").unwrap(); // Let's create a payment table. // It is temporary so we do not need `tmp` database to exist. // Unwap just to make sure no error happened. pool.prep_exec(r"CREATE TEMPORARY TABLE tmp.payment ( customer_id int not null, amount int not null, account_name text )", ()).unwrap(); let payments = vec![ Payment { customer_id: 1, amount: 2, account_name: None }, Payment { customer_id: 3, amount: 4, account_name: Some("foo".into()) }, Payment { customer_id: 5, amount: 6, account_name: None }, Payment { customer_id: 7, amount: 8, account_name: None }, Payment { customer_id: 9, amount: 10, account_name: Some("bar".into()) }, ]; // Let's insert payments to the database // We will use into_iter() because we do not need to map Stmt to anything else. // Also we assume that no error happened in `prepare`. for mut stmt in pool.prepare(r"INSERT INTO tmp.payment (customer_id, amount, account_name) VALUES (:customer_id, :amount, :account_name)").into_iter() { for p in payments.iter() { // `execute` takes ownership of `params` so we pass account name by reference. // Unwrap each result just to make sure no errors happened. stmt.execute(params!{ "customer_id" => p.customer_id, "amount" => p.amount, "account_name" => &p.account_name, }).unwrap(); } } // Let's select payments from database let selected_payments: Vec<Payment> = pool.prep_exec("SELECT customer_id, amount, account_name from tmp.payment", ()) .map(|result| { // In this closure we will map `QueryResult` to `Vec<Payment>` // `QueryResult` is iterator over `MyResult<row, err>` so first call to `map` // will map each `MyResult` to contained `row` (no proper error handling) // and second call to `map` will map each `row` to `Payment` result.map(|x| x.unwrap()).map(|row| { let (customer_id, amount, account_name) = mysql::from_row(row); Payment { customer_id: customer_id, amount: amount, account_name: account_name, } }).collect() // Collect payments so now `QueryResult` is mapped to `Vec<Payment>` }).unwrap(); // Unwrap `Vec<Payment>` }
- Oracle (crate oci_rs)
- For MongoDB there is the mongodb crate, among many others, developed by the MongoDB lab:
To get an idea how this works, here is some code (mongodb.rs) that connects to a local MongoDB and does some insert, update, delete, and find operations on a collection of movies:
let client = Client::connect("localhost", 27017) .expect("Failed to initialize client."); let coll = client.db("media").collection("movies"); coll.insert_one(doc!{ "title" => "Back to the Future" }, None).unwrap(); coll.update_one(doc!{}, doc!{ "director" => "Robert Zemeckis" }, None).unwrap(); coll.delete_many(doc!{}, None).unwrap(); let mut cursor = coll.find(None, None).unwrap(); for result in cursor { if let Ok(item) = result { if let Some(&Bson::String(ref title)) = item.get("title") { println!("title: {}", title); } } }
- For Redis, there are the redis or simple_redis crates; see http://zsiciarz.github.io/24daysofrust/book/vol1/day18.html for a quick start
- If you are interested in Object Relational Mapper (ORM) frameworks, the diesel crate is the most popular (see http://zsiciarz.github.io/24daysofrust/book/vol2/day17.html); it can be used for Sqlite, Mysql and Postgres; look at the deuterium_orm crate for a simpler framework
- If there is as yet no dedicated driver, you can probably use an ODBC connection through the odbc-sys or odbc-safe crates
- To use cypher queries for a neo4j database, use the rusted_cypher crate
- Furthermore, there are crates for leveldb, Cassandra (from Apache), RocksDB (from Facebook), Firebase, CouchDB, and InfluxDB