#[macro_use]
extern crate avocado_derive;
extern crate avocado;
#[macro_use]
extern crate magnet_derive;
extern crate magnet_schema;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
extern crate bson;
extern crate mongodb;
use std::fmt;
use std::fs::create_dir_all;
use std::env::temp_dir;
use std::process::{ Command, Stdio };
use std::error::Error;
use avocado::prelude::*;
#[derive(Debug, Serialize, Deserialize, BsonSchema)]
#[serde(tag = "type", content = "value")]
enum Contact {
Phone(String),
Email(String),
}
#[derive(Debug, Serialize, Deserialize, BsonSchema)]
struct NaiveDate {
year: u32,
month: u32,
day: u32,
}
#[derive(Debug, Serialize, Deserialize, Doc, BsonSchema)]
#[index(keys(legal_name = "ascending"))]
#[options(query_options = "user_query_options")]
struct User {
#[serde(rename = "_id")]
id: Uid<User>,
legal_name: String,
contact: Option<Contact>,
birthday: NaiveDate,
}
fn user_query_options() -> FindOptions {
FindOptions {
no_cursor_timeout: true,
..Default::default()
}
}
#[derive(Debug, Clone, Copy)]
struct UsersBornBetween {
min_year: u32,
max_year: u32,
has_contact: bool,
}
impl Query<User> for UsersBornBetween {
type Output = User;
fn filter(&self) -> Document {
doc!{
"$and": [
{ "birthday.year": { "$gte": self.min_year } },
{ "birthday.year": { "$lte": self.max_year } },
{ "contact": { "$exists": true } },
{
"contact": {
"$type": if self.has_contact {
BsonType::DOCUMENT
} else {
BsonType::NULL
}
}
},
]
}
}
}
#[derive(Debug)]
struct AnyError(Box<Error>);
impl fmt::Display for AnyError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
impl<E: Error + 'static> From<E> for AnyError {
fn from(error: E) -> Self {
AnyError(Box::new(error))
}
}
fn example_main() -> Result<(), AnyError> {
let port = "12984"; let mut dbpath = temp_dir();
dbpath.push("avocado_example_db");
create_dir_all(&dbpath)?;
let mut mongodb_process = Command::new("mongod")
.arg("--noscripting")
.arg("--dbpath")
.arg(&dbpath)
.arg("--port")
.arg(port)
.stdout(Stdio::piped())
.spawn()?;
let _guard = {
struct Guard<F: FnOnce() -> ()>(Option<F>);
impl<F: FnOnce() -> ()> Guard<F> {
fn new(f: F) -> Self {
Guard(Some(f))
}
}
impl<F: FnOnce() -> ()> Drop for Guard<F> {
fn drop(&mut self) {
self.0.take().unwrap()();
}
}
Guard::new(|| { mongodb_process.kill().ok(); })
};
let client = Client::with_uri(&format!("mongodb://localhost:{}/", port))?;
let db = client.db("avocado_example_db");
let users: Collection<User> = db.empty_collection()?;
let mut user_docs = [
User {
id: Uid::new_oid()?,
legal_name: String::from("Donald E. Knuth"),
contact: None, birthday: NaiveDate {
year: 1938,
month: 1,
day: 10,
}
},
User {
id: Uid::new_oid()?,
legal_name: String::from("Steven Paul Jobs"),
contact: Some(Contact::Email(String::from("sjobs@apple.com"))),
birthday: NaiveDate {
year: 1955,
month: 2,
day: 24,
}
},
];
users.insert_many(&user_docs)?;
user_docs[0].legal_name = String::from("Donald Ervin Knuth");
users.replace_entity(&user_docs[0])?;
let mut dijkstra = User {
id: Uid::new_oid()?,
legal_name: String::from("Edsger W. Dijkstra"),
contact: Some(Contact::Phone(String::from("+31 10 123 4567"))),
birthday: NaiveDate {
year: 1930,
month: 5,
day: 11,
}
};
users.upsert_entity(&dijkstra)?;
dijkstra.legal_name = String::from("Edsger Wybe Dijkstra");
users.upsert_entity(&dijkstra)?;
let born_between_50_and_60 = UsersBornBetween {
min_year: 1950,
max_year: 1960,
has_contact: true,
};
println!("");
println!("Born between 1950 and 1960, provided contact:");
println!("---------------------------------------------");
for user in users.find_many(born_between_50_and_60)? {
println!("{:#?}", user?);
}
let born_before_1950 = UsersBornBetween {
min_year: 0,
max_year: 1950,
has_contact: false,
};
println!("");
println!("Born before 1950, has no contact:");
println!("---------------------------------");
for user in users.find_many(&born_before_1950)? {
println!("{:#?}", user?);
}
println!("");
println!("Born before 1960:");
println!("-----------------");
for user in users.find_many(doc!{ "birthday.year": { "$lte": 1960 } })? {
println!("{:#?}", user?);
}
let did_delete_dijkstra = users.delete_entity(&dijkstra)?;
let num_deleted_other = users.delete_entities(&user_docs)?;
println!("");
println!("Deleted Dijkstra's sensitive info: {}", did_delete_dijkstra);
println!("Deleted other people's info: {}", num_deleted_other);
Ok(())
}
fn main() {
example_main().expect("error running example");
}