From c6f146d07e32f6ad4b686989e9885f3b7b963243 Mon Sep 17 00:00:00 2001 From: Keenan Brock Date: Tue, 26 Sep 2023 12:05:55 -0400 Subject: [PATCH] Add support for virtual depth column still need to consider whether to keep depth_cache_column as deprecated --- lib/ancestry/has_ancestry.rb | 38 ++++++++++++++++++++---------------- test/environment.rb | 16 ++++++++++++++- 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/lib/ancestry/has_ancestry.rb b/lib/ancestry/has_ancestry.rb index f14b68fa..84cc4c8c 100644 --- a/lib/ancestry/has_ancestry.rb +++ b/lib/ancestry/has_ancestry.rb @@ -70,26 +70,30 @@ def has_ancestry options = {} # Create ancestry column accessor and set to option or default if options[:cache_depth] - # Create accessor for column name and set to option or default - self.cattr_accessor :depth_cache_column - self.depth_cache_column = - if options[:cache_depth] == true - options[:depth_cache_column]&.to_s || 'ancestry_depth' - else - options[:cache_depth].to_s + if options[:cache_depth] == :virtual + # NOTE: not setting self.depth_cache_column so the code does not try to update the column + depth_cache_sql = options[:depth_cache_column]&.to_s || 'ancestry_depth' + else + # Create accessor for column name and set to option or default + self.cattr_accessor :depth_cache_column + self.depth_cache_column = + if options[:cache_depth] == true + options[:depth_cache_column]&.to_s || 'ancestry_depth' + else + options[:cache_depth].to_s + end + if options[:depth_cache_column] + ActiveSupport::Deprecation.warn("has_ancestry :depth_cache_column is deprecated. Use :cache_depth instead.") end - if options[:depth_cache_column] - ActiveSupport::Deprecation.warn("has_ancestry :depth_cache_column is deprecated. Use :cache_depth instead.") - end - - # Cache depth in depth cache column before save - before_validation :cache_depth - before_save :cache_depth - # Validate depth column - validates_numericality_of depth_cache_column, :greater_than_or_equal_to => 0, :only_integer => true, :allow_nil => false + # Cache depth in depth cache column before save + before_validation :cache_depth + before_save :cache_depth - depth_cache_sql = depth_cache_column + # Validate depth column + validates_numericality_of depth_cache_column, :greater_than_or_equal_to => 0, :only_integer => true, :allow_nil => false + depth_cache_sql = depth_cache_column + end else # this is not efficient, but it works depth_cache_sql = ancestry_depth_sql diff --git a/test/environment.rb b/test/environment.rb index a87f40fc..018e66fb 100644 --- a/test/environment.rb +++ b/test/environment.rb @@ -126,7 +126,21 @@ def self.with_model options = {} ActiveRecord::Base.connection.create_table 'test_nodes', **table_options do |table| table.send(column_type, options[:ancestry_column], **column_options(force_allow_nil: skip_ancestry)) - table.integer options[:cache_depth] == true ? :ancestry_depth : options[:cache_depth] if options[:cache_depth] + case options[:cache_depth] + when true + table.integer :ancestry_depth + when :virtual + # sorry, this duplicates has_ancestry a little + ancestry_format = options[:ancestry_format] || Ancestry.default_ancestry_format + path_module = ancestry_format == :materialized_path2 ? Ancestry::MaterializedPath2 : Ancestry::MaterializedPath + ancestry_depth_sql = path_module.construct_depth_sql("test_nodes", options[:ancestry_column], '/') + + table.virtual :ancestry_depth, type: :integer, as: ancestry_depth_sql, stored: true + when nil, false + # no column + else + table.integer options[:cache_depth] + end if options[:counter_cache] counter_cache_column = options[:counter_cache] == true ? :children_count : options[:counter_cache] table.integer counter_cache_column, default: 0, null: false