Skip to content

Commit

Permalink
Can preload has_one associations with existing records (#553)
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewmcgarvey authored Dec 3, 2020
1 parent 1d249d8 commit ad871ba
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 1 deletion.
51 changes: 51 additions & 0 deletions spec/preloading/preloading_has_one_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,55 @@ describe "Preloading has_one associations" do

SignInCredential::BaseQuery.times_called.should eq 0
end

context "with existing record" do
it "works" do
with_lazy_load(enabled: false) do
admin = AdminBox.create
sign_in_credential = SignInCredentialBox.create &.user_id(admin.id)

admin = Admin::BaseQuery.preload_sign_in_credential(admin)

admin.sign_in_credential.should eq sign_in_credential
end
end

it "works with multiple" do
with_lazy_load(enabled: false) do
admin = AdminBox.create
sign_in_credential = SignInCredentialBox.create &.user_id(admin.id)
admin2 = AdminBox.create
sign_in_credential2 = SignInCredentialBox.create &.user_id(admin2.id)

admins = Admin::BaseQuery.preload_sign_in_credential([admin, admin2])

admins[0].sign_in_credential.should eq(sign_in_credential)
admins[1].sign_in_credential.should eq(sign_in_credential2)
end
end

it "works with custom query" do
with_lazy_load(enabled: false) do
user = UserBox.create
sign_in_credential = SignInCredentialBox.create &.user_id(user.id)

user = UserQuery.preload_sign_in_credential(user, SignInCredential::BaseQuery.new.id.not.eq(sign_in_credential.id))

user.sign_in_credential.should be_nil
end
end

it "does not modify original record" do
with_lazy_load(enabled: false) do
admin = AdminBox.create
SignInCredentialBox.create &.user_id(admin.id)

Admin::BaseQuery.preload_sign_in_credential(admin)

expect_raises Avram::LazyLoadError do
admin.sign_in_credential
end
end
end
end
end
17 changes: 16 additions & 1 deletion src/avram/associations/has_one.cr
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,21 @@ module Avram::Associations::HasOne

private macro define_has_one_base_query(assoc_name, model, foreign_key)
class BaseQuery
def self.preload_{{ assoc_name }}(record, preload_query = {{ model }}::BaseQuery.new)
preload_{{ assoc_name }}(records: [record], preload_query: preload_query).first
end

def self.preload_{{ assoc_name }}(records : Enumerable, preload_query = {{ model }}::BaseQuery.new)
ids = records.map(&.id)
empty_results = {} of {{ model }}::PrimaryKeyType => Array({{ model }})
{{ assoc_name }} = ids.empty? ? empty_results : preload_query.{{ foreign_key }}.in(ids).results.group_by(&.{{ foreign_key }})
records.map(&.dup)
.map do |record|
assoc = {{ assoc_name }}[record.id]?.try(&.first?)
record.tap(&.__set_preloaded_{{ assoc_name }}(assoc))
end
end

def preload_{{ assoc_name }}
preload_{{ assoc_name }}({{ model }}::BaseQuery.new)
end
Expand All @@ -53,7 +68,7 @@ module Avram::Associations::HasOne
add_preload do |records|
ids = records.map(&.id)
empty_results = {} of {{ model }}::PrimaryKeyType => Array({{ model }})
{{ assoc_name }} = ids.empty? ? empty_results : preload_query.dup.{{ foreign_key }}.in(ids).results.group_by(&.{{ foreign_key }})
{{ assoc_name }} = ids.empty? ? empty_results : preload_query.{{ foreign_key }}.in(ids).results.group_by(&.{{ foreign_key }})
records.each do |record|
record.__set_preloaded_{{ assoc_name }} {{ assoc_name }}[record.id]?.try(&.first?)
end
Expand Down

0 comments on commit ad871ba

Please sign in to comment.