@@ -42,6 +42,23 @@ defmodule Ecto.Repo.EmbeddedTest do
4242 end
4343 end
4444
45+ defmodule DeepEmbed do
46+ use Ecto.Schema
47+
48+ embedded_schema do
49+ embeds_one :embed , MyEmbed
50+ embeds_many :embeds , MyEmbed
51+ end
52+ end
53+
54+ defmodule DeepSchema do
55+ use Ecto.Schema
56+
57+ schema "deep_schema" do
58+ embeds_one :deep_embed , DeepEmbed
59+ end
60+ end
61+
4562 @ uuid "30313233-3435-4637-9839-616263646566"
4663
4764 ## insert
@@ -203,6 +220,9 @@ defmodule Ecto.Repo.EmbeddedTest do
203220 TestRepo . insert! ( % MySchema { embed: % MyEmbed { x: "xyz" } , embeds: [ % MyEmbed { x: "xyz" } ] } )
204221 refute_received { :transaction , _ , _ }
205222
223+ TestRepo . insert! ( % MySchema { embed: % MyEmbed { x: "xyz" , sub_embed: % SubEmbed { y: "xyz" } } } )
224+ refute_received { :transaction , _ , _ }
225+
206226 embed =
207227 % MyEmbed { x: "xyz" }
208228 |> Ecto.Changeset . change ( )
@@ -292,6 +312,57 @@ defmodule Ecto.Repo.EmbeddedTest do
292312 assert_received { :prepared_in_transaction? , true }
293313 end
294314
315+ test "runs embed prepare callbacks surfaced from a map in struct data in transaction" do
316+ sub_embed = embed_changeset_with_prepare ( % SubEmbed { y: "xyz" } )
317+ deep_embed = % DeepEmbed { embed: % { x: "xyz" , sub_embed: sub_embed } }
318+
319+ TestRepo . insert! ( % DeepSchema { deep_embed: deep_embed } )
320+ assert_received { :transaction , _ , _ }
321+ assert_received { :prepared_in_transaction? , true }
322+ end
323+
324+ test "runs embed prepare callbacks surfaced from a struct in struct data in transaction" do
325+ sub_embed = embed_changeset_with_prepare ( % SubEmbed { y: "xyz" } )
326+ deep_embed = % DeepEmbed { embed: % MyEmbed { x: "xyz" , sub_embed: sub_embed } }
327+
328+ TestRepo . insert! ( % DeepSchema { deep_embed: deep_embed } )
329+ assert_received { :transaction , _ , _ }
330+ assert_received { :prepared_in_transaction? , true }
331+ end
332+
333+ test "runs embed prepare callbacks surfaced from a list in struct data in transaction" do
334+ embed_with_prepare = embed_changeset_with_prepare ( % MyEmbed { x: "xyz" } )
335+ deep_embed = % DeepEmbed { embeds: [ % MyEmbed { x: "abc" } , embed_with_prepare ] }
336+
337+ TestRepo . insert! ( % DeepSchema { deep_embed: deep_embed } )
338+ assert_received { :transaction , _ , _ }
339+ assert_received { :prepared_in_transaction? , true }
340+ end
341+
342+ test "runs embed prepare callbacks surfaced from a changeset without action in struct data in transaction" do
343+ sub_embed = embed_changeset_with_prepare ( % SubEmbed { y: "xyz" } )
344+ embed_without_action = Ecto.Changeset . change ( % MyEmbed { x: "xyz" , sub_embed: sub_embed } )
345+ deep_embed = % DeepEmbed { embed: embed_without_action }
346+
347+ TestRepo . insert! ( % DeepSchema { deep_embed: deep_embed } )
348+ assert_received { :transaction , _ , _ }
349+ assert_received { :prepared_in_transaction? , true }
350+ end
351+
352+ test "does not run embed prepare callbacks in struct data overridden by changes" do
353+ overridden_embed = embed_changeset_with_prepare ( % MyEmbed { x: "xyz" } )
354+ deep_embed = Ecto.Changeset . change ( % DeepEmbed { embed: overridden_embed } )
355+ deep_embed = % { deep_embed | changes: % { embed: nil } }
356+
357+ % DeepSchema { }
358+ |> Ecto.Changeset . change ( )
359+ |> Ecto.Changeset . put_embed ( :deep_embed , deep_embed )
360+ |> TestRepo . insert! ( )
361+
362+ refute_received { :transaction , _ , _ }
363+ refute_received { :prepared_in_transaction? , _ }
364+ end
365+
295366 test "raises on embed changesets for another struct" do
296367 changeset = Ecto.Changeset . change ( % MySchema { } )
297368 embed = % Ecto.Changeset { data: % URI { } , valid?: true }
0 commit comments