zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

assoc.exs (28816B)


      1 defmodule Ecto.Integration.AssocTest do
      2   use Ecto.Integration.Case, async: Application.compile_env(:ecto, :async_integration_tests, true)
      3 
      4   alias Ecto.Integration.TestRepo
      5   import Ecto.Query
      6 
      7   alias Ecto.Integration.Custom
      8   alias Ecto.Integration.Post
      9   alias Ecto.Integration.User
     10   alias Ecto.Integration.PostUser
     11   alias Ecto.Integration.Comment
     12   alias Ecto.Integration.Permalink
     13 
     14   test "has_many assoc" do
     15     p1 = TestRepo.insert!(%Post{title: "1"})
     16     p2 = TestRepo.insert!(%Post{title: "2"})
     17 
     18     %Comment{id: cid1} = TestRepo.insert!(%Comment{text: "1", post_id: p1.id})
     19     %Comment{id: cid2} = TestRepo.insert!(%Comment{text: "2", post_id: p1.id})
     20     %Comment{id: cid3} = TestRepo.insert!(%Comment{text: "3", post_id: p2.id})
     21 
     22     [c1, c2] = TestRepo.all Ecto.assoc(p1, :comments)
     23     assert c1.id == cid1
     24     assert c2.id == cid2
     25 
     26     [c1, c2, c3] = TestRepo.all Ecto.assoc([p1, p2], :comments)
     27     assert c1.id == cid1
     28     assert c2.id == cid2
     29     assert c3.id == cid3
     30   end
     31 
     32   test "has_one assoc" do
     33     p1 = TestRepo.insert!(%Post{title: "1"})
     34     p2 = TestRepo.insert!(%Post{title: "2"})
     35 
     36     %Permalink{id: lid1} = TestRepo.insert!(%Permalink{url: "1", post_id: p1.id})
     37     %Permalink{}         = TestRepo.insert!(%Permalink{url: "2"})
     38     %Permalink{id: lid3} = TestRepo.insert!(%Permalink{url: "3", post_id: p2.id})
     39 
     40     [l1, l3] = TestRepo.all Ecto.assoc([p1, p2], :permalink)
     41     assert l1.id == lid1
     42     assert l3.id == lid3
     43   end
     44 
     45   test "belongs_to assoc" do
     46     %Post{id: pid1} = TestRepo.insert!(%Post{title: "1"})
     47     %Post{id: pid2} = TestRepo.insert!(%Post{title: "2"})
     48 
     49     l1 = TestRepo.insert!(%Permalink{url: "1", post_id: pid1})
     50     l2 = TestRepo.insert!(%Permalink{url: "2"})
     51     l3 = TestRepo.insert!(%Permalink{url: "3", post_id: pid2})
     52 
     53     assert [p1, p2] = TestRepo.all Ecto.assoc([l1, l2, l3], :post)
     54     assert p1.id == pid1
     55     assert p2.id == pid2
     56   end
     57 
     58   test "has_many through assoc" do
     59     p1 = TestRepo.insert!(%Post{})
     60     p2 = TestRepo.insert!(%Post{})
     61 
     62     u1 = TestRepo.insert!(%User{name: "zzz"})
     63     u2 = TestRepo.insert!(%User{name: "aaa"})
     64 
     65     %Comment{} = TestRepo.insert!(%Comment{post_id: p1.id, author_id: u1.id})
     66     %Comment{} = TestRepo.insert!(%Comment{post_id: p1.id, author_id: u1.id})
     67     %Comment{} = TestRepo.insert!(%Comment{post_id: p1.id, author_id: u2.id})
     68     %Comment{} = TestRepo.insert!(%Comment{post_id: p2.id, author_id: u2.id})
     69 
     70     query = Ecto.assoc([p1, p2], :comments_authors) |> order_by([a], a.name)
     71     assert [^u2, ^u1] = TestRepo.all(query)
     72 
     73     # Dynamic through
     74     query = Ecto.assoc([p1, p2], [:comments, :author]) |> order_by([a], a.name)
     75     assert [^u2, ^u1] = TestRepo.all(query)
     76   end
     77 
     78   @tag :on_replace_nilify
     79   test "has_many through-through assoc leading" do
     80     p1 = TestRepo.insert!(%Post{})
     81     p2 = TestRepo.insert!(%Post{})
     82 
     83     u1 = TestRepo.insert!(%User{})
     84     u2 = TestRepo.insert!(%User{})
     85 
     86     pl1 = TestRepo.insert!(%Permalink{user_id: u1.id, url: "zzz"})
     87     pl2 = TestRepo.insert!(%Permalink{user_id: u2.id, url: "aaa"})
     88 
     89     %Comment{} = TestRepo.insert!(%Comment{post_id: p1.id, author_id: u1.id})
     90     %Comment{} = TestRepo.insert!(%Comment{post_id: p1.id, author_id: u1.id})
     91     %Comment{} = TestRepo.insert!(%Comment{post_id: p1.id, author_id: u2.id})
     92     %Comment{} = TestRepo.insert!(%Comment{post_id: p2.id, author_id: u2.id})
     93 
     94     query = Ecto.assoc([p1, p2], :comments_authors_permalinks) |> order_by([p], p.url)
     95     assert [^pl2, ^pl1] = TestRepo.all(query)
     96 
     97     # Dynamic through
     98     query = Ecto.assoc([p1, p2], [:comments, :author, :permalink]) |> order_by([p], p.url)
     99     assert [^pl2, ^pl1] = TestRepo.all(query)
    100   end
    101 
    102   test "has_many through-through assoc trailing" do
    103     p1  = TestRepo.insert!(%Post{})
    104     u1  = TestRepo.insert!(%User{})
    105     pl1 = TestRepo.insert!(%Permalink{user_id: u1.id, post_id: p1.id})
    106 
    107     %Comment{} = TestRepo.insert!(%Comment{post_id: p1.id, author_id: u1.id})
    108 
    109     query = Ecto.assoc([pl1], :post_comments_authors)
    110     assert [^u1] = TestRepo.all(query)
    111 
    112     # Dynamic through
    113     query = Ecto.assoc([pl1], [:post, :comments, :author])
    114     assert [^u1] = TestRepo.all(query)
    115   end
    116 
    117   test "has_many through has_many, many_to_many and has_many" do
    118     user1 = %User{id: uid1} = TestRepo.insert!(%User{name: "Gabriel"})
    119     %User{id: uid2} = TestRepo.insert!(%User{name: "Isadora"})
    120     %User{id: uid3} = TestRepo.insert!(%User{name: "Joey Mush"})
    121 
    122     p1 = TestRepo.insert!(%Post{title: "p1", author_id: uid1})
    123     p2 = TestRepo.insert!(%Post{title: "p2", author_id: uid2})
    124     p3 = TestRepo.insert!(%Post{title: "p3", author_id: uid2})
    125     TestRepo.insert!(%Post{title: "p4", author_id: uid3})
    126 
    127     TestRepo.insert_all "posts_users", [[post_id: p1.id, user_id: uid1],
    128                                         [post_id: p1.id, user_id: uid2],
    129                                         [post_id: p2.id, user_id: uid3]]
    130 
    131     [pid1, pid2, pid3] =
    132       Ecto.assoc(user1, :related_2nd_order_posts)
    133       |> TestRepo.all()
    134       |> Enum.map(fn %Post{id: id} -> id end)
    135       |> Enum.sort()
    136 
    137     assert p1.id == pid1
    138     assert p2.id == pid2
    139     assert p3.id == pid3
    140   end
    141 
    142   test "has_many through has_many, belongs_to and a nested has through" do
    143     user1 = TestRepo.insert!(%User{name: "Gabriel"})
    144     user2 = TestRepo.insert!(%User{name: "Isadora"})
    145     user3 = TestRepo.insert!(%User{name: "Joey"})
    146 
    147     post1 = TestRepo.insert!(%Post{title: "p1"})
    148     post2 = TestRepo.insert!(%Post{title: "p2"})
    149 
    150     TestRepo.insert!(%Comment{author_id: user1.id, text: "c1", post_id: post1.id})
    151     TestRepo.insert!(%Comment{author_id: user2.id, text: "c2", post_id: post1.id})
    152     TestRepo.insert!(%Comment{author_id: user3.id, text: "c3", post_id: post2.id})
    153 
    154     [u1_id, u2_id] =
    155       Ecto.assoc(user1, :co_commenters)
    156       |> TestRepo.all()
    157       |> Enum.map(fn %User{id: id} -> id end)
    158       |> Enum.sort()
    159 
    160     assert u1_id == user1.id
    161     assert u2_id == user2.id
    162   end
    163 
    164   test "has_many through two many_to_many associations" do
    165     user1 = %User{id: uid1} = TestRepo.insert!(%User{name: "Gabriel"})
    166     %User{id: uid2} = TestRepo.insert!(%User{name: "Isadora"})
    167     %User{id: uid3} = TestRepo.insert!(%User{name: "Joey Mush"})
    168 
    169     p1 = TestRepo.insert!(%Post{title: "p1", author_id: uid1})
    170     TestRepo.insert!(%Post{title: "p2", author_id: uid2})
    171     p3 = TestRepo.insert!(%Post{title: "p3", author_id: uid2})
    172     p4 = TestRepo.insert!(%Post{title: "p4", author_id: uid3})
    173 
    174     TestRepo.insert_all "posts_users", [[post_id: p3.id, user_id: uid1],
    175                                         [post_id: p3.id, user_id: uid2],
    176                                         [post_id: p1.id, user_id: uid3]]
    177 
    178     TestRepo.insert!(%PostUser{post_id: p1.id, user_id: uid2})
    179     TestRepo.insert!(%PostUser{post_id: p3.id, user_id: uid1})
    180     TestRepo.insert!(%PostUser{post_id: p3.id, user_id: uid2})
    181     TestRepo.insert!(%PostUser{post_id: p4.id, user_id: uid3})
    182 
    183     [u1, u2] =
    184       Ecto.assoc(user1, :users_through_schema_posts)
    185       |> TestRepo.all()
    186       |> Enum.map(fn %User{id: id} -> id end)
    187       |> Enum.sort()
    188 
    189     assert uid1 == u1
    190     assert uid2 == u2
    191   end
    192 
    193   test "has_many through with where" do
    194     post1 = TestRepo.insert!(%Post{title: "p1"})
    195     post2 = TestRepo.insert!(%Post{title: "p2"})
    196     post3 = TestRepo.insert!(%Post{title: "p3"})
    197 
    198     author = TestRepo.insert!(%User{name: "john"})
    199 
    200     TestRepo.insert!(%Comment{text: "1", lock_version: 1, post_id: post1.id, author_id: author.id})
    201     TestRepo.insert!(%Comment{text: "2", lock_version: 2, post_id: post2.id, author_id: author.id})
    202     TestRepo.insert!(%Comment{text: "3", lock_version: 2, post_id: post3.id, author_id: author.id})
    203 
    204     [p2, p3] = Ecto.assoc(author, :v2_comments_posts) |> TestRepo.all() |> Enum.sort_by(&(&1.id))
    205     assert p2.id == post2.id
    206     assert p3.id == post3.id
    207   end
    208 
    209   test "many_to_many assoc" do
    210     p1 = TestRepo.insert!(%Post{title: "1"})
    211     p2 = TestRepo.insert!(%Post{title: "2"})
    212     p3 = TestRepo.insert!(%Post{title: "3"})
    213 
    214     %User{id: uid1} = TestRepo.insert!(%User{name: "john"})
    215     %User{id: uid2} = TestRepo.insert!(%User{name: "mary"})
    216 
    217     TestRepo.insert_all "posts_users", [[post_id: p1.id, user_id: uid1],
    218                                         [post_id: p1.id, user_id: uid2],
    219                                         [post_id: p2.id, user_id: uid2]]
    220 
    221     [u1, u2] = TestRepo.all Ecto.assoc([p1], :users)
    222     assert u1.id == uid1
    223     assert u2.id == uid2
    224 
    225     [u2] = TestRepo.all Ecto.assoc([p2], :users)
    226     assert u2.id == uid2
    227     [] = TestRepo.all Ecto.assoc([p3], :users)
    228 
    229     [u1, u2, u2] = TestRepo.all Ecto.assoc([p1, p2, p3], :users)
    230     assert u1.id == uid1
    231     assert u2.id == uid2
    232   end
    233 
    234   ## Changesets
    235 
    236   test "has_one changeset assoc (on_replace: :delete)" do
    237     # Insert new
    238     changeset =
    239       %Post{title: "1"}
    240       |> Ecto.Changeset.change
    241       |> Ecto.Changeset.put_assoc(:permalink, %Permalink{url: "1"})
    242     post = TestRepo.insert!(changeset)
    243     assert post.permalink.id
    244     assert post.permalink.post_id == post.id
    245     assert post.permalink.url == "1"
    246     post = TestRepo.get!(from(Post, preload: [:permalink]), post.id)
    247     assert post.permalink.url == "1"
    248 
    249     # Replace with new
    250     changeset =
    251       post
    252       |> Ecto.Changeset.change
    253       |> Ecto.Changeset.put_assoc(:permalink, %Permalink{url: "2"})
    254     post = TestRepo.update!(changeset)
    255     assert post.permalink.id
    256     assert post.permalink.post_id == post.id
    257     assert post.permalink.url == "2"
    258     post = TestRepo.get!(from(Post, preload: [:permalink]), post.id)
    259     assert post.permalink.url == "2"
    260 
    261     # Replacing with existing
    262     existing = TestRepo.insert!(%Permalink{url: "3"})
    263     changeset =
    264       post
    265       |> Ecto.Changeset.change
    266       |> Ecto.Changeset.put_assoc(:permalink, existing)
    267     post = TestRepo.update!(changeset)
    268     assert post.permalink.id
    269     assert post.permalink.post_id == post.id
    270     assert post.permalink.url == "3"
    271     post = TestRepo.get!(from(Post, preload: [:permalink]), post.id)
    272     assert post.permalink.url == "3"
    273 
    274     # Replacing with nil (on_replace: :delete)
    275     changeset =
    276       post
    277       |> Ecto.Changeset.change
    278       |> Ecto.Changeset.put_assoc(:permalink, nil)
    279     post = TestRepo.update!(changeset)
    280     refute post.permalink
    281     post = TestRepo.get!(from(Post, preload: [:permalink]), post.id)
    282     refute post.permalink
    283 
    284     assert [0] == TestRepo.all(from(p in Permalink, select: count(p.id)))
    285   end
    286 
    287   test "has_one changeset assoc (on_replace: :delete_if_exists)" do
    288     permalink = TestRepo.insert!(%Permalink{url: "1"})
    289     post = TestRepo.insert!(%Post{title: "1", permalink: permalink, force_permalink: permalink})
    290     TestRepo.delete!(permalink)
    291 
    292     assert_raise Ecto.StaleEntryError, fn ->
    293       post
    294       |> Ecto.Changeset.change()
    295       |> Ecto.Changeset.put_assoc(:permalink, nil)
    296       |> TestRepo.update!()
    297     end
    298 
    299     post =
    300       post
    301       |> Ecto.Changeset.change()
    302       |> Ecto.Changeset.put_assoc(:force_permalink, nil)
    303       |> TestRepo.update!()
    304 
    305     assert post.force_permalink == nil
    306   end
    307 
    308   @tag :on_replace_nilify
    309   test "has_one changeset assoc (on_replace: :nilify)" do
    310     # Insert new
    311     changeset =
    312       %User{name: "1"}
    313       |> Ecto.Changeset.change
    314       |> Ecto.Changeset.put_assoc(:permalink, %Permalink{url: "1"})
    315     user = TestRepo.insert!(changeset)
    316     assert user.permalink.id
    317     assert user.permalink.user_id == user.id
    318     assert user.permalink.url == "1"
    319     user = TestRepo.get!(from(User, preload: [:permalink]), user.id)
    320     assert user.permalink.url == "1"
    321 
    322     # Replace with new
    323     changeset =
    324       user
    325       |> Ecto.Changeset.change
    326       |> Ecto.Changeset.put_assoc(:permalink, %Permalink{url: "2"})
    327     user = TestRepo.update!(changeset)
    328     assert user.permalink.id
    329     assert user.permalink.user_id == user.id
    330     assert user.permalink.url == "2"
    331     user = TestRepo.get!(from(User, preload: [:permalink]), user.id)
    332     assert user.permalink.url == "2"
    333 
    334     # Replacing with nil (on_replace: :nilify)
    335     changeset =
    336       user
    337       |> Ecto.Changeset.change
    338       |> Ecto.Changeset.put_assoc(:permalink, nil)
    339     user = TestRepo.update!(changeset)
    340     refute user.permalink
    341     user = TestRepo.get!(from(User, preload: [:permalink]), user.id)
    342     refute user.permalink
    343 
    344     assert [2] == TestRepo.all(from(p in Permalink, select: count(p.id)))
    345   end
    346 
    347   @tag :on_replace_update
    348   test "has_one changeset assoc (on_replace: :update)" do
    349     # Insert new
    350     changeset =
    351       %Post{title: "1"}
    352       |> Ecto.Changeset.change
    353       |> Ecto.Changeset.put_assoc(:update_permalink, %Permalink{url: "1"})
    354     post = TestRepo.insert!(changeset)
    355     assert post.update_permalink.id
    356     assert post.update_permalink.post_id == post.id
    357     assert post.update_permalink.url == "1"
    358     post = TestRepo.get!(from(Post, preload: [:update_permalink]), post.id)
    359     assert post.update_permalink.url == "1"
    360 
    361     perma = post.update_permalink
    362 
    363     # Put on update
    364     changeset =
    365       post
    366       |> Ecto.Changeset.change()
    367       |> Ecto.Changeset.put_assoc(:update_permalink, %{url: "2"})
    368     post = TestRepo.update!(changeset)
    369     assert post.update_permalink.id == perma.id
    370     assert post.update_permalink.post_id == post.id
    371     assert post.update_permalink.url == "2"
    372     post = TestRepo.get!(from(Post, preload: [:update_permalink]), post.id)
    373     assert post.update_permalink.url == "2"
    374 
    375     # Cast on update
    376     changeset =
    377       post
    378       |> Ecto.Changeset.cast(%{update_permalink: %{url: "3"}}, [])
    379       |> Ecto.Changeset.cast_assoc(:update_permalink)
    380     post = TestRepo.update!(changeset)
    381     assert post.update_permalink.id == perma.id
    382     assert post.update_permalink.post_id == post.id
    383     assert post.update_permalink.url == "3"
    384     post = TestRepo.get!(from(Post, preload: [:update_permalink]), post.id)
    385     assert post.update_permalink.url == "3"
    386 
    387     # Replace with new struct
    388     assert_raise RuntimeError, ~r"you are only allowed\sto update the existing entry", fn ->
    389       post
    390       |> Ecto.Changeset.change()
    391       |> Ecto.Changeset.put_assoc(:update_permalink, %Permalink{url: "4"})
    392     end
    393 
    394     # Replace with existing struct
    395     assert_raise RuntimeError, ~r"you are only allowed\sto update the existing entry", fn ->
    396       post
    397       |> Ecto.Changeset.change()
    398       |> Ecto.Changeset.put_assoc(:update_permalink, TestRepo.insert!(%Permalink{url: "5"}))
    399     end
    400 
    401     # Replacing with nil (on_replace: :update)
    402     changeset =
    403       post
    404       |> Ecto.Changeset.change
    405       |> Ecto.Changeset.put_assoc(:update_permalink, nil)
    406     post = TestRepo.update!(changeset)
    407     refute post.update_permalink
    408     post = TestRepo.get!(from(Post, preload: [:update_permalink]), post.id)
    409     refute post.update_permalink
    410 
    411     assert [2] == TestRepo.all(from(p in Permalink, select: count(p.id)))
    412   end
    413 
    414   test "has_many changeset assoc (on_replace: :delete)" do
    415     c1 = TestRepo.insert! %Comment{text: "1"}
    416     c2 = %Comment{text: "2"}
    417 
    418     # Inserting
    419     changeset =
    420       %Post{title: "1"}
    421       |> Ecto.Changeset.change
    422       |> Ecto.Changeset.put_assoc(:comments, [c2])
    423     post = TestRepo.insert!(changeset)
    424     [c2] = post.comments
    425     assert c2.id
    426     assert c2.post_id == post.id
    427     post = TestRepo.get!(from(Post, preload: [:comments]), post.id)
    428     [c2] = post.comments
    429     assert c2.text == "2"
    430 
    431     # Updating
    432     changeset =
    433       post
    434       |> Ecto.Changeset.change
    435       |> Ecto.Changeset.put_assoc(:comments, [Ecto.Changeset.change(c1, text: "11"),
    436                                               Ecto.Changeset.change(c2, text: "22")])
    437     post = TestRepo.update!(changeset)
    438     [c1, _c2] = post.comments |> Enum.sort_by(&(&1.id))
    439     assert c1.id
    440     assert c1.post_id == post.id
    441     post = TestRepo.get!(from(Post, preload: [:comments]), post.id)
    442     [c1, c2] = post.comments |> Enum.sort_by(&(&1.id))
    443     assert c1.text == "11"
    444     assert c2.text == "22"
    445 
    446     # Replacing (on_replace: :delete)
    447     changeset =
    448       post
    449       |> Ecto.Changeset.change
    450       |> Ecto.Changeset.put_assoc(:comments, [])
    451     post = TestRepo.update!(changeset)
    452     assert post.comments == []
    453     post = TestRepo.get!(from(Post, preload: [:comments]), post.id)
    454     assert post.comments == []
    455 
    456     assert [0] == TestRepo.all(from(c in Comment, select: count(c.id)))
    457   end
    458 
    459   test "has_many changeset assoc (on_replace: :delete_if_exists)" do
    460     comment = TestRepo.insert!(%Comment{text: "1"})
    461     post = TestRepo.insert!(%Post{title: "1", comments: [comment], force_comments: [comment]})
    462 
    463     TestRepo.delete!(comment)
    464 
    465     assert_raise Ecto.StaleEntryError, fn ->
    466       post
    467       |> Ecto.Changeset.change()
    468       |> Ecto.Changeset.put_assoc(:comments, [])
    469       |> TestRepo.update!()
    470     end
    471 
    472     post =
    473       post
    474       |> Ecto.Changeset.change()
    475       |> Ecto.Changeset.put_assoc(:force_comments, [])
    476       |> TestRepo.update!()
    477 
    478     assert post.force_comments == []
    479   end
    480 
    481   test "has_many changeset assoc (on_replace: :nilify)" do
    482     c1 = TestRepo.insert! %Comment{text: "1"}
    483     c2 = %Comment{text: "2"}
    484 
    485     # Inserting
    486     changeset =
    487       %User{name: "1"}
    488       |> Ecto.Changeset.change
    489       |> Ecto.Changeset.put_assoc(:comments, [c1, c2])
    490     user = TestRepo.insert!(changeset)
    491     [c1, c2] = user.comments
    492     assert c1.id
    493     assert c1.author_id == user.id
    494     assert c2.id
    495     assert c2.author_id == user.id
    496     user = TestRepo.get!(from(User, preload: [:comments]), user.id)
    497     [c1, c2] = user.comments
    498     assert c1.text == "1"
    499     assert c2.text == "2"
    500 
    501     # Replacing (on_replace: :nilify)
    502     changeset =
    503       user
    504       |> Ecto.Changeset.change
    505       |> Ecto.Changeset.put_assoc(:comments, [])
    506     user = TestRepo.update!(changeset)
    507     assert user.comments == []
    508     user = TestRepo.get!(from(User, preload: [:comments]), user.id)
    509     assert user.comments == []
    510 
    511     assert [2] == TestRepo.all(from(c in Comment, select: count(c.id)))
    512   end
    513 
    514   test "many_to_many changeset assoc" do
    515     u1 = TestRepo.insert! %User{name: "1"}
    516     u2 = %User{name: "2"}
    517 
    518     # Inserting
    519     changeset =
    520       %Post{title: "1"}
    521       |> Ecto.Changeset.change
    522       |> Ecto.Changeset.put_assoc(:users, [u2])
    523     post = TestRepo.insert!(changeset)
    524     [u2] = post.users
    525     assert u2.id
    526     post = TestRepo.get!(from(Post, preload: [:users]), post.id)
    527     [u2] = post.users
    528     assert u2.name == "2"
    529 
    530     assert [1] == TestRepo.all(from(j in "posts_users", select: count(j.post_id)))
    531 
    532     # Updating
    533     changeset =
    534       post
    535       |> Ecto.Changeset.change
    536       |> Ecto.Changeset.put_assoc(:users, [Ecto.Changeset.change(u1, name: "11"),
    537                                            Ecto.Changeset.change(u2, name: "22")])
    538     post = TestRepo.update!(changeset)
    539     [u1, _u2] = post.users |> Enum.sort_by(&(&1.id))
    540     assert u1.id
    541     post = TestRepo.get!(from(Post, preload: [:users]), post.id)
    542     [u1, u2] = post.users |> Enum.sort_by(&(&1.id))
    543     assert u1.name == "11"
    544     assert u2.name == "22"
    545 
    546     assert [2] == TestRepo.all(from(j in "posts_users", select: count(j.post_id)))
    547 
    548     # Replacing (on_replace: :delete)
    549     changeset =
    550       post
    551       |> Ecto.Changeset.change
    552       |> Ecto.Changeset.put_assoc(:users, [])
    553     post = TestRepo.update!(changeset)
    554     assert post.users == []
    555     post = TestRepo.get!(from(Post, preload: [:users]), post.id)
    556     assert post.users == []
    557 
    558     assert [0] == TestRepo.all(from(j in "posts_users", select: count(j.post_id)))
    559     assert [2] == TestRepo.all(from(c in User, select: count(c.id)))
    560   end
    561 
    562   test "many_to_many changeset assoc with schema" do
    563     p1 = TestRepo.insert! %Post{title: "1"}
    564     p2 = %Post{title: "2"}
    565 
    566     # Inserting
    567     changeset =
    568       %User{name: "1"}
    569       |> Ecto.Changeset.change
    570       |> Ecto.Changeset.put_assoc(:schema_posts, [p2])
    571     user = TestRepo.insert!(changeset)
    572     [p2] = user.schema_posts
    573     assert p2.id
    574     user = TestRepo.get!(from(User, preload: [:schema_posts]), user.id)
    575     [p2] = user.schema_posts
    576     assert p2.title == "2"
    577 
    578     [up2] = TestRepo.all(PostUser) |> Enum.sort_by(&(&1.id))
    579     assert up2.post_id == p2.id
    580     assert up2.user_id == user.id
    581     assert up2.inserted_at
    582     assert up2.updated_at
    583 
    584     # Updating
    585     changeset =
    586       user
    587       |> Ecto.Changeset.change
    588       |> Ecto.Changeset.put_assoc(:schema_posts, [Ecto.Changeset.change(p1, title: "11"),
    589                                                   Ecto.Changeset.change(p2, title: "22")])
    590     user = TestRepo.update!(changeset)
    591     [p1, _p2] = user.schema_posts |> Enum.sort_by(&(&1.id))
    592     assert p1.id
    593     user = TestRepo.get!(from(User, preload: [:schema_posts]), user.id)
    594     [p1, p2] = user.schema_posts |> Enum.sort_by(&(&1.id))
    595     assert p1.title == "11"
    596     assert p2.title == "22"
    597 
    598     [_up2, up1] = TestRepo.all(PostUser) |> Enum.sort_by(&(&1.id))
    599     assert up1.post_id == p1.id
    600     assert up1.user_id == user.id
    601     assert up1.inserted_at
    602     assert up1.updated_at
    603   end
    604 
    605   test "many_to_many changeset assoc with self-referential binary_id" do
    606     assoc_custom = TestRepo.insert!(%Custom{uuid: Ecto.UUID.generate()})
    607     custom = TestRepo.insert!(%Custom{customs: [assoc_custom]})
    608 
    609     custom = Custom |> TestRepo.get!(custom.bid) |> TestRepo.preload(:customs)
    610     assert [_] = custom.customs
    611 
    612     custom =
    613       custom
    614       |> Ecto.Changeset.change(%{})
    615       |> Ecto.Changeset.put_assoc(:customs, [])
    616       |> TestRepo.update!
    617     assert [] = custom.customs
    618 
    619     custom = Custom |> TestRepo.get!(custom.bid) |> TestRepo.preload(:customs)
    620     assert [] = custom.customs
    621   end
    622 
    623   @tag :unique_constraint
    624   test "has_many changeset assoc with constraints" do
    625     author = TestRepo.insert!(%User{name: "john doe"})
    626     p1 = TestRepo.insert!(%Post{title: "hello", author_id: author.id})
    627     TestRepo.insert!(%Post{title: "world", author_id: author.id})
    628 
    629     # Asserts that `unique_constraint` for `uuid` exists
    630     assert_raise Ecto.ConstraintError, fn ->
    631       TestRepo.insert!(%Post{title: "another", author_id: author.id, uuid: p1.uuid})
    632     end
    633 
    634     author = TestRepo.preload author, [:posts]
    635     posts_params = Enum.map author.posts, fn %Post{uuid: u} ->
    636       %{uuid: u, title: "fresh"}
    637     end
    638 
    639     # This will only work if we delete before performing inserts
    640     changeset =
    641       author
    642       |> Ecto.Changeset.cast(%{"posts" => posts_params}, ~w())
    643       |> Ecto.Changeset.cast_assoc(:posts)
    644     author = TestRepo.update! changeset
    645     assert Enum.map(author.posts, &(&1.title)) == ["fresh", "fresh"]
    646   end
    647 
    648   test "belongs_to changeset assoc" do
    649     # Insert new
    650     changeset =
    651       %Permalink{url: "1"}
    652       |> Ecto.Changeset.change
    653       |> Ecto.Changeset.put_assoc(:post, %Post{title: "1"})
    654     perma = TestRepo.insert!(changeset)
    655     post = perma.post
    656     assert perma.post_id
    657     assert perma.post_id == post.id
    658     assert perma.post.title == "1"
    659 
    660     # Replace with new
    661     changeset =
    662       perma
    663       |> Ecto.Changeset.change
    664       |> Ecto.Changeset.put_assoc(:post, %Post{title: "2"})
    665     perma = TestRepo.update!(changeset)
    666     assert perma.post.id != post.id
    667     post = perma.post
    668     assert perma.post_id
    669     assert perma.post_id == post.id
    670     assert perma.post.title == "2"
    671 
    672     # Replace with existing
    673     existing = TestRepo.insert!(%Post{title: "3"})
    674     changeset =
    675       perma
    676       |> Ecto.Changeset.change
    677       |> Ecto.Changeset.put_assoc(:post, existing)
    678     perma = TestRepo.update!(changeset)
    679     post = perma.post
    680     assert perma.post_id == post.id
    681     assert perma.post_id == existing.id
    682     assert perma.post.title == "3"
    683 
    684     # Replace with nil
    685     changeset =
    686       perma
    687       |> Ecto.Changeset.change
    688       |> Ecto.Changeset.put_assoc(:post, nil)
    689     perma = TestRepo.update!(changeset)
    690     assert perma.post == nil
    691     assert perma.post_id == nil
    692   end
    693 
    694   test "belongs_to changeset assoc (on_replace: :update)" do
    695     # Insert new
    696     changeset =
    697       %Permalink{url: "1"}
    698       |> Ecto.Changeset.change
    699       |> Ecto.Changeset.put_assoc(:update_post, %Post{title: "1"})
    700     perma = TestRepo.insert!(changeset)
    701     post = perma.update_post
    702     assert perma.post_id
    703     assert perma.post_id == post.id
    704     assert perma.update_post.title == "1"
    705 
    706     # Casting on update
    707     changeset =
    708       perma
    709       |> Ecto.Changeset.cast(%{update_post: %{title: "2"}}, [])
    710       |> Ecto.Changeset.cast_assoc(:update_post)
    711     perma = TestRepo.update!(changeset)
    712     assert perma.update_post.id == post.id
    713     post = perma.update_post
    714     assert perma.post_id
    715     assert perma.post_id == post.id
    716     assert perma.update_post.title == "2"
    717 
    718     # Replace with nil
    719     changeset =
    720       perma
    721       |> Ecto.Changeset.change
    722       |> Ecto.Changeset.put_assoc(:update_post, nil)
    723     perma = TestRepo.update!(changeset)
    724     assert perma.update_post == nil
    725     assert perma.post_id == nil
    726   end
    727 
    728   test "inserting struct with associations" do
    729     tree = %Permalink{
    730       url: "root",
    731       post: %Post{
    732         title: "belongs_to",
    733         comments: [
    734           %Comment{text: "child 1"},
    735           %Comment{text: "child 2"},
    736         ]
    737       }
    738     }
    739 
    740     tree = TestRepo.insert!(tree)
    741     assert tree.id
    742     assert tree.post.id
    743     assert length(tree.post.comments) == 2
    744     assert Enum.all?(tree.post.comments, & &1.id)
    745 
    746     tree = TestRepo.get!(from(Permalink, preload: [post: :comments]), tree.id)
    747     assert tree.id
    748     assert tree.post.id
    749     assert length(tree.post.comments) == 2
    750     assert Enum.all?(tree.post.comments, & &1.id)
    751   end
    752 
    753   test "inserting struct with empty associations" do
    754     permalink = TestRepo.insert!(%Permalink{url: "root", post: nil})
    755     assert permalink.post == nil
    756 
    757     post = TestRepo.insert!(%Post{title: "empty", comments: []})
    758     assert post.comments == []
    759   end
    760 
    761   test "inserting changeset with empty cast associations" do
    762     changeset =
    763       %Permalink{}
    764       |> Ecto.Changeset.cast(%{url: "root", post: nil}, [:url])
    765       |> Ecto.Changeset.cast_assoc(:post)
    766     permalink = TestRepo.insert!(changeset)
    767     assert permalink.post == nil
    768 
    769     changeset =
    770       %Post{}
    771       |> Ecto.Changeset.cast(%{title: "root", comments: []}, [:title])
    772       |> Ecto.Changeset.cast_assoc(:comments)
    773     post = TestRepo.insert!(changeset)
    774     assert post.comments == []
    775   end
    776 
    777   test "inserting changeset with empty put associations" do
    778     changeset =
    779       %Permalink{}
    780       |> Ecto.Changeset.change()
    781       |> Ecto.Changeset.put_assoc(:post, nil)
    782     permalink = TestRepo.insert!(changeset)
    783     assert permalink.post == nil
    784 
    785     changeset =
    786       %Post{}
    787       |> Ecto.Changeset.change()
    788       |> Ecto.Changeset.put_assoc(:comments, [])
    789     post = TestRepo.insert!(changeset)
    790     assert post.comments == []
    791   end
    792 
    793   test "updating changeset with empty cast associations" do
    794     post = TestRepo.insert!(%Post{})
    795     c1 = TestRepo.insert!(%Comment{post_id: post.id})
    796     c2 = TestRepo.insert!(%Comment{post_id: post.id})
    797 
    798     assert TestRepo.all(Comment) == [c1, c2]
    799 
    800     post = TestRepo.get!(from(Post, preload: [:comments]), post.id)
    801 
    802     post
    803     |> Ecto.Changeset.change
    804     |> Ecto.Changeset.put_assoc(:comments, [])
    805     |> TestRepo.update!()
    806 
    807     assert TestRepo.all(Comment) == []
    808   end
    809 
    810   ## Dependent
    811 
    812   test "has_many assoc on delete deletes all" do
    813     post = TestRepo.insert!(%Post{})
    814     TestRepo.insert!(%Comment{post_id: post.id})
    815     TestRepo.insert!(%Comment{post_id: post.id})
    816     TestRepo.delete!(post)
    817 
    818     assert TestRepo.all(Comment) == []
    819     refute Process.get(Comment)
    820   end
    821 
    822   test "has_many assoc on delete nilifies all" do
    823     user = TestRepo.insert!(%User{})
    824     TestRepo.insert!(%Comment{author_id: user.id})
    825     TestRepo.insert!(%Comment{author_id: user.id})
    826     TestRepo.delete!(user)
    827 
    828     author_ids = Comment |> TestRepo.all() |> Enum.map(fn(comment) -> comment.author_id end)
    829 
    830     assert author_ids == [nil, nil]
    831     refute Process.get(Comment)
    832   end
    833 
    834   test "has_many assoc on delete does nothing" do
    835     user = TestRepo.insert!(%User{})
    836     TestRepo.insert!(%Post{author_id: user.id})
    837 
    838     TestRepo.delete!(user)
    839     assert Enum.count(TestRepo.all(Post)) == 1
    840   end
    841 
    842   test "many_to_many assoc on delete deletes all" do
    843     p1 = TestRepo.insert!(%Post{title: "1", visits: 1})
    844     p2 = TestRepo.insert!(%Post{title: "2", visits: 2})
    845 
    846     u1 = TestRepo.insert!(%User{name: "john"})
    847     u2 = TestRepo.insert!(%User{name: "mary"})
    848 
    849     TestRepo.insert_all "posts_users", [[post_id: p1.id, user_id: u1.id],
    850                                         [post_id: p1.id, user_id: u1.id],
    851                                         [post_id: p2.id, user_id: u2.id]]
    852     TestRepo.delete!(p1)
    853 
    854     [pid2] = TestRepo.all from(p in Post, select: p.id)
    855     assert pid2 == p2.id
    856 
    857     [[pid2, uid2]] = TestRepo.all from(j in "posts_users", select: [j.post_id, j.user_id])
    858     assert pid2 == p2.id
    859     assert uid2 == u2.id
    860 
    861     [uid1, uid2] = TestRepo.all from(u in User, select: u.id)
    862     assert uid1 == u1.id
    863     assert uid2 == u2.id
    864   end
    865 end