Skip to content
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

Allow select: map(x, fields), select_merge: %{} as source query for insert_all. Fixes #4430 #4431

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

nmk
Copy link

@nmk nmk commented Jun 13, 2024

No description provided.


TestRepo.insert_all(MySchema, query)

assert_received {:insert_all, %{source: "my_schema"}, {%Ecto.Query{}, _params}}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to check the fields here? We need to check that both x and y are being sent.

Enum.map(args, fn {field, _} -> extract_field(field, dumper) end)

%Ecto.Query.SelectExpr{expr: {:merge, _ctx, merge_args}, take: %{^ix => {_fun, take_fields}}} ->
[_, {_, _, merge_fields}] = merge_args
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it can be in the reverse order too like this

{:merge, [],
   [
     {:%{}, [], [y: {{:., [type: :binary], [{:&, [], [0]}, :yyy]}, [], []}]},
     {:&, [], [0]}
   ]}

@greg-rychlewski
Copy link
Member

We should be extra sure we are catching all the cases here https://github.com/elixir-ecto/ecto/blob/master/lib/ecto/query/builder/select.ex#L367

@greg-rychlewski
Copy link
Member

Playing around with it more. This can get pretty dicey with nested merges. For example this query

from s in MySchema,
          where: s.x > ^threshold,
          select: %{y: s.y},
          select_merge: map(s, [:x]),
          select_merge: %{x: s.x}

turns into this

{:merge, [],
   [
     {:merge, [],
      [
        {:%{}, [], [y: {{:., [type: :binary], [{:&, [], [0]}, :yyy]}, [], []}]},
        {:&, [], [0]}
      ]},
     {:%{}, [], [x: {{:., [type: :string], [{:&, [], [0]}, :x]}, [], []}]}
   ]}

@nmk
Copy link
Author

nmk commented Jun 14, 2024

@greg-rychlewski I can see in

test "normalize: select_merge with map/2 does not duplicate fields" do
that there is a fields field on the Ecto.Query.SelectExpr struct. Would it be possible to use this field to extract the headers?

@josevalim
Copy link
Member

That will lose you the field names. However, in the planner module, we have a function for extracting fields of a subquery, maybe that can be used, but I think in this case it is probably better to improve the error message and have a single select with a map for simplicity, for full control over the database changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants