Add `merge` to `Arguments`
Add merge to Arguments
Currently, there is no convenient way to merge two sets of query builder arguments.
Why?
In my use case, I need to combine arguments from multiple queries, but there's no existing method to do this.
Here is one of my use case
I am building a custom QueryBuilder that would like to take Arguments as a parameter, but can't because of the limitation of the add method on the trait.
I would like something like :
macro_rules! binding {
[$($arg:expr),* $(,)?] => {{
let mut args = <Postgres as sqlx::Database>::Arguments::default();
$(
args.add($arg).expect("failed to add binding");
)*
args
}};
}
CustomBuilder::new()
.select_raw("price * ? as price_tax, ? as name", binding![1.2, "test"])
.from("products")
.where_raw("price > ?", binding![10])
// ...
fn select_raw_expr_bindings<T, B>(mut self, columns: T, bindings: B) -> Self
where
T: Into<String>,
B: Arguments<'q>,
{
self.ensure_bindings();
self.bindings
.as_mut()
.expect("bindings should be initialized")
.merge(bindings); // Merge here
self.columns = ColumnExpr::Raw(columns.into());
self
}
But, this is what I have at the moment :
pub struct SelectBuilder<'q> {
columns: ColumnExpr<'q>,
table: Ident<'q>,
bindings: Option<<Postgres as Database>::Arguments<'q>>,
where_node: Option<Node<'q>>,
// ...
}
// ...
fn select_raw_expr<T, B>(mut self, columns: T, bindings: B) -> Self
where
T: Into<String>,
B: IntoIterator,
B::Item: 'q + sqlx::Encode<'q, Postgres> + sqlx::Type<Postgres>,
{
self.ensure_bindings();
for binding in bindings {
self.bindings
.as_mut()
.expect("bindings should be initialized")
.add(value)
.expect("failed to add value to bindings");
}
self.columns = ColumnExpr::Raw(columns.into());
self
}
What I have has a significant limitation; it requires all bindings in the iterator to be of the same type. For example, [1, "test"] would not work because it combines different types (integer and str) in the same collection.
Introducing a merge function would allow developers to combine multiple sets of Arguments.
Here is another method for which I need to wait for merge to be accepted.
pub fn where_subquery<C, F>(mut self, column: C, operator: Operator, subquery_fn: F) -> Self
where
C: Into<Ident<'q>>,
F: FnOnce(SelectFromBuilder) -> SelectBuilder<'q>,
{
let (query, bindings) = subquery_fn(SelectFromBuilder).into_parts();
if let Some(bindings) = bindings {
self.ensure_bindings();
// TODO: wait for merge to be accepted for subqueries
todo!()
} else {
self.where_raw_expr(
format!("{} {} ({})", column.into().format(), operator, query),
None::<Vec<&str>>,
)
}
}
Thank you
@abonander could you review please?
I get to PRs when I can. Pinging me only fills up my notifications.
Bumping this PR—really looking forward to seeing it merged!