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)?;