acts_as_many_trees 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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