acts_as_recursive_tree 3.3.0 → 3.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b60be808a8b0a3e93edfbb83a83cc8b270eebade9888ddc6038bb4af4429d7da
4
- data.tar.gz: 96622ef4e488bbd73de8dd4d0ae51c51a2b11843219d2a34669367ace4f77d60
3
+ metadata.gz: 2ce9f3e8c4b5dd8d5e61e04d9234a07920f2063955d134110a40c217950595ea
4
+ data.tar.gz: baa87fc513a6fd8e49538309b1833e418328b1f7317584fc828d20689cbbd32b
5
5
  SHA512:
6
- metadata.gz: fca6f5732cc344c395d1d74f3cc13ac5be4af9ea74eb545764b28ef1a7550fcb3300975cccce92a2772f5d3ca1e12fb1e4a6e124f07037f66099b86256918c57
7
- data.tar.gz: 8b2cf07e6aa5ef4543f6d81200ac3421d918039140480314496c416f8ff3f6fce65a1ba43bdcae837f67df5e279e9281d8680ca76945d84a8115877eeb4cc7d2
6
+ metadata.gz: 7e21465a62a28f6ca757402689abe0709e131d3104f3334646105af34d594a0704d2aaf54fb72b11cb039fd7436845bec0dd335506ed8f5c48c599f89ae9a502
7
+ data.tar.gz: 242a7f33a0595155d0fc75eec0f17769ae0d92314db07a6cb5acab96737574498266efb6f2aa8f30af3ef3c9a4b87895cb7ab0ebf75d3d9469173131917a32e1
@@ -20,7 +20,7 @@ jobs:
20
20
  strategy:
21
21
  matrix:
22
22
  ruby-version: ['2.5', '2.6', '2.7', '3.0', '3.1', '3.2']
23
- gemfile: [ar_52, ar_60, ar_61, ar_70]
23
+ gemfile: [ar_52, ar_60, ar_61, ar_70, ar_next]
24
24
  exclude:
25
25
  - ruby-version: '3.2'
26
26
  gemfile: ar_52
@@ -36,12 +36,12 @@ jobs:
36
36
  gemfile: ar_61
37
37
  - ruby-version: '3.0'
38
38
  gemfile: ar_52
39
- # - ruby-version: '2.6'
40
- # gemfile: ar_next
39
+ - ruby-version: '2.6'
40
+ gemfile: ar_next
41
41
  - ruby-version: '2.6'
42
42
  gemfile: ar_70
43
- # - ruby-version: '2.5'
44
- # gemfile: ar_next
43
+ - ruby-version: '2.5'
44
+ gemfile: ar_next
45
45
  - ruby-version: '2.5'
46
46
  gemfile: ar_70
47
47
  env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ### Version 3.5.0
2
+ - Added :dependent option for setting explicit deletion behaviour (issue #31)
3
+ - Added automatic cycle detection when supported (currently only PostgresSQL 14+) (issue #22)
4
+
5
+ ### Version 3.4.0
6
+ - Rails 7.1 compatibility
7
+ - Added ar_next to test matrix
8
+ - Added updated databasecleaner to test latest active record from git
9
+
1
10
  ### Version 3.3.0
2
11
  - added __includes:__ option to __preload_tree__
3
12
 
data/README.md CHANGED
@@ -18,6 +18,7 @@ ActsAsRecursiveTree currently supports following ActiveRecord versions and is te
18
18
  * ActiveRecord 6.0.x
19
19
  * ActiveRecord 6.1.x
20
20
  * ActiveRecord 7.0.x
21
+ * ActiveRecord 7.1.x
21
22
 
22
23
  ## Supported Rubies
23
24
  ActsAsRecursiveTree is tested with following rubies:
@@ -54,18 +55,26 @@ class Node < ActiveRecord::Base
54
55
  recursive_tree
55
56
  end
56
57
  ```
57
- That's it. This will assume that your model has a column named `parent_id` which will be used for traversal. If your column is something different, then you can specifiy it in the call to `recursive_tree`:
58
+ That's it. This will assume that your model has a column named `parent_id` which will be used for traversal. If your column is something different, then you can specify it in the call to `recursive_tree`:
58
59
 
59
60
  ```ruby
60
61
  recursive_tree parent_key: :some_other_column
61
62
  ```
62
63
 
63
- Some extra special stuff - if your parent relation is also polymorphic, the specify the polymorphic column:
64
+ Some extra special stuff - if your parent relation is also polymorphic, then specify the polymorphic column:
64
65
 
65
66
  ```ruby
66
67
  recursive_tree parent_type_column: :some_other_type_column
67
68
  ```
68
69
 
70
+ Controlling deletion behaviour:
71
+
72
+ By default, it is up to the user code to delete all child nodes in a tree when a parent node gets deleted. This can be controlled by the `:dependent` option, which will be set on the `children` association (see [#has_many](https://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many) in the Rails doc).
73
+
74
+ ```ruby
75
+ recursive_tree dependent: :nullify # or :destroy, etc.
76
+ ```
77
+
69
78
  ## Usage
70
79
 
71
80
  After you set up a model for usage, there are now several methods you can use.
@@ -215,6 +224,15 @@ Instance Methods make no difference of the class from which they are called:
215
224
  sub_node_instance.descendants # => returns Node and SubNode instances
216
225
  ```
217
226
 
227
+ ## A note on endless recursion / cycle detection
228
+
229
+ ### Inserting
230
+ As of now it is up to the user code to guarantee there will be no cycles created in the parent/child entries. If not, your DB might run into an endless recursion. Inserting/updating records that will cause a cycle is not prevented by some validation checks, so you have to do this by your own. This might change in a future version.
231
+
232
+ ### Querying
233
+ If you want to make sure to not run into an endless recursion when querying, then there are following options:
234
+ 1. Add a maximum depth to the query options. If an cycle is present in your data, the recursion will stop when reaching the max depth and stop further traversing.
235
+ 2. When you are on recent version of PostgreSQL (14+) you are lucky. Postgres added the CYCLE detection feature to detect cycles and prevent endless recursion. Our query builder will add this feature if your DB does support this.
218
236
 
219
237
  ## Contributing
220
238
 
@@ -23,12 +23,12 @@ Gem::Specification.new do |spec|
23
23
  spec.test_files = spec.files.grep(%r{^spec/})
24
24
  spec.require_paths = ['lib']
25
25
 
26
- spec.add_runtime_dependency 'activerecord', '>= 5.2.0', '< 7.1'
27
- spec.add_runtime_dependency 'activesupport', '>= 5.2.0', '< 7.1'
26
+ spec.add_runtime_dependency 'activerecord', '>= 5.2.0', '< 8'
27
+ spec.add_runtime_dependency 'activesupport', '>= 5.2.0', '< 8'
28
28
  spec.add_runtime_dependency 'zeitwerk', '>= 2.4'
29
29
 
30
30
  spec.add_development_dependency 'appraisal', '~> 2.4'
31
- spec.add_development_dependency 'database_cleaner', '~> 2.0'
31
+ spec.add_development_dependency 'database_cleaner-active_record', '~> 2.1'
32
32
  spec.add_development_dependency 'rake'
33
33
  spec.add_development_dependency 'rspec-rails', '>= 3.5'
34
34
  spec.add_development_dependency 'rubocop', '~> 1.23.0'
@@ -7,13 +7,14 @@ module ActsAsRecursiveTree
7
7
  #
8
8
  # * <tt>foreign_key</tt> - specifies the column name to use for tracking
9
9
  # of the tree (default: +parent_id+)
10
- def recursive_tree(parent_key: :parent_id, parent_type_column: nil)
10
+ def recursive_tree(parent_key: :parent_id, parent_type_column: nil, dependent: nil)
11
11
  class_attribute(:_recursive_tree_config, instance_writer: false)
12
12
 
13
13
  self._recursive_tree_config = Config.new(
14
14
  model_class: self,
15
15
  parent_key: parent_key.to_sym,
16
- parent_type_column: parent_type_column.try(:to_sym)
16
+ parent_type_column: parent_type_column.try(:to_sym),
17
+ dependent: dependent
17
18
  )
18
19
 
19
20
  include ActsAsRecursiveTree::Model
@@ -16,7 +16,8 @@ module ActsAsRecursiveTree
16
16
  has_many :children,
17
17
  class_name: base_class.to_s,
18
18
  foreign_key: _recursive_tree_config.parent_key,
19
- inverse_of: :parent
19
+ inverse_of: :parent,
20
+ dependent: _recursive_tree_config.dependent
20
21
 
21
22
  has_many :self_and_siblings,
22
23
  through: :parent,
@@ -5,7 +5,7 @@ module ActsAsRecursiveTree
5
5
  class Ancestors < RelationBuilder
6
6
  self.traversal_strategy = ActsAsRecursiveTree::Builders::Strategies::Ancestor
7
7
 
8
- def get_query_options(_)
8
+ def get_query_options(&block)
9
9
  opts = super
10
10
  opts.ensure_ordering!
11
11
  opts
@@ -16,7 +16,7 @@ module ActsAsRecursiveTree
16
16
  select_manager
17
17
  end
18
18
 
19
- def get_query_options(_)
19
+ def get_query_options(&_block)
20
20
  # do not allow any custom options
21
21
  ActsAsRecursiveTree::Options::QueryOptions.new
22
22
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'securerandom'
4
+
3
5
  module ActsAsRecursiveTree
4
6
  module Builders
5
7
  #
@@ -12,40 +14,42 @@ module ActsAsRecursiveTree
12
14
 
13
15
  class_attribute :traversal_strategy, instance_writer: false
14
16
 
15
- attr_reader :klass, :ids, :recursive_temp_table, :travers_loc_table, :without_ids
16
-
17
- mattr_reader(:random) { Random.new }
17
+ attr_reader :klass, :ids, :without_ids
18
18
 
19
19
  # Delegators for easier accessing config and query options
20
- delegate :primary_key, :depth_column, :parent_key, :parent_type_column, to: :@config
20
+ delegate :primary_key, :depth_column, :parent_key, :parent_type_column, to: :config
21
21
  delegate :depth_present?, :depth, :condition, :ensure_ordering, to: :@query_opts
22
22
 
23
23
  def initialize(klass, ids, exclude_ids: false, &block)
24
24
  @klass = klass
25
- @config = klass._recursive_tree_config
26
- @ids = ActsAsRecursiveTree::Options::Values.create(ids, @config)
25
+ @ids = ActsAsRecursiveTree::Options::Values.create(ids, klass._recursive_tree_config)
27
26
  @without_ids = exclude_ids
28
27
 
29
- @query_opts = get_query_options(block)
28
+ @query_opts = get_query_options(&block)
29
+
30
+ # random seed for the temp tables
31
+ @rand_int = SecureRandom.rand(1_000_000)
32
+ end
33
+
34
+ def recursive_temp_table
35
+ @recursive_temp_table ||= Arel::Table.new("recursive_#{klass.table_name}_#{@rand_int}_temp")
36
+ end
37
+
38
+ def travers_loc_table
39
+ @travers_loc_table ||= Arel::Table.new("traverse_#{@rand_int}_loc")
40
+ end
30
41
 
31
- rand_int = random.rand(1_000_000)
32
- @recursive_temp_table = Arel::Table.new("recursive_#{klass.table_name}_#{rand_int}_temp")
33
- @travers_loc_table = Arel::Table.new("traverse_#{rand_int}_loc")
42
+ def config
43
+ klass._recursive_tree_config
34
44
  end
35
45
 
36
46
  #
37
47
  # Constructs a new QueryOptions and yield it to the proc if one is present.
38
48
  # Subclasses may override this method to provide sane defaults.
39
49
  #
40
- # @param proc [Proc] a proc or nil
41
- #
42
50
  # @return [ActsAsRecursiveTree::Options::QueryOptions] the new QueryOptions instance
43
- def get_query_options(proc)
44
- opts = ActsAsRecursiveTree::Options::QueryOptions.new
45
-
46
- proc&.call(opts)
47
-
48
- opts
51
+ def get_query_options(&block)
52
+ ActsAsRecursiveTree::Options::QueryOptions.from(&block)
49
53
  end
50
54
 
51
55
  def base_table
@@ -71,11 +75,7 @@ module ActsAsRecursiveTree
71
75
  end
72
76
 
73
77
  def create_select_manger(column = nil)
74
- projections = if column
75
- travers_loc_table[column]
76
- else
77
- Arel.star
78
- end
78
+ projections = column ? travers_loc_table[column] : Arel.star
79
79
 
80
80
  select_mgr = travers_loc_table.project(projections).with(:recursive, build_cte_table)
81
81
 
@@ -85,10 +85,24 @@ module ActsAsRecursiveTree
85
85
  def build_cte_table
86
86
  Arel::Nodes::As.new(
87
87
  travers_loc_table,
88
- build_base_select.union(build_union_select)
88
+ add_pg_cycle_detection(
89
+ build_base_select.union(build_union_select)
90
+ )
91
+ )
92
+ end
93
+
94
+ def add_pg_cycle_detection(union_query)
95
+ return union_query unless config.cycle_detection?
96
+
97
+ Arel::Nodes::InfixOperation.new(
98
+ '',
99
+ union_query,
100
+ Arel.sql("CYCLE #{primary_key} SET is_cycle USING path")
89
101
  )
90
102
  end
91
103
 
104
+ # Builds SQL:
105
+ # SELECT id, parent_id, 0 AS depth FROM base_table WHERE id = 123
92
106
  def build_base_select
93
107
  id_node = base_table[primary_key]
94
108
 
@@ -5,13 +5,14 @@ module ActsAsRecursiveTree
5
5
  # Stores the configuration of one Model class
6
6
  #
7
7
  class Config
8
- attr_reader :parent_key, :parent_type_column, :depth_column
8
+ attr_reader :parent_key, :parent_type_column, :depth_column, :dependent
9
9
 
10
- def initialize(model_class:, parent_key:, parent_type_column:, depth_column: :recursive_depth)
10
+ def initialize(model_class:, parent_key:, parent_type_column:, depth_column: :recursive_depth, dependent: nil)
11
11
  @model_class = model_class
12
12
  @parent_key = parent_key
13
13
  @parent_type_column = parent_type_column
14
14
  @depth_column = depth_column
15
+ @dependent = dependent
15
16
  end
16
17
 
17
18
  #
@@ -20,5 +21,15 @@ module ActsAsRecursiveTree
20
21
  def primary_key
21
22
  @primary_key ||= @model_class.primary_key.to_sym
22
23
  end
24
+
25
+ #
26
+ # Checks if SQL cycle detection can be used. This is currently supported only on PostgreSQL 14+.
27
+ # @return [TrueClass|FalseClass]
28
+ def cycle_detection?
29
+ return @cycle_detection if defined?(@cycle_detection)
30
+
31
+ @cycle_detection = @model_class.connection.adapter_name == 'PostgreSQL' &&
32
+ @model_class.connection.database_version >= 140_000
33
+ end
23
34
  end
24
35
  end
@@ -5,6 +5,12 @@ module ActsAsRecursiveTree
5
5
  class QueryOptions
6
6
  STRATEGIES = %i[subselect join].freeze
7
7
 
8
+ def self.from
9
+ options = new
10
+ yield(options) if block_given?
11
+ options
12
+ end
13
+
8
14
  attr_accessor :condition
9
15
  attr_reader :ensure_ordering, :query_strategy
10
16
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActsAsRecursiveTree
4
- VERSION = '3.3.0'
4
+ VERSION = '3.5.0'
5
5
  end
@@ -3,15 +3,15 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  RSpec.describe ActsAsRecursiveTree::Builders::Ancestors do
6
- context 'basic' do
6
+ context 'without additional setup' do
7
7
  it_behaves_like 'build recursive query'
8
8
  it_behaves_like 'ancestor query'
9
- include_context 'context with ordering'
9
+ include_context 'with ordering'
10
10
  end
11
11
 
12
12
  context 'with options' do
13
- include_context 'setup with enforced ordering' do
14
- it_behaves_like 'with ordering'
13
+ include_context 'with enforced ordering setup' do
14
+ it_behaves_like 'is adding ordering'
15
15
  end
16
16
  end
17
17
  end
@@ -3,16 +3,16 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  RSpec.describe ActsAsRecursiveTree::Builders::Descendants do
6
- context 'basic' do
6
+ context 'without additional setup' do
7
7
  it_behaves_like 'build recursive query'
8
8
  it_behaves_like 'descendant query'
9
- include_context 'context without ordering'
9
+ include_context 'without ordering'
10
10
  end
11
11
 
12
12
  context 'with options' do
13
- include_context 'setup with enforced ordering' do
13
+ include_context 'with enforced ordering setup' do
14
14
  let(:ordering) { true }
15
- it_behaves_like 'with ordering'
15
+ it_behaves_like 'is adding ordering'
16
16
  end
17
17
  end
18
18
  end
@@ -3,16 +3,16 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  RSpec.describe ActsAsRecursiveTree::Builders::Leaves do
6
- context 'basic' do
6
+ context 'without additional setup' do
7
7
  it_behaves_like 'build recursive query'
8
8
  it_behaves_like 'descendant query'
9
- include_context 'context without ordering'
9
+ include_context 'without ordering'
10
10
  end
11
11
 
12
12
  context 'with options' do
13
- include_context 'setup with enforced ordering' do
13
+ include_context 'with enforced ordering setup' do
14
14
  let(:ordering) { true }
15
- it_behaves_like 'without ordering'
15
+ it_behaves_like 'not adding ordering'
16
16
  end
17
17
  end
18
18
  end
@@ -20,13 +20,13 @@ RSpec.describe ActsAsRecursiveTree::Options::Values do
20
20
  let(:table) { Arel::Table.new('test_table') }
21
21
  let(:attribute) { table['test_attr'] }
22
22
 
23
- context 'invalid agurment' do
23
+ context 'with invalid agurment' do
24
24
  it 'raises exception' do
25
25
  expect { described_class.create(nil) }.to raise_exception(/is not supported/)
26
26
  end
27
27
  end
28
28
 
29
- context 'single value' do
29
+ context 'with single value' do
30
30
  let(:single_value) { 3 }
31
31
 
32
32
  it_behaves_like 'single values' do
@@ -38,8 +38,8 @@ RSpec.describe ActsAsRecursiveTree::Options::Values do
38
38
  end
39
39
  end
40
40
 
41
- context 'multi value' do
42
- context 'Array' do
41
+ context 'with multi value' do
42
+ context 'with Array' do
43
43
  subject(:value) { described_class.create(array) }
44
44
 
45
45
  let(:array) { [1, 2, 3] }
@@ -55,7 +55,7 @@ RSpec.describe ActsAsRecursiveTree::Options::Values do
55
55
  end
56
56
  end
57
57
 
58
- context 'Range' do
58
+ context 'with Range' do
59
59
  subject(:value) { described_class.create(range) }
60
60
 
61
61
  let(:range) { 1..3 }
@@ -71,7 +71,7 @@ RSpec.describe ActsAsRecursiveTree::Options::Values do
71
71
  end
72
72
  end
73
73
 
74
- context 'Relation' do
74
+ context 'with Relation' do
75
75
  subject(:value) { described_class.create(relation, double) }
76
76
 
77
77
  let(:relation) { Node.where(name: 'test') }
data/spec/spec_helper.rb CHANGED
@@ -9,7 +9,7 @@ require 'active_record'
9
9
  require 'acts_as_recursive_tree'
10
10
  require_relative 'db/database'
11
11
 
12
- require 'database_cleaner'
12
+ require 'database_cleaner-active_record'
13
13
 
14
14
  # Requires supporting ruby files with custom matchers and macros, etc,
15
15
  # in spec/support/ and its subdirectories.
@@ -76,7 +76,7 @@ RSpec.configure do |config|
76
76
  # # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
77
77
  # # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
78
78
  # # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
79
- config.disable_monkey_patching!
79
+ config.disable_monkey_patching!
80
80
  #
81
81
  # # This setting enables warnings. It's recommended, but in some cases may
82
82
  # # be too noisy due to issues in dependencies.
@@ -1,12 +1,13 @@
1
+ # frozen_string_literal: true
1
2
 
2
- RSpec.shared_context 'setup with enforced ordering' do
3
+ RSpec.shared_context 'with enforced ordering setup' do
3
4
  let(:ordering) { false }
4
- include_context 'base_setup' do
5
+ include_context 'with base_setup' do
5
6
  let(:proc) { ->(config) { config.ensure_ordering! } }
6
7
  end
7
8
  end
8
9
 
9
- RSpec.shared_context 'base_setup' do
10
+ RSpec.shared_context 'with base_setup' do
10
11
  subject(:query) { builder.build.to_sql }
11
12
 
12
13
  let(:model_id) { 1 }
@@ -33,30 +34,30 @@ RSpec.shared_examples 'basic recursive examples' do
33
34
  end
34
35
 
35
36
  RSpec.shared_examples 'build recursive query' do
36
- context 'simple id' do
37
+ context 'with simple id' do
37
38
  context 'with simple class' do
38
- include_context 'base_setup' do
39
+ include_context 'with base_setup' do
39
40
  let(:model_class) { Node }
40
41
  it_behaves_like 'basic recursive examples'
41
42
  end
42
43
  end
43
44
 
44
45
  context 'with class with different parent key' do
45
- include_context 'base_setup' do
46
+ include_context 'with base_setup' do
46
47
  let(:model_class) { NodeWithOtherParentKey }
47
48
  it_behaves_like 'basic recursive examples'
48
49
  end
49
50
  end
50
51
 
51
52
  context 'with Subclass' do
52
- include_context 'base_setup' do
53
+ include_context 'with base_setup' do
53
54
  let(:model_class) { Floor }
54
55
  it_behaves_like 'basic recursive examples'
55
56
  end
56
57
  end
57
58
 
58
59
  context 'with polymorphic parent relation' do
59
- include_context 'base_setup' do
60
+ include_context 'with base_setup' do
60
61
  let(:model_class) { NodeWithPolymorphicParent }
61
62
  it_behaves_like 'basic recursive examples'
62
63
  end
@@ -65,34 +66,34 @@ RSpec.shared_examples 'build recursive query' do
65
66
  end
66
67
 
67
68
  RSpec.shared_examples 'ancestor query' do
68
- include_context 'base_setup'
69
+ include_context 'with base_setup'
69
70
 
70
71
  it { is_expected.to match(/"#{builder.travers_loc_table.name}"."#{model_class._recursive_tree_config.parent_key}" = "#{model_class.table_name}"."#{model_class.primary_key}"/) }
71
72
  end
72
73
 
73
74
  RSpec.shared_examples 'descendant query' do
74
- include_context 'base_setup'
75
+ include_context 'with base_setup'
75
76
 
76
77
  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}"/) }
77
78
  it { is_expected.to match(/#{Regexp.escape(builder.travers_loc_table.project(builder.travers_loc_table[model_class.primary_key]).to_sql)}/) }
78
79
  end
79
80
 
80
- RSpec.shared_context 'context with ordering' do
81
- include_context 'base_setup' do
82
- it_behaves_like 'with ordering'
81
+ RSpec.shared_context 'with ordering' do
82
+ include_context 'with base_setup' do
83
+ it_behaves_like 'is adding ordering'
83
84
  end
84
85
  end
85
86
 
86
- RSpec.shared_context 'context without ordering' do
87
- include_context 'base_setup' do
88
- it_behaves_like 'without ordering'
87
+ RSpec.shared_context 'without ordering' do
88
+ include_context 'with base_setup' do
89
+ it_behaves_like 'not adding ordering'
89
90
  end
90
91
  end
91
92
 
92
- RSpec.shared_examples 'with ordering' do
93
+ RSpec.shared_examples 'is adding ordering' do
93
94
  it { is_expected.to match(/ORDER BY #{Regexp.escape(builder.recursive_temp_table[model_class._recursive_tree_config.depth_column].asc.to_sql)}/) }
94
95
  end
95
96
 
96
- RSpec.shared_examples 'without ordering' do
97
+ RSpec.shared_examples 'not adding ordering' do
97
98
  it { is_expected.not_to match(/ORDER BY/) }
98
99
  end
@@ -3,25 +3,21 @@
3
3
  # Helper methods for simple tree creation
4
4
  module TreeMethods
5
5
  def create_tree(max_level, current_level: 0, node: nil, create_node_info: false, stop_at: -1)
6
- node = Node.create!(name: 'root') if node.nil?
6
+ node ||= Node.create!(name: 'root')
7
7
 
8
8
  1.upto(max_level - current_level) do |index|
9
- child = node.children.create!(
10
- name: "child #{index} - level #{current_level}",
11
- active: stop_at > current_level
12
- )
9
+ child = node.children.create!(name: "child #{index} - level #{current_level}", active: stop_at > current_level)
13
10
 
14
11
  child.create_node_info(status: stop_at > current_level ? 'foo' : 'bar') if create_node_info
15
12
 
16
13
  create_tree(
17
14
  max_level,
18
- current_level: current_level + 1,
19
- node: child,
15
+ current_level: current_level + 1,
16
+ node: child,
20
17
  create_node_info: create_node_info,
21
- stop_at: stop_at
18
+ stop_at: stop_at
22
19
  )
23
20
  end
24
-
25
21
  node
26
22
  end
27
23
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_as_recursive_tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.3.0
4
+ version: 3.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wolfgang Wedelich-John
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-01-26 00:00:00.000000000 Z
12
+ date: 2023-08-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -20,7 +20,7 @@ dependencies:
20
20
  version: 5.2.0
21
21
  - - "<"
22
22
  - !ruby/object:Gem::Version
23
- version: '7.1'
23
+ version: '8'
24
24
  type: :runtime
25
25
  prerelease: false
26
26
  version_requirements: !ruby/object:Gem::Requirement
@@ -30,7 +30,7 @@ dependencies:
30
30
  version: 5.2.0
31
31
  - - "<"
32
32
  - !ruby/object:Gem::Version
33
- version: '7.1'
33
+ version: '8'
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: activesupport
36
36
  requirement: !ruby/object:Gem::Requirement
@@ -40,7 +40,7 @@ dependencies:
40
40
  version: 5.2.0
41
41
  - - "<"
42
42
  - !ruby/object:Gem::Version
43
- version: '7.1'
43
+ version: '8'
44
44
  type: :runtime
45
45
  prerelease: false
46
46
  version_requirements: !ruby/object:Gem::Requirement
@@ -50,7 +50,7 @@ dependencies:
50
50
  version: 5.2.0
51
51
  - - "<"
52
52
  - !ruby/object:Gem::Version
53
- version: '7.1'
53
+ version: '8'
54
54
  - !ruby/object:Gem::Dependency
55
55
  name: zeitwerk
56
56
  requirement: !ruby/object:Gem::Requirement
@@ -80,19 +80,19 @@ dependencies:
80
80
  - !ruby/object:Gem::Version
81
81
  version: '2.4'
82
82
  - !ruby/object:Gem::Dependency
83
- name: database_cleaner
83
+ name: database_cleaner-active_record
84
84
  requirement: !ruby/object:Gem::Requirement
85
85
  requirements:
86
86
  - - "~>"
87
87
  - !ruby/object:Gem::Version
88
- version: '2.0'
88
+ version: '2.1'
89
89
  type: :development
90
90
  prerelease: false
91
91
  version_requirements: !ruby/object:Gem::Requirement
92
92
  requirements:
93
93
  - - "~>"
94
94
  - !ruby/object:Gem::Version
95
- version: '2.0'
95
+ version: '2.1'
96
96
  - !ruby/object:Gem::Dependency
97
97
  name: rake
98
98
  requirement: !ruby/object:Gem::Requirement