How do I see :state
for a given changeset from Ecto.Schema.Metadata
to know if a changeset is going to update
or insert
?
#Ecto.Changeset<
action: nil,
changes: %{
contents: [
#Ecto.Changeset<action: :update, changes: %{}, errors: [],
data: #ConstraintTest.Schema.Content<>, valid?: true>,
#Ecto.Changeset<
action: :update,
changes: %{},
errors: [id: {āhas already been takenā, []}],
data: #ConstraintTest.Schema.Content<>,
valid?: false
>
]
},
errors: [],
data: #ConstraintTest.Schema.Post<>,
valid?: false
There is āactionā.
right, so my action is nil
, but it still seems to know whether to insert
or update
the given changeset.
I can run Repo.insert_or_update
with the changeset and see whether or not it did an insert
or update
based on the [debug]
message. so i guess my question is answered, but still curious if you can see what its going to do before you Repo.insert_or_update
.
There is no way to always know if the data will be inserted or updated, as this operation is an upsert in most cases, the case when you can know is when you explicitly have the schema from a select and create a changeset with updated fields.
According to the Ecto.Repo docs, insert_or_update/2
requires loading the existing structs from the database in order to use it. So if you follow the pattern outlined in the docs and re-posted below, the result of the pattern matching in the case
block will indicate whether itāll be inserted or updated.
Please note that for this to work, you will have to load existing structs from the database.
result =
case MyRepo.get(Post, id) do
nil -> %Post{id: id} # Post not found, we build one (aka to be inserted)
post -> post # Post exists, let's use it (aka to be updated)
end
|> Post.changeset(changes)
|> MyRepo.insert_or_update
This makes sense because thereās no way to know if the upsert will be an update or insert until you hit the database at least once to see if the id is already present or not.