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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 470e6f4791e0acb15b9f6acffb5e576c2143f7f2
4
- data.tar.gz: 291fc163aeffb728c54f176dffe70151ec16e7bf
3
+ metadata.gz: 633c463bad4d37f9c467cba4852ebcbdc10cb87b
4
+ data.tar.gz: e18295cde70abd5712d5bf316584ced556d321a9
5
5
  SHA512:
6
- metadata.gz: 9b84921e9a4dc3de94d6cbe6e09c1ae5568df1a2dcdcbec8d488148bbfc0eafcddae0827d7ea70a3082c990526835dc1c0090dd56814e73c6716343b66456122
7
- data.tar.gz: 839aa50646e2d2a56f13b1f5bbb1078f6bc87fe42ae5c0196bdcd9f1638c1baeccce494e6a5c4f3d82a41006435d729639122d59cd4f7825d45c4d161b3fdfc8
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
- on = Arel::Nodes::On.new(Arel::Nodes::Equality.new(arel_table[:id],hierarchy_class.arel_table[:descendant_id])
65
- .and(hierarchy_class.arel_table[:hierarchy_scope].eq(tree_name))
66
- .and(hierarchy_class.arel_table[:generation].not_eq(0))
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
- outer_join = Arel::Nodes::OuterJoin.new(hierarchy_class.arel_table,on)
69
- joins(outer_join).merge(hierarchy_class.where(ancestor_id: nil))
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,tree_name=self.default_tree_name)
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,new_parent,hierarchy_scope='',after_node=nil,before_node=nil)
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
- create_tree(wrk_item,wrk_parent,temp_name)
104
- delete_item_ancestors(wrk_item)
105
- delete_ancestors_of_item_children(wrk_item,hierarchy_scope)
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.create_tree(wrk_item,wrk_parent,temp_name,existing_name='')
135
- if wrk_parent
136
- if existing_name != wrk_item.hierarchy_scope
137
- sql=<<-SQL
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=#{wrk_parent.descendant_id}
142
- and b.ancestor_id=#{wrk_item.ancestor_id}
143
- and a.hierarchy_scope = b.hierarchy_scope
144
- and a.hierarchy_scope = '#{wrk_item.hierarchy_scope}'
145
- union
146
- select c.ancestor_id,c.descendant_id,c.generation,'#{temp_name}',c.position
147
- from #{table_name} c
148
- where c.ancestor_id = #{wrk_item.descendant_id}
149
- and c.hierarchy_scope = '#{wrk_item.hierarchy_scope}'
150
- union
151
- select c.ancestor_id,c.descendant_id,c.generation,'#{temp_name}',c.position
152
- from #{table_name} c
153
- where c.ancestor_id = #{wrk_item.descendant_id}
154
- and c.ancestor_id <> c.descendant_id
155
- and c.hierarchy_scope = '#{existing_name}'
156
- union
157
- select #{wrk_parent.descendant_id},c.descendant_id,#{wrk_parent.generation}+c.generation+1,'#{temp_name}',c.position
158
- from #{table_name} c
159
- where c.ancestor_id = #{wrk_item.descendant_id}
160
- and c.ancestor_id <> c.descendant_id
161
- and c.hierarchy_scope = '#{existing_name}'
162
- SQL
163
- else
164
- sql=<<-SQL
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
- SQL
178
- end
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
- delete.where(descendant_id: item.id,hierarchy_scope: hierarchy_scope ).where.not(generation: 0)
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 p1.ancestor_id = #{item.descendant_id}
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
@@ -1,3 +1,3 @@
1
1
  module ActsAsManyTrees
2
- VERSION = "0.2.2"
2
+ VERSION = "0.3.0"
3
3
  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.2.2
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-07 00:00:00.000000000 Z
11
+ date: 2016-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails