closure_tree 3.4.3 → 3.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -203,6 +203,9 @@ When you include ```acts_as_tree``` in your model, you can provide a hash to ove
203
203
  * ```Tag.roots``` returns all root nodes
204
204
  * ```Tag.leaves``` returns all leaf nodes
205
205
  * ```Tag.hash_tree``` returns an [ordered, nested hash](#nested-hashes) that can be depth-limited.
206
+ * ```Tag.find_by_path(path)``` returns the node whose name path is ```path```. See (#find_or_create_by_path).
207
+ * ```Tag.find_or_create_by_path(path)``` 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).
208
+ * ```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```.
206
209
 
207
210
  ### Instance methods
208
211
 
@@ -224,6 +227,12 @@ When you include ```acts_as_tree``` in your model, you can provide a hash to ove
224
227
  * ```tag.descendant_ids``` returns an array of the IDs of the descendants.
225
228
  * ```tag.self_and_descendants``` returns a scope of all children, childrens' children, etc., including self, ordered by depth.
226
229
  * ```tag.hash_tree``` returns an [ordered, nested hash](#nested-hashes) that can be depth-limited.
230
+ * ```tag.find_by_path(path)``` returns the node whose name path *from ```tag```* is ```path```. See (#find_or_create_by_path).
231
+ * ```tag.find_or_create_by_path(path)``` returns the node whose name path *from ```tag```* is ```path```, and will create the node if it doesn't exist already.See (#find_or_create_by_path).
232
+ * ```tag.find_all_by_generation(generation_level)``` returns the descendant nodes who are ```generation_level``` away from ```tag```.
233
+ * ```tag.find_all_by_generation(0).to_a``` == ```[tag]```
234
+ * ```tag.find_all_by_generation(1)``` == ```tag.children```
235
+ * ```tag.find_all_by_generation(2)``` will return the tag's grandchildren, and so on.
227
236
  * ```tag.destroy``` will destroy a node and do <em>something</em> to its children, which is determined by the ```:dependent``` option passed to ```acts_as_tree```.
228
237
 
229
238
  ## <a id="sti"></a>Polymorphic hierarchies with STI
@@ -320,13 +329,12 @@ Closure tree is [tested under every combination](http://travis-ci.org/#!/mceache
320
329
  * The latest Rails 3.0, 3.1, and 3.2 branches, and
321
330
  * MySQL, PostgreSQL, and SQLite.
322
331
 
323
-
324
332
  ## Change log
325
333
 
326
- ### 3.4.3
334
+ ### 3.5.0
327
335
 
328
- * Fixed [issue 19](https://github.com/mceachen/closure_tree/issues/19), which caused
329
- ```self_and_siblings``` to fail if ```parent_id``` was not the ```parent_column_name```
336
+ * Added ```find_all_by_generation```
337
+ for [feature request 17](https://github.com/mceachen/closure_tree/issues/17)).
330
338
 
331
339
  ### 3.4.2
332
340
 
@@ -87,6 +87,25 @@ module ClosureTree
87
87
  roots.inject(ActiveSupport::OrderedHash.new) { |h, ea| h.merge(ea.hash_tree(options)) }
88
88
  end
89
89
 
90
+ def find_all_by_generation(generation_level)
91
+ s = joins(<<-SQL)
92
+ INNER JOIN (
93
+ SELECT #{primary_key} as root_id
94
+ FROM #{quoted_table_name}
95
+ WHERE #{quoted_parent_column_name} IS NULL
96
+ ) AS roots
97
+ INNER JOIN (
98
+ SELECT ancestor_id, descendant_id
99
+ FROM #{quoted_hierarchy_table_name}
100
+ GROUP BY 1, 2
101
+ HAVING MAX(#{quoted_hierarchy_table_name}.generations) = #{generation_level.to_i}
102
+ ) AS descendants
103
+ ON #{quoted_table_name}.#{primary_key} = descendants.descendant_id
104
+ AND roots.root_id = ancestor_id
105
+ SQL
106
+ order_option ? s.order(order_option) : s
107
+ end
108
+
90
109
  def self.leaves
91
110
  s = joins(<<-SQL)
92
111
  INNER JOIN (
@@ -94,7 +113,7 @@ module ClosureTree
94
113
  FROM #{quoted_hierarchy_table_name}
95
114
  GROUP BY 1
96
115
  HAVING MAX(#{quoted_hierarchy_table_name}.generations) = 0
97
- ) AS leaves ON (#{quoted_table_name}.#{primary_key} = leaves.ancestor_id)
116
+ ) AS leaves ON #{quoted_table_name}.#{primary_key} = leaves.ancestor_id
98
117
  SQL
99
118
  order_option ? s.order(order_option) : s
100
119
  end
@@ -205,6 +224,19 @@ module ClosureTree
205
224
  node
206
225
  end
207
226
 
227
+ def find_all_by_generation(generation_level)
228
+ s = self.class.joins(<<-SQL)
229
+ INNER JOIN (
230
+ SELECT descendant_id
231
+ FROM #{quoted_hierarchy_table_name}
232
+ WHERE ancestor_id = #{self.id}
233
+ GROUP BY 1
234
+ HAVING MAX(#{quoted_hierarchy_table_name}.generations) = #{generation_level.to_i}
235
+ ) AS descendants ON #{quoted_table_name}.#{self.class.primary_key} = descendants.descendant_id
236
+ SQL
237
+ order_option ? s.order(order_option) : s
238
+ end
239
+
208
240
  def hash_tree(options = {})
209
241
  tree = ActiveSupport::OrderedHash.new
210
242
  tree[self] = ActiveSupport::OrderedHash.new
@@ -1,3 +1,3 @@
1
1
  module ClosureTree
2
- VERSION = "3.4.3" unless defined?(::ClosureTree::VERSION)
2
+ VERSION = "3.5.0" unless defined?(::ClosureTree::VERSION)
3
3
  end
data/spec/label_spec.rb CHANGED
@@ -65,6 +65,48 @@ describe Label do
65
65
  end
66
66
  end
67
67
 
68
+ context "find_all_by_generation" do
69
+ before :all do
70
+ nuke_db
71
+ @d1 = Label.find_or_create_by_path %w(a b c1 d1)
72
+ @d2 = Label.find_or_create_by_path %w(a b c2 d2)
73
+ @c1 = @d1.parent
74
+ @c2 = @d2.parent
75
+ @b = @c1.parent
76
+ @a = @b.parent
77
+ end
78
+
79
+ it "finds roots from the class method" do
80
+ Label.find_all_by_generation(1).to_a.should == [@b]
81
+ end
82
+
83
+ it "finds roots from themselves" do
84
+ @a.find_all_by_generation(0).to_a.should == [@a]
85
+ end
86
+
87
+ it "finds itself for non-roots" do
88
+ @b.find_all_by_generation(0).to_a.should == [@b]
89
+ end
90
+
91
+ it "finds children for roots" do
92
+ Label.find_all_by_generation(1).to_a.should == [@b]
93
+ end
94
+
95
+ it "finds children" do
96
+ @a.find_all_by_generation(1).to_a.should == [@b]
97
+ @b.find_all_by_generation(1).to_a.should == [@c1, @c2]
98
+ end
99
+
100
+ it "finds grandchildren for roots" do
101
+ Label.find_all_by_generation(2).to_a.should == [@c1, @c2]
102
+ end
103
+
104
+ it "finds grandchildren" do
105
+ @a.find_all_by_generation(2).to_a.should == [@c1, @c2]
106
+ @b.find_all_by_generation(2).to_a.should == [@d1, @d2]
107
+ end
108
+ end
109
+
68
110
  context "Deterministic siblings sort with custom integer column" do
69
111
  nuke_db
70
112
  fixtures :labels
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: closure_tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.3
4
+ version: 3.5.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -192,7 +192,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
192
192
  version: '0'
193
193
  segments:
194
194
  - 0
195
- hash: -1873822360950581335
195
+ hash: 1009921537345124595
196
196
  required_rubygems_version: !ruby/object:Gem::Requirement
197
197
  none: false
198
198
  requirements:
@@ -201,7 +201,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
201
201
  version: '0'
202
202
  segments:
203
203
  - 0
204
- hash: -1873822360950581335
204
+ hash: 1009921537345124595
205
205
  requirements: []
206
206
  rubyforge_project:
207
207
  rubygems_version: 1.8.23