From 76c34f2470d64608d2a3a5a468dfa6259c0017d0 Mon Sep 17 00:00:00 2001 From: Keenan Brock Date: Sat, 11 Mar 2023 00:44:35 -0500 Subject: [PATCH] update depth_cache_column using math Use math to adjust the depth_cache instead of re-calculating the depth Goal is to remove regular expression change --- lib/ancestry/materialized_path_pg.rb | 26 +++++++++++++++++++++----- test/concerns/depth_caching_test.rb | 21 ++++++++++++++++++++- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/lib/ancestry/materialized_path_pg.rb b/lib/ancestry/materialized_path_pg.rb index 5374be7c..99c5f3df 100644 --- a/lib/ancestry/materialized_path_pg.rb +++ b/lib/ancestry/materialized_path_pg.rb @@ -7,17 +7,33 @@ def update_descendants_with_new_ancestry ancestry_column = ancestry_base_class.ancestry_column old_ancestry = self.class.generate_ancestry( path_ids_before_last_save ) new_ancestry = self.class.generate_ancestry( path_ids ) - update_clause = [ + descendants_clause = [ "#{ancestry_column} = replace(#{ancestry_column}, '#{old_ancestry}', '#{new_ancestry}')" ] - if ancestry_base_class.respond_to?(:depth_cache_column) && respond_to?(ancestry_base_class.depth_cache_column) - depth_cache_column = ancestry_base_class.depth_cache_column.to_s - update_clause << "#{depth_cache_column} = length(regexp_replace(regexp_replace(ancestry, '^#{Regexp.escape(old_ancestry)}', '#{new_ancestry}'), '[^#{ancestry_base_class.ancestry_delimiter}]', '', 'g')) #{ancestry_base_class.ancestry_format == :materialized_path2 ? '-' : '+'} 1" - end + update_descendants_hook(descendants_clause, old_ancestry, new_ancestry) + unscoped_descendants_before_save.update_all descendants_clause.join(', ') unscoped_descendants_before_save.update_all update_clause.join(', ') end end + + # TODO: only install this if depth_cache is turned on (use chain_methods?) + def update_descendants_hook(descendants_clause, old_ancestry, new_ancestry) + if ancestry_base_class.respond_to?(:depth_cache_column) && respond_to?(ancestry_base_class.depth_cache_column) + depth_cache_column = ancestry_base_class.depth_cache_column.to_s + depth_change = ancestry_depth_change(old_ancestry, new_ancestry) + if depth_change != 0 + descendants_clause << "#{depth_cache_column} = #{depth_cache_column} + #{depth_change}" + end + end + end + end + end + + # pulled out to make testing easier + def ancestry_depth_change(old_value, new_value) + parse_ancestry_column(new_value).size - parse_ancestry_column(old_value).size + end end end diff --git a/test/concerns/depth_caching_test.rb b/test/concerns/depth_caching_test.rb index 6fae4cba..7f90d982 100644 --- a/test/concerns/depth_caching_test.rb +++ b/test/concerns/depth_caching_test.rb @@ -90,4 +90,23 @@ def test_exception_on_unknown_depth_column end end end -end \ No newline at end of file + + def test_ancestry_depth_change + AncestryTestDatabase.with_model do |model| + # this lets us test ancestry_depth_change but leaves model in a strange state + # do not create objects + model.extend(Ancestry::MaterializedPathPg) + { + [[], [1]] => +1, + [[1], []] => -1, + [[1], [2]] => 0, + [[1], [1, 2, 3]] => +2, + [[1, 2, 3], [1]] => -2 + }.each do |(before, after), diff| + a_before = model.generate_ancestry(before) + a_after = model.generate_ancestry(after) + assert_equal(diff, model.ancestry_depth_change(a_before, a_after)) + end + end + end +end