closure_tree 3.4.3 → 3.5.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.
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