Skip to content

Commit

Permalink
Allow lazy loading associations
Browse files Browse the repository at this point in the history
Closes #215
  • Loading branch information
paulcsmith committed Mar 23, 2018
1 parent 1c3d84b commit 0cfede7
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 33 deletions.
37 changes: 37 additions & 0 deletions spec/lazy_loading_spec.cr
@@ -0,0 +1,37 @@
require "./spec_helper"

include LazyLoadHelpers

describe "Lazy loading associations" do
it "can lazy load has_many and has_many through" do
post = PostBox.save
comment = CommentBox.new.post_id(post.id).save
tag = TagBox.save
tagging = TaggingBox.new.post_id(post.id).tag_id(tag.id).save

post.comments!.should eq([comment])
post.tags!.should eq([tag])
end

it "can lazy load has_one" do
admin = AdminBox.save
sign_in_credential = SignInCredentialBox.new.user_id(admin.id).save
admin.sign_in_credential!.should eq(sign_in_credential)
end

it "can lazy load optional has_one" do
user = UserBox.save
user.sign_in_credential!.should be_nil
end

it "can lazy load belongs_to" do
post = PostBox.save
comment = CommentBox.new.post_id(post.id).save
comment.post!.should eq(post)
end

it "can lazy load optional belongs_to" do
employee = EmployeeBox.save
employee.manager!.should be_nil
end
end
16 changes: 2 additions & 14 deletions spec/preloading_spec.cr
@@ -1,5 +1,7 @@
require "./spec_helper"

include LazyLoadHelpers

describe "Preloading" do
it "can disable lazy loading" do
with_lazy_load(enabled: false) do
Expand Down Expand Up @@ -162,17 +164,3 @@ describe "Preloading" do
posts.results.first.comments.should eq([comment])
end
end

private def with_lazy_load(enabled)
begin
LuckyRecord::Repo.configure do
settings.lazy_load_enabled = enabled
end

yield
ensure
LuckyRecord::Repo.configure do
settings.lazy_load_enabled = true
end
end
end
15 changes: 15 additions & 0 deletions spec/support/lazy_load_helpers.cr
@@ -0,0 +1,15 @@
module LazyLoadHelpers
private def with_lazy_load(enabled)
begin
LuckyRecord::Repo.configure do
settings.lazy_load_enabled = enabled
end

yield
ensure
LuckyRecord::Repo.configure do
settings.lazy_load_enabled = true
end
end
end
end
62 changes: 43 additions & 19 deletions src/lucky_record/associations.cr
Expand Up @@ -24,30 +24,38 @@ module LuckyRecord::Associations

def {{ assoc_name.id }} : Array({{ model }})
@_preloaded_{{ assoc_name }} \
|| lazy_load_{{ assoc_name }} \
|| maybe_lazy_load_{{ assoc_name }} \
|| raise LuckyRecord::LazyLoadError.new {{ @type.name.stringify }}, {{ assoc_name.stringify }}
end

private def lazy_load_{{ assoc_name }} : Array({{ model }})?
def {{ assoc_name.id }}! : Array({{ model }})
@_preloaded_{{ assoc_name }} || lazy_load_{{ assoc_name }}
end

private def maybe_lazy_load_{{ assoc_name }} : Array({{ model }})?
if lazy_load_enabled?
{% if through %}
{{ model }}::BaseQuery
.new
.join_{{ through.id }}
.{{ through.id }} do |through_query|
through_query.{{ foreign_key.id }}(id)
end
.preload_{{ through.id }}
.results
{% else %}
{{ model }}::BaseQuery
.new
.{{ foreign_key }}(id)
.results
{% end %}
lazy_load_{{ assoc_name }}
end
end

private def lazy_load_{{ assoc_name }} : Array({{ model }})
{% if through %}
{{ model }}::BaseQuery
.new
.join_{{ through.id }}
.{{ through.id }} do |through_query|
through_query.{{ foreign_key.id }}(id)
end
.preload_{{ through.id }}
.results
{% else %}
{{ model }}::BaseQuery
.new
.{{ foreign_key }}(id)
.results
{% end %}
end

class BaseQuery < LuckyRecord::Query
def preload_{{ assoc_name }}
preload({{ model }}::BaseQuery.new)
Expand Down Expand Up @@ -113,10 +121,18 @@ module LuckyRecord::Associations
@_preloaded_{{ assoc_name }} = record
end

def {{ assoc_name.id }}! : {{ model }}{% if nilable %}?{% end %}
get_{{ assoc_name.id }}(allow_lazy: true)
end

def {{ assoc_name.id }} : {{ model }}{% if nilable %}?{% end %}
get_{{ assoc_name.id }}
end

private def get_{{ assoc_name.id }}(allow_lazy : Bool = false) : {{ model }}{% if nilable %}?{% end %}
if _{{ assoc_name }}_preloaded?
@_preloaded_{{ assoc_name }}{% unless nilable %}.not_nil!{% end %}
elsif lazy_load_enabled?
elsif lazy_load_enabled? || allow_lazy
query = {{ model }}::BaseQuery.new
query.{{ foreign_key.id }}(id)

Expand Down Expand Up @@ -160,10 +176,18 @@ module LuckyRecord::Associations

association table_name: :{{ model.resolve.constant(:TABLE_NAME).id }}, type: {{ model }}, foreign_key: :id

def {{ assoc_name.id }}! : {{ model }}{% if nilable %}?{% end %}
get_{{ assoc_name.id }}(allow_lazy: true)
end

def {{ assoc_name.id }} : {{ model }}{% if nilable %}?{% end %}
get_{{ assoc_name.id }}
end

private def get_{{ assoc_name.id }}(allow_lazy : Bool = false) : {{ model }}{% if nilable %}?{% end %}
if _{{ assoc_name }}_preloaded?
@_preloaded_{{ assoc_name }}{% unless nilable %}.not_nil!{% end %}
elsif lazy_load_enabled?
elsif lazy_load_enabled? || allow_lazy
{{ foreign_key }}.try do |value|
{{ model }}::BaseQuery.new.find(value)
end
Expand Down

0 comments on commit 0cfede7

Please sign in to comment.