closure_tree 7.0.0 → 7.1.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 +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +12 -9
- data/Appraisals +18 -3
- data/CHANGELOG.md +5 -0
- data/README.md +4 -7
- data/_config.yml +1 -0
- data/lib/closure_tree.rb +1 -0
- data/lib/closure_tree/finders.rb +13 -0
- data/lib/closure_tree/hash_tree_support.rb +2 -2
- data/lib/closure_tree/hierarchy_maintenance.rb +18 -1
- data/lib/closure_tree/support.rb +7 -5
- data/lib/closure_tree/support_attributes.rb +1 -1
- data/lib/closure_tree/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 417c1d78863c2c69db6e25b1fcf4e241c12287adf8db72953652072d36ee7f79
|
4
|
+
data.tar.gz: 45505a5b14cd3d9de2e0a823ef4805d27e9b27bc55fe3edbe1ae0aee05d62db1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c606867a720cc4dd7ddfc608ef0f61e5e06decd8623caa86938629d6089b7b86e3c95f68df864ba306f533d5287e6765559f023e18cc6157410852164fd1f4e0
|
7
|
+
data.tar.gz: 0bbd08988841abd22f52d706501d3556ea7cc52319ac212ea86ee1b82315aa83de2cb58327ac21cecaa465a53e9305d73fa0b0ab6031ad58f3e7d04acab4c5d3
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -2,13 +2,11 @@ cache: bundler
|
|
2
2
|
sudo: false
|
3
3
|
language: ruby
|
4
4
|
rvm:
|
5
|
-
- 2.6.
|
6
|
-
- 2.5.
|
7
|
-
- 2.4.4
|
8
|
-
- 2.3.6
|
9
|
-
- 2.2.10
|
5
|
+
- 2.6.3
|
6
|
+
- 2.5.5
|
10
7
|
|
11
8
|
gemfile:
|
9
|
+
- gemfiles/activerecord_6.0.gemfile
|
12
10
|
- gemfiles/activerecord_5.2.gemfile
|
13
11
|
- gemfiles/activerecord_5.1.gemfile
|
14
12
|
- gemfiles/activerecord_5.0.gemfile
|
@@ -20,11 +18,16 @@ env:
|
|
20
18
|
- DB=mysql
|
21
19
|
- DB=postgresql
|
22
20
|
|
21
|
+
services:
|
22
|
+
- mysql
|
23
|
+
- postgresql
|
24
|
+
|
23
25
|
script: WITH_ADVISORY_LOCK_PREFIX=$TRAVIS_JOB_ID bundle exec rake --trace spec:all
|
24
26
|
|
25
27
|
matrix:
|
26
28
|
allow_failures:
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
- gemfile: gemfiles/activerecord_edge.gemfile
|
30
|
+
- gemfile: gemfiles/activerecord_6.0.gemfile
|
31
|
+
exclude:
|
32
|
+
- rvm: 2.5.5
|
33
|
+
gemfile: gemfiles/activerecord_edge.gemfile
|
data/Appraisals
CHANGED
@@ -4,7 +4,7 @@ appraise 'activerecord-4.2' do
|
|
4
4
|
platforms :ruby do
|
5
5
|
gem 'mysql2', "< 0.5"
|
6
6
|
gem 'pg', "~> 0.21"
|
7
|
-
gem 'sqlite3'
|
7
|
+
gem 'sqlite3', '~> 1.3.13'
|
8
8
|
end
|
9
9
|
|
10
10
|
platforms :jruby do
|
@@ -19,7 +19,7 @@ appraise 'activerecord-5.0' do
|
|
19
19
|
platforms :ruby do
|
20
20
|
gem 'mysql2'
|
21
21
|
gem 'pg'
|
22
|
-
gem 'sqlite3'
|
22
|
+
gem 'sqlite3', '~> 1.3.13'
|
23
23
|
end
|
24
24
|
|
25
25
|
platforms :jruby do
|
@@ -34,7 +34,7 @@ appraise 'activerecord-5.1' do
|
|
34
34
|
platforms :ruby do
|
35
35
|
gem 'mysql2'
|
36
36
|
gem 'pg'
|
37
|
-
gem 'sqlite3'
|
37
|
+
gem 'sqlite3', '~> 1.3.13'
|
38
38
|
end
|
39
39
|
|
40
40
|
platforms :jruby do
|
@@ -59,6 +59,21 @@ appraise 'activerecord-5.2' do
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
+
appraise 'activerecord-6.0' do
|
63
|
+
gem 'activerecord', '~> 6.0.0'
|
64
|
+
platforms :ruby do
|
65
|
+
gem 'mysql2'
|
66
|
+
gem 'pg'
|
67
|
+
gem 'sqlite3'
|
68
|
+
end
|
69
|
+
|
70
|
+
platforms :jruby do
|
71
|
+
gem 'activerecord-jdbcmysql-adapter'
|
72
|
+
gem 'activerecord-jdbcpostgresql-adapter'
|
73
|
+
gem 'activerecord-jdbcsqlite3-adapter'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
62
77
|
appraise 'activerecord-edge' do
|
63
78
|
gem 'activerecord', github: 'rails/rails'
|
64
79
|
platforms :ruby do
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
### 7.1.0
|
4
|
+
Closure Tree is now tested against Rails 6.0
|
5
|
+
- Directly require core_ext for String#strip_heredoc[PR 350](https://github.com/ClosureTree/closure_tree/pull/350)
|
6
|
+
- Call Module#module_parent instead of deprecated #parent[PR 354](https://github.com/ClosureTree/closure_tree/pull/354)
|
7
|
+
|
3
8
|
### 7.0.0
|
4
9
|
Closure Tree is now tested against Rails 5.2
|
5
10
|
|
data/README.md
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# Closure Tree
|
2
2
|
|
3
|
-
__Important: please [vote on the future of ClosureTree](https://github.com/ClosureTree/closure_tree/issues/277)!__
|
4
|
-
|
5
3
|
### Closure_tree lets your ActiveRecord models act as nodes in a [tree data structure](http://en.wikipedia.org/wiki/Tree_%28data_structure%29)
|
6
4
|
|
7
5
|
Common applications include modeling hierarchical data, like tags, threaded comments, page graphs in CMSes,
|
@@ -10,7 +8,6 @@ and tracking user referrals.
|
|
10
8
|
[](https://gitter.im/closure_tree/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
11
9
|
[](http://travis-ci.org/ClosureTree/closure_tree)
|
12
10
|
[](https://badge.fury.io/rb/closure_tree)
|
13
|
-
[](https://gemnasium.com/github.com/ClosureTree/closure_tree)
|
14
11
|
|
15
12
|
Dramatically more performant than
|
16
13
|
[ancestry](https://github.com/stefankroes/ancestry) and
|
@@ -28,7 +25,7 @@ closure_tree has some great features:
|
|
28
25
|
* 2 SQL INSERTs on node creation
|
29
26
|
* 3 SQL INSERT/UPDATEs on node reparenting
|
30
27
|
* __Support for [concurrency](#concurrency)__ (using [with_advisory_lock](https://github.com/ClosureTree/with_advisory_lock))
|
31
|
-
* __Tested against ActiveRecord 4.2, 5.0,
|
28
|
+
* __Tested against ActiveRecord 4.2, 5.0, 5.1, 5.2 and 6.0 with Ruby 2.5 and 2.6__
|
32
29
|
* Support for reparenting children (and all their descendants)
|
33
30
|
* Support for [single-table inheritance (STI)](#sti) within the hierarchy
|
34
31
|
* ```find_or_create_by_path``` for [building out heterogeneous hierarchies quickly and conveniently](#find_or_create_by_path)
|
@@ -341,7 +338,7 @@ When you include ```has_closure_tree``` in your model, you can provide a hash to
|
|
341
338
|
* ```Tag.find_or_create_by_path(path, attributes)``` returns the node whose name path is ```path```, and will create the node if it doesn't exist already.See (#find_or_create_by_path).
|
342
339
|
* ```Tag.find_all_by_generation(generation_level)``` returns the descendant nodes who are ```generation_level``` away from a root. ```Tag.find_all_by_generation(0)``` is equivalent to ```Tag.roots```.
|
343
340
|
* ```Tag.with_ancestor(ancestors)``` scopes to all descendants whose ancestor is in the given list.
|
344
|
-
|
341
|
+
* ```Tag.lowest_common_ancestor(descendants)``` finds the lowest common ancestor of the descendants.
|
345
342
|
### Instance methods
|
346
343
|
|
347
344
|
* ```tag.root``` returns the root for this node
|
@@ -665,8 +662,8 @@ end
|
|
665
662
|
|
666
663
|
Closure tree is [tested under every valid combination](http://travis-ci.org/#!/ClosureTree/closure_tree) of
|
667
664
|
|
668
|
-
* Ruby 2.
|
669
|
-
* ActiveRecord 4.2, 5.
|
665
|
+
* Ruby 2.5, 2.6
|
666
|
+
* ActiveRecord 4.2, 5.x and 6.0
|
670
667
|
* PostgreSQL, MySQL, and SQLite. Concurrency tests are only run with MySQL and PostgreSQL.
|
671
668
|
|
672
669
|
Assuming you're using [rbenv](https://github.com/sstephenson/rbenv), you can use ```tests.sh``` to
|
data/_config.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
theme: jekyll-theme-leap-day
|
data/lib/closure_tree.rb
CHANGED
data/lib/closure_tree/finders.rb
CHANGED
@@ -99,6 +99,19 @@ module ClosureTree
|
|
99
99
|
_ct.scope_with_order(scope)
|
100
100
|
end
|
101
101
|
|
102
|
+
def lowest_common_ancestor(*descendants)
|
103
|
+
descendants = descendants.first if descendants.length == 1 && descendants.first.respond_to?(:each)
|
104
|
+
ancestor_id = hierarchy_class
|
105
|
+
.where(descendant_id: descendants)
|
106
|
+
.group(:ancestor_id)
|
107
|
+
.having("COUNT(ancestor_id) = #{descendants.count}")
|
108
|
+
.order(Arel.sql('MIN(generations) ASC'))
|
109
|
+
.limit(1)
|
110
|
+
.pluck(:ancestor_id).first
|
111
|
+
|
112
|
+
find_by(primary_key => ancestor_id) if ancestor_id
|
113
|
+
end
|
114
|
+
|
102
115
|
def find_all_by_generation(generation_level)
|
103
116
|
s = joins(<<-SQL.strip_heredoc)
|
104
117
|
INNER JOIN (
|
@@ -14,7 +14,7 @@ module ClosureTree
|
|
14
14
|
ON #{quoted_table_name}.#{model_class.primary_key} = generation_depth.descendant_id
|
15
15
|
SQL
|
16
16
|
scope_with_order(scope.joins(generation_depth), 'generation_depth.depth')
|
17
|
-
|
17
|
+
end
|
18
18
|
|
19
19
|
def hash_tree(tree_scope, limit_depth = nil)
|
20
20
|
limited_scope = limit_depth ? tree_scope.where("#{quoted_hierarchy_table_name}.generations <= #{limit_depth - 1}") : tree_scope
|
@@ -33,4 +33,4 @@ module ClosureTree
|
|
33
33
|
tree
|
34
34
|
end
|
35
35
|
end
|
36
|
-
end
|
36
|
+
end
|
@@ -112,11 +112,28 @@ module ClosureTree
|
|
112
112
|
# Note that the hierarchy table will be truncated.
|
113
113
|
def rebuild!
|
114
114
|
_ct.with_advisory_lock do
|
115
|
-
|
115
|
+
cleanup!
|
116
116
|
roots.find_each { |n| n.send(:rebuild!) } # roots just uses the parent_id column, so this is safe.
|
117
117
|
end
|
118
118
|
nil
|
119
119
|
end
|
120
|
+
|
121
|
+
def cleanup!
|
122
|
+
hierarchy_table = hierarchy_class.arel_table
|
123
|
+
|
124
|
+
[:descendant_id, :ancestor_id].each do |foreign_key|
|
125
|
+
alias_name = foreign_key.to_s.split('_').first + "s"
|
126
|
+
alias_table = Arel::Table.new(table_name).alias(alias_name)
|
127
|
+
arel_join = hierarchy_table.join(alias_table, Arel::Nodes::OuterJoin)
|
128
|
+
.on(alias_table[primary_key].eq(hierarchy_table[foreign_key]))
|
129
|
+
.join_sources
|
130
|
+
|
131
|
+
lonely_childs = hierarchy_class.joins(arel_join).where(alias_table[primary_key].eq(nil))
|
132
|
+
ids = lonely_childs.pluck(foreign_key)
|
133
|
+
|
134
|
+
hierarchy_class.where(hierarchy_table[foreign_key].in(ids)).delete_all
|
135
|
+
end
|
136
|
+
end
|
120
137
|
end
|
121
138
|
end
|
122
139
|
end
|
data/lib/closure_tree/support.rb
CHANGED
@@ -32,13 +32,15 @@ module ClosureTree
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def hierarchy_class_for_model
|
35
|
-
|
35
|
+
parent_class = ActiveSupport::VERSION::MAJOR >= 6 ? model_class.module_parent : model_class.parent
|
36
|
+
hierarchy_class = parent_class.const_set(short_hierarchy_class_name, Class.new(ActiveRecord::Base))
|
36
37
|
use_attr_accessible = use_attr_accessible?
|
37
38
|
include_forbidden_attributes_protection = include_forbidden_attributes_protection?
|
38
|
-
|
39
|
+
model_class_name = model_class.to_s
|
40
|
+
hierarchy_class.class_eval do
|
39
41
|
include ActiveModel::ForbiddenAttributesProtection if include_forbidden_attributes_protection
|
40
|
-
belongs_to :ancestor, :
|
41
|
-
belongs_to :descendant, :
|
42
|
+
belongs_to :ancestor, class_name: model_class_name
|
43
|
+
belongs_to :descendant, class_name: model_class_name
|
42
44
|
attr_accessible :ancestor, :descendant, :generations if use_attr_accessible
|
43
45
|
def ==(other)
|
44
46
|
self.class == other.class && ancestor_id == other.ancestor_id && descendant_id == other.descendant_id
|
@@ -47,7 +49,7 @@ module ClosureTree
|
|
47
49
|
def hash
|
48
50
|
ancestor_id.hash << 31 ^ descendant_id.hash
|
49
51
|
end
|
50
|
-
|
52
|
+
end
|
51
53
|
hierarchy_class.table_name = hierarchy_table_name
|
52
54
|
hierarchy_class
|
53
55
|
end
|
data/lib/closure_tree/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: closure_tree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.
|
4
|
+
version: 7.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthew McEachen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-01-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -153,6 +153,7 @@ files:
|
|
153
153
|
- MIT-LICENSE
|
154
154
|
- README.md
|
155
155
|
- Rakefile
|
156
|
+
- _config.yml
|
156
157
|
- closure_tree.gemspec
|
157
158
|
- lib/closure_tree.rb
|
158
159
|
- lib/closure_tree/active_record_support.rb
|
@@ -198,8 +199,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
198
199
|
- !ruby/object:Gem::Version
|
199
200
|
version: '0'
|
200
201
|
requirements: []
|
201
|
-
|
202
|
-
rubygems_version: 2.7.6
|
202
|
+
rubygems_version: 3.0.3
|
203
203
|
signing_key:
|
204
204
|
specification_version: 4
|
205
205
|
summary: Easily and efficiently make your ActiveRecord model support hierarchies
|