From f84e111a80d475611eba5b1a082ca8d8d8df399e Mon Sep 17 00:00:00 2001 From: Jeremy Woertink Date: Fri, 1 Sep 2023 10:54:07 -0700 Subject: [PATCH] Move protected preload method to public so it can be used. Fixes #941 (#961) --- .../preloading/preloading_belongs_to_spec.cr | 21 +++++++++++++++---- .../preloading/preloading_has_many_spec.cr | 5 +++++ .../preloading_has_many_through_spec.cr | 9 +++++--- .../preloading/preloading_has_one_spec.cr | 3 +++ src/avram/associations.cr | 5 +++-- src/avram/associations/belongs_to.cr | 8 +++---- src/avram/associations/has_many.cr | 12 +++++------ src/avram/associations/has_one.cr | 8 +++---- 8 files changed, 48 insertions(+), 23 deletions(-) diff --git a/spec/avram/preloading/preloading_belongs_to_spec.cr b/spec/avram/preloading/preloading_belongs_to_spec.cr index 3644a1ce0..b22d751d9 100644 --- a/spec/avram/preloading/preloading_belongs_to_spec.cr +++ b/spec/avram/preloading/preloading_belongs_to_spec.cr @@ -14,26 +14,34 @@ describe "Preloading belongs_to associations" do CommentFactory.create &.post_id(post.id) comments = Comment::BaseQuery.new.preload_post + comment = comments.first.as(Comment) - comments.first.post.should eq(post) + comment.post.should eq(post) + comment.post_preloaded?.should eq(true) Post::BaseQuery.times_called.should eq 1 end end it "works with optional association" do with_lazy_load(enabled: false) do - employee = EmployeeFactory.create + EmployeeFactory.create manager = ManagerFactory.create employees = Employee::BaseQuery.new.preload_manager - employees.first.manager.should be_nil + employee = employees.first.as(Employee) + employee.manager.should be_nil + # This is a strange edge case when the object went through + # preloading, but no association exists + employee.manager_preloaded?.should eq(true) 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) + employee = employees.first.as(Employee) + employee.manager.should eq(manager) + employee.manager_preloaded?.should eq(true) end end @@ -43,6 +51,7 @@ describe "Preloading belongs_to associations" do comment = CommentFactory.create &.post_id(post.id) comment = Comment::BaseQuery.find(comment.id) + comment.post_preloaded?.should eq(false) expect_raises Avram::LazyLoadError do comment.post @@ -59,6 +68,8 @@ describe "Preloading belongs_to associations" do comment = Comment::BaseQuery.new.preload_post(Post::BaseQuery.new.preload_comments).find(comment.id) comment.post.comments.should eq([comment, comment2]) + comment.post_preloaded?.should eq(true) + comment.post.comments_preloaded?.should eq(true) end end @@ -69,6 +80,8 @@ describe "Preloading belongs_to associations" do query = Comment::BaseQuery.new.preload_post 2.times { query.results } + comment = query.results.first.as(Comment) + comment.post_preloaded?.should eq(true) end it "works with uuid foreign keys" do diff --git a/spec/avram/preloading/preloading_has_many_spec.cr b/spec/avram/preloading/preloading_has_many_spec.cr index 52b173010..22f704c2b 100644 --- a/spec/avram/preloading/preloading_has_many_spec.cr +++ b/spec/avram/preloading/preloading_has_many_spec.cr @@ -17,6 +17,7 @@ describe "Preloading has_many associations" do posts.results.first.comments.should eq([comment]) Comment::BaseQuery.times_called.should eq 1 + posts.results.first.comments_preloaded?.should eq(true) end end @@ -33,6 +34,7 @@ describe "Preloading has_many associations" do results = posts.results results.size.should eq(1) results.first.comments.should eq([comment]) + results.first.comments_preloaded?.should eq(true) end end @@ -76,6 +78,7 @@ describe "Preloading has_many associations" do it "raises error if accessing association without preloading first" do with_lazy_load(enabled: false) do post = PostFactory.create + post.comments_preloaded?.should eq(false) expect_raises Avram::LazyLoadError do post.comments @@ -90,6 +93,7 @@ describe "Preloading has_many associations" do posts = Post::BaseQuery.new.preload_comments posts.results.first.comments.should eq([] of Comment) + posts.results.first.comments_preloaded?.should eq(true) end end @@ -99,6 +103,7 @@ describe "Preloading has_many associations" do posts = Post::BaseQuery.new.preload_comments 2.times { posts.results } + posts.results.first.comments_preloaded?.should eq(true) end it "does not fail when getting results multiple times with custom query" do diff --git a/spec/avram/preloading/preloading_has_many_through_spec.cr b/spec/avram/preloading/preloading_has_many_through_spec.cr index bda5b5c8c..7bba77dae 100644 --- a/spec/avram/preloading/preloading_has_many_through_spec.cr +++ b/spec/avram/preloading/preloading_has_many_through_spec.cr @@ -17,10 +17,11 @@ describe "Preloading has_many through associations" do TaggingFactory.create &.tag_id(tag.id).post_id(post.id) TaggingFactory.create &.tag_id(tag.id).post_id(other_post.id) - post_tags = Post::BaseQuery.new.preload_tags.results.first.tags + post = Post::BaseQuery.new.preload_tags.results.first + post.tags_preloaded?.should eq(true) - post_tags.size.should eq(1) - post_tags.should eq([tag]) + post.tags.size.should eq(1) + post.tags.should eq([tag]) end end @@ -46,6 +47,7 @@ describe "Preloading has_many through associations" do posts = Post::BaseQuery.new.preload_tags 2.times { posts.results } + posts.results.first.tags_preloaded?.should eq(true) end end @@ -129,6 +131,7 @@ describe "Preloading has_many through associations" do tag = TagFactory.create original_post = PostFactory.create TaggingFactory.create &.tag_id(tag.id).post_id(original_post.id) + original_post.tags_preloaded?.should eq(false) Post::BaseQuery.preload_tags(original_post) diff --git a/spec/avram/preloading/preloading_has_one_spec.cr b/spec/avram/preloading/preloading_has_one_spec.cr index 817f336ec..8ccacc869 100644 --- a/spec/avram/preloading/preloading_has_one_spec.cr +++ b/spec/avram/preloading/preloading_has_one_spec.cr @@ -14,6 +14,7 @@ describe "Preloading has_one associations" do admin = Admin::BaseQuery.new.preload_sign_in_credential + admin.first.sign_in_credential_preloaded?.should eq(true) admin.first.sign_in_credential.should eq sign_in_credential end end @@ -49,6 +50,7 @@ describe "Preloading has_one associations" do with_lazy_load(enabled: false) do admin = AdminFactory.create SignInCredentialFactory.create &.user_id(admin.id) + admin.sign_in_credential_preloaded?.should eq(false) expect_raises Avram::LazyLoadError do admin.sign_in_credential @@ -95,6 +97,7 @@ describe "Preloading has_one associations" do admin = Admin::BaseQuery.preload_sign_in_credential(admin) admin.sign_in_credential.should eq sign_in_credential + admin.sign_in_credential_preloaded?.should eq(true) end end diff --git a/src/avram/associations.cr b/src/avram/associations.cr index 7a8b0331d..b321cb523 100644 --- a/src/avram/associations.cr +++ b/src/avram/associations.cr @@ -19,7 +19,8 @@ module Avram::Associations get_{{ assoc_name.id }} end - protected getter? _{{ assoc_name }}_preloaded : Bool = false + # Returns `true` if the association has been preloaded + getter? {{ assoc_name }}_preloaded : Bool = false private getter _preloaded_{{ assoc_name }} : {{ model }}? end @@ -30,7 +31,7 @@ module Avram::Associations {% if !nilable %} raise Avram::MissingRequiredAssociationError.new(self.class, {{ model }}) if record.nil? {% end %} - @_{{ assoc_name }}_preloaded = true + @{{ assoc_name }}_preloaded = true @_preloaded_{{ assoc_name }} = record end end diff --git a/src/avram/associations/belongs_to.cr b/src/avram/associations/belongs_to.cr index d1e003b66..0741c703f 100644 --- a/src/avram/associations/belongs_to.cr +++ b/src/avram/associations/belongs_to.cr @@ -30,7 +30,7 @@ module Avram::Associations::BelongsTo private macro define_belongs_to_private_assoc_getter(assoc_name, model, foreign_key, nilable) private def get_{{ assoc_name.id }}(allow_lazy : Bool = false) : {{ model }}{% if nilable %}?{% end %} - if _{{ assoc_name }}_preloaded? + if {{ assoc_name }}_preloaded? @_preloaded_{{ assoc_name }}{% unless nilable %}.not_nil!{% end %} elsif lazy_load_enabled? || allow_lazy {{ foreign_key }}.try do |value| @@ -58,7 +58,7 @@ module Avram::Associations::BelongsTo end def self.preload_{{ assoc_name }}(record : {{ class_type }}, preload_query : {{ model }}::BaseQuery, force : Bool = false) : {{ class_type }} - return record if record._{{ assoc_name }}_preloaded? && !force + return record if record.{{ assoc_name }}_preloaded? && !force new_record = record.dup assoc = record.{{ foreign_key }}.try { |id| preload_query.id(id).first? } @@ -78,7 +78,7 @@ module Avram::Associations::BelongsTo def self.preload_{{ assoc_name }}(records : Enumerable({{ class_type }}), preload_query : {{ model }}::BaseQuery, force : Bool = false) : Array({{ class_type }}) ids = records.compact_map do |record| - if record._{{ assoc_name }}_preloaded? && !force + if record.{{ assoc_name }}_preloaded? && !force nil else record.{{ foreign_key }} @@ -87,7 +87,7 @@ module Avram::Associations::BelongsTo empty_results = {} of {{ model }}::PrimaryKeyType => Array({{ model }}) {{ assoc_name }} = ids.empty? ? empty_results : preload_query.id.in(ids).results.group_by(&.id) records.map do |record| - if record._{{ assoc_name }}_preloaded? && !force + if record.{{ assoc_name }}_preloaded? && !force next record end diff --git a/src/avram/associations/has_many.cr b/src/avram/associations/has_many.cr index 69f70a46c..dc9acd6da 100644 --- a/src/avram/associations/has_many.cr +++ b/src/avram/associations/has_many.cr @@ -58,13 +58,13 @@ module Avram::Associations::HasMany {% if through %} def self.preload_{{ assoc_name }}(record : {{ class_type }}, preload_query : {{ model }}::BaseQuery, force : Bool = false) : {{ class_type }} - return record if record._{{ assoc_name }}_preloaded? && !force + return record if record.{{ assoc_name }}_preloaded? && !force preload_{{ assoc_name }}(records: [record], preload_query: preload_query, force: force).first end {% else %} def self.preload_{{ assoc_name }}(record : {{ class_type }}, preload_query : {{ model }}::BaseQuery, force : Bool = false) : {{ class_type }} - return record if record._{{ assoc_name }}_preloaded? && !force + return record if record.{{ assoc_name }}_preloaded? && !force new_record = record.dup new_record._preloaded_{{ assoc_name }} = preload_query.{{ foreign_key }}(record.id).results @@ -102,7 +102,7 @@ module Avram::Associations::HasMany {% else %} def self.preload_{{ assoc_name }}(records : Enumerable({{ class_type }}), preload_query : {{ model }}::BaseQuery, force : Bool = false) : Array({{ class_type }}) ids = records.compact_map do |record| - if record._{{ assoc_name }}_preloaded? && !force + if record.{{ assoc_name }}_preloaded? && !force nil else record.id @@ -111,7 +111,7 @@ module Avram::Associations::HasMany 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 do |record| - if record._{{ assoc_name }}_preloaded? && !force + if record.{{ assoc_name }}_preloaded? && !force next record end @@ -171,10 +171,10 @@ module Avram::Associations::HasMany private macro define_has_many_lazy_loading(assoc_name, model, foreign_key, through) @_preloaded_{{ assoc_name }} : Array({{ model }})? - protected getter? _{{ assoc_name }}_preloaded : Bool = false + getter? {{ assoc_name }}_preloaded : Bool = false def _preloaded_{{ assoc_name }}=(vals : Array({{ model }})) : Array({{ model }}) - @_{{ assoc_name }}_preloaded = true + @{{ assoc_name }}_preloaded = true @_preloaded_{{ assoc_name }} = vals end diff --git a/src/avram/associations/has_one.cr b/src/avram/associations/has_one.cr index c42aeb9fc..ceac6f571 100644 --- a/src/avram/associations/has_one.cr +++ b/src/avram/associations/has_one.cr @@ -30,7 +30,7 @@ module Avram::Associations::HasOne private macro define_has_one_private_assoc_getter(assoc_name, model, foreign_key, nilable) private def get_{{ assoc_name.id }}(allow_lazy : Bool = false) : {{ model }}{% if nilable %}?{% end %} - if _{{ assoc_name }}_preloaded? + if {{ assoc_name }}_preloaded? @_preloaded_{{ assoc_name }}{% unless nilable %}.not_nil!{% end %} elsif lazy_load_enabled? || allow_lazy {{ model }}::BaseQuery.new @@ -54,7 +54,7 @@ module Avram::Associations::HasOne end def self.preload_{{ assoc_name }}(record : {{ class_type }}, preload_query : {{ model }}::BaseQuery, force : Bool = false) : {{ class_type }} - return record if record._{{ assoc_name }}_preloaded? && !force + return record if record.{{ assoc_name }}_preloaded? && !force new_record = record.dup assoc = preload_query.{{ foreign_key }}(record.id).first? @@ -73,7 +73,7 @@ module Avram::Associations::HasOne def self.preload_{{ assoc_name }}(records : Enumerable({{ class_type }}), preload_query : {{ model }}::BaseQuery, force : Bool = false) : Array({{ class_type }}) ids = records.compact_map do |record| - if record._{{ assoc_name }}_preloaded? && !force + if record.{{ assoc_name }}_preloaded? && !force nil else record.id @@ -82,7 +82,7 @@ module Avram::Associations::HasOne 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 do |record| - if record._{{ assoc_name }}_preloaded? && !force + if record.{{ assoc_name }}_preloaded? && !force next record end