acts_as_recursive_tree 3.1.0 → 3.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b3681366c263bd90e2479c6a4761042825547241a15e828678c260789f05ad54
4
- data.tar.gz: c526e787809100bcba957ddeae424ffa068afe7f10e8e2ece1aec354cce6c70b
3
+ metadata.gz: b60be808a8b0a3e93edfbb83a83cc8b270eebade9888ddc6038bb4af4429d7da
4
+ data.tar.gz: 96622ef4e488bbd73de8dd4d0ae51c51a2b11843219d2a34669367ace4f77d60
5
5
  SHA512:
6
- metadata.gz: 2b4e5b9a5a1462b39cc8c2cc0184d8db0653b1d02be8728d2bf46fa309d847224765c3e6b8ac885f064a42f64b34375d9e032e888d5588c9940d55225ceced4a
7
- data.tar.gz: 4e8a2077169e98b889671412c87c80d21f03541bbcdc62cefe520e47c626459c29ff1ee6a07bb54a9ebd94ca8418c4369d27ff9950a3c559b0bd7ef41970afc6
6
+ metadata.gz: fca6f5732cc344c395d1d74f3cc13ac5be4af9ea74eb545764b28ef1a7550fcb3300975cccce92a2772f5d3ca1e12fb1e4a6e124f07037f66099b86256918c57
7
+ data.tar.gz: 8b2cf07e6aa5ef4543f6d81200ac3421d918039140480314496c416f8ff3f6fce65a1ba43bdcae837f67df5e279e9281d8680ca76945d84a8115877eeb4cc7d2
@@ -19,19 +19,35 @@ jobs:
19
19
  runs-on: ubuntu-latest
20
20
  strategy:
21
21
  matrix:
22
- ruby-version: ['2.5', '2.6', '2.7', '3.0']
22
+ ruby-version: ['2.5', '2.6', '2.7', '3.0', '3.1', '3.2']
23
23
  gemfile: [ar_52, ar_60, ar_61, ar_70]
24
24
  exclude:
25
+ - ruby-version: '3.2'
26
+ gemfile: ar_52
27
+ - ruby-version: '3.2'
28
+ gemfile: ar_60
29
+ - ruby-version: '3.2'
30
+ gemfile: ar_61
31
+ - ruby-version: '3.1'
32
+ gemfile: ar_52
33
+ - ruby-version: '3.1'
34
+ gemfile: ar_60
35
+ - ruby-version: '3.1'
36
+ gemfile: ar_61
25
37
  - ruby-version: '3.0'
26
38
  gemfile: ar_52
27
- - ruby-version: '2.5'
28
- gemfile: ar_70
39
+ # - ruby-version: '2.6'
40
+ # gemfile: ar_next
29
41
  - ruby-version: '2.6'
30
42
  gemfile: ar_70
43
+ # - ruby-version: '2.5'
44
+ # gemfile: ar_next
45
+ - ruby-version: '2.5'
46
+ gemfile: ar_70
31
47
  env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps
32
48
  BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile
33
49
  steps:
34
- - uses: actions/checkout@v2
50
+ - uses: actions/checkout@v3
35
51
  - name: Set up Ruby
36
52
  # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
37
53
  # change this to (see https://github.com/ruby/setup-ruby#versioning):
data/.gitignore CHANGED
@@ -17,3 +17,4 @@ db.log
17
17
  test.sqlite3
18
18
  /gemfiles/*.lock
19
19
  /gemfiles/.bundle
20
+ /.ruby-version
data/Appraisals CHANGED
@@ -16,6 +16,13 @@ appraise 'ar-61' do
16
16
  end
17
17
 
18
18
  appraise 'ar-70' do
19
- gem 'activerecord', '~> 7.0.0'
20
- gem 'activesupport', '~> 7.0.0'
19
+ gem 'activerecord', '~> 7.0'
20
+ gem 'activesupport', '~> 7.0'
21
+ end
22
+
23
+ appraise 'ar-next' do
24
+ git 'https://github.com/rails/rails.git', branch: 'main' do
25
+ gem 'activerecord'
26
+ gem 'activesupport'
27
+ end
21
28
  end
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ### Version 3.3.0
2
+ - added __includes:__ option to __preload_tree__
3
+
4
+ ### Version 3.2.0
5
+ - Added #preload_tree method to preload the parent/child relations of a single node
6
+
1
7
  ### Version 3.1.0
2
8
  - Rails 7 support
3
9
 
data/README.md CHANGED
@@ -19,6 +19,17 @@ ActsAsRecursiveTree currently supports following ActiveRecord versions and is te
19
19
  * ActiveRecord 6.1.x
20
20
  * ActiveRecord 7.0.x
21
21
 
22
+ ## Supported Rubies
23
+ ActsAsRecursiveTree is tested with following rubies:
24
+ * MRuby 2.5
25
+ * MRuby 2.6
26
+ * MRuby 2.7
27
+ * MRuby 3.0
28
+ * MRuby 3.1
29
+ * MRuby 3.2
30
+
31
+ Other Ruby implementations are not tested, but should also work.
32
+
22
33
  ## Installation
23
34
 
24
35
  Add this line to your application's Gemfile:
@@ -123,7 +134,11 @@ __Additional methods:__
123
134
  __Utility methods:__
124
135
  * `root?` - returns true if this node is a root node
125
136
  * `leaf?` - returns true if this node is a leave node
137
+ * `preload_tree` - fetches all descendants of this node and assigns the proper parent/children associations. You are then able to traverse the tree through the children/parent association without querying the database again. You can also pass arguments to `includes` which will be forwarded when fetching records.
126
138
 
139
+ ```ruby
140
+ node.preload_tree(includes: [:association, :another_association])
141
+ ```
127
142
 
128
143
  ## Customizing the recursion
129
144
 
@@ -201,17 +216,6 @@ sub_node_instance.descendants # => returns Node and SubNode instances
201
216
  ```
202
217
 
203
218
 
204
- ## Known Issues
205
-
206
- When using PostgreSQL as underlying database system chances are good that you encounter following error message:
207
-
208
- `
209
- ActiveRecord::StatementInvalid: PG::ProtocolViolation: ERROR: bind message supplies 1 parameters, but prepared statement "" requires 2
210
- `
211
-
212
- This is a known ActiveRecord issue which should be fixed in Rails 5.2. Alternative
213
-
214
-
215
219
  ## Contributing
216
220
 
217
221
  1. Fork it ( https://github.com/1and1/acts_as_recursive_tree/fork )
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
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', '~> 1.5'
31
+ spec.add_development_dependency 'database_cleaner', '~> 2.0'
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'
@@ -2,7 +2,7 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activerecord", "~> 7.0.0"
6
- gem "activesupport", "~> 7.0.0"
5
+ gem "activerecord", "~> 7.0"
6
+ gem "activesupport", "~> 7.0"
7
7
 
8
8
  gemspec path: "../"
@@ -0,0 +1,10 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ git "https://github.com/rails/rails.git", branch: "main" do
6
+ gem "activerecord"
7
+ gem "activesupport"
8
+ end
9
+
10
+ gemspec path: "../"
@@ -8,7 +8,8 @@ module ActsAsRecursiveTree
8
8
  # * <tt>foreign_key</tt> - specifies the column name to use for tracking
9
9
  # of the tree (default: +parent_id+)
10
10
  def recursive_tree(parent_key: :parent_id, parent_type_column: nil)
11
- class_attribute :_recursive_tree_config
11
+ class_attribute(:_recursive_tree_config, instance_writer: false)
12
+
12
13
  self._recursive_tree_config = Config.new(
13
14
  model_class: self,
14
15
  parent_key: parent_key.to_sym,
@@ -91,6 +91,16 @@ module ActsAsRecursiveTree
91
91
  children.none?
92
92
  end
93
93
 
94
+ #
95
+ # Fetches all descendants of this node and assigns the parent/children associations
96
+ #
97
+ # @param includes [Array|Hash] pass the same arguments that should be passed to the #includes() method.
98
+ #
99
+ def preload_tree(includes: nil)
100
+ ActsAsRecursiveTree::Preloaders::Descendants.new(self, includes: includes).preload!
101
+ true
102
+ end
103
+
94
104
  def base_class
95
105
  self.class.base_class
96
106
  end
@@ -99,11 +109,11 @@ module ActsAsRecursiveTree
99
109
 
100
110
  module ClassMethods
101
111
  def self_and_ancestors_of(ids, &block)
102
- Builders::Ancestors.build(self, ids, &block)
112
+ ActsAsRecursiveTree::Builders::Ancestors.build(self, ids, &block)
103
113
  end
104
114
 
105
115
  def ancestors_of(ids, &block)
106
- Builders::Ancestors.build(self, ids, exclude_ids: true, &block)
116
+ ActsAsRecursiveTree::Builders::Ancestors.build(self, ids, exclude_ids: true, &block)
107
117
  end
108
118
 
109
119
  def roots_of(ids)
@@ -111,15 +121,15 @@ module ActsAsRecursiveTree
111
121
  end
112
122
 
113
123
  def self_and_descendants_of(ids, &block)
114
- Builders::Descendants.build(self, ids, &block)
124
+ ActsAsRecursiveTree::Builders::Descendants.build(self, ids, &block)
115
125
  end
116
126
 
117
127
  def descendants_of(ids, &block)
118
- Builders::Descendants.build(self, ids, exclude_ids: true, &block)
128
+ ActsAsRecursiveTree::Builders::Descendants.build(self, ids, exclude_ids: true, &block)
119
129
  end
120
130
 
121
131
  def leaves_of(ids, &block)
122
- Builders::Leaves.build(self, ids, &block)
132
+ ActsAsRecursiveTree::Builders::Leaves.build(self, ids, &block)
123
133
  end
124
134
  end
125
135
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActsAsRecursiveTree
4
+ module Preloaders
5
+ #
6
+ # Preloads all descendants records for a given node and sets the parent and child associations on each record
7
+ # based on the preloaded data. After this, calling #parent or #children will not trigger a database query.
8
+ #
9
+ class Descendants
10
+ def initialize(node, includes: nil)
11
+ @node = node
12
+ @parent_key = node._recursive_tree_config.parent_key
13
+ @includes = includes
14
+ end
15
+
16
+ def preload!
17
+ apply_records(@node)
18
+ end
19
+
20
+ private
21
+
22
+ def records
23
+ @records ||= begin
24
+ descendants = @node.descendants
25
+ descendants = descendants.includes(*@includes) if @includes
26
+ descendants.to_a
27
+ end
28
+ end
29
+
30
+ def apply_records(parent_node)
31
+ children = records.select { |child| child.send(@parent_key) == parent_node.id }
32
+
33
+ parent_node.association(:children).target = children
34
+
35
+ children.each do |child|
36
+ child.association(:parent).target = parent_node
37
+ apply_records(child)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActsAsRecursiveTree
4
- VERSION = '3.1.0'
4
+ VERSION = '3.3.0'
5
5
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe ActsAsRecursiveTree::Builders::Ancestors do
6
+ context 'basic' do
7
+ it_behaves_like 'build recursive query'
8
+ it_behaves_like 'ancestor query'
9
+ include_context 'context with ordering'
10
+ end
11
+
12
+ context 'with options' do
13
+ include_context 'setup with enforced ordering' do
14
+ it_behaves_like 'with ordering'
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe ActsAsRecursiveTree::Builders::Descendants do
6
+ context 'basic' do
7
+ it_behaves_like 'build recursive query'
8
+ it_behaves_like 'descendant query'
9
+ include_context 'context without ordering'
10
+ end
11
+
12
+ context 'with options' do
13
+ include_context 'setup with enforced ordering' do
14
+ let(:ordering) { true }
15
+ it_behaves_like 'with ordering'
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe ActsAsRecursiveTree::Builders::Leaves do
6
+ context 'basic' do
7
+ it_behaves_like 'build recursive query'
8
+ it_behaves_like 'descendant query'
9
+ include_context 'context without ordering'
10
+ end
11
+
12
+ context 'with options' do
13
+ include_context 'setup with enforced ordering' do
14
+ let(:ordering) { true }
15
+ it_behaves_like 'without ordering'
16
+ end
17
+ end
18
+ end
@@ -2,21 +2,21 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- shared_examples 'single values' do
6
- subject(:value) { described_class.create(single_value) }
5
+ RSpec.describe ActsAsRecursiveTree::Options::Values do
6
+ shared_examples 'single values' do
7
+ subject(:value) { described_class.create(single_value) }
7
8
 
8
- it { is_expected.to be_a ActsAsRecursiveTree::Options::Values::SingleValue }
9
+ it { is_expected.to be_a described_class::SingleValue }
9
10
 
10
- it 'apply_toes' do
11
- expect(value.apply_to(attribute).to_sql).to end_with " = #{single_value}"
12
- end
11
+ it 'apply_toes' do
12
+ expect(value.apply_to(attribute).to_sql).to end_with " = #{single_value}"
13
+ end
13
14
 
14
- it 'apply_negated_toes' do
15
- expect(value.apply_negated_to(attribute).to_sql).to end_with " != #{single_value}"
15
+ it 'apply_negated_toes' do
16
+ expect(value.apply_negated_to(attribute).to_sql).to end_with " != #{single_value}"
17
+ end
16
18
  end
17
- end
18
19
 
19
- describe ActsAsRecursiveTree::Options::Values do
20
20
  let(:table) { Arel::Table.new('test_table') }
21
21
  let(:attribute) { table['test_attr'] }
22
22
 
@@ -44,7 +44,7 @@ describe ActsAsRecursiveTree::Options::Values do
44
44
 
45
45
  let(:array) { [1, 2, 3] }
46
46
 
47
- it { is_expected.to be_a ActsAsRecursiveTree::Options::Values::MultiValue }
47
+ it { is_expected.to be_a described_class::MultiValue }
48
48
 
49
49
  it 'apply_toes' do
50
50
  expect(value.apply_to(attribute).to_sql).to end_with " IN (#{array.join(', ')})"
@@ -60,7 +60,7 @@ describe ActsAsRecursiveTree::Options::Values do
60
60
 
61
61
  let(:range) { 1..3 }
62
62
 
63
- it { is_expected.to be_a ActsAsRecursiveTree::Options::Values::RangeValue }
63
+ it { is_expected.to be_a described_class::RangeValue }
64
64
 
65
65
  it 'apply_toes' do
66
66
  expect(value.apply_to(attribute).to_sql).to end_with "BETWEEN #{range.begin} AND #{range.end}"
@@ -83,7 +83,7 @@ describe ActsAsRecursiveTree::Options::Values do
83
83
  end
84
84
  end
85
85
 
86
- it { is_expected.to be_a ActsAsRecursiveTree::Options::Values::Relation }
86
+ it { is_expected.to be_a described_class::Relation }
87
87
 
88
88
  it 'apply_toes' do
89
89
  expect(value.apply_to(attribute).to_sql).to match(/IN \(SELECT.*\)/)
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe ActsAsRecursiveTree::Preloaders::Descendants do
6
+ include TreeMethods
7
+
8
+ let(:preloader) { described_class.new(root.reload, includes: included_associations) }
9
+ let(:included_associations) { nil }
10
+ let(:root) { create_tree(2, create_node_info: true) }
11
+ let(:children) { root.children }
12
+
13
+ describe '#preload! will set the associations target attribute' do
14
+ before do
15
+ preloader.preload!
16
+ end
17
+
18
+ it 'sets the children association' do
19
+ children.each do |child|
20
+ expect(child.association(:children).target).not_to be_nil
21
+ end
22
+ end
23
+
24
+ it 'sets the parent association' do
25
+ children.each do |child|
26
+ expect(child.association(:parent).target).not_to be_nil
27
+ end
28
+ end
29
+ end
30
+
31
+ describe '#preload! will include associations' do
32
+ let(:included_associations) { :node_info }
33
+
34
+ before do
35
+ preloader.preload!
36
+ end
37
+
38
+ it 'sets the children association' do
39
+ children.each do |child|
40
+ expect(child.association(included_associations).target).not_to be_nil
41
+ end
42
+ end
43
+ end
44
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Location do
5
+ RSpec.describe Location do
6
6
  before do
7
7
  @building = Building.create!(name: 'big house')
8
8
 
@@ -2,17 +2,8 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Node do
6
- def create_tree(max_level, current_level = 0, node = nil)
7
- node = Node.create!(name: 'root') if node.nil?
8
-
9
- 1.upto(max_level - current_level) do |index|
10
- child = node.children.create!(name: "child #{index} - level #{current_level}")
11
- create_tree(max_level, current_level + 1, child)
12
- end
13
-
14
- node
15
- end
5
+ RSpec.describe Node do
6
+ include TreeMethods
16
7
 
17
8
  before do
18
9
  @root = create_tree(3)
@@ -2,57 +2,68 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe 'Relation' do
6
- def create_tree(max_level, current_level: 0, node: nil, stop_at: nil)
7
- node = Node.create!(name: 'root') if node.nil?
8
-
9
- 1.upto(max_level - current_level) do |index|
10
- child = node.children.create!(name: "child #{index} - level #{current_level}", active: stop_at > current_level)
11
- child.create_node_info(status: stop_at > current_level ? 'foo' : 'bar')
12
- create_tree(max_level, current_level: current_level + 1, node: child, stop_at: stop_at)
13
- end
5
+ RSpec.describe 'Relation' do
6
+ include TreeMethods
14
7
 
15
- node
16
- end
8
+ let(:root) { create_tree(4, stop_at: 2) }
17
9
 
18
- before do
19
- @root = create_tree(4, stop_at: 2)
20
- @child = @root.children.first
21
- end
10
+ describe '#descendants' do
11
+ context 'with simple relation' do
12
+ let(:descendants) { root.descendants { |opts| opts.condition = Node.where(active: true) }.to_a }
22
13
 
23
- context 'descendants' do
24
- it 'works with simple relation' do
25
- desc = @root.descendants { |opts| opts.condition = Node.where(active: true) }
26
- desc.all.each do |node|
27
- expect(node.active).to be_truthy
14
+ it 'returns only active nodes' do
15
+ descendants.each do |node|
16
+ expect(node.active).to be_truthy
17
+ end
28
18
  end
29
19
  end
30
20
 
31
- it 'works with joins relation' do
32
- desc = @root.descendants { |opts| opts.condition = Node.joins(:node_info).where.not(node_infos: { status: 'bar' }) }
33
- desc.all.each do |node|
34
- expect(node.node_info.status).to eql('foo')
21
+ context 'with condition on joined association' do
22
+ let(:descendants) do
23
+ root.descendants do |opts|
24
+ opts.condition = Node.joins(:node_info).where.not(node_infos: { status: 'bar' })
25
+ end
26
+ end
27
+
28
+ it 'returns only node with condition fulfilled' do
29
+ descendants.each do |node|
30
+ expect(node.node_info.status).to eql('foo')
31
+ end
35
32
  end
36
33
  end
37
34
  end
38
35
 
39
- context 'ancestors' do
40
- it 'works with simple relation' do
41
- ancestors = @root.leaves.first.ancestors { |opts| opts.condition = Node.where(active: false) }.to_a
36
+ describe '#ancestors' do
37
+ context 'with simple_relation' do
38
+ let(:ancestors) { root.leaves.first.ancestors { |opts| opts.condition = Node.where(active: false) }.to_a }
42
39
 
43
- ancestors.each do |node|
44
- expect(node.active).to be_falsey
40
+ it 'return only active nodes' do
41
+ ancestors.each do |node|
42
+ expect(node.active).to be_falsey
43
+ end
45
44
  end
46
45
 
47
- expect(ancestors).not_to include(@root)
46
+ it 'does not return the root node' do
47
+ expect(ancestors).not_to include(root)
48
+ end
48
49
  end
49
50
 
50
- it 'works with joins relation' do
51
- ancestors = @root.leaves.first.ancestors { |opts| opts.condition = Node.joins(:node_info).where.not(node_infos: { status: 'foo' }) }
52
- ancestors.all.each do |node|
53
- expect(node.node_info.status).to eql('bar')
51
+ context 'with condition on joined association' do
52
+ let(:ancestors) do
53
+ root.leaves.first.ancestors do |opts|
54
+ opts.condition = Node.joins(:node_info).where.not(node_infos: { status: 'foo' })
55
+ end
56
+ end
57
+
58
+ it 'return only nodes for the matching condition' do
59
+ ancestors.each do |node|
60
+ expect(node.node_info.status).to eql('bar')
61
+ end
62
+ end
63
+
64
+ it 'does not return the root node' do
65
+ expect(ancestors).not_to include(root)
54
66
  end
55
- expect(ancestors).not_to include(@root)
56
67
  end
57
68
  end
58
69
  end
data/spec/spec_helper.rb CHANGED
@@ -11,6 +11,10 @@ require_relative 'db/database'
11
11
 
12
12
  require 'database_cleaner'
13
13
 
14
+ # Requires supporting ruby files with custom matchers and macros, etc,
15
+ # in spec/support/ and its subdirectories.
16
+ Dir[File.join(__dir__, 'support/**/*.rb')].sort.each { |f| require f }
17
+
14
18
  # This file was generated by the `rspec --init` command. Conventionally, all
15
19
  # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
16
20
  # The generated `.rspec` file contains `--require spec_helper` which will cause
@@ -72,7 +76,7 @@ RSpec.configure do |config|
72
76
  # # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
73
77
  # # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
74
78
  # # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
75
- # config.disable_monkey_patching!
79
+ config.disable_monkey_patching!
76
80
  #
77
81
  # # This setting enables warnings. It's recommended, but in some cases may
78
82
  # # be too noisy due to issues in dependencies.
@@ -1,15 +1,12 @@
1
- # frozen_string_literal: true
2
1
 
3
- require 'spec_helper'
4
-
5
- shared_context 'setup with enforced ordering' do
2
+ RSpec.shared_context 'setup with enforced ordering' do
6
3
  let(:ordering) { false }
7
4
  include_context 'base_setup' do
8
5
  let(:proc) { ->(config) { config.ensure_ordering! } }
9
6
  end
10
7
  end
11
8
 
12
- shared_context 'base_setup' do
9
+ RSpec.shared_context 'base_setup' do
13
10
  subject(:query) { builder.build.to_sql }
14
11
 
15
12
  let(:model_id) { 1 }
@@ -21,7 +18,7 @@ shared_context 'base_setup' do
21
18
  end
22
19
  end
23
20
 
24
- shared_examples 'basic recursive examples' do
21
+ RSpec.shared_examples 'basic recursive examples' do
25
22
  it { is_expected.to start_with "SELECT \"#{model_class.table_name}\".* FROM \"#{model_class.table_name}\"" }
26
23
 
27
24
  it { is_expected.to match(/WHERE "#{model_class.table_name}"."#{model_class.primary_key}" = #{model_id}/) }
@@ -35,7 +32,7 @@ shared_examples 'basic recursive examples' do
35
32
  }
36
33
  end
37
34
 
38
- shared_examples 'build recursive query' do
35
+ RSpec.shared_examples 'build recursive query' do
39
36
  context 'simple id' do
40
37
  context 'with simple class' do
41
38
  include_context 'base_setup' do
@@ -67,79 +64,35 @@ shared_examples 'build recursive query' do
67
64
  end
68
65
  end
69
66
 
70
- shared_examples 'ancestor query' do
67
+ RSpec.shared_examples 'ancestor query' do
71
68
  include_context 'base_setup'
72
69
 
73
70
  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}"/) }
74
71
  end
75
72
 
76
- shared_examples 'descendant query' do
73
+ RSpec.shared_examples 'descendant query' do
77
74
  include_context 'base_setup'
78
75
 
79
76
  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}"/) }
80
77
  it { is_expected.to match(/#{Regexp.escape(builder.travers_loc_table.project(builder.travers_loc_table[model_class.primary_key]).to_sql)}/) }
81
78
  end
82
79
 
83
- shared_context 'context with ordering' do
80
+ RSpec.shared_context 'context with ordering' do
84
81
  include_context 'base_setup' do
85
82
  it_behaves_like 'with ordering'
86
83
  end
87
84
  end
88
85
 
89
- shared_context 'context without ordering' do
86
+ RSpec.shared_context 'context without ordering' do
90
87
  include_context 'base_setup' do
91
88
  it_behaves_like 'without ordering'
92
89
  end
93
90
  end
94
91
 
95
- shared_examples 'with ordering' do
92
+ RSpec.shared_examples 'with ordering' do
96
93
  it { is_expected.to match(/ORDER BY #{Regexp.escape(builder.recursive_temp_table[model_class._recursive_tree_config.depth_column].asc.to_sql)}/) }
97
94
  end
98
95
 
99
- shared_examples 'without ordering' do
96
+ RSpec.shared_examples 'without ordering' do
100
97
  it { is_expected.not_to match(/ORDER BY/) }
101
98
  end
102
-
103
- describe ActsAsRecursiveTree::Builders::Descendants do
104
- context 'basic' do
105
- it_behaves_like 'build recursive query'
106
- it_behaves_like 'descendant query'
107
- include_context 'context without ordering'
108
- end
109
-
110
- context 'with options' do
111
- include_context 'setup with enforced ordering' do
112
- let(:ordering) { true }
113
- it_behaves_like 'with ordering'
114
- end
115
- end
116
- end
117
-
118
- describe ActsAsRecursiveTree::Builders::Ancestors do
119
- context 'basic' do
120
- it_behaves_like 'build recursive query'
121
- it_behaves_like 'ancestor query'
122
- include_context 'context with ordering'
123
- end
124
-
125
- context 'with options' do
126
- include_context 'setup with enforced ordering' do
127
- it_behaves_like 'with ordering'
128
- end
129
- end
130
- end
131
-
132
- describe ActsAsRecursiveTree::Builders::Leaves do
133
- context 'basic' do
134
- it_behaves_like 'build recursive query'
135
- it_behaves_like 'descendant query'
136
- include_context 'context without ordering'
137
- end
138
-
139
- context 'with options' do
140
- include_context 'setup with enforced ordering' do
141
- let(:ordering) { true }
142
- it_behaves_like 'without ordering'
143
- end
144
- end
145
- end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Helper methods for simple tree creation
4
+ module TreeMethods
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?
7
+
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
+ )
13
+
14
+ child.create_node_info(status: stop_at > current_level ? 'foo' : 'bar') if create_node_info
15
+
16
+ create_tree(
17
+ max_level,
18
+ current_level: current_level + 1,
19
+ node: child,
20
+ create_node_info: create_node_info,
21
+ stop_at: stop_at
22
+ )
23
+ end
24
+
25
+ node
26
+ end
27
+ 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.1.0
4
+ version: 3.3.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: 2021-12-20 00:00:00.000000000 Z
12
+ date: 2023-01-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -85,14 +85,14 @@ dependencies:
85
85
  requirements:
86
86
  - - "~>"
87
87
  - !ruby/object:Gem::Version
88
- version: '1.5'
88
+ version: '2.0'
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: '1.5'
95
+ version: '2.0'
96
96
  - !ruby/object:Gem::Dependency
97
97
  name: rake
98
98
  requirement: !ruby/object:Gem::Requirement
@@ -205,6 +205,7 @@ files:
205
205
  - gemfiles/ar_60.gemfile
206
206
  - gemfiles/ar_61.gemfile
207
207
  - gemfiles/ar_70.gemfile
208
+ - gemfiles/ar_next.gemfile
208
209
  - lib/acts_as_recursive_tree.rb
209
210
  - lib/acts_as_recursive_tree/acts_macro.rb
210
211
  - lib/acts_as_recursive_tree/associations.rb
@@ -222,10 +223,15 @@ files:
222
223
  - lib/acts_as_recursive_tree/options/depth_condition.rb
223
224
  - lib/acts_as_recursive_tree/options/query_options.rb
224
225
  - lib/acts_as_recursive_tree/options/values.rb
226
+ - lib/acts_as_recursive_tree/preloaders/descendants.rb
225
227
  - lib/acts_as_recursive_tree/railtie.rb
226
228
  - lib/acts_as_recursive_tree/scopes.rb
227
229
  - lib/acts_as_recursive_tree/version.rb
228
- - spec/builders_spec.rb
230
+ - spec/acts_as_recursive_tree/builders/ancestors_spec.rb
231
+ - spec/acts_as_recursive_tree/builders/descendants_spec.rb
232
+ - spec/acts_as_recursive_tree/builders/leaves_spec.rb
233
+ - spec/acts_as_recursive_tree/options/values_spec.rb
234
+ - spec/acts_as_recursive_tree/preloaders/descendants_spec.rb
229
235
  - spec/db/database.rb
230
236
  - spec/db/database.yml
231
237
  - spec/db/models.rb
@@ -234,7 +240,8 @@ files:
234
240
  - spec/model/node_spec.rb
235
241
  - spec/model/relation_spec.rb
236
242
  - spec/spec_helper.rb
237
- - spec/values_spec.rb
243
+ - spec/support/shared_examples/builders.rb
244
+ - spec/support/tree_methods.rb
238
245
  homepage: https://github.com/1and1/acts_as_recursive_tree
239
246
  licenses:
240
247
  - MIT
@@ -261,7 +268,11 @@ signing_key:
261
268
  specification_version: 4
262
269
  summary: Drop in replacement for acts_as_tree but using recursive queries
263
270
  test_files:
264
- - spec/builders_spec.rb
271
+ - spec/acts_as_recursive_tree/builders/ancestors_spec.rb
272
+ - spec/acts_as_recursive_tree/builders/descendants_spec.rb
273
+ - spec/acts_as_recursive_tree/builders/leaves_spec.rb
274
+ - spec/acts_as_recursive_tree/options/values_spec.rb
275
+ - spec/acts_as_recursive_tree/preloaders/descendants_spec.rb
265
276
  - spec/db/database.rb
266
277
  - spec/db/database.yml
267
278
  - spec/db/models.rb
@@ -270,4 +281,5 @@ test_files:
270
281
  - spec/model/node_spec.rb
271
282
  - spec/model/relation_spec.rb
272
283
  - spec/spec_helper.rb
273
- - spec/values_spec.rb
284
+ - spec/support/shared_examples/builders.rb
285
+ - spec/support/tree_methods.rb