acts_as_recursive_tree 2.0.2 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.gitignore +2 -1
- data/Appraisals +26 -0
- data/CHANGELOG.md +12 -0
- data/acts_as_recursive_tree.gemspec +4 -4
- data/lib/acts_as_recursive_tree.rb +1 -0
- data/lib/acts_as_recursive_tree/acts_macro.rb +3 -6
- data/lib/acts_as_recursive_tree/associations.rb +3 -3
- data/lib/acts_as_recursive_tree/builders.rb +1 -0
- data/lib/acts_as_recursive_tree/builders/ancestors.rb +1 -4
- data/lib/acts_as_recursive_tree/builders/descendants.rb +1 -3
- data/lib/acts_as_recursive_tree/builders/leaves.rb +1 -1
- data/lib/acts_as_recursive_tree/builders/relation_builder.rb +29 -25
- data/lib/acts_as_recursive_tree/builders/strategy.rb +30 -0
- data/lib/acts_as_recursive_tree/builders/strategy/ancestor.rb +17 -0
- data/lib/acts_as_recursive_tree/builders/strategy/descendant.rb +17 -0
- data/lib/acts_as_recursive_tree/builders/strategy/join.rb +33 -0
- data/lib/acts_as_recursive_tree/builders/strategy/subselect.rb +23 -0
- data/lib/acts_as_recursive_tree/config.rb +22 -0
- data/lib/acts_as_recursive_tree/options/query_options.rb +8 -1
- data/lib/acts_as_recursive_tree/options/values.rb +13 -1
- data/lib/acts_as_recursive_tree/version.rb +1 -1
- data/spec/builders_spec.rb +5 -2
- data/spec/db/database.rb +8 -2
- data/spec/values_spec.rb +2 -2
- metadata +31 -24
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 | 
            -
             | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 2 | 
            +
            SHA256:
         | 
| 3 | 
            +
              metadata.gz: ea1cf22b09ed91c55f3388b8c794a3d820eb353896feca3df3cd16bfadd1e1fb
         | 
| 4 | 
            +
              data.tar.gz: 55605034be64624f710175f2bc5714273f87e39124799fa4952dfb8425f9719d
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 4e357b5809c1aa3c28789af9c81d6ac17739f04b40cec8e43a6ecb2b690ea69e9d3752aab7cf3579fb38042b387132c9e02ddf5b3facc54b1206b33eb184d194
         | 
| 7 | 
            +
              data.tar.gz: 97a0ecfa41d4085f2a6a14a964be479747f4857af9400e9412699f6b7a21324c2af3632bba5831576ac08156fa8ff01ff06025e09c46b0e51fe64221b8a8bef6
         | 
    
        data/.gitignore
    CHANGED
    
    
    
        data/Appraisals
    ADDED
    
    | @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            appraise "ar-50" do
         | 
| 2 | 
            +
                ruby '~> 2'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                gem 'activerecord', '~> 5.0.0'
         | 
| 5 | 
            +
                gem 'sqlite3', '~> 1.3.6'
         | 
| 6 | 
            +
            end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            appraise "ar-51" do
         | 
| 9 | 
            +
                ruby '~> 2'
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                gem 'activerecord', '~> 5.1.0'
         | 
| 12 | 
            +
            end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            appraise "ar-52" do
         | 
| 15 | 
            +
                ruby '~> 2'
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                gem 'activerecord', '~> 5.2.0'
         | 
| 18 | 
            +
            end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            appraise "ar-60" do
         | 
| 21 | 
            +
                gem 'activerecord', '~> 6.0.0'
         | 
| 22 | 
            +
            end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            appraise "ar-61" do
         | 
| 25 | 
            +
                gem 'activerecord', '~> 6.1.0'
         | 
| 26 | 
            +
            end
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,3 +1,15 @@ | |
| 1 | 
            +
            ### Version 2.2.0
         | 
| 2 | 
            +
            - Rails 6.0 support
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            ### Version 2.1.1
         | 
| 5 | 
            +
            - Enabled subselect query when using depth
         | 
| 6 | 
            +
            - new QueryOption query_strategy for forcing a specific strategy (:join, :subselect)
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            ### Version 2.1.0
         | 
| 9 | 
            +
            - BUGFIX association self_and_siblings not working
         | 
| 10 | 
            +
            - BUGFIX primary_key of model is retrieved on first usage and not on setup
         | 
| 11 | 
            +
            - NEW when no ordering/depth is required, then use subselect instead of joining the temp table
         | 
| 12 | 
            +
             | 
| 1 13 | 
             
            ### Version 2.0.2
         | 
| 2 14 | 
             
            - fix for condition relation was executed before merging
         | 
| 3 15 |  | 
| @@ -6,8 +6,8 @@ require 'acts_as_recursive_tree/version' | |
| 6 6 | 
             
            Gem::Specification.new do |spec|
         | 
| 7 7 | 
             
              spec.name        = 'acts_as_recursive_tree'
         | 
| 8 8 | 
             
              spec.version     = ActsAsRecursiveTree::VERSION
         | 
| 9 | 
            -
              spec.authors     = ['Wolfgang Wedelich-John']
         | 
| 10 | 
            -
              spec.email       = ['wolfgang.wedelich@1und1.de']
         | 
| 9 | 
            +
              spec.authors     = ['Wolfgang Wedelich-John', 'Willem Mulder']
         | 
| 10 | 
            +
              spec.email       = ['wolfgang.wedelich@1und1.de', '14mRh4X0r@gmail.com']
         | 
| 11 11 | 
             
              spec.summary     = %q{Drop in replacement for acts_as_tree but using recursive queries}
         | 
| 12 12 | 
             
              spec.description = %q{
         | 
| 13 13 | 
             
              This is a ruby gem that provides drop in replacement for acts_as_tree but makes use of SQL recursive statement. Be sure to have a DBMS that supports recursive queries when using this gem (e.g. PostgreSQL or SQLite). }
         | 
| @@ -20,11 +20,11 @@ Gem::Specification.new do |spec| | |
| 20 20 | 
             
              spec.test_files            = spec.files.grep(%r{^spec/})
         | 
| 21 21 | 
             
              spec.require_paths         = ['lib']
         | 
| 22 22 |  | 
| 23 | 
            -
              spec.add_runtime_dependency 'activerecord', '>= 5.0.0', '< 6. | 
| 23 | 
            +
              spec.add_runtime_dependency 'activerecord', '>= 5.0.0', '< 6.2.0'
         | 
| 24 24 |  | 
| 25 | 
            -
              spec.add_development_dependency 'bundler', '~> 1.7'
         | 
| 26 25 | 
             
              spec.add_development_dependency 'database_cleaner', '~> 1.5'
         | 
| 27 26 | 
             
              spec.add_development_dependency 'rake', '~> 10.0'
         | 
| 28 27 | 
             
              spec.add_development_dependency 'rspec-rails', '~> 3.5'
         | 
| 29 28 | 
             
              spec.add_development_dependency 'sqlite3', '~> 1.3'
         | 
| 29 | 
            +
              spec.add_development_dependency 'appraisal', '~> 2.4'
         | 
| 30 30 | 
             
            end
         | 
| @@ -1,5 +1,3 @@ | |
| 1 | 
            -
            require 'ostruct'
         | 
| 2 | 
            -
             | 
| 3 1 | 
             
            module ActsAsRecursiveTree
         | 
| 4 2 | 
             
              module ActsMacro
         | 
| 5 3 |  | 
| @@ -11,11 +9,10 @@ module ActsAsRecursiveTree | |
| 11 9 | 
             
                def recursive_tree(parent_key: :parent_id, parent_type_column: nil)
         | 
| 12 10 |  | 
| 13 11 | 
             
                  class_attribute :_recursive_tree_config
         | 
| 14 | 
            -
                  self._recursive_tree_config =  | 
| 15 | 
            -
                     | 
| 12 | 
            +
                  self._recursive_tree_config = Config.new(
         | 
| 13 | 
            +
                    model_class:        self,
         | 
| 16 14 | 
             
                    parent_key:         parent_key.to_sym,
         | 
| 17 | 
            -
                    parent_type_column: parent_type_column.try(:to_sym) | 
| 18 | 
            -
                    depth_column:       :recursive_depth
         | 
| 15 | 
            +
                    parent_type_column: parent_type_column.try(:to_sym)
         | 
| 19 16 | 
             
                  )
         | 
| 20 17 |  | 
| 21 18 | 
             
                  include ActsAsRecursiveTree::Model
         | 
| @@ -17,9 +17,9 @@ module ActsAsRecursiveTree | |
| 17 17 | 
             
                           inverse_of:  :parent
         | 
| 18 18 |  | 
| 19 19 | 
             
                  has_many :self_and_siblings,
         | 
| 20 | 
            -
                            | 
| 21 | 
            -
                            | 
| 22 | 
            -
                            | 
| 20 | 
            +
                           through: :parent,
         | 
| 21 | 
            +
                           source: :children,
         | 
| 22 | 
            +
                           class_name:  self.base_class.to_s
         | 
| 23 23 | 
             
                end
         | 
| 24 24 | 
             
              end
         | 
| 25 25 | 
             
            end
         | 
| @@ -1,10 +1,7 @@ | |
| 1 1 | 
             
            module ActsAsRecursiveTree
         | 
| 2 2 | 
             
              module Builders
         | 
| 3 3 | 
             
                class Ancestors < RelationBuilder
         | 
| 4 | 
            -
             | 
| 5 | 
            -
                  def build_join_condition
         | 
| 6 | 
            -
                    travers_loc_table[parent_key].eq(base_table[primary_key])
         | 
| 7 | 
            -
                  end
         | 
| 4 | 
            +
                  self.traversal_strategy = ActsAsRecursiveTree::Builders::Strategy::Ancestor
         | 
| 8 5 |  | 
| 9 6 | 
             
                  def get_query_options(_)
         | 
| 10 7 | 
             
                    opts = super
         | 
| @@ -1,9 +1,7 @@ | |
| 1 1 | 
             
            module ActsAsRecursiveTree
         | 
| 2 2 | 
             
              module Builders
         | 
| 3 3 | 
             
                class Descendants < RelationBuilder
         | 
| 4 | 
            -
                   | 
| 5 | 
            -
                    base_table[parent_key].eq(travers_loc_table[primary_key])
         | 
| 6 | 
            -
                  end
         | 
| 4 | 
            +
                  self.traversal_strategy = ActsAsRecursiveTree::Builders::Strategy::Descendant
         | 
| 7 5 | 
             
                end
         | 
| 8 6 | 
             
              end
         | 
| 9 7 | 
             
            end
         | 
| @@ -1,14 +1,20 @@ | |
| 1 1 | 
             
            module ActsAsRecursiveTree
         | 
| 2 2 | 
             
              module Builders
         | 
| 3 | 
            +
                #
         | 
| 4 | 
            +
                # Constructs the Arel necessary for recursion.
         | 
| 5 | 
            +
                #
         | 
| 3 6 | 
             
                class RelationBuilder
         | 
| 4 7 |  | 
| 5 8 | 
             
                  def self.build(klass, ids, exclude_ids: false, &block)
         | 
| 6 9 | 
             
                    new(klass, ids, exclude_ids: exclude_ids, &block).build
         | 
| 7 10 | 
             
                  end
         | 
| 8 11 |  | 
| 12 | 
            +
                  class_attribute :traversal_strategy, instance_writer: false
         | 
| 13 | 
            +
             | 
| 9 14 | 
             
                  attr_reader :klass, :ids, :recursive_temp_table, :travers_loc_table, :without_ids
         | 
| 10 15 | 
             
                  mattr_reader(:random) { Random.new }
         | 
| 11 16 |  | 
| 17 | 
            +
                  # Delegators for easier accessing config and query options
         | 
| 12 18 | 
             
                  delegate :primary_key, :depth_column, :parent_key, :parent_type_column, to: :@config
         | 
| 13 19 | 
             
                  delegate :depth_present?, :depth, :condition, :ensure_ordering, to: :@query_opts
         | 
| 14 20 |  | 
| @@ -25,6 +31,13 @@ module ActsAsRecursiveTree | |
| 25 31 | 
             
                    @travers_loc_table    = Arel::Table.new("traverse_#{rand_int}_loc")
         | 
| 26 32 | 
             
                  end
         | 
| 27 33 |  | 
| 34 | 
            +
                  #
         | 
| 35 | 
            +
                  # Constructs a new QueryOptions and yield it to the proc if one is present.
         | 
| 36 | 
            +
                  # Subclasses may override this method to provide sane defaults.
         | 
| 37 | 
            +
                  #
         | 
| 38 | 
            +
                  # @param proc [Proc] a proc or nil
         | 
| 39 | 
            +
                  #
         | 
| 40 | 
            +
                  # @return [ActsAsRecursiveTree::Options::QueryOptions] the new QueryOptions instance
         | 
| 28 41 | 
             
                  def get_query_options(proc)
         | 
| 29 42 | 
             
                    opts = ActsAsRecursiveTree::Options::QueryOptions.new
         | 
| 30 43 |  | 
| @@ -38,18 +51,9 @@ module ActsAsRecursiveTree | |
| 38 51 | 
             
                  end
         | 
| 39 52 |  | 
| 40 53 | 
             
                  def build
         | 
| 41 | 
            -
                     | 
| 42 | 
            -
                      create_select_manger.as(recursive_temp_table.name)
         | 
| 43 | 
            -
                    ).on(
         | 
| 44 | 
            -
                      base_table[primary_key].eq(recursive_temp_table[primary_key])
         | 
| 45 | 
            -
                    )
         | 
| 46 | 
            -
             | 
| 47 | 
            -
                    relation = klass.joins(final_select_mgr.join_sources)
         | 
| 54 | 
            +
                    relation = Strategy.for_query_options(@query_opts).build(self)
         | 
| 48 55 |  | 
| 49 56 | 
             
                    relation = apply_except_id(relation)
         | 
| 50 | 
            -
                    relation = apply_depth(relation)
         | 
| 51 | 
            -
                    relation = apply_order(relation)
         | 
| 52 | 
            -
             | 
| 53 57 | 
             
                    relation
         | 
| 54 58 | 
             
                  end
         | 
| 55 59 |  | 
| @@ -58,19 +62,22 @@ module ActsAsRecursiveTree | |
| 58 62 | 
             
                    relation.where(ids.apply_negated_to(base_table[primary_key]))
         | 
| 59 63 | 
             
                  end
         | 
| 60 64 |  | 
| 61 | 
            -
                  def apply_depth( | 
| 62 | 
            -
                    return  | 
| 65 | 
            +
                  def apply_depth(select_manager)
         | 
| 66 | 
            +
                    return select_manager unless depth_present?
         | 
| 63 67 |  | 
| 64 | 
            -
                     | 
| 68 | 
            +
                    select_manager.where(depth.apply_to(travers_loc_table[depth_column]))
         | 
| 65 69 | 
             
                  end
         | 
| 66 70 |  | 
| 67 | 
            -
                  def  | 
| 68 | 
            -
                     | 
| 69 | 
            -
             | 
| 70 | 
            -
             | 
| 71 | 
            +
                  def create_select_manger(column = nil)
         | 
| 72 | 
            +
                    projections = if column
         | 
| 73 | 
            +
                      travers_loc_table[column]
         | 
| 74 | 
            +
                    else
         | 
| 75 | 
            +
                      Arel.star
         | 
| 76 | 
            +
                    end
         | 
| 71 77 |  | 
| 72 | 
            -
             | 
| 73 | 
            -
             | 
| 78 | 
            +
                    select_mgr = travers_loc_table.project(projections).with(:recursive, build_cte_table)
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                    apply_depth(select_mgr)
         | 
| 74 81 | 
             
                  end
         | 
| 75 82 |  | 
| 76 83 | 
             
                  def build_cte_table
         | 
| @@ -93,7 +100,9 @@ module ActsAsRecursiveTree | |
| 93 100 | 
             
                  end
         | 
| 94 101 |  | 
| 95 102 | 
             
                  def build_union_select
         | 
| 96 | 
            -
                    join_condition = apply_parent_type_column( | 
| 103 | 
            +
                    join_condition = apply_parent_type_column(
         | 
| 104 | 
            +
                      traversal_strategy.build(self)
         | 
| 105 | 
            +
                    )
         | 
| 97 106 |  | 
| 98 107 | 
             
                    select_manager = base_table.join(travers_loc_table).on(join_condition)
         | 
| 99 108 |  | 
| @@ -124,11 +133,6 @@ module ActsAsRecursiveTree | |
| 124 133 | 
             
                    return relation if condition.nil?
         | 
| 125 134 | 
             
                    relation.merge(condition)
         | 
| 126 135 | 
             
                  end
         | 
| 127 | 
            -
             | 
| 128 | 
            -
                  def build_join_condition
         | 
| 129 | 
            -
                    raise 'not implemented'
         | 
| 130 | 
            -
                  end
         | 
| 131 | 
            -
             | 
| 132 136 | 
             
                end
         | 
| 133 137 | 
             
              end
         | 
| 134 138 | 
             
            end
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            module ActsAsRecursiveTree
         | 
| 2 | 
            +
              module Builders
         | 
| 3 | 
            +
                #
         | 
| 4 | 
            +
                # Strategy module for different strategies of how to build the resulting query.
         | 
| 5 | 
            +
                #
         | 
| 6 | 
            +
                module Strategy
         | 
| 7 | 
            +
                  extend ActiveSupport::Autoload
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  autoload :Join
         | 
| 10 | 
            +
                  autoload :Subselect
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  autoload :Descendant
         | 
| 13 | 
            +
                  autoload :Ancestor
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  #
         | 
| 16 | 
            +
                  # Returns a Strategy appropriate for query_opts
         | 
| 17 | 
            +
                  #
         | 
| 18 | 
            +
                  # @param query_opts [ActsAsRecursiveTree::Options::QueryOptions]
         | 
| 19 | 
            +
                  #
         | 
| 20 | 
            +
                  # @return a strategy class best suited for the opts
         | 
| 21 | 
            +
                  def self.for_query_options(query_opts)
         | 
| 22 | 
            +
                    if query_opts.ensure_ordering || query_opts.query_strategy == :join
         | 
| 23 | 
            +
                      Join
         | 
| 24 | 
            +
                    else
         | 
| 25 | 
            +
                      Subselect
         | 
| 26 | 
            +
                    end
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            end
         | 
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            module ActsAsRecursiveTree
         | 
| 2 | 
            +
              module Builders
         | 
| 3 | 
            +
                module Strategy
         | 
| 4 | 
            +
                  #
         | 
| 5 | 
            +
                  # Strategy for building ancestors relation
         | 
| 6 | 
            +
                  #
         | 
| 7 | 
            +
                  module Ancestor
         | 
| 8 | 
            +
                    #
         | 
| 9 | 
            +
                    # Builds the relation
         | 
| 10 | 
            +
                    #
         | 
| 11 | 
            +
                    def self.build(builder)
         | 
| 12 | 
            +
                      builder.travers_loc_table[builder.parent_key].eq(builder.base_table[builder.primary_key])
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
            end
         | 
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            module ActsAsRecursiveTree
         | 
| 2 | 
            +
              module Builders
         | 
| 3 | 
            +
                module Strategy
         | 
| 4 | 
            +
                  #
         | 
| 5 | 
            +
                  # Strategy for building descendants relation
         | 
| 6 | 
            +
                  #
         | 
| 7 | 
            +
                  module Descendant
         | 
| 8 | 
            +
                    #
         | 
| 9 | 
            +
                    # Builds the relation
         | 
| 10 | 
            +
                    #
         | 
| 11 | 
            +
                    def self.build(builder)
         | 
| 12 | 
            +
                      builder.base_table[builder.parent_key].eq(builder.travers_loc_table[builder.primary_key])
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
            end
         | 
| @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            module ActsAsRecursiveTree
         | 
| 2 | 
            +
              module Builders
         | 
| 3 | 
            +
                module Strategy
         | 
| 4 | 
            +
                  #
         | 
| 5 | 
            +
                  # Build a relation using an INNER JOIN.
         | 
| 6 | 
            +
                  #
         | 
| 7 | 
            +
                  module Join
         | 
| 8 | 
            +
                    #
         | 
| 9 | 
            +
                    # Builds the relation.
         | 
| 10 | 
            +
                    #
         | 
| 11 | 
            +
                    # @param builder [ActsAsRecursiveTree::Builders::RelationBuilder]
         | 
| 12 | 
            +
                    # @return [ActiveRecord::Relation]
         | 
| 13 | 
            +
                    def self.build(builder)
         | 
| 14 | 
            +
                      final_select_mgr = builder.base_table.join(
         | 
| 15 | 
            +
                        builder.create_select_manger.as(builder.recursive_temp_table.name)
         | 
| 16 | 
            +
                      ).on(
         | 
| 17 | 
            +
                        builder.base_table[builder.primary_key].eq(builder.recursive_temp_table[builder.primary_key])
         | 
| 18 | 
            +
                      )
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                      relation = builder.klass.joins(final_select_mgr.join_sources)
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                      relation = apply_order(builder, relation)
         | 
| 23 | 
            +
                      relation
         | 
| 24 | 
            +
                    end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                    def self.apply_order(builder, relation)
         | 
| 27 | 
            +
                      return relation unless builder.ensure_ordering
         | 
| 28 | 
            +
                      relation.order(builder.recursive_temp_table[builder.depth_column].asc)
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
            end
         | 
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            module ActsAsRecursiveTree
         | 
| 2 | 
            +
              module Builders
         | 
| 3 | 
            +
                module Strategy
         | 
| 4 | 
            +
                  #
         | 
| 5 | 
            +
                  # Strategy for building a relation using an WHERE ID IN(...).
         | 
| 6 | 
            +
                  #
         | 
| 7 | 
            +
                  module Subselect
         | 
| 8 | 
            +
                    #
         | 
| 9 | 
            +
                    # Builds the relation.
         | 
| 10 | 
            +
                    #
         | 
| 11 | 
            +
                    # @param builder [ActsAsRecursiveTree::Builders::RelationBuilder]
         | 
| 12 | 
            +
                    # @return [ActiveRecord::Relation]
         | 
| 13 | 
            +
                    def self.build(builder)
         | 
| 14 | 
            +
                      builder.klass.where(
         | 
| 15 | 
            +
                        builder.base_table[builder.primary_key].in(
         | 
| 16 | 
            +
                          builder.create_select_manger(builder.primary_key)
         | 
| 17 | 
            +
                        )
         | 
| 18 | 
            +
                      )
         | 
| 19 | 
            +
                    end
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
            end
         | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            module ActsAsRecursiveTree
         | 
| 2 | 
            +
              #
         | 
| 3 | 
            +
              # Stores the configuration of one Model class
         | 
| 4 | 
            +
              #
         | 
| 5 | 
            +
              class Config
         | 
| 6 | 
            +
                attr_reader :parent_key, :parent_type_column, :depth_column
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def initialize(model_class:, parent_key:, parent_type_column:, depth_column: :recursive_depth)
         | 
| 9 | 
            +
                  @model_class        = model_class
         | 
| 10 | 
            +
                  @parent_key         = parent_key
         | 
| 11 | 
            +
                  @parent_type_column = parent_type_column
         | 
| 12 | 
            +
                  @depth_column       = depth_column
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                #
         | 
| 16 | 
            +
                # Returns the primary key for the model class.
         | 
| 17 | 
            +
                # @return [Symbol]
         | 
| 18 | 
            +
                def primary_key
         | 
| 19 | 
            +
                  @primary_key ||= @model_class.primary_key.to_sym
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
            end
         | 
| @@ -2,8 +2,10 @@ module ActsAsRecursiveTree | |
| 2 2 | 
             
              module Options
         | 
| 3 3 | 
             
                class QueryOptions
         | 
| 4 4 |  | 
| 5 | 
            +
                  STRATEGIES = %i[subselect, join].freeze
         | 
| 6 | 
            +
             | 
| 5 7 | 
             
                  attr_accessor :condition
         | 
| 6 | 
            -
                  attr_reader :ensure_ordering
         | 
| 8 | 
            +
                  attr_reader :ensure_ordering, :query_strategy
         | 
| 7 9 |  | 
| 8 10 | 
             
                  def depth
         | 
| 9 11 | 
             
                    @depth ||= DepthCondition.new
         | 
| @@ -16,6 +18,11 @@ module ActsAsRecursiveTree | |
| 16 18 | 
             
                  def depth_present?
         | 
| 17 19 | 
             
                    @depth.present?
         | 
| 18 20 | 
             
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  def query_strategy=(strategy)
         | 
| 23 | 
            +
                    raise "invalid strategy #{strategy} - only #{STRATEGIES} are allowed" unless STRATEGIES.include?(strategy)
         | 
| 24 | 
            +
                    @query_strategy = strategy
         | 
| 25 | 
            +
                  end
         | 
| 19 26 | 
             
                end
         | 
| 20 27 | 
             
              end
         | 
| 21 28 | 
             
            end
         | 
| @@ -38,6 +38,16 @@ module ActsAsRecursiveTree | |
| 38 38 | 
             
                    end
         | 
| 39 39 | 
             
                  end
         | 
| 40 40 |  | 
| 41 | 
            +
                  class RangeValue < Base
         | 
| 42 | 
            +
                    def apply_to(attribute)
         | 
| 43 | 
            +
                      attribute.between(prepared_value)
         | 
| 44 | 
            +
                    end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                    def apply_negated_to(attribute)
         | 
| 47 | 
            +
                      attribute.not_between(prepared_value)
         | 
| 48 | 
            +
                    end
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
             | 
| 41 51 | 
             
                  class MultiValue < Base
         | 
| 42 52 | 
             
                    def apply_to(attribute)
         | 
| 43 53 | 
             
                      attribute.in(prepared_value)
         | 
| @@ -62,6 +72,8 @@ module ActsAsRecursiveTree | |
| 62 72 | 
             
                      SingleValue
         | 
| 63 73 | 
             
                    when ::ActiveRecord::Relation
         | 
| 64 74 | 
             
                      Relation
         | 
| 75 | 
            +
                    when Range
         | 
| 76 | 
            +
                      RangeValue
         | 
| 65 77 | 
             
                    when Enumerable
         | 
| 66 78 | 
             
                      MultiValue
         | 
| 67 79 | 
             
                    when ::ActiveRecord::Base
         | 
| @@ -74,4 +86,4 @@ module ActsAsRecursiveTree | |
| 74 86 | 
             
                  end
         | 
| 75 87 | 
             
                end
         | 
| 76 88 | 
             
              end
         | 
| 77 | 
            -
            end
         | 
| 89 | 
            +
            end
         | 
    
        data/spec/builders_spec.rb
    CHANGED
    
    | @@ -20,12 +20,14 @@ end | |
| 20 20 |  | 
| 21 21 | 
             
            shared_examples 'basic recursive examples' do
         | 
| 22 22 | 
             
              it { is_expected.to start_with "SELECT \"#{model_class.table_name}\".* FROM \"#{model_class.table_name}\"" }
         | 
| 23 | 
            +
             | 
| 23 24 | 
             
              it { is_expected.to match /WHERE "#{model_class.table_name}"."#{model_class.primary_key}" = #{model_id}/ }
         | 
| 25 | 
            +
             | 
| 24 26 | 
             
              it { is_expected.to match /WITH RECURSIVE "#{builder.travers_loc_table.name}" AS/ }
         | 
| 27 | 
            +
             | 
| 25 28 | 
             
              it { is_expected.to match /SELECT "#{model_class.table_name}"."#{model_class.primary_key}", "#{model_class.table_name}"."#{model_class._recursive_tree_config.parent_key}", 0 AS recursive_depth FROM "#{model_class.table_name}"/ }
         | 
| 29 | 
            +
             | 
| 26 30 | 
             
              it { is_expected.to match /SELECT "#{model_class.table_name}"."#{model_class.primary_key}", "#{model_class.table_name}"."#{model_class._recursive_tree_config.parent_key}", \("#{builder.travers_loc_table.name}"."recursive_depth" \+ 1\) AS recursive_depth FROM "#{model_class.table_name}"/ }
         | 
| 27 | 
            -
              it { is_expected.to match /#{Regexp.escape(builder.travers_loc_table.project(Arel.star).to_sql)}/ }
         | 
| 28 | 
            -
              it { is_expected.to match /"#{model_class.table_name}"."#{model_class.primary_key}" = "#{builder.recursive_temp_table.name}"."#{model_class.primary_key}"/ }
         | 
| 29 31 | 
             
            end
         | 
| 30 32 |  | 
| 31 33 | 
             
            shared_examples 'build recursive query' do
         | 
| @@ -70,6 +72,7 @@ shared_examples 'descendant query' do | |
| 70 72 | 
             
              include_context 'base_setup'
         | 
| 71 73 |  | 
| 72 74 | 
             
              it { is_expected.to match /"#{model_class.table_name}"."#{model_class._recursive_tree_config.parent_key}" = "#{builder.travers_loc_table.name}"."#{model_class.primary_key}"/ }
         | 
| 75 | 
            +
              it { is_expected.to match /#{Regexp.escape(builder.travers_loc_table.project(builder.travers_loc_table[model_class.primary_key]).to_sql)}/ }
         | 
| 73 76 | 
             
            end
         | 
| 74 77 |  | 
| 75 78 | 
             
            shared_context 'context with ordering' do
         | 
    
        data/spec/db/database.rb
    CHANGED
    
    | @@ -8,10 +8,16 @@ ActiveRecord::Migration.verbose = false | |
| 8 8 |  | 
| 9 9 | 
             
            ActiveRecord::Base.configurations = YAML::load(File.read("#{database_folder}/database.yml"))
         | 
| 10 10 |  | 
| 11 | 
            -
             | 
| 11 | 
            +
            if ActiveRecord.version >= Gem::Version.new('6.1.0')
         | 
| 12 | 
            +
              config = ActiveRecord::Base.configurations.configs_for env_name: database_adapter, name: "primary"
         | 
| 13 | 
            +
              database = config.database
         | 
| 14 | 
            +
            else
         | 
| 15 | 
            +
              config = ActiveRecord::Base.configurations[database_adapter]
         | 
| 16 | 
            +
              database = config["database"]
         | 
| 17 | 
            +
            end
         | 
| 12 18 |  | 
| 13 19 | 
             
            # remove database if present
         | 
| 14 | 
            -
            FileUtils.rm  | 
| 20 | 
            +
            FileUtils.rm database, force: true
         | 
| 15 21 |  | 
| 16 22 | 
             
            ActiveRecord::Base.establish_connection(database_adapter.to_sym)
         | 
| 17 23 | 
             
            ActiveRecord::Base.establish_connection(config)
         | 
    
        data/spec/values_spec.rb
    CHANGED
    
    | @@ -57,7 +57,7 @@ describe ActsAsRecursiveTree::Options::Values do | |
| 57 57 | 
             
                  let(:range) { 1..3 }
         | 
| 58 58 | 
             
                  subject(:value) { described_class.create(range) }
         | 
| 59 59 |  | 
| 60 | 
            -
                  it { is_expected.to be_a ActsAsRecursiveTree::Options::Values:: | 
| 60 | 
            +
                  it { is_expected.to be_a ActsAsRecursiveTree::Options::Values::RangeValue }
         | 
| 61 61 |  | 
| 62 62 | 
             
                  it 'should apply_to' do
         | 
| 63 63 | 
             
                    expect(value.apply_to(attribute).to_sql).to end_with "BETWEEN #{range.begin} AND #{range.end}"
         | 
| @@ -83,4 +83,4 @@ describe ActsAsRecursiveTree::Options::Values do | |
| 83 83 | 
             
                  end
         | 
| 84 84 | 
             
                end
         | 
| 85 85 | 
             
              end
         | 
| 86 | 
            -
            end
         | 
| 86 | 
            +
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,15 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: acts_as_recursive_tree
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 2. | 
| 4 | 
            +
              version: 2.2.1
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Wolfgang Wedelich-John
         | 
| 8 | 
            -
             | 
| 8 | 
            +
            - Willem Mulder
         | 
| 9 | 
            +
            autorequire:
         | 
| 9 10 | 
             
            bindir: bin
         | 
| 10 11 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 12 | 
            +
            date: 2021-07-30 00:00:00.000000000 Z
         | 
| 12 13 | 
             
            dependencies:
         | 
| 13 14 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 15 | 
             
              name: activerecord
         | 
| @@ -19,7 +20,7 @@ dependencies: | |
| 19 20 | 
             
                    version: 5.0.0
         | 
| 20 21 | 
             
                - - "<"
         | 
| 21 22 | 
             
                  - !ruby/object:Gem::Version
         | 
| 22 | 
            -
                    version: 6. | 
| 23 | 
            +
                    version: 6.2.0
         | 
| 23 24 | 
             
              type: :runtime
         | 
| 24 25 | 
             
              prerelease: false
         | 
| 25 26 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| @@ -29,21 +30,7 @@ dependencies: | |
| 29 30 | 
             
                    version: 5.0.0
         | 
| 30 31 | 
             
                - - "<"
         | 
| 31 32 | 
             
                  - !ruby/object:Gem::Version
         | 
| 32 | 
            -
                    version: 6. | 
| 33 | 
            -
            - !ruby/object:Gem::Dependency
         | 
| 34 | 
            -
              name: bundler
         | 
| 35 | 
            -
              requirement: !ruby/object:Gem::Requirement
         | 
| 36 | 
            -
                requirements:
         | 
| 37 | 
            -
                - - "~>"
         | 
| 38 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 39 | 
            -
                    version: '1.7'
         | 
| 40 | 
            -
              type: :development
         | 
| 41 | 
            -
              prerelease: false
         | 
| 42 | 
            -
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 43 | 
            -
                requirements:
         | 
| 44 | 
            -
                - - "~>"
         | 
| 45 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 46 | 
            -
                    version: '1.7'
         | 
| 33 | 
            +
                    version: 6.2.0
         | 
| 47 34 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 48 35 | 
             
              name: database_cleaner
         | 
| 49 36 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -100,11 +87,26 @@ dependencies: | |
| 100 87 | 
             
                - - "~>"
         | 
| 101 88 | 
             
                  - !ruby/object:Gem::Version
         | 
| 102 89 | 
             
                    version: '1.3'
         | 
| 90 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 91 | 
            +
              name: appraisal
         | 
| 92 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 93 | 
            +
                requirements:
         | 
| 94 | 
            +
                - - "~>"
         | 
| 95 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 96 | 
            +
                    version: '2.4'
         | 
| 97 | 
            +
              type: :development
         | 
| 98 | 
            +
              prerelease: false
         | 
| 99 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 100 | 
            +
                requirements:
         | 
| 101 | 
            +
                - - "~>"
         | 
| 102 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 103 | 
            +
                    version: '2.4'
         | 
| 103 104 | 
             
            description: "\n  This is a ruby gem that provides drop in replacement for acts_as_tree
         | 
| 104 105 | 
             
              but makes use of SQL recursive statement. Be sure to have a DBMS that supports recursive
         | 
| 105 106 | 
             
              queries when using this gem (e.g. PostgreSQL or SQLite). "
         | 
| 106 107 | 
             
            email:
         | 
| 107 108 | 
             
            - wolfgang.wedelich@1und1.de
         | 
| 109 | 
            +
            - 14mRh4X0r@gmail.com
         | 
| 108 110 | 
             
            executables: []
         | 
| 109 111 | 
             
            extensions: []
         | 
| 110 112 | 
             
            extra_rdoc_files: []
         | 
| @@ -113,6 +115,7 @@ files: | |
| 113 115 | 
             
            - ".rspec"
         | 
| 114 116 | 
             
            - ".rubocop.yml"
         | 
| 115 117 | 
             
            - ".rubocop_todo.yml"
         | 
| 118 | 
            +
            - Appraisals
         | 
| 116 119 | 
             
            - CHANGELOG.md
         | 
| 117 120 | 
             
            - Gemfile
         | 
| 118 121 | 
             
            - LICENSE.txt
         | 
| @@ -127,6 +130,12 @@ files: | |
| 127 130 | 
             
            - lib/acts_as_recursive_tree/builders/descendants.rb
         | 
| 128 131 | 
             
            - lib/acts_as_recursive_tree/builders/leaves.rb
         | 
| 129 132 | 
             
            - lib/acts_as_recursive_tree/builders/relation_builder.rb
         | 
| 133 | 
            +
            - lib/acts_as_recursive_tree/builders/strategy.rb
         | 
| 134 | 
            +
            - lib/acts_as_recursive_tree/builders/strategy/ancestor.rb
         | 
| 135 | 
            +
            - lib/acts_as_recursive_tree/builders/strategy/descendant.rb
         | 
| 136 | 
            +
            - lib/acts_as_recursive_tree/builders/strategy/join.rb
         | 
| 137 | 
            +
            - lib/acts_as_recursive_tree/builders/strategy/subselect.rb
         | 
| 138 | 
            +
            - lib/acts_as_recursive_tree/config.rb
         | 
| 130 139 | 
             
            - lib/acts_as_recursive_tree/model.rb
         | 
| 131 140 | 
             
            - lib/acts_as_recursive_tree/options.rb
         | 
| 132 141 | 
             
            - lib/acts_as_recursive_tree/options/depth_condition.rb
         | 
| @@ -149,7 +158,7 @@ homepage: https://github.com/1and1/acts_as_recursive_tree | |
| 149 158 | 
             
            licenses:
         | 
| 150 159 | 
             
            - MIT
         | 
| 151 160 | 
             
            metadata: {}
         | 
| 152 | 
            -
            post_install_message: | 
| 161 | 
            +
            post_install_message:
         | 
| 153 162 | 
             
            rdoc_options: []
         | 
| 154 163 | 
             
            require_paths:
         | 
| 155 164 | 
             
            - lib
         | 
| @@ -164,9 +173,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 164 173 | 
             
                - !ruby/object:Gem::Version
         | 
| 165 174 | 
             
                  version: '0'
         | 
| 166 175 | 
             
            requirements: []
         | 
| 167 | 
            -
             | 
| 168 | 
            -
             | 
| 169 | 
            -
            signing_key: 
         | 
| 176 | 
            +
            rubygems_version: 3.1.6
         | 
| 177 | 
            +
            signing_key:
         | 
| 170 178 | 
             
            specification_version: 4
         | 
| 171 179 | 
             
            summary: Drop in replacement for acts_as_tree but using recursive queries
         | 
| 172 180 | 
             
            test_files:
         | 
| @@ -180,4 +188,3 @@ test_files: | |
| 180 188 | 
             
            - spec/model/relation_spec.rb
         | 
| 181 189 | 
             
            - spec/spec_helper.rb
         | 
| 182 190 | 
             
            - spec/values_spec.rb
         | 
| 183 | 
            -
            has_rdoc: 
         |