closure_tree 7.0.0 → 7.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Join the chat at https://gitter.im/closure_tree/Lobby](https://badges.gitter.im/closure_tree/Lobby.svg)](https://gitter.im/closure_tree/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
11
9
|
[![Build Status](https://api.travis-ci.org/ClosureTree/closure_tree.svg?branch=master)](http://travis-ci.org/ClosureTree/closure_tree)
|
12
10
|
[![Gem Version](https://badge.fury.io/rb/closure_tree.svg)](https://badge.fury.io/rb/closure_tree)
|
13
|
-
[![Dependency Status](https://gemnasium.com/badges/github.com/ClosureTree/closure_tree.svg)](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
|