Hi, I'm trying to write a wrapper macro for sqlx to give me some more compile-time guarantees for a use-case that is not supported by mariadb (binding a list to ?). For that I want to first concat! something to the query, before passing the result to sqlx' query_as! macro:
macro_rules! query_in_list {
($ty:ty, $query:literal for $name:ident in $list:ident) => {
query_in_list!($ty, $query for $name in $list { $name })
};
($ty:ty, $query:literal for $name:ident in $list:ident { $block:expr }) => {{
let _ = sqlx::query_as!($ty, concat!($query, "( ? );"));
let _ = sqlx::query_as!($ty, concat!($query, "( ?, ? );"));
let mut builder = sqlx::QueryBuilder::new(concat!($query, " ( "));
let mut separated = builder.separated(", ");
for $name in $list {
separated.push_bind($block);
}
separated.push_unseparated(" );");
builder
}};
}
let builder = query_in_list! {
OrgPermissionsQueryResult,
r#"SELECT organization_id AS org_id, permissions
FROM roles
JOIN roles_permissions_organization USING (role_id)
WHERE idp_group IN "#
for group in groups
};
This however does not work, as it tries to pass the whole concat!(...) into the macro, instead of just the result? Is there any way to evaluate it early? e.g. concat!! or passing it to an "early evaluate" macro or something similar?
I'm not sure why it doesn't work in this case, but you could separate the problem in two parts: first expand it iteratively to see what the concat! produces, or make a dummy, simpler declarative macro with the same pattern but only that concat! alone and print out the result. Then in a second step, give that output to query_as! and see if that's where the problem occurs.
Why would you like to evaluate the concat! before passing it to another declarative macro? Here, I suppose you could assign a temporary variable, but I don't see the advantage.
There absolutely is a reason to pass literal: the whole point of sqlx is to parse that literal to validate it. Kinda like format_args. And, of course, format_args does what @will_i_code wants… and that's why it's not a regular macro but part of the compiler.
It's one of the very well-known things that was ripped out when they rushed to stability Rust 1.0 about 10 years ago. Lindy's law tells us ETA for that feature return is 10 years now…
sqlx::query_as! actually uses the expr specifier for that parameter.
But it seems to use a procedural macro to expand it... I'm not sure why they made that choice instead of literal, but then again, it "absolutely" is only version 0.8.6.