You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Refactor the query builder to make it easier to add new AST passes
I had initially wanted to move us towards a more of a visitor pattern,
where the `AstVisitor` trait would have most of the methods from
`QueryBuilder`, with `BindCollector` and `fn
unsafe_to_cache_prepared(&mut self)` tacked on. However, I quickly hit a
wall there when I realized that `BindCollector` cannot be made object
safe, which would prevent me from making `QueryFragment` object safe, so
that won't work.
The benefit of using the visitor pattern here would have been that it
would be easier for code *outside* of Diesel to add new AST passes if it
wanted to (within limits, I don't want to go so far as to have
`visit_specific_type` as that would be even more painful than what we
have now). This form doesn't bring that benefit.
However, using an enum instead does make it easier for us to add new
passes within Diesel itself, since we now have a single function which
will apply to all future AST passes for the majority of nodes (most
nodes don't care about any pass other than `to_sql`, they just call
their children).
The plan is to follow this up by moving `to_sql` into the `walk_ast`
method as well, and eliminate `Changeset`, and `InsertValues` since
it'll now be easier to add the new "this is like that other pass, but
slightly different for this one case" type passes.
The signature is a little funky here, since we're passing a mutable
reference to an enum which just wraps a mutable reference. I really only
want the inner `&mut`, since I want implementors to be able to mutate
the `QueryBuilder` or `BindCollector`, but not change the variant. The
reason for the outer `&mut` is because reborrowing doesn't apply to
structs. We can't pass `AstPass<'a>` multiple times, as it's not `Copy`.
When we pass a mutable reference directly, Rust creates a new reference
with a narrowed lifetime. We can't do that here. The reason I kept the
inner `&mut` instead of just having `AstPass` own the value is that we'd
have no way to cleanly get the value being mutated back out of it when
we were done.
0 commit comments