I’d like to create an abstraction of the Ecto.Repo.insert_or_update function which will allow me to pass in the key by which to check if the record exists. This would allow me to write a single function to insert or update records in my database for multiple schemas. I’m looking for some guidance on how to do this using metaprogramming.
Below is the sample code for this, take from the example on Hex: https://hexdocs.pm/ecto/Ecto.Repo.html#c:insert_or_update/2
I want to pass three variables to my generic function: model
, key
and params
.
-
model
is name of the schema I am inserting/updating -
key
is the name of the field in the model by which I want to do a lookup to check if a record exists -
params
is the data I want to update.
For example, say I am getting user data from an external source that I want to update. The parameter values would look like this:
model = %User{}
key = :name
params = %{name: "John", email: "john@doe.com", dob: "1970-01-01"}
I’d like to pass in these values to the following function to lookup the user by name and update his record if he exists, or insert it otherwise. However, this isn’t working:
def persist(model, key, params) do
quote do
case Repo.get_by(model, unquote(key) params[key]) do
nil -> struct(model)
record -> record
end
|> model.changeset(params)
|> Repo.insert_or_update
end
end
The code unquote(key)
renders as :name
, whereas Ecto.Repo.get_by
requires it to be in the format name:
I’d love some guidance here. I’m new to metaprogramming.
Thanks!