acts_as_many_trees 0.2.2 → 0.3.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/lib/acts_as_many_trees/base.rb +19 -10
- data/lib/acts_as_many_trees/hierarchy_table.rb +142 -41
- data/lib/acts_as_many_trees/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: 633c463bad4d37f9c467cba4852ebcbdc10cb87b
|
4
|
+
data.tar.gz: e18295cde70abd5712d5bf316584ced556d321a9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2319dc68f438895276c0d6072df2ec3cd56c79376958e3f338c97590a960a2241a6c455ae52b18c742eeed84a63a3fdf15115c2ff342dc0e1226f94e296c1aef
|
7
|
+
data.tar.gz: b3dd7f7a3720dcf927927d51d071a425017fc4276559cb5fb6a1f764e01fcbad7bc42305260e8545dcbd8e4575df890542624f47de3146436de03f587505d3b4
|
@@ -61,12 +61,19 @@ module ActsAsManyTrees
|
|
61
61
|
}
|
62
62
|
|
63
63
|
scope :roots , ->(tree_name=self.default_tree_name){
|
64
|
-
|
65
|
-
|
66
|
-
|
64
|
+
h1 = hierarchy_class.arel_table
|
65
|
+
h2 = hierarchy_class.arel_table.alias
|
66
|
+
on1 = Arel::Nodes::On.new(Arel::Nodes::Equality.new(arel_table[:id],h1[:descendant_id])
|
67
|
+
.and(h1[:hierarchy_scope].eq(tree_name))
|
68
|
+
.and(h1[:generation].eq(0))
|
67
69
|
)
|
68
|
-
|
69
|
-
|
70
|
+
on2 = Arel::Nodes::On.new(Arel::Nodes::Equality.new(h1[:ancestor_id],h2[:descendant_id])
|
71
|
+
.and(Arel::Nodes::Equality.new(h1[:hierarchy_scope],h2[:hierarchy_scope]))
|
72
|
+
.and(h2[:generation].not_eq(0))
|
73
|
+
)
|
74
|
+
inner_join = Arel::Nodes::InnerJoin.new(h1,on1)
|
75
|
+
outer_join = Arel::Nodes::OuterJoin.new(h2,on2)
|
76
|
+
joins(inner_join).joins(outer_join).merge(where(Arel::Nodes::Equality.new(h2[:ancestor_id],nil)))
|
70
77
|
}
|
71
78
|
scope :not_this,->(this_id) { where.not(id: this_id)}
|
72
79
|
end
|
@@ -81,22 +88,24 @@ module ActsAsManyTrees
|
|
81
88
|
new_parent=inpt_parent[:new_parent]
|
82
89
|
after_node=inpt_parent[:after_node]
|
83
90
|
before_node=inpt_parent[:before_node]
|
84
|
-
tree_name=inpt_parent[:tree_name] ||
|
91
|
+
tree_name = inpt_parent[:tree_name] || (new_parent ? new_parent.default_tree_name : self.default_tree_name)
|
92
|
+
existing_tree_name = inpt_parent[:existing_tree_name] || self.default_tree_name
|
85
93
|
else
|
86
94
|
new_parent=inpt_parent
|
87
95
|
after_node=inpt_parent.children.last unless inpt_parent.nil?
|
88
96
|
before_node=inpt_parent.next_sibling unless inpt_parent.nil?
|
89
97
|
tree_name = inpt_parent ? inpt_parent.default_tree_name : self.default_tree_name
|
98
|
+
existing_tree_name = self.default_tree_name
|
90
99
|
end
|
91
|
-
hierarchy_class.set_parent_of(self,new_parent,tree_name,after_node,before_node)
|
100
|
+
hierarchy_class.set_parent_of(item:self,new_parent:new_parent,hierarchy_scope:tree_name,existing_scope:existing_tree_name,after_node:after_node,before_node:before_node)
|
92
101
|
end
|
93
102
|
|
94
|
-
def set_parent(new_parent
|
95
|
-
hierarchy_class.set_parent_of(self,new_parent,tree_name)
|
103
|
+
def set_parent(new_parent:,tree_name:self.default_tree_name,existing_tree:self.default_tree_name,clone_sub_tree:false)
|
104
|
+
hierarchy_class.set_parent_of(item:self,new_parent:new_parent,hierarchy_scope:tree_name,existing_scope:existing_tree,clone_sub_tree:clone_sub_tree)
|
96
105
|
end
|
97
106
|
|
98
107
|
def add_child(new_child,tree_name=self.default_tree_name)
|
99
|
-
hierarchy_class.set_parent_of(new_child,self,tree_name)
|
108
|
+
hierarchy_class.set_parent_of(item:new_child,new_parent:self,hierarchy_scope:tree_name)
|
100
109
|
end
|
101
110
|
|
102
111
|
def parent(tree_name=self.default_tree_name)
|
@@ -63,7 +63,7 @@ module ActsAsManyTrees
|
|
63
63
|
scope :roots,->do
|
64
64
|
t1 = arel_table
|
65
65
|
t2 = arel_table.alias
|
66
|
-
t1.project(Arel::star).join(t2,Arel::Nodes::OuterJoin)
|
66
|
+
j=t1.project(Arel::star).join(t2,Arel::Nodes::OuterJoin)
|
67
67
|
.on(t1[:ancestor_id]
|
68
68
|
.eq(t2[:descendant_id])
|
69
69
|
.and(t1[:hierarchy_scope].eq(t2[:hierarchy_scope])
|
@@ -71,6 +71,7 @@ module ActsAsManyTrees
|
|
71
71
|
)
|
72
72
|
.where(t2[:ancestor_id].eq(nil)
|
73
73
|
)
|
74
|
+
joins(j)
|
74
75
|
end
|
75
76
|
scope :self_and_siblings, ->(item,hierarchy_scope='')do
|
76
77
|
joins(:siblings)
|
@@ -79,7 +80,7 @@ module ActsAsManyTrees
|
|
79
80
|
joins(:siblings).where(:position,lt(rec.position))
|
80
81
|
end
|
81
82
|
|
82
|
-
def self.set_parent_of(item
|
83
|
+
def self.set_parent_of(item:,new_parent:,hierarchy_scope:'',existing_scope:'',clone_sub_tree:false,after_node:nil,before_node:nil)
|
83
84
|
if new_parent
|
84
85
|
wrk_parent = self.find_by(descendant_id:new_parent.id,ancestor_id:new_parent.id,generation: 0,hierarchy_scope: hierarchy_scope)
|
85
86
|
unless wrk_parent
|
@@ -87,6 +88,9 @@ module ActsAsManyTrees
|
|
87
88
|
wrk_parent=self.create(descendant_id:new_parent.id,ancestor_id:new_parent.id,generation: 0,hierarchy_scope: hierarchy_scope,position: position)
|
88
89
|
end
|
89
90
|
end
|
91
|
+
# puts 'ppppppppppp'
|
92
|
+
# debug_tree('')
|
93
|
+
# puts 'pppppppp'
|
90
94
|
if item
|
91
95
|
after_position = after_this(wrk_parent,after_node,hierarchy_scope)
|
92
96
|
before_position = before_this(before_node,hierarchy_scope)
|
@@ -100,14 +104,44 @@ module ActsAsManyTrees
|
|
100
104
|
temp_name = SecureRandom.hex
|
101
105
|
# BEWARE this works when added default trees and adding default trees to a new scope but it won't work when moving
|
102
106
|
# items within a named tree or when adding items from one named scope to another
|
103
|
-
|
104
|
-
|
105
|
-
|
107
|
+
# puts "hierarchy_scope #{hierarchy_scope} existing_scope #{existing_scope}"
|
108
|
+
if (hierarchy_scope != existing_scope)
|
109
|
+
# debug_tree(existing_scope)
|
110
|
+
# debug_tree(hierarchy_scope)
|
111
|
+
# debug_tree(temp_name)
|
112
|
+
if clone_sub_tree
|
113
|
+
clone_sub_tree(item:wrk_item,temp_name:temp_name,existing_name:existing_scope)
|
114
|
+
else
|
115
|
+
clone_item_only(item:wrk_item,new_parent:wrk_parent,hierarchy_scope:temp_name)
|
116
|
+
end
|
117
|
+
add_all_ancestors(wrk_item,wrk_parent,temp_name)
|
118
|
+
# debug_tree(temp_name)
|
119
|
+
else
|
120
|
+
# debug_tree
|
121
|
+
# debug_tree(temp_name)
|
122
|
+
# # add_all_ancestors(wrk_item,wrk_parent,temp_name)
|
123
|
+
# puts wrk_item.attributes
|
124
|
+
# puts wrk_parent.attributes
|
125
|
+
create_tree(wrk_item:wrk_item,wrk_parent:wrk_parent,temp_name:temp_name)
|
126
|
+
# debug_tree(temp_name)
|
127
|
+
# delete_item_ancestors(wrk_item)
|
128
|
+
#where({descendant_id: wrk_item.descendant_id,hierarchy_scope: hierarchy_scope }).delete_all
|
129
|
+
# delete_ancestors(wrk_item,wrk_item.hierarchy_scope)
|
130
|
+
delete_ancestors_of_item_children(wrk_item,hierarchy_scope)
|
131
|
+
end
|
106
132
|
reset_descendant_position(wrk_item,before_position,temp_name)
|
107
133
|
rename_tree(temp_name,hierarchy_scope)
|
134
|
+
# debug_tree('')
|
135
|
+
# puts "***************\n\n"
|
108
136
|
end
|
109
137
|
end
|
110
138
|
|
139
|
+
def self.debug_tree(hierarchy_scope='')
|
140
|
+
puts '======================'
|
141
|
+
self.where(hierarchy_scope:hierarchy_scope).order([:ancestor_id,:generation]).each{|r| puts r.attributes}
|
142
|
+
puts '**********************'
|
143
|
+
end
|
144
|
+
|
111
145
|
private
|
112
146
|
# the new position is after the maximum of the after_node, the parent, the current maximum of all
|
113
147
|
def self.after_this(wrk_parent,after_node,hierarchy_scope)
|
@@ -131,51 +165,110 @@ module ActsAsManyTrees
|
|
131
165
|
position
|
132
166
|
end
|
133
167
|
|
134
|
-
def self.
|
135
|
-
|
136
|
-
|
137
|
-
|
168
|
+
def self.clone_item_only(item:,new_parent:,hierarchy_scope:)
|
169
|
+
sql=<<-SQL
|
170
|
+
insert into #{table_name}(ancestor_id,descendant_id,generation,hierarchy_scope,position)
|
171
|
+
select b.ancestor_id,a.descendant_id,b.generation+1,'#{hierarchy_scope}',a.position
|
172
|
+
from #{table_name} a,#{table_name} b
|
173
|
+
where b.descendant_id = #{new_parent.descendant_id}
|
174
|
+
and a.descendant_id = #{item.descendant_id}
|
175
|
+
and a.hierarchy_scope = '#{item.hierarchy_scope}'
|
176
|
+
and a.hierarchy_scope = b.hierarchy_scope
|
177
|
+
and a.generation = 0
|
178
|
+
SQL
|
179
|
+
connection.execute(sql)
|
180
|
+
end
|
181
|
+
|
182
|
+
def self.clone_sub_tree(item:,temp_name:,existing_name:'')
|
183
|
+
sql=<<-SQL
|
184
|
+
insert into #{table_name}(ancestor_id,descendant_id,generation,hierarchy_scope,position)
|
185
|
+
WITH RECURSIVE sub_trees(ancestor_id,descendant_id,generation,hierarchy_scope,position) AS
|
186
|
+
(select ancestor_id,descendant_id,generation,'#{temp_name}',position from #{table_name}
|
187
|
+
where descendant_id = #{item.descendant_id}
|
188
|
+
and hierarchy_scope = '#{existing_name}'
|
189
|
+
UNION
|
190
|
+
select s.ancestor_id,s.descendant_id,
|
191
|
+
s.generation,'#{temp_name}',s.position
|
192
|
+
from #{table_name} s, sub_trees st
|
193
|
+
where s.ancestor_id = st.descendant_id
|
194
|
+
and s.hierarchy_scope = '#{existing_name}'
|
195
|
+
)
|
196
|
+
select * from sub_trees;
|
197
|
+
SQL
|
198
|
+
connection.execute(sql)
|
199
|
+
end
|
200
|
+
|
201
|
+
def self.add_all_ancestors(item,parent,temp_name)
|
202
|
+
sql=<<-SQL
|
138
203
|
insert into #{table_name}(ancestor_id,descendant_id,generation,hierarchy_scope,position)
|
139
204
|
select a.ancestor_id,b.descendant_id,a.generation+b.generation+1,'#{temp_name}',b.position
|
140
205
|
from #{table_name} a, #{table_name} b
|
141
|
-
where a.descendant_id=#{
|
142
|
-
and b.ancestor_id=#{
|
143
|
-
and
|
144
|
-
and a.hierarchy_scope = '#{
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
and
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
206
|
+
where a.descendant_id=#{parent.descendant_id}
|
207
|
+
and b.ancestor_id=#{item.descendant_id}
|
208
|
+
and b.hierarchy_scope = '#{temp_name}'
|
209
|
+
and a.hierarchy_scope = '#{parent.hierarchy_scope}'
|
210
|
+
SQL
|
211
|
+
connection.execute(sql)
|
212
|
+
end
|
213
|
+
|
214
|
+
def self.create_tree(wrk_item:,wrk_parent:,temp_name:)
|
215
|
+
if wrk_parent
|
216
|
+
# if existing_name != wrk_item.hierarchy_scope
|
217
|
+
# puts 'new hierarchy'
|
218
|
+
# sql=<<-SQL
|
219
|
+
# insert into #{table_name}(ancestor_id,descendant_id,generation,hierarchy_scope,position)
|
220
|
+
# select a.ancestor_id,b.descendant_id,a.generation+b.generation+1,'#{temp_name}',b.position
|
221
|
+
# from #{table_name} a, #{table_name} b
|
222
|
+
# where a.descendant_id=#{wrk_parent.descendant_id}
|
223
|
+
# and b.ancestor_id=#{wrk_item.ancestor_id}
|
224
|
+
# and a.hierarchy_scope = b.hierarchy_scope
|
225
|
+
# and a.hierarchy_scope = '#{wrk_item.hierarchy_scope}'
|
226
|
+
# union
|
227
|
+
# select c.ancestor_id,c.descendant_id,c.generation,'#{temp_name}',c.position
|
228
|
+
# from #{table_name} c
|
229
|
+
# where c.ancestor_id = #{wrk_item.descendant_id}
|
230
|
+
# and c.hierarchy_scope = '#{wrk_item.hierarchy_scope}'
|
231
|
+
# union
|
232
|
+
# select c.ancestor_id,c.descendant_id,c.generation,'#{temp_name}',c.position
|
233
|
+
# from #{table_name} c
|
234
|
+
# where c.ancestor_id = #{wrk_item.descendant_id}
|
235
|
+
# and c.ancestor_id <> c.descendant_id
|
236
|
+
# and c.hierarchy_scope = '#{existing_name}'
|
237
|
+
# union
|
238
|
+
# select #{wrk_parent.descendant_id},c.descendant_id,#{wrk_parent.generation}+c.generation+1,'#{temp_name}',c.position
|
239
|
+
# from #{table_name} c
|
240
|
+
# where c.ancestor_id = #{wrk_item.descendant_id}
|
241
|
+
# and c.ancestor_id <> c.descendant_id
|
242
|
+
# and c.hierarchy_scope = '#{existing_name}'
|
243
|
+
# /* add existing descendants of descendants in the new tree */
|
244
|
+
# union
|
245
|
+
# select c.ancestor_id,c.descendant_id,c.generation,'#{temp_name}',c.position
|
246
|
+
# from #{table_name} c, #{table_name} d
|
247
|
+
# where c.ancestor_id = d.descendant_id
|
248
|
+
# and d.ancestor_id =#{wrk_item.descendant_id}
|
249
|
+
# and d.hierarchy_scope = c.hierarchy_scope
|
250
|
+
# and c.ancestor_id != c.descendant_id
|
251
|
+
# and c.hierarchy_scope = '#{existing_name}'
|
252
|
+
# SQL
|
253
|
+
# else
|
254
|
+
sql=<<-SQL
|
165
255
|
insert into #{table_name}(ancestor_id,descendant_id,generation,hierarchy_scope,position)
|
256
|
+
/* add self and descendants to the new parent */
|
166
257
|
select a.ancestor_id,b.descendant_id,a.generation+b.generation+1,'#{temp_name}',b.position
|
167
258
|
from #{table_name} a, #{table_name} b
|
168
259
|
where a.descendant_id=#{wrk_parent.descendant_id}
|
169
260
|
and b.ancestor_id=#{wrk_item.ancestor_id}
|
170
261
|
and a.hierarchy_scope = b.hierarchy_scope
|
171
262
|
and a.hierarchy_scope = '#{wrk_item.hierarchy_scope}'
|
263
|
+
|
264
|
+
/* add existing descendants in the new tree */
|
172
265
|
union
|
173
266
|
select c.ancestor_id,c.descendant_id,c.generation,'#{temp_name}',c.position
|
174
267
|
from #{table_name} c
|
175
268
|
where c.ancestor_id = #{wrk_item.descendant_id}
|
176
269
|
and c.hierarchy_scope = '#{wrk_item.hierarchy_scope}'
|
177
|
-
|
178
|
-
|
270
|
+
|
271
|
+
SQL
|
179
272
|
else
|
180
273
|
sql=<<-SQL
|
181
274
|
insert into #{table_name}(ancestor_id,descendant_id,generation,hierarchy_scope,position)
|
@@ -203,25 +296,33 @@ module ActsAsManyTrees
|
|
203
296
|
|
204
297
|
def self.rename_tree(old_name,new_name)
|
205
298
|
sql=<<-SQL
|
206
|
-
update #{table_name}
|
299
|
+
update #{table_name} h1
|
207
300
|
set hierarchy_scope='#{new_name}'
|
208
301
|
where hierarchy_scope='#{old_name}'
|
302
|
+
and not exists(select h2.ancestor_id from #{table_name} h2
|
303
|
+
where h1.ancestor_id = h2.ancestor_id
|
304
|
+
and h1.descendant_id = h2.descendant_id
|
305
|
+
and h2.hierarchy_scope = '#{new_name}'
|
306
|
+
)
|
209
307
|
SQL
|
210
308
|
connection.execute(sql)
|
211
309
|
end
|
212
310
|
|
213
|
-
def self.delete_ancestors(item,hierarchy_scope)
|
214
|
-
|
311
|
+
def self.delete_ancestors(item,hierarchy_scope='')
|
312
|
+
puts "#{item.id}"
|
313
|
+
self.delete(descendant_id: item.id,hierarchy_scope: hierarchy_scope )
|
215
314
|
end
|
216
315
|
|
217
316
|
def self.delete_ancestors_of_item_children(item,hierarchy_scope)
|
218
317
|
sql = <<-SQL
|
219
|
-
delete from #{table_name} as p using #{table_name} as p1
|
318
|
+
delete from #{table_name} as p using #{table_name} as p1, #{table_name} as p2
|
220
319
|
where p.descendant_id = p1.descendant_id
|
221
|
-
and
|
320
|
+
and p.ancestor_id = p2.ancestor_id
|
321
|
+
and p2.descendant_id = #{item.descendant_id}
|
322
|
+
and p1.ancestor_id = p2.descendant_id
|
323
|
+
and p2.hierarchy_scope = p1.hierarchy_scope
|
222
324
|
and p.hierarchy_scope = p1.hierarchy_scope
|
223
325
|
and p1.hierarchy_scope = '#{hierarchy_scope}'
|
224
|
-
and p.generation > 0
|
225
326
|
SQL
|
226
327
|
connection.execute(sql)
|
227
328
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acts_as_many_trees
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Small
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-02-
|
11
|
+
date: 2016-02-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|