acts_as_recursive_tree 2.0.0 → 2.0.1
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/CHANGELOG.md +3 -0
- data/README.md +37 -0
- data/lib/acts_as_recursive_tree/builders/ancestors.rb +1 -1
- data/lib/acts_as_recursive_tree/builders/descendants.rb +1 -1
- data/lib/acts_as_recursive_tree/builders/leaves.rb +3 -3
- data/lib/acts_as_recursive_tree/builders/relation_builder.rb +39 -27
- data/lib/acts_as_recursive_tree/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ffd168c454a68c9fdc6ae7fb32b705bdaba8964f
|
4
|
+
data.tar.gz: 2367e9b864ee904abc49198936f5afb59bb2d46b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4c4e359bbc497ff24f6ba6e8ccfbd846ce17178c0842850d3e3a0bee43e7d15cd8cd6a0a40072aa74d48e538d4a4dc892be743a677c34c39b7280348588ed74e
|
7
|
+
data.tar.gz: 12c7f7bac25c0547573d66bc8efa7b6e6ea4e3815f3490c929b8551886512c2cef6619f48a954d02a89518a79ac4da412d66fb69973b8321245d9bd7049952ba
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -164,7 +164,44 @@ node_instance.descendants{ |opts| opts.ensure_ordering! }
|
|
164
164
|
|
165
165
|
NOTE: if there are many descendants this may cause a severe increase in execution time!
|
166
166
|
|
167
|
+
## Single Table Inheritance (STI)
|
168
|
+
|
169
|
+
STI works out of the box. Consider following classes:
|
170
|
+
|
171
|
+
```ruby
|
172
|
+
class Node < ActiveRecord::Base
|
173
|
+
recursive_tree
|
174
|
+
end
|
175
|
+
|
176
|
+
class SubNode < Node
|
167
177
|
|
178
|
+
end
|
179
|
+
```
|
180
|
+
|
181
|
+
When calling ClassMethods the results depend on the class on which you call the method:
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
Node.descendants_of(123) # => returns Node and SubNode instances
|
185
|
+
SubNode.descendants_of(123) # => returns SubNode instances only
|
186
|
+
```
|
187
|
+
|
188
|
+
Instance Methods make no difference of the class from which they are called:
|
189
|
+
|
190
|
+
```ruby
|
191
|
+
sub_node_instance.descendants # => returns Node and SubNode instances
|
192
|
+
```
|
193
|
+
|
194
|
+
|
195
|
+
## Known Issues
|
196
|
+
|
197
|
+
When using PostgreSQL as underlying database system chances are good that you encounter following error message:
|
198
|
+
|
199
|
+
`
|
200
|
+
ActiveRecord::StatementInvalid: PG::ProtocolViolation: ERROR: bind message supplies 1 parameters, but prepared statement "" requires 2
|
201
|
+
`
|
202
|
+
|
203
|
+
This is a known ActiveRecord issue which should be fixed in Rails 5.2. Alternative
|
204
|
+
|
168
205
|
|
169
206
|
## Contributing
|
170
207
|
|
@@ -6,10 +6,10 @@ module ActsAsRecursiveTree
|
|
6
6
|
select_manager = super
|
7
7
|
|
8
8
|
select_manager.where(
|
9
|
-
travers_loc_table[
|
9
|
+
travers_loc_table[primary_key].not_in(
|
10
10
|
travers_loc_table.where(
|
11
|
-
travers_loc_table[
|
12
|
-
).project(travers_loc_table[
|
11
|
+
travers_loc_table[parent_key].not_eq(nil)
|
12
|
+
).project(travers_loc_table[parent_key])
|
13
13
|
)
|
14
14
|
)
|
15
15
|
select_manager
|
@@ -6,13 +6,16 @@ module ActsAsRecursiveTree
|
|
6
6
|
new(klass, ids, exclude_ids: exclude_ids, &block).build
|
7
7
|
end
|
8
8
|
|
9
|
-
attr_reader :klass, :ids, :recursive_temp_table, :travers_loc_table
|
10
|
-
attr_reader :query_opts, :without_ids
|
9
|
+
attr_reader :klass, :ids, :recursive_temp_table, :travers_loc_table, :without_ids
|
11
10
|
mattr_reader(:random) { Random.new }
|
12
11
|
|
12
|
+
delegate :primary_key, :depth_column, :parent_key, :parent_type_column, to: :@config
|
13
|
+
delegate :depth_present?, :depth, :condition, :ensure_ordering, to: :@query_opts
|
14
|
+
|
13
15
|
def initialize(klass, ids, exclude_ids: false, &block)
|
14
16
|
@klass = klass
|
15
|
-
@
|
17
|
+
@config = klass._recursive_tree_config
|
18
|
+
@ids = ActsAsRecursiveTree::Options::Values.create(ids, @config)
|
16
19
|
@without_ids = exclude_ids
|
17
20
|
|
18
21
|
@query_opts = get_query_options(block)
|
@@ -34,15 +37,11 @@ module ActsAsRecursiveTree
|
|
34
37
|
klass.arel_table
|
35
38
|
end
|
36
39
|
|
37
|
-
def config
|
38
|
-
klass._recursive_tree_config
|
39
|
-
end
|
40
|
-
|
41
40
|
def build
|
42
41
|
final_select_mgr = base_table.join(
|
43
42
|
create_select_manger.as(recursive_temp_table.name)
|
44
43
|
).on(
|
45
|
-
base_table[
|
44
|
+
base_table[primary_key].eq(recursive_temp_table[primary_key])
|
46
45
|
)
|
47
46
|
|
48
47
|
relation = klass.joins(final_select_mgr.join_sources)
|
@@ -56,18 +55,18 @@ module ActsAsRecursiveTree
|
|
56
55
|
|
57
56
|
def apply_except_id(relation)
|
58
57
|
return relation unless without_ids
|
59
|
-
relation.where(ids.apply_negated_to(base_table[
|
58
|
+
relation.where(ids.apply_negated_to(base_table[primary_key]))
|
60
59
|
end
|
61
60
|
|
62
61
|
def apply_depth(relation)
|
63
|
-
return relation unless
|
62
|
+
return relation unless depth_present?
|
64
63
|
|
65
|
-
relation.where(
|
64
|
+
relation.where(depth.apply_to(recursive_temp_table[depth_column]))
|
66
65
|
end
|
67
66
|
|
68
67
|
def apply_order(relation)
|
69
|
-
return relation unless
|
70
|
-
relation.order(recursive_temp_table[
|
68
|
+
return relation unless ensure_ordering
|
69
|
+
relation.order(recursive_temp_table[depth_column].asc)
|
71
70
|
end
|
72
71
|
|
73
72
|
def create_select_manger
|
@@ -82,34 +81,47 @@ module ActsAsRecursiveTree
|
|
82
81
|
end
|
83
82
|
|
84
83
|
def build_base_select
|
85
|
-
id_node = base_table[
|
84
|
+
id_node = base_table[primary_key]
|
86
85
|
|
87
86
|
base_table.where(
|
88
87
|
ids.apply_to(id_node)
|
89
88
|
).project(
|
90
89
|
id_node,
|
91
|
-
base_table[
|
92
|
-
Arel.sql('0').as(
|
90
|
+
base_table[parent_key],
|
91
|
+
Arel.sql('0').as(depth_column.to_s)
|
93
92
|
)
|
94
93
|
end
|
95
94
|
|
96
95
|
def build_union_select
|
97
|
-
|
98
|
-
|
99
|
-
)
|
96
|
+
join_condition = apply_parent_type_column(build_join_condition)
|
97
|
+
|
98
|
+
select_manager = base_table.join(travers_loc_table).on(join_condition)
|
100
99
|
|
101
100
|
# need to use ActiveRecord here for merging relation
|
102
|
-
relation =
|
103
|
-
|
104
|
-
|
101
|
+
relation = build_base_join_select(select_manager)
|
102
|
+
|
103
|
+
relation = apply_query_opts_condition(relation)
|
104
|
+
relation.arel
|
105
|
+
end
|
106
|
+
|
107
|
+
def apply_parent_type_column(arel_condition)
|
108
|
+
return arel_condition unless parent_type_column.present?
|
109
|
+
arel_condition.and(base_table[parent_type_column].eq(klass.base_class))
|
110
|
+
end
|
111
|
+
|
112
|
+
def build_base_join_select(select_manager)
|
113
|
+
klass.select(
|
114
|
+
base_table[primary_key],
|
115
|
+
base_table[parent_key],
|
105
116
|
Arel.sql(
|
106
|
-
(travers_loc_table[
|
107
|
-
).as(
|
117
|
+
(travers_loc_table[depth_column] + 1).to_sql
|
118
|
+
).as(depth_column.to_s)
|
108
119
|
).unscope(where: :type).joins(select_manager.join_sources)
|
120
|
+
end
|
109
121
|
|
110
|
-
|
111
|
-
|
112
|
-
relation.
|
122
|
+
def apply_query_opts_condition(relation)
|
123
|
+
return relation unless condition.present?
|
124
|
+
relation.merge(condition)
|
113
125
|
end
|
114
126
|
|
115
127
|
def build_join_condition
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acts_as_recursive_tree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wolfgang Wedelich-John
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-01-
|
11
|
+
date: 2018-01-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|