Repository: elixir-ecto/ecto
Pull request #4230 (2023-07-14 08:03:25)

Add parent prefix to association parent on_delete query
Resolved https://github.com/elixir-ecto/ecto/issues/4225

Seeking initial feedback before I try this out in a local project.

From what I can tell, this should be the only place where this needs to be handled for all of the associations that support this option?

I could use some pointers on testing. I didn't see any obvious place to add tests. It doesn't look like the on_delete queries are tested in repo tests, I assume because the query is not returned anywhere in the public API. Maybe integration test?

josevalim: For the tests, take a look at many_to_many. It seems we have some tests to verify the proper `delete_all` queries are sent and you can start asserting the prefix on those. Also note that integration tests are failing. It may be that you should set the query prefix only the the parent  has a query prefix (otherwise you may discard the default prefix of the schema).
josevalim: Perhaps that's covered for many to many but not the other association types. So you can mirror those tests into the other associations. :)
josevalim: Looks good to me @tfwright! Can you please do the same changes for `nillify_all` and include tests? It also has the wrong behaviour. :)
tfwright: @josevalim I think the change handles both behaviors but I added tests I think should prove it

Patch:
diff --git a/lib/ecto/association.ex b/lib/ecto/association.ex
index 0b9ae570..4da3269b 100644
--- a/lib/ecto/association.ex
+++ b/lib/ecto/association.ex
@@ -996,7 +996,14 @@ defmodule Ecto.Association.Has do
          parent
        ) do
     if value = Map.get(parent, owner_key) do
-      from x in queryable, where: field(x, ^related_key) == ^value
+      query = from x in queryable, where: field(x, ^related_key) == ^value
+
+      parent
+      |> Ecto.get_meta(:prefix)
+      |> case do
+        nil -> query
+        prefix -> Ecto.Query.put_query_prefix(query, prefix)
+      end
     end
   end
 end


Test patch:
diff --git a/test/ecto/repo/has_assoc_test.exs b/test/ecto/repo/has_assoc_test.exs
index b2af1efe..48831c8c 100644
--- a/test/ecto/repo/has_assoc_test.exs
+++ b/test/ecto/repo/has_assoc_test.exs
@@ -41,11 +41,51 @@ defmodule Ecto.Repo.HasAssocTest do
       has_one :assoc, MyAssoc, on_replace: :delete
       has_one :nilify_assoc, MyAssoc, on_replace: :nilify
       has_one :delete_assoc, MyAssoc
+      has_one :on_delete_delete_assoc, MyAssoc, on_delete: :delete_all
+      has_one :on_delete_nilify_assoc, MyAssoc, on_delete: :nilify_all
       has_many :assocs, MyAssoc, on_replace: :delete
       has_many :delete_assocs, MyAssoc
+      has_many :on_delete_delete_assocs, MyAssoc, on_delete: :delete_all
+      has_many :on_delete_nilify_assocs, MyAssoc, on_delete: :nilify_all
     end
   end
 
+  test "on delete deleting has_one assoc preserves parent schema prefix" do
+    %MySchema{id: 1}
+    |> Ecto.put_meta(prefix: "prefix")
+    |> Ecto.Changeset.change
+    |> TestRepo.delete!()
+
+    assert_received {:delete_all, %{prefix: "prefix", from: %{source: {"my_assoc", _}}}}
+  end
+
+  test "on delete deleting has_many assocs preserves parent schema prefix" do
+    %MySchema{id: 1}
+    |> Ecto.put_meta(prefix: "prefix")
+    |> Ecto.Changeset.change
+    |> TestRepo.delete!()
+
+    assert_received {:delete_all, %{prefix: "prefix", from: %{source: {"my_assoc", _}}}}
+  end
+
+  test "on delete nilifying has_one assoc preserves parent schema prefix" do
+    %MySchema{id: 1}
+    |> Ecto.put_meta(prefix: "prefix")
+    |> Ecto.Changeset.change
+    |> TestRepo.delete!()
+
+    assert_received {:update_all, %{prefix: "prefix", from: %{source: {"my_assoc", _}}}}
+  end
+
+  test "on delete nilifying has_many assocs preserves parent schema prefix" do
+    %MySchema{id: 1}
+    |> Ecto.put_meta(prefix: "prefix")
+    |> Ecto.Changeset.change
+    |> TestRepo.delete!()
+
+    assert_received {:update_all, %{prefix: "prefix", from: %{source: {"my_assoc", _}}}}
+  end
+
   test "handles assocs on insert" do
     sample = %MyAssoc{x: "xyz"}