Packages
ecto
1.1.4
3.14.1
3.14.0
3.13.6
3.13.5
3.13.4
3.13.3
3.13.2
3.13.1
3.13.0
3.12.6
3.12.5
3.12.4
3.12.3
3.12.2
3.12.1
3.12.0
3.11.2
3.11.1
3.11.0
3.10.3
3.10.2
3.10.1
3.10.0
3.9.6
3.9.5
3.9.4
3.9.3
3.9.2
3.9.1
3.9.0
3.8.4
3.8.3
3.8.2
3.8.1
3.8.0
3.7.2
3.7.1
3.7.0
3.6.2
3.6.1
3.6.0
3.5.8
3.5.7
3.5.6
3.5.5
3.5.4
3.5.3
3.5.2
3.5.1
3.5.0
3.5.0-rc.1
3.5.0-rc.0
3.4.6
3.4.5
3.4.4
3.4.3
3.4.2
3.4.1
3.4.0
3.3.4
3.3.3
3.3.2
3.3.1
3.3.0
3.2.5
3.2.4
3.2.3
3.2.2
3.2.1
3.2.0
3.1.7
3.1.6
3.1.5
3.1.4
3.1.3
3.1.2
3.1.1
3.1.0
3.0.9
3.0.8
3.0.7
3.0.6
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
3.0.0
3.0.0-rc.1
3.0.0-rc.0
2.2.12
2.2.11
2.2.10
2.2.9
2.2.8
2.2.7
2.2.6
2.2.5
2.2.4
2.2.3
2.2.2
2.2.1
2.2.0
2.2.0-rc.1
2.2.0-rc.0
2.1.6
2.1.5
2.1.4
2.1.3
2.1.2
2.1.1
2.1.0
2.1.0-rc.5
2.1.0-rc.4
2.1.0-rc.3
2.1.0-rc.2
2.1.0-rc.1
2.1.0-rc.0
2.0.6
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
2.0.0-rc.6
2.0.0-rc.5
2.0.0-rc.4
2.0.0-rc.3
2.0.0-rc.2
2.0.0-rc.1
2.0.0-rc.0
2.0.0-beta.2
2.0.0-beta.1
2.0.0-beta.0
1.1.9
1.1.8
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.16.0
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
0.13.0
0.12.1
0.12.0
0.12.0-rc
0.11.3
0.11.2
0.11.1
0.11.0
0.10.3
0.10.2
0.10.1
0.10.0
0.9.0
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.0
0.5.1
0.5.0
0.4.0
0.3.0
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.0
A toolkit for data mapping and language integrated query for Elixir
Current section
Files
Jump to
Current section
Files
integration_test/cases/preload.exs
defmodule Ecto.Integration.PreloadTest do
use Ecto.Integration.Case
alias Ecto.Integration.TestRepo
import Ecto.Query
alias Ecto.Integration.Post
alias Ecto.Integration.Comment
alias Ecto.Integration.Permalink
alias Ecto.Integration.User
alias Ecto.Integration.Custom
test "preload empty" do
assert TestRepo.preload([], :anything_goes) == []
end
test "preload has_many" do
p1 = TestRepo.insert!(%Post{title: "1"})
p2 = TestRepo.insert!(%Post{title: "2"})
p3 = TestRepo.insert!(%Post{title: "3"})
# We use the same text to expose bugs in preload sorting
%Comment{id: cid1} = TestRepo.insert!(%Comment{text: "1", post_id: p1.id})
%Comment{id: cid3} = TestRepo.insert!(%Comment{text: "2", post_id: p2.id})
%Comment{id: cid2} = TestRepo.insert!(%Comment{text: "2", post_id: p1.id})
%Comment{id: cid4} = TestRepo.insert!(%Comment{text: "3", post_id: p2.id})
assert %Ecto.Association.NotLoaded{} = p1.comments
assert [p3, p1, p2] = TestRepo.preload([p3, p1, p2], :comments)
assert [%Comment{id: ^cid1}, %Comment{id: ^cid2}] = p1.comments |> sort_by_id
assert [%Comment{id: ^cid3}, %Comment{id: ^cid4}] = p2.comments |> sort_by_id
assert [] = p3.comments
end
test "preload has_one" do
p1 = TestRepo.insert!(%Post{title: "1"})
p2 = TestRepo.insert!(%Post{title: "2"})
p3 = TestRepo.insert!(%Post{title: "3"})
%Permalink{id: pid1} = TestRepo.insert!(%Permalink{url: "1", post_id: p1.id})
%Permalink{} = TestRepo.insert!(%Permalink{url: "2", post_id: nil})
%Permalink{id: pid3} = TestRepo.insert!(%Permalink{url: "3", post_id: p3.id})
assert %Ecto.Association.NotLoaded{} = p1.permalink
assert %Ecto.Association.NotLoaded{} = p2.permalink
assert [p3, p1, p2] = TestRepo.preload([p3, p1, p2], :permalink)
assert %Permalink{id: ^pid1} = p1.permalink
refute p2.permalink
assert %Permalink{id: ^pid3} = p3.permalink
end
test "preload belongs_to" do
%Post{id: pid1} = TestRepo.insert!(%Post{title: "1"})
TestRepo.insert!(%Post{title: "2"})
%Post{id: pid3} = TestRepo.insert!(%Post{title: "3"})
pl1 = TestRepo.insert!(%Permalink{url: "1", post_id: pid1})
pl2 = TestRepo.insert!(%Permalink{url: "2", post_id: nil})
pl3 = TestRepo.insert!(%Permalink{url: "3", post_id: pid3})
assert %Ecto.Association.NotLoaded{} = pl1.post
assert [ple3, ple1, ple2] = TestRepo.preload([pl3, pl1, pl2],
post: from(p in Post, where: false))
refute ple1.post
refute ple2.post
refute ple3.post
assert [pl3, pl1, pl2] = TestRepo.preload([pl3, pl1, pl2], :post)
assert %Post{id: ^pid1} = pl1.post
refute pl2.post
assert %Post{id: ^pid3} = pl3.post
end
test "preload with query" do
p1 = TestRepo.insert!(%Post{title: "1"})
p2 = TestRepo.insert!(%Post{title: "2"})
p3 = TestRepo.insert!(%Post{title: "3"})
# We use the same text to expose bugs in preload sorting
%Comment{id: cid1} = TestRepo.insert!(%Comment{text: "1", post_id: p1.id})
%Comment{id: cid3} = TestRepo.insert!(%Comment{text: "2", post_id: p2.id})
%Comment{id: cid2} = TestRepo.insert!(%Comment{text: "2", post_id: p1.id})
%Comment{id: cid4} = TestRepo.insert!(%Comment{text: "3", post_id: p2.id})
assert %Ecto.Association.NotLoaded{} = p1.comments
# With custom query
assert [pe3, pe1, pe2] = TestRepo.preload([p3, p1, p2],
comments: from(c in Comment, where: false))
assert [] = pe1.comments
assert [] = pe2.comments
assert [] = pe3.comments
# With custom ordered query
assert [pe3, pe1, pe2] = TestRepo.preload([p3, p1, p2],
comments: from(c in Comment, order_by: [desc: c.text]))
assert [%Comment{id: ^cid2}, %Comment{id: ^cid1}] = pe1.comments
assert [%Comment{id: ^cid4}, %Comment{id: ^cid3}] = pe2.comments
assert [] = pe3.comments
# With custom ordered query with preload
assert [pe3, pe1, pe2] = TestRepo.preload([p3, p1, p2],
comments: {from(c in Comment, order_by: [desc: c.text]), :post})
assert [%Comment{id: ^cid2} = c2, %Comment{id: ^cid1} = c1] = pe1.comments
assert [%Comment{id: ^cid4} = c4, %Comment{id: ^cid3} = c3] = pe2.comments
assert [] = pe3.comments
assert c1.post.title == "1"
assert c2.post.title == "1"
assert c3.post.title == "2"
assert c4.post.title == "2"
end
test "preload has_many through" do
%Post{id: pid1} = p1 = TestRepo.insert!(%Post{})
%Post{id: pid2} = p2 = TestRepo.insert!(%Post{})
%User{id: uid1} = TestRepo.insert!(%User{name: "foo"})
%User{id: uid2} = TestRepo.insert!(%User{name: "bar"})
%Comment{} = TestRepo.insert!(%Comment{post_id: pid1, author_id: uid1})
%Comment{} = TestRepo.insert!(%Comment{post_id: pid1, author_id: uid1})
%Comment{} = TestRepo.insert!(%Comment{post_id: pid1, author_id: uid2})
%Comment{} = TestRepo.insert!(%Comment{post_id: pid2, author_id: uid2})
## Single preload
p1 = TestRepo.preload(p1, :comments_authors)
# Through was preloaded
[u1, u2] = p1.comments_authors |> sort_by_id
assert u1.id == uid1
assert u2.id == uid2
# But we also preloaded everything along the way
assert [c1, c2, c3] = p1.comments |> sort_by_id
assert c1.author.id == uid1
assert c2.author.id == uid1
assert c3.author.id == uid2
## Multiple preloads
[p1, p2] = TestRepo.preload([p1, p2], :comments_authors)
# Through was preloaded
[u1, u2] = p1.comments_authors |> sort_by_id
assert u1.id == uid1
assert u2.id == uid2
[u2] = p2.comments_authors
assert u2.id == uid2
# But we also preloaded everything along the way
assert [c1, c2, c3] = p1.comments |> sort_by_id
assert c1.author.id == uid1
assert c2.author.id == uid1
assert c3.author.id == uid2
assert [c4] = p2.comments
assert c4.author.id == uid2
end
test "preload through with query" do
%Post{id: pid1} = p1 = TestRepo.insert!(%Post{})
%User{id: uid1} = TestRepo.insert!(%User{name: "foo"})
%User{id: uid2} = TestRepo.insert!(%User{name: "bar"})
%Comment{} = TestRepo.insert!(%Comment{post_id: pid1, author_id: uid1})
%Comment{} = TestRepo.insert!(%Comment{post_id: pid1, author_id: uid1})
%Comment{} = TestRepo.insert!(%Comment{post_id: pid1, author_id: uid2})
p1 = TestRepo.preload(p1, comments_authors: from(u in User, where: u.name == "foo"))
[%{id: ^uid1}] = p1.comments_authors |> sort_by_id
end
test "preload has_one through" do
%Post{id: pid1} = TestRepo.insert!(%Post{})
%Post{id: pid2} = TestRepo.insert!(%Post{})
%Permalink{id: lid1} = TestRepo.insert!(%Permalink{post_id: pid1})
%Permalink{id: lid2} = TestRepo.insert!(%Permalink{post_id: pid2})
%Comment{} = c1 = TestRepo.insert!(%Comment{post_id: pid1})
%Comment{} = c2 = TestRepo.insert!(%Comment{post_id: pid1})
%Comment{} = c3 = TestRepo.insert!(%Comment{post_id: pid2})
[c1, c2, c3] = TestRepo.preload([c1, c2, c3], :post_permalink)
# Through was preloaded
assert c1.post.id == pid1
assert c1.post.permalink.id == lid1
assert c1.post_permalink.id == lid1
assert c2.post.id == pid1
assert c2.post.permalink.id == lid1
assert c2.post_permalink.id == lid1
assert c3.post.id == pid2
assert c3.post.permalink.id == lid2
assert c3.post_permalink.id == lid2
end
test "preload has_many through-through" do
%Post{id: pid1} = TestRepo.insert!(%Post{})
%Post{id: pid2} = TestRepo.insert!(%Post{})
%Permalink{} = l1 = TestRepo.insert!(%Permalink{post_id: pid1})
%Permalink{} = l2 = TestRepo.insert!(%Permalink{post_id: pid2})
%User{id: uid1} = TestRepo.insert!(%User{name: "foo"})
%User{id: uid2} = TestRepo.insert!(%User{name: "bar"})
%Comment{} = TestRepo.insert!(%Comment{post_id: pid1, author_id: uid1})
%Comment{} = TestRepo.insert!(%Comment{post_id: pid1, author_id: uid1})
%Comment{} = TestRepo.insert!(%Comment{post_id: pid1, author_id: uid2})
%Comment{} = TestRepo.insert!(%Comment{post_id: pid2, author_id: uid2})
# With custom query
[le1, le2] = TestRepo.preload([l1, l2],
post_comments_authors: from(u in User, where: u.name == "foo"))
assert [u1] = le1.post_comments_authors
assert u1.id == uid1
assert [] = le2.post_comments_authors
# With assoc query
[l1, l2] = TestRepo.preload([l1, l2], :post_comments_authors)
# Through was preloaded
[u1, u2] = l1.post_comments_authors |> sort_by_id
assert u1.id == uid1
assert u2.id == uid2
[u2] = l2.post_comments_authors
assert u2.id == uid2
# But we also preloaded everything along the way
assert l1.post.id == pid1
assert l1.post.comments != []
assert l2.post.id == pid2
assert l2.post.comments != []
end
test "preload has_many through nested" do
%Post{id: pid1} = p1 = TestRepo.insert!(%Post{})
%Post{id: pid2} = p2 = TestRepo.insert!(%Post{})
%User{id: uid1} = TestRepo.insert!(%User{})
%User{id: uid2} = TestRepo.insert!(%User{})
%Comment{} = c1 = TestRepo.insert!(%Comment{post_id: pid1, author_id: uid1})
%Comment{} = c2 = TestRepo.insert!(%Comment{post_id: pid1, author_id: uid1})
%Comment{} = c3 = TestRepo.insert!(%Comment{post_id: pid1, author_id: uid2})
%Comment{} = c4 = TestRepo.insert!(%Comment{post_id: pid2, author_id: uid2})
[p1, p2] = TestRepo.preload([p1, p2], [:permalink, comments_authors: :comments])
# Through was preloaded
[u1, u2] = p1.comments_authors |> sort_by_id
assert u1.id == uid1
assert u2.id == uid2
assert [c1, c2] == u1.comments |> sort_by_id
[u2] = p2.comments_authors
assert u2.id == uid2
assert [c3, c4] == u2.comments |> sort_by_id
end
test "preload belongs_to with shared assocs" do
%Post{id: pid1} = TestRepo.insert!(%Post{title: "1"})
%Post{id: pid2} = TestRepo.insert!(%Post{title: "2"})
c1 = TestRepo.insert!(%Comment{text: "1", post_id: pid1})
c2 = TestRepo.insert!(%Comment{text: "2", post_id: pid1})
c3 = TestRepo.insert!(%Comment{text: "3", post_id: pid2})
assert [c3, c1, c2] = TestRepo.preload([c3, c1, c2], :post)
assert %Post{id: ^pid1} = c1.post
assert %Post{id: ^pid1} = c2.post
assert %Post{id: ^pid2} = c3.post
end
@tag :invalid_prefix
test "preload custom prefix" do
p = TestRepo.insert!(%Post{title: "1"})
p = Ecto.put_meta(p, prefix: "this_surely_does_not_exist")
# This preload should fail because it points to a prefix that does not exist
assert catch_error(TestRepo.preload(p, [:comments]))
end
test "preload nested" do
p1 = TestRepo.insert!(%Post{title: "1"})
p2 = TestRepo.insert!(%Post{title: "2"})
TestRepo.insert!(%Comment{text: "1", post_id: p1.id})
TestRepo.insert!(%Comment{text: "2", post_id: p1.id})
TestRepo.insert!(%Comment{text: "3", post_id: p2.id})
TestRepo.insert!(%Comment{text: "4", post_id: p2.id})
assert [p2, p1] = TestRepo.preload([p2, p1], [comments: :post])
assert [c1, c2] = p1.comments
assert [c3, c4] = p2.comments
assert p1.id == c1.post.id
assert p1.id == c2.post.id
assert p2.id == c3.post.id
assert p2.id == c4.post.id
end
test "preload nested via custom query" do
p1 = TestRepo.insert!(%Post{title: "1"})
p2 = TestRepo.insert!(%Post{title: "2"})
TestRepo.insert!(%Comment{text: "1", post_id: p1.id})
TestRepo.insert!(%Comment{text: "2", post_id: p1.id})
TestRepo.insert!(%Comment{text: "3", post_id: p2.id})
TestRepo.insert!(%Comment{text: "4", post_id: p2.id})
query = from(c in Comment, preload: :post, order_by: [desc: c.text])
assert [p2, p1] = TestRepo.preload([p2, p1], comments: query)
assert [c2, c1] = p1.comments
assert [c4, c3] = p2.comments
assert p1.id == c1.post.id
assert p1.id == c2.post.id
assert p2.id == c3.post.id
assert p2.id == c4.post.id
end
test "preload has_many with no associated entries" do
p = TestRepo.insert!(%Post{title: "1"})
p = TestRepo.preload(p, :comments)
assert p.title == "1"
assert p.comments == []
end
test "preload has_one with no associated entries" do
p = TestRepo.insert!(%Post{title: "1"})
p = TestRepo.preload(p, :permalink)
assert p.title == "1"
assert p.permalink == nil
end
test "preload belongs_to with no associated entry" do
c = TestRepo.insert!(%Comment{text: "1"})
c = TestRepo.preload(c, :post)
assert c.text == "1"
assert c.post == nil
end
test "preload with binary_id" do
c = TestRepo.insert!(%Custom{})
u = TestRepo.insert!(%User{custom_id: c.bid})
u = TestRepo.preload(u, :custom)
assert u.custom.bid == c.bid
end
test "preload skips already loaded" do
p1 = TestRepo.insert!(%Post{title: "1"})
p2 = TestRepo.insert!(%Post{title: "2"})
%Comment{id: _} = TestRepo.insert!(%Comment{text: "1", post_id: p1.id})
%Comment{id: cid2} = TestRepo.insert!(%Comment{text: "2", post_id: p2.id})
assert %Ecto.Association.NotLoaded{} = p1.comments
p1 = %{p1 | comments: []}
assert [p1, p2] = TestRepo.preload([p1, p2], :comments)
assert [] = p1.comments
assert [%Comment{id: ^cid2}] = p2.comments
end
test "preload keyword query" do
p1 = TestRepo.insert!(%Post{title: "1"})
p2 = TestRepo.insert!(%Post{title: "2"})
TestRepo.insert!(%Post{title: "3"})
%Comment{id: cid1} = TestRepo.insert!(%Comment{text: "1", post_id: p1.id})
%Comment{id: cid2} = TestRepo.insert!(%Comment{text: "2", post_id: p1.id})
%Comment{id: cid3} = TestRepo.insert!(%Comment{text: "3", post_id: p2.id})
%Comment{id: cid4} = TestRepo.insert!(%Comment{text: "4", post_id: p2.id})
# Regular query
query = from(p in Post, preload: [:comments], select: p)
assert [p1, p2, p3] = TestRepo.all(query)
assert [%Comment{id: ^cid1}, %Comment{id: ^cid2}] = p1.comments |> sort_by_id
assert [%Comment{id: ^cid3}, %Comment{id: ^cid4}] = p2.comments |> sort_by_id
assert [] = p3.comments
# Query with interpolated preload query
query = from(p in Post, preload: [comments: ^from(c in Comment, where: false)], select: p)
assert [p1, p2, p3] = TestRepo.all(query)
assert [] = p1.comments
assert [] = p2.comments
assert [] = p3.comments
# Now let's use an interpolated preload too
comments = [:comments]
query = from(p in Post, preload: ^comments, select: {0, [p], 1, 2})
posts = TestRepo.all(query)
[p1, p2, p3] = Enum.map(posts, fn {0, [p], 1, 2} -> p end)
assert [%Comment{id: ^cid1}, %Comment{id: ^cid2}] = p1.comments |> sort_by_id
assert [%Comment{id: ^cid3}, %Comment{id: ^cid4}] = p2.comments |> sort_by_id
assert [] = p3.comments
end
defp sort_by_id(values) do
Enum.sort_by(values, &(&1.id))
end
end