Skip to content

Commit

Permalink
Merge pull request #663 from kbrock/child_ancestry_sql
Browse files Browse the repository at this point in the history
rebuild_counter_cache
  • Loading branch information
kbrock authored Apr 11, 2023
2 parents 8f06902 + 31bcc13 commit d7b577a
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 2 deletions.
25 changes: 25 additions & 0 deletions lib/ancestry/class_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -225,10 +225,35 @@ def rebuild_depth_cache!
end
end

# NOTE: this is temporarily kept separate from rebuild_depth_cache!
# this will become the implementation of rebuild_depth_cache!
def rebuild_depth_cache_sql!
update_all("#{depth_cache_column} = #{ancestry_depth_sql}")
end

def rebuild_counter_cache!
if %w(mysql mysql2).include?(connection.adapter_name.downcase)
connection.execute %{
UPDATE #{table_name} AS dest
LEFT JOIN (
SELECT #{table_name}.#{primary_key}, COUNT(*) AS child_count
FROM #{table_name}
JOIN #{table_name} children ON children.#{ancestry_column} = (#{child_ancestry_sql})
GROUP BY #{table_name}.#{primary_key}
) src USING(#{primary_key})
SET dest.#{counter_cache_column} = src.child_count
}
else
update_all %{
#{counter_cache_column} = (
SELECT COUNT(*)
FROM #{table_name} children
WHERE children.#{ancestry_column} = (#{child_ancestry_sql})
)
}
end
end

def unscoped_where
yield ancestry_base_class.default_scoped.unscope(:where)
end
Expand Down
16 changes: 16 additions & 0 deletions lib/ancestry/materialized_path.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,14 @@ def ancestry_root
nil
end

def child_ancestry_sql
%{
CASE WHEN #{table_name}.#{ancestry_column} IS NULL THEN CAST(#{table_name}.#{primary_key} AS CHAR)
ELSE #{concat("#{table_name}.#{ancestry_column}", "'#{ancestry_delimiter}'", "CAST(#{table_name}.#{primary_key} AS CHAR)")}
END
}
end

def ancestry_depth_sql
@ancestry_depth_sql ||=
begin
Expand Down Expand Up @@ -119,6 +127,14 @@ def ancestry_depth_change(old_value, new_value)
parse_ancestry_column(new_value).size - parse_ancestry_column(old_value).size
end

def concat(*args)
if %w(sqlite sqlite3).include?(connection.adapter_name.downcase)
args.join('||')
else
%{CONCAT(#{args.join(', ')})}
end
end

private

def ancestry_validation_options(ancestry_primary_key_format)
Expand Down
4 changes: 4 additions & 0 deletions lib/ancestry/materialized_path2.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ def ancestry_root
ancestry_delimiter
end

def child_ancestry_sql
concat("#{table_name}.#{ancestry_column}", "CAST(#{table_name}.#{primary_key} AS CHAR)", "'#{ancestry_delimiter}'")
end

def ancestry_depth_sql
@ancestry_depth_sql ||=
begin
Expand Down
15 changes: 15 additions & 0 deletions test/concerns/counter_cache_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,19 @@ def test_counter_cache_when_updating_record
end
end
end

def test_setting_counter_cache
AncestryTestDatabase.with_model :depth => 2, :width => 2, :counter_cache => true do |model, roots|
model.update_all(model.counter_cache_column => 0)
# ensure they are successfully broken
roots.each do |lvl0_node, _lvl0_children|
assert_equal 0, lvl0_node.reload.children_count
end
model.rebuild_counter_cache!
# ensure they are successfully built
roots.each do |lvl0_node, _lvl0_children|
assert_equal 2, lvl0_node.reload.children_count
end
end
end
end
2 changes: 0 additions & 2 deletions test/concerns/depth_caching_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,6 @@ def test_rebuild_depth_cache_with_sql
end

# Rebuild cache
# require "byebug"
# byebug
model.rebuild_depth_cache_sql!

# Assert cache was rebuild correctly
Expand Down

0 comments on commit d7b577a

Please sign in to comment.