acts_as_recursive_tree 3.0.0 → 3.2.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: 6cb3b3fef0f54be5c64a667f3ce289fb536bbdce72dc9758eae7a3c27385adf1
4
- data.tar.gz: 5c65367bf564d3d12b70506ec2ecdaed1e9aaed535a822ccebff0b1aefe99b59
3
+ metadata.gz: 001a83205a1b8198bce2a13dda33718cd7733f67d99b8dd7f77562d8a9c16abf
4
+ data.tar.gz: 8ba160e08df9f2b5b0c508ed94c404e17dcde6206c14cafc6cc6d1c0794e13bd
5
5
  SHA512:
6
- metadata.gz: 187193f5f118a30d1359cde9b40d239e2d89ed9166dce8c0e73469dd3baf28b86fd7874ed89c763f6bdeff4c8d012bb78fa6cd521998f28289134d7bd0cce13a
7
- data.tar.gz: 6ca7d12b131992d6f901d462c857b79a976e323f40d0f198d6e1c26f3ce1ff36d6707226d695687b8b1bfb2a1209f7ca754ab4412bb23d581771add1ee1826bd
6
+ metadata.gz: a3e9db36bef6ef087286641f6b58c30fc1bea95368a9bea2bfce0210fea9418cdfb9c897d9835a2c1f189a681472d885108602eb5b8186868621263242d0cdab
7
+ data.tar.gz: c7eb40f03f62e577da3a5baa6261f61408251f6ec0e0253fa18d1f11b7446487cc87c529a1960688ff8ef40468e34328d28cd155a11ff5de2da40d01f684e843
@@ -19,12 +19,31 @@ jobs:
19
19
  runs-on: ubuntu-latest
20
20
  strategy:
21
21
  matrix:
22
- ruby-version: ['2.5', '2.6', '2.7']
23
- gemfile: [ar_52, ar_60, ar_61]
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]
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
37
+ - ruby-version: '3.0'
38
+ gemfile: ar_52
39
+ - ruby-version: '2.5'
40
+ gemfile: ar_70
41
+ - ruby-version: '2.6'
42
+ gemfile: ar_70
24
43
  env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps
25
44
  BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile
26
45
  steps:
27
- - uses: actions/checkout@v2
46
+ - uses: actions/checkout@v3
28
47
  - name: Set up Ruby
29
48
  # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
30
49
  # 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/.rubocop.yml CHANGED
@@ -9,6 +9,9 @@ AllCops:
9
9
  NewCops: enable
10
10
  SuggestExtensions: false
11
11
 
12
+ Gemspec/RequireMFA:
13
+ Enabled: false
14
+
12
15
  Metrics/AbcSize:
13
16
  Max: 20
14
17
 
data/Appraisals CHANGED
@@ -14,3 +14,8 @@ appraise 'ar-61' do
14
14
  gem 'activerecord', '~> 6.1.0'
15
15
  gem 'activesupport', '~> 6.1.0'
16
16
  end
17
+
18
+ appraise 'ar-70' do
19
+ gem 'activerecord', '~> 7.0.1'
20
+ gem 'activesupport', '~> 7.0.1'
21
+ end
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ### Version 3.2.0
2
+ - Added #preload_tree method to preload the parent/child relations of a single node
3
+
4
+ ### Version 3.1.0
5
+ - Rails 7 support
6
+
1
7
  ### Version 3.0.0
2
8
  - BREAKING: Dropped support for Rails < 5.2
3
9
  - BREAKING: Increased minimum Ruby version to 2.5
data/README.md CHANGED
@@ -12,6 +12,23 @@ When you have tree based data in your application, you always to struggle with r
12
12
 
13
13
  Luckily, there is already a SQL standard that makes it very easy to retrieve data in the traditional parent/child relation. Currently this is only supported in sqlite and Postgres. With this it is possible to query complete trees without the need of extra tables or indices.
14
14
 
15
+ ## Supported environments
16
+ ActsAsRecursiveTree currently supports following ActiveRecord versions and is tested for compatibility:
17
+ * ActiveRecord 5.2.x
18
+ * ActiveRecord 6.0.x
19
+ * ActiveRecord 6.1.x
20
+ * ActiveRecord 7.0.x
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.
15
32
 
16
33
  ## Installation
17
34
 
@@ -117,7 +134,7 @@ __Additional methods:__
117
134
  __Utility methods:__
118
135
  * `root?` - returns true if this node is a root node
119
136
  * `leaf?` - returns true if this node is a leave node
120
-
137
+ * `preload_tree` - fetches all descendants of this node and assignes the proper parent/children associations. You are then able to traverse the tree through the children/parent association without querying the database again.
121
138
 
122
139
  ## Customizing the recursion
123
140
 
@@ -195,17 +212,6 @@ sub_node_instance.descendants # => returns Node and SubNode instances
195
212
  ```
196
213
 
197
214
 
198
- ## Known Issues
199
-
200
- When using PostgreSQL as underlying database system chances are good that you encounter following error message:
201
-
202
- `
203
- ActiveRecord::StatementInvalid: PG::ProtocolViolation: ERROR: bind message supplies 1 parameters, but prepared statement "" requires 2
204
- `
205
-
206
- This is a known ActiveRecord issue which should be fixed in Rails 5.2. Alternative
207
-
208
-
209
215
  ## Contributing
210
216
 
211
217
  1. Fork it ( https://github.com/1and1/acts_as_recursive_tree/fork )
@@ -16,24 +16,24 @@ Gem::Specification.new do |spec|
16
16
  spec.license = 'MIT'
17
17
  spec.metadata = {
18
18
  'bug_tracker_uri' => 'https://github.com/1and1/acts_as_recursive_tree/issues',
19
- 'changelog_uri' => 'https://github.com/1and1/acts_as_recursive_tree/CHANGELOG.md'
19
+ 'changelog_uri' => 'https://github.com/1and1/acts_as_recursive_tree/blob/main/CHANGELOG.md'
20
20
  }
21
21
  spec.required_ruby_version = '>= 2.5.0'
22
22
  spec.files = `git ls-files -z`.split("\x0")
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.0'
27
- spec.add_runtime_dependency 'activesupport', '>= 5.2.0', '< 7.0'
26
+ spec.add_runtime_dependency 'activerecord', '>= 5.2.0', '< 7.1'
27
+ spec.add_runtime_dependency 'activesupport', '>= 5.2.0', '< 7.1'
28
28
  spec.add_runtime_dependency 'zeitwerk', '>= 2.4'
29
29
 
30
30
  spec.add_development_dependency 'appraisal', '~> 2.4'
31
31
  spec.add_development_dependency 'database_cleaner', '~> 1.5'
32
32
  spec.add_development_dependency 'rake'
33
33
  spec.add_development_dependency 'rspec-rails', '>= 3.5'
34
- spec.add_development_dependency 'rubocop', '>= 1.8.0'
35
- spec.add_development_dependency 'rubocop-rails', '>= 2.9.0'
36
- spec.add_development_dependency 'rubocop-rspec', '>= 2.1.0'
34
+ spec.add_development_dependency 'rubocop', '~> 1.23.0'
35
+ spec.add_development_dependency 'rubocop-rails', '~> 2.12.0'
36
+ spec.add_development_dependency 'rubocop-rspec', '~> 2.6.0'
37
37
 
38
38
  spec.add_development_dependency 'sqlite3', '~> 1.3'
39
39
  end
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 7.0.1"
6
+ gem "activesupport", "~> 7.0.1"
7
+
8
+ 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,14 @@ 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
+ def preload_tree
98
+ ActsAsRecursiveTree::Preloaders::Descendants.new(self).preload!
99
+ true
100
+ end
101
+
94
102
  def base_class
95
103
  self.class.base_class
96
104
  end
@@ -0,0 +1,37 @@
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)
11
+ @node = node
12
+ @parent_key = node._recursive_tree_config.parent_key
13
+ end
14
+
15
+ def preload!
16
+ apply_records(@node)
17
+ end
18
+
19
+ private
20
+
21
+ def records
22
+ @records ||= @node.descendants.to_a
23
+ end
24
+
25
+ def apply_records(parent_node)
26
+ children = records.select { |child| child.send(@parent_key) == parent_node.id }
27
+
28
+ parent_node.association(:children).target = children
29
+
30
+ children.each do |child|
31
+ child.association(:parent).target = parent_node
32
+ apply_records(child)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActsAsRecursiveTree
4
- VERSION = '3.0.0'
4
+ VERSION = '3.2.0'
5
5
  end
@@ -0,0 +1,29 @@
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) }
9
+ let(:root) { create_tree(2) }
10
+ let(:children) { root.children }
11
+
12
+ describe '#preload! will set the associations target attribute' do
13
+ before do
14
+ preloader.preload!
15
+ end
16
+
17
+ it 'sets the children assoction' do
18
+ children.each do |child|
19
+ expect(child.association(:children).target).not_to be_nil
20
+ end
21
+ end
22
+
23
+ it 'sets the parent assoction' do
24
+ children.each do |child|
25
+ expect(child.association(:parent).target).not_to be_nil
26
+ end
27
+ end
28
+ end
29
+ end
data/spec/db/database.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'fileutils'
4
+
3
5
  database_folder = "#{File.dirname(__FILE__)}/../db"
4
6
  database_adapter = 'sqlite'
5
7
 
@@ -3,16 +3,7 @@
3
3
  require 'spec_helper'
4
4
 
5
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
6
+ include TreeMethods
16
7
 
17
8
  before do
18
9
  @root = create_tree(3)
@@ -24,7 +15,7 @@ describe Node do
24
15
  expect(@root.children.count).to be(3)
25
16
  end
26
17
 
27
- it 'does not include root node ' do
18
+ it 'does not include root node' do
28
19
  expect(@root.children).not_to include(@root)
29
20
  end
30
21
  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
@@ -0,0 +1,15 @@
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)
6
+ node = Node.create!(name: 'root') if node.nil?
7
+
8
+ 1.upto(max_level - current_level) do |index|
9
+ child = node.children.create!(name: "child #{index} - level #{current_level}")
10
+ create_tree(max_level, current_level + 1, child)
11
+ end
12
+
13
+ node
14
+ end
15
+ end
data/spec/values_spec.rb CHANGED
@@ -72,9 +72,16 @@ describe ActsAsRecursiveTree::Options::Values do
72
72
  end
73
73
 
74
74
  context 'Relation' do
75
- subject(:value) { described_class.create(relation, OpenStruct.new(primary_key: :id)) }
75
+ subject(:value) { described_class.create(relation, double) }
76
76
 
77
77
  let(:relation) { Node.where(name: 'test') }
78
+ let(:double) do
79
+ Class.new do
80
+ def self.primary_key
81
+ :id
82
+ end
83
+ end
84
+ end
78
85
 
79
86
  it { is_expected.to be_a ActsAsRecursiveTree::Options::Values::Relation }
80
87
 
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.0.0
4
+ version: 3.2.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-08-02 00:00:00.000000000 Z
12
+ date: 2023-01-23 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.0'
23
+ version: '7.1'
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.0'
33
+ version: '7.1'
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.0'
43
+ version: '7.1'
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.0'
53
+ version: '7.1'
54
54
  - !ruby/object:Gem::Dependency
55
55
  name: zeitwerk
56
56
  requirement: !ruby/object:Gem::Requirement
@@ -125,44 +125,44 @@ dependencies:
125
125
  name: rubocop
126
126
  requirement: !ruby/object:Gem::Requirement
127
127
  requirements:
128
- - - ">="
128
+ - - "~>"
129
129
  - !ruby/object:Gem::Version
130
- version: 1.8.0
130
+ version: 1.23.0
131
131
  type: :development
132
132
  prerelease: false
133
133
  version_requirements: !ruby/object:Gem::Requirement
134
134
  requirements:
135
- - - ">="
135
+ - - "~>"
136
136
  - !ruby/object:Gem::Version
137
- version: 1.8.0
137
+ version: 1.23.0
138
138
  - !ruby/object:Gem::Dependency
139
139
  name: rubocop-rails
140
140
  requirement: !ruby/object:Gem::Requirement
141
141
  requirements:
142
- - - ">="
142
+ - - "~>"
143
143
  - !ruby/object:Gem::Version
144
- version: 2.9.0
144
+ version: 2.12.0
145
145
  type: :development
146
146
  prerelease: false
147
147
  version_requirements: !ruby/object:Gem::Requirement
148
148
  requirements:
149
- - - ">="
149
+ - - "~>"
150
150
  - !ruby/object:Gem::Version
151
- version: 2.9.0
151
+ version: 2.12.0
152
152
  - !ruby/object:Gem::Dependency
153
153
  name: rubocop-rspec
154
154
  requirement: !ruby/object:Gem::Requirement
155
155
  requirements:
156
- - - ">="
156
+ - - "~>"
157
157
  - !ruby/object:Gem::Version
158
- version: 2.1.0
158
+ version: 2.6.0
159
159
  type: :development
160
160
  prerelease: false
161
161
  version_requirements: !ruby/object:Gem::Requirement
162
162
  requirements:
163
- - - ">="
163
+ - - "~>"
164
164
  - !ruby/object:Gem::Version
165
- version: 2.1.0
165
+ version: 2.6.0
166
166
  - !ruby/object:Gem::Dependency
167
167
  name: sqlite3
168
168
  requirement: !ruby/object:Gem::Requirement
@@ -204,6 +204,7 @@ files:
204
204
  - gemfiles/ar_52.gemfile
205
205
  - gemfiles/ar_60.gemfile
206
206
  - gemfiles/ar_61.gemfile
207
+ - gemfiles/ar_70.gemfile
207
208
  - lib/acts_as_recursive_tree.rb
208
209
  - lib/acts_as_recursive_tree/acts_macro.rb
209
210
  - lib/acts_as_recursive_tree/associations.rb
@@ -221,9 +222,11 @@ files:
221
222
  - lib/acts_as_recursive_tree/options/depth_condition.rb
222
223
  - lib/acts_as_recursive_tree/options/query_options.rb
223
224
  - lib/acts_as_recursive_tree/options/values.rb
225
+ - lib/acts_as_recursive_tree/preloaders/descendants.rb
224
226
  - lib/acts_as_recursive_tree/railtie.rb
225
227
  - lib/acts_as_recursive_tree/scopes.rb
226
228
  - lib/acts_as_recursive_tree/version.rb
229
+ - spec/acts_as_recursive_tree/preloaders/descendants_spec.rb
227
230
  - spec/builders_spec.rb
228
231
  - spec/db/database.rb
229
232
  - spec/db/database.yml
@@ -233,13 +236,14 @@ files:
233
236
  - spec/model/node_spec.rb
234
237
  - spec/model/relation_spec.rb
235
238
  - spec/spec_helper.rb
239
+ - spec/support/tree_methods.rb
236
240
  - spec/values_spec.rb
237
241
  homepage: https://github.com/1and1/acts_as_recursive_tree
238
242
  licenses:
239
243
  - MIT
240
244
  metadata:
241
245
  bug_tracker_uri: https://github.com/1and1/acts_as_recursive_tree/issues
242
- changelog_uri: https://github.com/1and1/acts_as_recursive_tree/CHANGELOG.md
246
+ changelog_uri: https://github.com/1and1/acts_as_recursive_tree/blob/main/CHANGELOG.md
243
247
  post_install_message:
244
248
  rdoc_options: []
245
249
  require_paths:
@@ -260,6 +264,7 @@ signing_key:
260
264
  specification_version: 4
261
265
  summary: Drop in replacement for acts_as_tree but using recursive queries
262
266
  test_files:
267
+ - spec/acts_as_recursive_tree/preloaders/descendants_spec.rb
263
268
  - spec/builders_spec.rb
264
269
  - spec/db/database.rb
265
270
  - spec/db/database.yml
@@ -269,4 +274,5 @@ test_files:
269
274
  - spec/model/node_spec.rb
270
275
  - spec/model/relation_spec.rb
271
276
  - spec/spec_helper.rb
277
+ - spec/support/tree_methods.rb
272
278
  - spec/values_spec.rb