Qqwy

Qqwy

TypeCheck Core Team

Ecto.Query.update dynamic field name

I am working on a library that allows re-ordering rows of an Ecto schema based on an integer column.

Right now, the column is hard-coded to always be :position. Of course, this should become configureable.

However, the code contains statements such as the following:

    |> Ecto.Multi.update_all(:decremented_higher_siblings_1, from( p in later_siblings, update: [set: [position: fragment("- (? - 1)", p.position)]]), []).

Note here the update: [set: ...] part (see the documentation of Ecto.Query.update.

I know Ecto.Query.field exists to set a dynamic field name, but as update uses a keyword list, I have no idea how to properly set the keyword list key there (as the line still is supposed to be read as macro, with the p variable available).

How to do this?

Marked As Solved

prem-prakash

prem-prakash

I could do that like this:

     update_args = Keyword.new([{f, new}])

     from(
       a in table,
       update: [set: ^update_args],
       where: field(a, ^f) == ^old
     )
     |> MyApp.Repo.update_all([])

Also Liked

halostatue

halostatue

For people, like me, who need this to be sort-of generalized, the following MOSTLY works. It turns out that I needed to do {:replace, columns} rather than :replace_all_except_primary_key because my input data was not including that, so there’s some behind the scenes stuff coming in Ecto 3.0 which will make this very clean, but this will generalize this in the short term.

defmodule ConflictUpdate do
  @moduledoc """
  A function to create an update query for an `on_conflict:` clause in
  `insert_all`.
  """

  @doc "A function to create an update query for a schema."
  @spec conflict_update(Ecto.Schema.t(), :replace_all | :replace_all_except_primary_key |
                               {:replace, list(atom)}) :: Macro.t()
  defmacro conflict_update(schema, pattern) do
    e_schema = Macro.expand_once(schema, __CALLER__)
    e_pattern = Macro.expand_once(pattern, __CALLER__)

    update_args =
      e_schema
      |> columns(e_pattern)
      |> Enum.map(& {&1, {:fragment, [], ["EXCLUDED.#{&1}"]}})
      |> Keyword.new

    {:update, [context: Elixir, import: Ecto.Query],
      [
        schema,
        [
          set: update_args
        ]
      ]
    }
  end

  defp columns(schema, :replace_all), do: schema.__schema__(:fields)

  defp columns(schema, :replace_all_except_primary_key),
  do: schema.__schema__(:fields) -- schema.__schema__(:primary_key)

  defp columns(_schema, {:replace, fields}), do: fields
end
Qqwy

Qqwy

TypeCheck Core Team

Wonderful! Thank you very much for solving this problem. :slight_smile:

Where Next?

Popular in Questions Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
vac
Hi, I’m quite new in Elixir and I’m trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and I...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New

Other popular topics Top

chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
marick
I had some trouble figuring out how to make many-to-many associations work. Once I got it working, I wrote a blog post. Because I’m a nov...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New

We're in Beta

About us Mission Statement