Skip to content

Instantly share code, notes, and snippets.

@tomaka
Last active September 28, 2016 12:42
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tomaka/67b54450a2ea11cf2f894d3fedcf7247 to your computer and use it in GitHub Desktop.
Save tomaka/67b54450a2ea11cf2f894d3fedcf7247 to your computer and use it in GitHub Desktop.
macro_rules! query {
($db:ident, $query:expr, [$($param:expr),*], {$($out_field:ident: $ty:ty),+ }) => ({
#[derive(Debug, Clone)]
#[allow(non_snake_case)]
struct Output {
$(
$out_field: $ty,
)+
}
let stmt = $db.prepare_cached($query).unwrap();
let rows = stmt.query(&[$($param),*]).unwrap();
rows.into_iter()
.map(|row| {
Output {
$(
$out_field: match row.get_opt(stmt.columns().iter().position(|c| c.name() == stringify!($out_field)).expect(&format!("no field named {}", stringify!($out_field)))) {
Some(Ok(f)) => f,
Some(Err(err)) => panic!("Error while executing {:?}: {:?}", $query, err),
None => panic!("Index doesn't reference a column"),
}
),+
}
})
.collect::<Vec<_>>()
});
}
macro_rules! query_single {
($db:ident, $query:expr, [$($param:expr),*], {$($out_field:ident:$ty:ty),+ }) => ({
query!($db, $query, [$($param),*], {$($out_field:$ty),+}).into_iter().next()
});
}
macro_rules! query_one_field {
($db:ident, $query:expr, [$($param:expr),*]) => ({
let stmt = match $db.prepare_cached($query) {
Ok(stmt) => stmt,
Err(err) => panic!("Error while executing {:?}: {:?}", $query, err)
};
let rows = stmt.query(&[$($param),*]).unwrap();
rows.into_iter()
.map(|row| match row.get_opt(0) {
Some(Ok(v)) => v,
Some(Err(err)) => panic!("Error while reading result of {:?}: {:?}", $query, err),
None => panic!("No column in the query output")
})
.collect::<Vec<_>>()
});
}
macro_rules! query_single_one_field {
($db:ident, $query:expr, [$($param:expr),*]) => ({
query_one_field!($db, $query, [$($param),*]).into_iter().next()
});
}
// Example usages:
let user: Option<_> = query_single!(database, r#"
SELECT name, email FROM users WHERE id = $1 LIMIT 1
"#, [&id], { name: Option<String>, email: String });
let user = match user { Some(u) => u, None => return err_404!("User doesn't exist") };
println!("user's email: ", user.email);
let users = query!(database, r#"SELECT id FROM users"#, [], { id: i32 });
for user in users {
let id = user.id;
}
let email: Option<String> = query_single_one_field!(database, r#"SELECT email FROM users WHERE id = $1"#, [&id]);
let emails: Vec<String> = query_single_one_field!(database, r#"SELECT email FROM users"#, []);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment