Module: ClosureTree::Finders::ClassMethods
- Defined in:
- lib/closure_tree/finders.rb
Instance Method Summary collapse
- #ct_scoped_attributes(scope, attributes, target_table = table_name) ⇒ Object
- #find_all_by_generation(generation_level) ⇒ Object
-
#find_by_path(path, attributes = {}, parent_id = nil) ⇒ Object
Find the node whose
ancestry_path
ispath
. -
#find_or_create_by_path(path, attributes = {}) ⇒ Object
Find or create nodes such that the
ancestry_path
ispath
. - #leaves ⇒ Object
-
#root ⇒ Object
Returns an arbitrary node that has no parents.
- #roots ⇒ Object
- #with_ancestor(*ancestors) ⇒ Object
- #without(instance) ⇒ Object
Instance Method Details
#ct_scoped_attributes(scope, attributes, target_table = table_name) ⇒ Object
109 110 111 112 113 |
# File 'lib/closure_tree/finders.rb', line 109 def ct_scoped_attributes(scope, attributes, target_table = table_name) attributes.inject(scope) do |scope, pair| scope.where("#{target_table}.#{pair.first}" => pair.last) end end |
#find_all_by_generation(generation_level) ⇒ Object
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/closure_tree/finders.rb', line 89 def find_all_by_generation(generation_level) s = joins(<<-SQL) INNER JOIN ( SELECT #{primary_key} as root_id FROM #{_ct.quoted_table_name} WHERE #{_ct.quoted_parent_column_name} IS NULL ) AS roots ON (1 = 1) INNER JOIN ( SELECT ancestor_id, descendant_id FROM #{_ct.quoted_hierarchy_table_name} GROUP BY 1, 2 HAVING MAX(generations) = #{generation_level.to_i} ) AS descendants ON ( #{_ct.quoted_table_name}.#{primary_key} = descendants.descendant_id AND roots.root_id = descendants.ancestor_id ) SQL _ct.scope_with_order(s) end |
#find_by_path(path, attributes = {}, parent_id = nil) ⇒ Object
Find the node whose ancestry_path
is path
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/closure_tree/finders.rb', line 116 def find_by_path(path, attributes = {}, parent_id = nil) path = path.is_a?(Enumerable) ? path.dup : [path] scope = where(_ct.name_sym => path.pop).readonly(false) scope = ct_scoped_attributes(scope, attributes) last_joined_table = _ct.table_name path.reverse.each_with_index do |ea, idx| next_joined_table = "p#{idx}" scope = scope.joins(<<-SQL) INNER JOIN #{_ct.quoted_table_name} AS #{next_joined_table} ON #{next_joined_table}.#{_ct.quoted_id_column_name} = #{connection.quote_table_name(last_joined_table)}.#{_ct.quoted_parent_column_name} SQL scope = scope.where("#{next_joined_table}.#{_ct.name_column}" => ea) scope = ct_scoped_attributes(scope, attributes, next_joined_table) last_joined_table = next_joined_table end scope = scope.where("#{last_joined_table}.#{_ct.parent_column_name}" => parent_id) scope.first end |
#find_or_create_by_path(path, attributes = {}) ⇒ Object
Find or create nodes such that the ancestry_path
is path
137 138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/closure_tree/finders.rb', line 137 def find_or_create_by_path(path, attributes = {}) find_by_path(path, attributes) || begin subpath = path.dup root_name = subpath.shift _ct.with_advisory_lock do # shenanigans because find_or_create can't infer that we want the same class as this: # Note that roots will already be constrained to this subclass (in the case of polymorphism): attrs = attributes.merge(_ct.name_sym => root_name) root = roots.where(attrs).first || roots.create!(attrs) root.find_or_create_by_path(subpath, attributes) end end end |
#leaves ⇒ Object
68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/closure_tree/finders.rb', line 68 def leaves s = joins(<<-SQL) INNER JOIN ( SELECT ancestor_id FROM #{_ct.quoted_hierarchy_table_name} GROUP BY 1 HAVING MAX(#{_ct.quoted_hierarchy_table_name}.generations) = 0 ) AS leaves ON (#{_ct.quoted_table_name}.#{primary_key} = leaves.ancestor_id) SQL _ct.scope_with_order(s.readonly(false)) end |
#root ⇒ Object
Returns an arbitrary node that has no parents.
64 65 66 |
# File 'lib/closure_tree/finders.rb', line 64 def root roots.first end |
#roots ⇒ Object
59 60 61 |
# File 'lib/closure_tree/finders.rb', line 59 def roots _ct.scope_with_order(where(_ct.parent_column_name => nil)) end |
#with_ancestor(*ancestors) ⇒ Object
80 81 82 83 84 85 86 87 |
# File 'lib/closure_tree/finders.rb', line 80 def with_ancestor(*ancestors) ancestor_ids = ancestors.map { |ea| ea.is_a?(ActiveRecord::Base) ? ea._ct_id : ea } scope = ancestor_ids.blank? ? scoped : joins(:ancestor_hierarchies). where("#{_ct.hierarchy_table_name}.ancestor_id" => ancestor_ids). where("#{_ct.hierarchy_table_name}.generations > 0"). readonly(false) _ct.scope_with_order(scope) end |
#without(instance) ⇒ Object
51 52 53 54 55 56 57 |
# File 'lib/closure_tree/finders.rb', line 51 def without(instance) if instance.new_record? all else where(["#{_ct.quoted_table_name}.#{_ct.quoted_id_column_name} != ?", instance.id]) end end |