Hey guys, I finally got the green light to upgrade our Phoenix/Elixir stack and I’m in the middle of updating what needs to be updated.
The issue I found is that moving from Ecto 3.3.3 to 3.10.1 (didn’t think it was a big jump without being a major version change when upgrading Phoenix) I see parts of the logic broken because the code expects Ecto.Repo.update!/2
to return the struct (as I see it says on the docs) but instead I see it returns an Ecto Changeset. I see this is expected on a bunch of places on the code so I’d like to know if there was a change in behavior and Changeset is the new return and the docs are outdated (which means I need to update a bunch of places in the code) or if this is a bug and I should report it and change to a lower version of Ecto?
Thanks in advance.
Hey @stoic.alchemist can you show code that exhibits this behavior, and the IO.inspect
output of the result? I have never seen this myself.
Sure thing, can’t show real code but I’ll emulate what’s happening:
iex> current_struct = %MyApp.MyModel{ key1: "value1"}
iex> updated_struct =
current_struct
|> Ecto.Changeset.change(key: "value2")
|> Ecto.Repo.update!
|> IO.inspect
#Ecto.Changeset<
action: nil,
changes: %{key: "value2"},
errors: [],
data: #MyApp.MyModel<>,
valid?: true
>
Please let me know if this is good enough, this is just a simplification of what’s happening, the real code goes around to a bunch of files (I’m also skipping the Model definition and such, I don’t think it’s important but I may be wrong)
Hey @stoic.alchemist is Ecto.Repo.update!
a typo? That function is not callable directly. Not being able to show real code is definitely going to be a bit tricky.
If you can’t show your code, can you show an example that reproduces this behavior?
2 Likes
You are not supposed to call Ecto.Repo
directly, you have to derive it via a macro in your own project. Then you use it like so: MyApp.Repo.update!
.
1 Like
Most definitely, we do have our own Repo definition, I’ll try to show as much as I can:
Repo definition:
defmodule MyApp.Repo do
use Ecto.Repo,
otp_app: :my_app,
adapter: Ecto.Adapters.Postgres
end
Model definition:
defmodule MyApp.MyModel do
use Ecto.Schema
import Ecto.Changeset
alias MyApp.MyModel
require Ecto.Query
schema "my_models" do
field :key, :string
@timestamps_opts [type: :utc_datetime_usec]
timestamps()
end
@fields [
:key
]
# A bunch of methods, around 200 lines or so
end
Now the Model it’s already initialized somewhere in the code:
# Somewhere inside a GenServer
my_model_struct
|> Ecto.Changeset.change(key: "value2")
|> MyApp.Repo.update!
|> IO.inspect() # Added to debug
This results in a:
#Ecto.Changeset<
action: nil,
changes: %{key: "value2"},
errors: [],
data: #MyApp.MyModel<>,
valid?: true
>
Being that I’m doing the upgrade I thought this was a change in behavior but the docs say otherwise
Ok, I found the reason why… sorry for all the fuzz… tests are failing because the unit test file has a setup to use a “fake” Repo that returns the given data, which in this case is an Ecto.Changeset, so… sorry for the noise
3 Likes
The docs indicate that this shouldn’t be possible, the return type of Ecto.Repo — Ecto v3.11.1 is Ecto.Schema.t()
. Without code we can run this is pretty tricky to sort out, I’ve not seen anything like that before.
1 Like
That’s a pretty weird and IMO unproductive test setup. I recommend you remove that fake repo.
Yes, I agree, I’ll figure out why that’s there and remove it if it’s not needed, this can hide bugs (or in this case waste time searching for not-bugs )
2 Likes