-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] Add support for named joins #2411
Conversation
{query, vars ++ tail_fn.(tail)} | ||
{tail, named} -> | ||
mapped_binds = | ||
Enum.map(named, fn {k, name} -> {k, quote(do: bind_mappings[unquote(name)])} end) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Function body is nested too deep (max depth is 2, was 3).
Ebert has finished reviewing this Pull Request and has found:
You can see more details about this review at https://ebertapp.io/github/elixir-ecto/ecto/pulls/2411. |
Thanks for the PR @zoldar! ❤️ 💚 💙 💛 💜 This is great I have a couple suggestions though.
Because this PR is potentially quite long, I would recommend breaking this into smaller tasks and we work step by step towards the end result: The first step is to make
We need to change it to support a keyword list as last argument and emit a warning if a keyword list is not given. So we want this:
This will also be necessary for us to support index hinting (#2392) in the future. But for now we will support only Now that we made joins extensible, the second step is to add support to Finally, as third step, we can include the Thoughts? |
@@ -268,6 +268,42 @@ defmodule Ecto.QueryTest do | |||
end | |||
end | |||
|
|||
describe "named joins" do | |||
test "assigns a name to a join" do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those tests are very fragile because they are asserting on the AST. The reason why we test them above is because we want to check if the query is optimizable but we are not worried about optimization here. My recommendation is to build actual queries and then traverse query.joins
(or query.aliases
if we follow my proposal) checking for the generated aliases, like you did in the dynamic tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is also very important to test what happens when we give an alias that already exists. We also need to check what happens when you try to use an alias that does not exist.
@@ -124,6 +124,13 @@ defmodule Ecto.Query.BuilderTest do | |||
escape(quote(do: ^([] ++ [])), [], __ENV__) | |||
end | |||
|
|||
test "escape_binding with named binding in the input" do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a fragile test too, we don't need to check the generated AST on expansion.
@@ -66,5 +72,29 @@ defmodule Ecto.Query.Builder.DynamicTest do | |||
"&0.foo() == ^0 and &1.bar() == ^1 and &0.baz() == ^2" | |||
assert params == [{"foo", {0, :foo}}, {"bar", {1, :bar}}, {"baz", {0, :baz}}] | |||
end | |||
|
|||
test "with ... binding in the middle" do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those tests are beautiful! I would recommend moving them to query_test.exs
as there is nothing specific to fragments about them. Have them work directly on the query and then check the result of query.joins
(or query.aliases
according to my proposal).
@josevalim Thank you for the feedback. All the points you made are valid to me and make sense. If nobody else has any objections, I'd start with stage one, as described by you, some time next week. |
I need a word of advice. When I've started working on introducing keyword opts in join/5, I've hit an issue with the fact that join actually allows to accept keyword list for In order for this to work, I guess it would be necessary to tell apart the case where it's meant to be treated as |
@zoldar yeah, you will have to check that it is either an empty list or it has Theoretically we could just go and break everything but that would be annoying for users. :) |
Closing in favor of plan laid out in #2411 (comment) and #2428. Leaving for reference though. |
Closes #2389
I took a stab at implementing support for named joins as discussed in #2389, using the ideas from initial post and #2389 (comment).
Example usage:
Marking it as work in progress because I'm definitely not sure whether
Other than that, I'll want to refactor
Query.Builder.escape_binding
for sure, because there's a lot of redundancy and excessive nesting at the moment. Also, docs will need update eventually as well when/if the proposed change gets into acceptable shape.Feedback appreciated.