Skip to content

Commit

Permalink
Preloading specs refactor (luckyframework#548)
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewmcgarvey authored Dec 1, 2020
1 parent 4ee9f04 commit 8d84271
Show file tree
Hide file tree
Showing 6 changed files with 416 additions and 344 deletions.
97 changes: 97 additions & 0 deletions spec/preloading/preloading_belongs_to_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
require "../spec_helper"

include LazyLoadHelpers

class Post::BaseQuery
include QuerySpy
end

describe "Preloading belongs_to associations" do
it "works" do
with_lazy_load(enabled: false) do
Post::BaseQuery.times_called = 0
post = PostBox.create
CommentBox.create &.post_id(post.id)

comments = Comment::BaseQuery.new.preload_post

comments.first.post.should eq(post)
Post::BaseQuery.times_called.should eq 1
end
end

it "works with optional association" do
with_lazy_load(enabled: false) do
employee = EmployeeBox.create
manager = ManagerBox.create

employees = Employee::BaseQuery.new.preload_manager
employees.first.manager.should be_nil

Employee::SaveOperation.new(employee).tap do |operation|
operation.manager_id.value = manager.id
operation.update!
end
employees = Employee::BaseQuery.new.preload_manager
employees.first.manager.should eq(manager)
end
end

it "raises error if accessing association without preloading first" do
with_lazy_load(enabled: false) do
post = PostBox.create
comment = CommentBox.create &.post_id(post.id)

comment = Comment::BaseQuery.find(comment.id)

expect_raises Avram::LazyLoadError do
comment.post
end
end
end

it "works with nested preloads" do
with_lazy_load(enabled: false) do
post = PostBox.create
comment = CommentBox.create &.post_id(post.id)
comment2 = CommentBox.create &.post_id(post.id)

comment = Comment::BaseQuery.new.preload_post(Post::BaseQuery.new.preload_comments).find(comment.id)

comment.post.comments.should eq([comment, comment2])
end
end

it "does not fail when getting results multiple times" do
post = PostBox.create
CommentBox.create &.post_id(post.id)

query = Comment::BaseQuery.new.preload_post

2.times { query.results }
end

it "works with uuid foreign keys" do
item = LineItemBox.create
PriceBox.new.line_item_id(item.id).create

PriceQuery.new.preload_line_item.first.line_item.should eq item
end

it "lazy loads if nothing is preloaded" do
post = PostBox.create
comment = CommentBox.create &.post_id(post.id)

comment = Comment::BaseQuery.find(comment.id)

comment.post.should eq(post)
end

it "skips running the preload when there's no results in the parent query" do
Post::BaseQuery.times_called = 0
comments = Comment::BaseQuery.new.preload_post
comments.results

Post::BaseQuery.times_called.should eq 0
end
end
145 changes: 145 additions & 0 deletions spec/preloading/preloading_has_many_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
require "../spec_helper"

include LazyLoadHelpers

class Comment::BaseQuery
include QuerySpy
end

describe "Preloading has_many associations" do
it "works" do
with_lazy_load(enabled: false) do
Comment::BaseQuery.times_called = 0
post = PostBox.create
comment = CommentBox.create &.post_id(post.id)

posts = Post::BaseQuery.new.preload_comments

posts.results.first.comments.should eq([comment])
Comment::BaseQuery.times_called.should eq 1
end
end

it "preserves additional criteria when used after adding a preload" do
with_lazy_load(enabled: false) do
post = PostBox.create
another_post = PostBox.create
comment = CommentBox.create &.post_id(post.id)

CommentBox.create &.post_id(another_post.id) # should not be preloaded

posts = Post::BaseQuery.new.preload_comments.limit(1)

results = posts.results
results.size.should eq(1)
results.first.comments.should eq([comment])
end
end

it "works with custom query" do
with_lazy_load(enabled: false) do
post = PostBox.create
comment = CommentBox.create &.post_id(post.id)

posts = Post::BaseQuery.new.preload_comments(
Comment::BaseQuery.new.id.not.eq(comment.id)
)

posts.results.first.comments.should eq([] of Comment)
end
end

it "works with UUID foreign keys" do
with_lazy_load(enabled: false) do
item = LineItemBox.create
scan = ScanBox.create &.line_item_id(item.id)

items = LineItem::BaseQuery.new.preload_scans

items.results.first.scans.should eq([scan])
end
end

it "works with nested preloads" do
with_lazy_load(enabled: false) do
post = PostBox.create
CommentBox.create &.post_id(post.id)

posts = Post::BaseQuery.new.preload_comments(
Comment::BaseQuery.new.preload_post
)

posts.first.comments.first.post.should eq(post)
end
end

it "raises error if accessing association without preloading first" do
with_lazy_load(enabled: false) do
post = PostBox.create

expect_raises Avram::LazyLoadError do
post.comments
end
end
end

it "uses an empty array if there are no associated records" do
with_lazy_load(enabled: false) do
PostBox.create

posts = Post::BaseQuery.new.preload_comments

posts.results.first.comments.should eq([] of Comment)
end
end

it "does not fail when getting results multiple times" do
PostBox.create

posts = Post::BaseQuery.new.preload_comments

2.times { posts.results }
end

it "does not fail when getting results multiple times with custom query" do
post = PostBox.create
_another_post = PostBox.create
comment = CommentBox.create &.post_id(post.id)

posts = Post::BaseQuery.new.preload_comments(
Comment::BaseQuery.new.id.not.eq(comment.id)
)

2.times { posts.results }
end

it "uses preloaded records if available, even if lazy load is enabled" do
with_lazy_load(enabled: true) do
post = PostBox.create
comment = CommentBox.create &.post_id(post.id)

posts = Post::BaseQuery.new.preload_comments(
Comment::BaseQuery.new.id.not.eq(comment.id)
)

posts.results.first.comments.should eq([] of Comment)
end
end

it "lazy loads if nothing is preloaded" do
post = PostBox.create
comment = CommentBox.create &.post_id(post.id)

posts = Post::BaseQuery.new

posts.results.first.comments.should eq([comment])
end

it "skips running the preload query when there's no results in the parent query" do
Comment::BaseQuery.times_called = 0
posts = Post::BaseQuery.new.preload_comments
posts.results

Comment::BaseQuery.times_called.should eq 0
end
end
81 changes: 81 additions & 0 deletions spec/preloading/preloading_has_many_through_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
require "../spec_helper"

include LazyLoadHelpers

class Comment::BaseQuery
include QuerySpy
end

describe "Preloading has_many through associations" do
context "through is a has_many association that has a belongs_to relationship to target" do
it "works" do
with_lazy_load(enabled: false) do
tag = TagBox.create
TagBox.create # unused tag
post = PostBox.create
other_post = PostBox.create
TaggingBox.create &.tag_id(tag.id).post_id(post.id)
TaggingBox.create &.tag_id(tag.id).post_id(other_post.id)

post_tags = Post::BaseQuery.new.preload_tags.results.first.tags

post_tags.size.should eq(1)
post_tags.should eq([tag])
end
end

it "works with uuid foreign keys" do
with_lazy_load(enabled: false) do
item = LineItemBox.create
other_item = LineItemBox.create
product = ProductBox.create
ProductBox.create # unused product
LineItemProductBox.create &.line_item_id(item.id).product_id(product.id)
LineItemProductBox.create &.line_item_id(other_item.id).product_id(product.id)

item_products = LineItemQuery.new.preload_associated_products.results.first.associated_products

item_products.size.should eq(1)
item_products.should eq([product])
end
end

it "does not fail when getting results multiple times" do
PostBox.create

posts = Post::BaseQuery.new.preload_tags

2.times { posts.results }
end
end

context "through is a has_many association that has a has_many relationship to target" do
it "works" do
with_lazy_load(enabled: false) do
manager = ManagerBox.create
employee = EmployeeBox.new.manager_id(manager.id).create
customer = CustomerBox.new.employee_id(employee.id).create

customers = Manager::BaseQuery.new.preload_customers.find(manager.id).customers

customers.size.should eq(1)
customers.should eq([customer])
end
end
end

context "through is a belongs_to association that has a belongs_to relationship to target" do
it "works" do
with_lazy_load(enabled: false) do
manager = ManagerBox.create
employee = EmployeeBox.new.manager_id(manager.id).create
customer = CustomerBox.new.employee_id(employee.id).create

managers = Customer::BaseQuery.new.preload_managers.find(customer.id).managers

managers.size.should eq(1)
managers.should eq([manager])
end
end
end
end
Loading

0 comments on commit 8d84271

Please sign in to comment.