Skip to content

Commit

Permalink
Merge pull request #296 from kbrock/base_conditions
Browse files Browse the repository at this point in the history
sql conditions to class level
  • Loading branch information
kbrock authored Dec 30, 2016
2 parents 27a29f1 + 95f83fc commit efb603e
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 35 deletions.
1 change: 1 addition & 0 deletions ancestry.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ EOF
'lib/ancestry/exceptions.rb',
'lib/ancestry/class_methods.rb',
'lib/ancestry/instance_methods.rb',
'lib/ancestry/materialized_path.rb',
'MIT-LICENSE',
'README.rdoc'
]
Expand Down
3 changes: 2 additions & 1 deletion lib/ancestry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
require_relative 'ancestry/instance_methods'
require_relative 'ancestry/exceptions'
require_relative 'ancestry/has_ancestry'
require_relative 'ancestry/materialized_path'

module Ancestry
ANCESTRY_PATTERN = /\A[0-9]+(\/[0-9]+)*\Z/
end
end
14 changes: 9 additions & 5 deletions lib/ancestry/has_ancestry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ def has_ancestry options = {}
# Include dynamic class methods
extend Ancestry::ClassMethods

# Include class methods that implement materialized path methods
extend Ancestry::MaterializedPath

# Create ancestry column accessor and set to option or default
cattr_accessor :ancestry_column
self.ancestry_column = options[:ancestry_column] || :ancestry
Expand All @@ -38,11 +41,12 @@ def has_ancestry options = {}

# Named scopes
scope :roots, lambda { where(ancestry_column => nil) }
scope :ancestors_of, lambda { |object| where(to_node(object).ancestor_conditions) }
scope :children_of, lambda { |object| where(to_node(object).child_conditions) }
scope :descendants_of, lambda { |object| where(to_node(object).descendant_conditions) }
scope :subtree_of, lambda { |object| where(to_node(object).subtree_conditions) }
scope :siblings_of, lambda { |object| where(to_node(object).sibling_conditions) }
scope :ancestors_of, lambda { |object| where(ancestor_conditions(object)) }
scope :path_of, lambda { |object| where(path_conditions(object)) }
scope :children_of, lambda { |object| where(child_conditions(object)) }
scope :descendants_of, lambda { |object| where(descendant_conditions(object)) }
scope :subtree_of, lambda { |object| where(subtree_conditions(object)) }
scope :siblings_of, lambda { |object| where(sibling_conditions(object)) }
scope :ordered_by_ancestry, lambda {
if %w(mysql mysql2 sqlite postgresql).include?(connection.adapter_name.downcase) && ActiveRecord::VERSION::MAJOR >= 5
reorder("coalesce(#{connection.quote_table_name(table_name)}.#{connection.quote_column_name(ancestry_column)}, '')")
Expand Down
35 changes: 6 additions & 29 deletions lib/ancestry/instance_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,7 @@ def ancestor_ids
end

def ancestor_conditions
t = get_arel_table
t[get_primary_key_column].in(ancestor_ids)
self.ancestry_base_class.ancestor_conditions(self)
end

def ancestors depth_options = {}
Expand All @@ -129,8 +128,7 @@ def path_ids
end

def path_conditions
t = get_arel_table
t[get_primary_key_column].in(path_ids)
self.ancestry_base_class.path_conditions(self)
end

def path depth_options = {}
Expand Down Expand Up @@ -197,8 +195,7 @@ def root_of?(node)
# Children

def child_conditions
t = get_arel_table
t[get_ancestry_column].eq(child_ancestry)
self.ancestry_base_class.child_conditions(self)
end

def children
Expand Down Expand Up @@ -226,8 +223,7 @@ def child_of?(node)
# Siblings

def sibling_conditions
t = get_arel_table
t[get_ancestry_column].eq(read_attribute(self.ancestry_base_class.ancestry_column))
self.ancestry_base_class.sibling_conditions(self)
end

def siblings
Expand Down Expand Up @@ -255,13 +251,7 @@ def sibling_of?(node)
# Descendants

def descendant_conditions
t = get_arel_table
# rails has case sensitive matching.
if ActiveRecord::VERSION::MAJOR >= 5
t[get_ancestry_column].matches("#{child_ancestry}/%", nil, true).or(t[get_ancestry_column].eq(child_ancestry))
else
t[get_ancestry_column].matches("#{child_ancestry}/%").or(t[get_ancestry_column].eq(child_ancestry))
end
self.ancestry_base_class.descendant_conditions(self)
end

def descendants depth_options = {}
Expand All @@ -279,8 +269,7 @@ def descendant_of?(node)
# Subtree

def subtree_conditions
t = get_arel_table
descendant_conditions.or(t[get_primary_key_column].eq(self.id))
self.ancestry_base_class.subtree_conditions(self)
end

def subtree depth_options = {}
Expand Down Expand Up @@ -332,17 +321,5 @@ def sane_ancestry?
def unscoped_find id
self.ancestry_base_class.unscoped { self.ancestry_base_class.find(id) }
end

def get_arel_table
self.ancestry_base_class.arel_table
end

def get_primary_key_column
self.ancestry_base_class.primary_key.to_sym
end

def get_ancestry_column
self.ancestry_base_class.ancestry_column.to_sym
end
end
end
44 changes: 44 additions & 0 deletions lib/ancestry/materialized_path.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
module Ancestry
module MaterializedPath
def ancestor_conditions(object)
t = arel_table
node = to_node(object)
t[primary_key].in(node.ancestor_ids)
end

def path_conditions(object)
t = arel_table
node = to_node(object)
t[primary_key].in(node.path_ids)
end

def child_conditions(object)
t = arel_table
node = to_node(object)
t[ancestry_column].eq(node.child_ancestry)
end

def descendant_conditions(object)
t = arel_table
node = to_node(object)
# rails has case sensitive matching.
if ActiveRecord::VERSION::MAJOR >= 5
t[ancestry_column].matches("#{node.child_ancestry}/%", nil, true).or(t[ancestry_column].eq(node.child_ancestry))
else
t[ancestry_column].matches("#{node.child_ancestry}/%").or(t[ancestry_column].eq(node.child_ancestry))
end
end

def subtree_conditions(object)
t = arel_table
node = to_node(object)
descendant_conditions(object).or(t[primary_key].eq(node.id))
end

def sibling_conditions(object)
t = arel_table
node = to_node(object)
t[ancestry_column].eq(node[ancestry_column])
end
end
end

0 comments on commit efb603e

Please sign in to comment.