diff --git a/lib/data_layer.ex b/lib/data_layer.ex index 5183c62..dbea911 100644 --- a/lib/data_layer.ex +++ b/lib/data_layer.ex @@ -1359,6 +1359,7 @@ defmodule AshSqlite.DataLayer do changeset.context ) |> Ecto.Query.select(^select) + |> pkey_filter(changeset.data) case AshSql.Atomics.query_with_atomics( resource, @@ -1410,6 +1411,15 @@ defmodule AshSqlite.DataLayer do end end + defp pkey_filter(query, %resource{} = record) do + pkey = + record + |> Map.take(Ash.Resource.Info.primary_key(resource)) + |> Map.to_list() + + Ecto.Query.where(query, ^pkey) + end + @impl true def destroy(resource, %{data: record} = changeset) do ecto_changeset = ecto_changeset(record, changeset, :delete) diff --git a/test/update_test.exs b/test/update_test.exs new file mode 100644 index 0000000..a9e81b8 --- /dev/null +++ b/test/update_test.exs @@ -0,0 +1,46 @@ +defmodule AshSqlite.Test.UpdateTest do + use AshSqlite.RepoCase, async: false + alias AshSqlite.Test.Post + + require Ash.Query + + test "updating a record when multiple records are in the table will only update the desired record" do + # This test is here because of a previous bug in update that caused + # all records in the table to be updated. + id_1 = Ash.UUID.generate() + id_2 = Ash.UUID.generate() + + new_post_1 = + Post + |> Ash.Changeset.for_create(:create, %{ + id: id_1, + title: "new_post_1" + }) + |> Ash.create!() + + _new_post_2 = + Post + |> Ash.Changeset.for_create(:create, %{ + id: id_2, + title: "new_post_2" + }) + |> Ash.create!() + + {:ok, updated_post_1} = + new_post_1 + |> Ash.Changeset.for_update(:update, %{ + title: "new_post_1_updated" + }) + |> Ash.update() + + # It is deliberate that post 2 is re-fetched from the db after the + # update to post 1. This ensure that post 2 was not updated. + post_2 = Ash.get!(Post, id_2) + + assert updated_post_1.id == id_1 + assert updated_post_1.title == "new_post_1_updated" + + assert post_2.id == id_2 + assert post_2.title == "new_post_2" + end +end