macro_rules! query_dyn {
($($tt:tt)*) => { ... };
}Expand description
Constructs a new query dynamically at runtime. See also query!.
§Usage
This macro expands to an expression with the type Result<Query>.
The first parameter is the SQL query and is always given as a &str. This string may contain
parameter bindings on the form $ident where ident is any valid Rust identifier ($abc,
$value_123, etc.). The order of the parameters does not matter.
// We can construct the actual query at runtime
let mut sql = "INSERT INTO people VALUES".to_owned();
sql.push_str("($age, $name)");
let age = 42;
let insert_person = query_dyn!(
&sql,
name = "John Wick", // Binds "$name" to "John Wick"
age, // Binds "$age" to the value of `age`
)?;The query and all the parameters are passed into Query::parse, so the above would be expanded
into:
// We can construct the actual query at runtime
let mut sql = "INSERT INTO people VALUES".to_string();
sql.push_str("($age, $name)");
let age = 42;
let insert_person = Query::parse(
&sql,
&[("name", &"John Wick"), ("age", &age)],
);§Dynamic Binding
Optionally, you may also choose to include additional bindings at runtime by using the
..bindings syntax. This is supported for any type that implements IntoIterator<Item = (&str, Parameter)>, ie. Vec<(&str, Parameter)>, HashMap<&str, Parameter>, Option<(&str, Parameter)>, iterators, and so on.
Dynamic bindings may be mixed with static bindings:
let mut bindings = Vec::new();
// We use the `as Parameter` to please the type checker.
// Alternatively, we could specify the type for bindings: `Vec<(&str, Parameter)>`.
bindings.push(("age", &42 as Parameter));
bindings.push(("name", &"John Wick" as Parameter));
let sql = "INSERT INTO people VALUES ($age, $name, $height)".to_string();
let insert_person = query_dyn!(
&sql,
height = 192,
..bindings,
)?;§A larger example
Let’s say that we wanted to dynamically add filters to our query:
// We have the query we want to execute
let mut sql = "SELECT * FROM people".to_string();
// and some filters we got from the user.
let age_filter: Option<i32> = Some(32);
let name_filter: Option<&str> = None;
// Then we dynamically build a list of filters and bindings to use:
let mut filters = Vec::new();
let mut bindings = Vec::new();
// We add the filters as needed.
if let Some(age) = age_filter.as_ref() {
filters.push("age > $min_age");
bindings.push(("min_age", age as Parameter));
}
if let Some(name) = name_filter.as_ref() {
filters.push("name LIKE $name");
bindings.push(("name", name as Parameter));
}
// And add them to the query.
if filters.len() > 0 {
sql += &format!(" WHERE {}", filters.join(" AND "));
}
// Then we can use it as normal.
let query: Query = query_dyn!(&sql, ..bindings)?;