acts_as_recursive_tree 3.2.0 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +7 -3
- data/Appraisals +9 -2
- data/CHANGELOG.md +8 -0
- data/README.md +6 -1
- data/acts_as_recursive_tree.gemspec +3 -3
- data/gemfiles/ar_70.gemfile +2 -2
- data/gemfiles/ar_next.gemfile +10 -0
- data/lib/acts_as_recursive_tree/model.rb +9 -7
- data/lib/acts_as_recursive_tree/preloaders/descendants.rb +8 -3
- data/lib/acts_as_recursive_tree/version.rb +1 -1
- data/spec/acts_as_recursive_tree/builders/ancestors_spec.rb +17 -0
- data/spec/acts_as_recursive_tree/builders/descendants_spec.rb +18 -0
- data/spec/acts_as_recursive_tree/builders/leaves_spec.rb +18 -0
- data/spec/{values_spec.rb → acts_as_recursive_tree/options/values_spec.rb} +13 -13
- data/spec/acts_as_recursive_tree/preloaders/descendants_spec.rb +19 -4
- data/spec/model/location_spec.rb +1 -1
- data/spec/model/node_spec.rb +1 -1
- data/spec/model/relation_spec.rb +46 -35
- data/spec/spec_helper.rb +2 -2
- data/spec/{builders_spec.rb → support/shared_examples/builders.rb} +10 -58
- data/spec/support/tree_methods.rb +15 -3
- metadata +20 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f74110127d12218381c9578cf59546b125dddd7f2f994dcbc8fff16b13f27f9f
|
4
|
+
data.tar.gz: e63babd0dc010e7cded02689cc9fb3ae54f8a9a817de3c00031cbc118e2a652c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3711b930aa6bbb744cdf6ad0e34af98df9065294c0d8d498ec7daafb1ebd8e534acbab8195a5752b47dd1da5650a73e4a2c72d3371d6d2856d885f0cae0d4331
|
7
|
+
data.tar.gz: 3697fb438ee57c0cbb3d652c26278f6bcd016eab1f8c1d1d60cb0b319f74dd1566af889827a1fca7823b201d16a692b32a9411a95a2850e3f582c928f01aa378
|
data/.github/workflows/ci.yml
CHANGED
@@ -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,9 +36,13 @@ jobs:
|
|
36
36
|
gemfile: ar_61
|
37
37
|
- ruby-version: '3.0'
|
38
38
|
gemfile: ar_52
|
39
|
-
- ruby-version: '2.5'
|
40
|
-
gemfile: ar_70
|
41
39
|
- ruby-version: '2.6'
|
40
|
+
gemfile: ar_next
|
41
|
+
- ruby-version: '2.6'
|
42
|
+
gemfile: ar_70
|
43
|
+
- ruby-version: '2.5'
|
44
|
+
gemfile: ar_next
|
45
|
+
- ruby-version: '2.5'
|
42
46
|
gemfile: ar_70
|
43
47
|
env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps
|
44
48
|
BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile
|
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
|
20
|
-
gem 'activesupport', '~> 7.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,11 @@
|
|
1
|
+
### Version 3.4.0
|
2
|
+
- Rails 7.1 compatibility
|
3
|
+
- Added ar_next to test matrix
|
4
|
+
- Added updated databasecleaner to test latest active record from git
|
5
|
+
|
6
|
+
### Version 3.3.0
|
7
|
+
- added __includes:__ option to __preload_tree__
|
8
|
+
|
1
9
|
### Version 3.2.0
|
2
10
|
- Added #preload_tree method to preload the parent/child relations of a single node
|
3
11
|
|
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:
|
@@ -134,7 +135,11 @@ __Additional methods:__
|
|
134
135
|
__Utility methods:__
|
135
136
|
* `root?` - returns true if this node is a root node
|
136
137
|
* `leaf?` - returns true if this node is a leave node
|
137
|
-
* `preload_tree` - fetches all descendants of this node and
|
138
|
+
* `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.
|
139
|
+
|
140
|
+
```ruby
|
141
|
+
node.preload_tree(includes: [:association, :another_association])
|
142
|
+
```
|
138
143
|
|
139
144
|
## Customizing the recursion
|
140
145
|
|
@@ -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', '<
|
27
|
-
spec.add_runtime_dependency 'activesupport', '>= 5.2.0', '<
|
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', '~> 1
|
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'
|
data/gemfiles/ar_70.gemfile
CHANGED
@@ -94,8 +94,10 @@ module ActsAsRecursiveTree
|
|
94
94
|
#
|
95
95
|
# Fetches all descendants of this node and assigns the parent/children associations
|
96
96
|
#
|
97
|
-
|
98
|
-
|
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!
|
99
101
|
true
|
100
102
|
end
|
101
103
|
|
@@ -107,11 +109,11 @@ module ActsAsRecursiveTree
|
|
107
109
|
|
108
110
|
module ClassMethods
|
109
111
|
def self_and_ancestors_of(ids, &block)
|
110
|
-
Builders::Ancestors.build(self, ids, &block)
|
112
|
+
ActsAsRecursiveTree::Builders::Ancestors.build(self, ids, &block)
|
111
113
|
end
|
112
114
|
|
113
115
|
def ancestors_of(ids, &block)
|
114
|
-
Builders::Ancestors.build(self, ids, exclude_ids: true, &block)
|
116
|
+
ActsAsRecursiveTree::Builders::Ancestors.build(self, ids, exclude_ids: true, &block)
|
115
117
|
end
|
116
118
|
|
117
119
|
def roots_of(ids)
|
@@ -119,15 +121,15 @@ module ActsAsRecursiveTree
|
|
119
121
|
end
|
120
122
|
|
121
123
|
def self_and_descendants_of(ids, &block)
|
122
|
-
Builders::Descendants.build(self, ids, &block)
|
124
|
+
ActsAsRecursiveTree::Builders::Descendants.build(self, ids, &block)
|
123
125
|
end
|
124
126
|
|
125
127
|
def descendants_of(ids, &block)
|
126
|
-
Builders::Descendants.build(self, ids, exclude_ids: true, &block)
|
128
|
+
ActsAsRecursiveTree::Builders::Descendants.build(self, ids, exclude_ids: true, &block)
|
127
129
|
end
|
128
130
|
|
129
131
|
def leaves_of(ids, &block)
|
130
|
-
Builders::Leaves.build(self, ids, &block)
|
132
|
+
ActsAsRecursiveTree::Builders::Leaves.build(self, ids, &block)
|
131
133
|
end
|
132
134
|
end
|
133
135
|
end
|
@@ -7,9 +7,10 @@ module ActsAsRecursiveTree
|
|
7
7
|
# based on the preloaded data. After this, calling #parent or #children will not trigger a database query.
|
8
8
|
#
|
9
9
|
class Descendants
|
10
|
-
def initialize(node)
|
11
|
-
@node
|
10
|
+
def initialize(node, includes: nil)
|
11
|
+
@node = node
|
12
12
|
@parent_key = node._recursive_tree_config.parent_key
|
13
|
+
@includes = includes
|
13
14
|
end
|
14
15
|
|
15
16
|
def preload!
|
@@ -19,7 +20,11 @@ module ActsAsRecursiveTree
|
|
19
20
|
private
|
20
21
|
|
21
22
|
def records
|
22
|
-
@records ||=
|
23
|
+
@records ||= begin
|
24
|
+
descendants = @node.descendants
|
25
|
+
descendants = descendants.includes(*@includes) if @includes
|
26
|
+
descendants.to_a
|
27
|
+
end
|
23
28
|
end
|
24
29
|
|
25
30
|
def apply_records(parent_node)
|
@@ -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
|
-
|
6
|
-
|
5
|
+
RSpec.describe ActsAsRecursiveTree::Options::Values do
|
6
|
+
shared_examples 'single values' do
|
7
|
+
subject(:value) { described_class.create(single_value) }
|
7
8
|
|
8
|
-
|
9
|
+
it { is_expected.to be_a described_class::SingleValue }
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
it 'apply_toes' do
|
12
|
+
expect(value.apply_to(attribute).to_sql).to end_with " = #{single_value}"
|
13
|
+
end
|
13
14
|
|
14
|
-
|
15
|
-
|
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
|
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
|
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
|
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.*\)/)
|
@@ -5,8 +5,9 @@ require 'spec_helper'
|
|
5
5
|
RSpec.describe ActsAsRecursiveTree::Preloaders::Descendants do
|
6
6
|
include TreeMethods
|
7
7
|
|
8
|
-
let(:preloader) { described_class.new(root.reload) }
|
9
|
-
let(:
|
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) }
|
10
11
|
let(:children) { root.children }
|
11
12
|
|
12
13
|
describe '#preload! will set the associations target attribute' do
|
@@ -14,16 +15,30 @@ RSpec.describe ActsAsRecursiveTree::Preloaders::Descendants do
|
|
14
15
|
preloader.preload!
|
15
16
|
end
|
16
17
|
|
17
|
-
it 'sets the children
|
18
|
+
it 'sets the children association' do
|
18
19
|
children.each do |child|
|
19
20
|
expect(child.association(:children).target).not_to be_nil
|
20
21
|
end
|
21
22
|
end
|
22
23
|
|
23
|
-
it 'sets the parent
|
24
|
+
it 'sets the parent association' do
|
24
25
|
children.each do |child|
|
25
26
|
expect(child.association(:parent).target).not_to be_nil
|
26
27
|
end
|
27
28
|
end
|
28
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
|
29
44
|
end
|
data/spec/model/location_spec.rb
CHANGED
data/spec/model/node_spec.rb
CHANGED
data/spec/model/relation_spec.rb
CHANGED
@@ -2,57 +2,68 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
describe 'Relation' do
|
6
|
-
|
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
|
-
|
16
|
-
end
|
8
|
+
let(:root) { create_tree(4, stop_at: 2) }
|
17
9
|
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
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
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
-
|
40
|
-
|
41
|
-
ancestors
|
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
|
-
|
44
|
-
|
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
|
-
|
46
|
+
it 'does not return the root node' do
|
47
|
+
expect(ancestors).not_to include(root)
|
48
|
+
end
|
48
49
|
end
|
49
50
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
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
@@ -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
|
-
|
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,15 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
|
-
shared_context 'setup with enforced ordering' do
|
1
|
+
RSpec.shared_context 'setup with enforced ordering' do
|
6
2
|
let(:ordering) { false }
|
7
3
|
include_context 'base_setup' do
|
8
4
|
let(:proc) { ->(config) { config.ensure_ordering! } }
|
9
5
|
end
|
10
6
|
end
|
11
7
|
|
12
|
-
shared_context 'base_setup' do
|
8
|
+
RSpec.shared_context 'base_setup' do
|
13
9
|
subject(:query) { builder.build.to_sql }
|
14
10
|
|
15
11
|
let(:model_id) { 1 }
|
@@ -21,7 +17,7 @@ shared_context 'base_setup' do
|
|
21
17
|
end
|
22
18
|
end
|
23
19
|
|
24
|
-
shared_examples 'basic recursive examples' do
|
20
|
+
RSpec.shared_examples 'basic recursive examples' do
|
25
21
|
it { is_expected.to start_with "SELECT \"#{model_class.table_name}\".* FROM \"#{model_class.table_name}\"" }
|
26
22
|
|
27
23
|
it { is_expected.to match(/WHERE "#{model_class.table_name}"."#{model_class.primary_key}" = #{model_id}/) }
|
@@ -35,7 +31,7 @@ shared_examples 'basic recursive examples' do
|
|
35
31
|
}
|
36
32
|
end
|
37
33
|
|
38
|
-
shared_examples 'build recursive query' do
|
34
|
+
RSpec.shared_examples 'build recursive query' do
|
39
35
|
context 'simple id' do
|
40
36
|
context 'with simple class' do
|
41
37
|
include_context 'base_setup' do
|
@@ -67,79 +63,35 @@ shared_examples 'build recursive query' do
|
|
67
63
|
end
|
68
64
|
end
|
69
65
|
|
70
|
-
shared_examples 'ancestor query' do
|
66
|
+
RSpec.shared_examples 'ancestor query' do
|
71
67
|
include_context 'base_setup'
|
72
68
|
|
73
69
|
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
70
|
end
|
75
71
|
|
76
|
-
shared_examples 'descendant query' do
|
72
|
+
RSpec.shared_examples 'descendant query' do
|
77
73
|
include_context 'base_setup'
|
78
74
|
|
79
75
|
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
76
|
it { is_expected.to match(/#{Regexp.escape(builder.travers_loc_table.project(builder.travers_loc_table[model_class.primary_key]).to_sql)}/) }
|
81
77
|
end
|
82
78
|
|
83
|
-
shared_context 'context with ordering' do
|
79
|
+
RSpec.shared_context 'context with ordering' do
|
84
80
|
include_context 'base_setup' do
|
85
81
|
it_behaves_like 'with ordering'
|
86
82
|
end
|
87
83
|
end
|
88
84
|
|
89
|
-
shared_context 'context without ordering' do
|
85
|
+
RSpec.shared_context 'context without ordering' do
|
90
86
|
include_context 'base_setup' do
|
91
87
|
it_behaves_like 'without ordering'
|
92
88
|
end
|
93
89
|
end
|
94
90
|
|
95
|
-
shared_examples 'with ordering' do
|
91
|
+
RSpec.shared_examples 'with ordering' do
|
96
92
|
it { is_expected.to match(/ORDER BY #{Regexp.escape(builder.recursive_temp_table[model_class._recursive_tree_config.depth_column].asc.to_sql)}/) }
|
97
93
|
end
|
98
94
|
|
99
|
-
shared_examples 'without ordering' do
|
95
|
+
RSpec.shared_examples 'without ordering' do
|
100
96
|
it { is_expected.not_to match(/ORDER BY/) }
|
101
97
|
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
|
@@ -2,12 +2,24 @@
|
|
2
2
|
|
3
3
|
# Helper methods for simple tree creation
|
4
4
|
module TreeMethods
|
5
|
-
def create_tree(max_level, current_level
|
5
|
+
def create_tree(max_level, current_level: 0, node: nil, create_node_info: false, stop_at: -1)
|
6
6
|
node = Node.create!(name: 'root') if node.nil?
|
7
7
|
|
8
8
|
1.upto(max_level - current_level) do |index|
|
9
|
-
child = node.children.create!(
|
10
|
-
|
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
|
+
)
|
11
23
|
end
|
12
24
|
|
13
25
|
node
|
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.
|
4
|
+
version: 3.4.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-
|
12
|
+
date: 2023-03-13 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: '
|
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: '
|
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: '
|
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: '
|
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: '1
|
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: '1
|
95
|
+
version: '2.1'
|
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
|
@@ -226,8 +227,11 @@ files:
|
|
226
227
|
- lib/acts_as_recursive_tree/railtie.rb
|
227
228
|
- lib/acts_as_recursive_tree/scopes.rb
|
228
229
|
- lib/acts_as_recursive_tree/version.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
|
229
234
|
- spec/acts_as_recursive_tree/preloaders/descendants_spec.rb
|
230
|
-
- spec/builders_spec.rb
|
231
235
|
- spec/db/database.rb
|
232
236
|
- spec/db/database.yml
|
233
237
|
- spec/db/models.rb
|
@@ -236,8 +240,8 @@ files:
|
|
236
240
|
- spec/model/node_spec.rb
|
237
241
|
- spec/model/relation_spec.rb
|
238
242
|
- spec/spec_helper.rb
|
243
|
+
- spec/support/shared_examples/builders.rb
|
239
244
|
- spec/support/tree_methods.rb
|
240
|
-
- spec/values_spec.rb
|
241
245
|
homepage: https://github.com/1and1/acts_as_recursive_tree
|
242
246
|
licenses:
|
243
247
|
- MIT
|
@@ -264,8 +268,11 @@ signing_key:
|
|
264
268
|
specification_version: 4
|
265
269
|
summary: Drop in replacement for acts_as_tree but using recursive queries
|
266
270
|
test_files:
|
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
|
267
275
|
- spec/acts_as_recursive_tree/preloaders/descendants_spec.rb
|
268
|
-
- spec/builders_spec.rb
|
269
276
|
- spec/db/database.rb
|
270
277
|
- spec/db/database.yml
|
271
278
|
- spec/db/models.rb
|
@@ -274,5 +281,5 @@ test_files:
|
|
274
281
|
- spec/model/node_spec.rb
|
275
282
|
- spec/model/relation_spec.rb
|
276
283
|
- spec/spec_helper.rb
|
284
|
+
- spec/support/shared_examples/builders.rb
|
277
285
|
- spec/support/tree_methods.rb
|
278
|
-
- spec/values_spec.rb
|