Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sql conditions to class level #296

Merged
merged 1 commit into from
Dec 30, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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