class ThroughHierarchy::Hierarchicals::Hierarchical
Attributes
source[R]
Public Class Methods
new(source, target, hierarchy, as:, parent: nil)
click to toggle source
source should be an Arel::Table or Arel::TableAlias TODO: parent only on derived tables. Make that a separate class or module.
# File lib/through_hierarchy/hierarchicals/hierarchical.rb, line 8 def initialize(source, target, hierarchy, as:, parent: nil) @source = source set_target(target) @hierarchy = hierarchy @polymorphic_name = as.to_s @parent = parent end
Public Instance Methods
and_conditions(conditions)
click to toggle source
# File lib/through_hierarchy/hierarchicals/hierarchical.rb, line 41 def and_conditions(conditions) conditions.reduce{|q, cond| q.and(cond)} end
filter(model)
click to toggle source
# File lib/through_hierarchy/hierarchicals/hierarchical.rb, line 53 def filter(model) foreign_type_column.eq(model_type(model)). and(foreign_key_column.eq(model_key(model))) end
filters()
click to toggle source
# File lib/through_hierarchy/hierarchicals/hierarchical.rb, line 49 def filters or_conditions(hierarchy_models.map{|model| filter(model)}) end
foreign_key_column()
click to toggle source
# File lib/through_hierarchy/hierarchicals/hierarchical.rb, line 77 def foreign_key_column @source[foreign_key_name] end
foreign_key_name()
click to toggle source
# File lib/through_hierarchy/hierarchicals/hierarchical.rb, line 69 def foreign_key_name @polymorphic_name.foreign_key end
foreign_type_column()
click to toggle source
# File lib/through_hierarchy/hierarchicals/hierarchical.rb, line 81 def foreign_type_column @source[foreign_type_name] end
foreign_type_name()
click to toggle source
# File lib/through_hierarchy/hierarchicals/hierarchical.rb, line 73 def foreign_type_name @polymorphic_name + "_type" end
hierarchy_joins()
click to toggle source
TODO: some of these may be :through others, so this may generate redundant joins
# File lib/through_hierarchy/hierarchicals/hierarchical.rb, line 37 def hierarchy_joins @hierarchy end
hierarchy_models()
click to toggle source
# File lib/through_hierarchy/hierarchicals/hierarchical.rb, line 32 def hierarchy_models [@model] + @hierarchy.map{|m| @model.reflect_on_association(m).klass} end
hierarchy_rank()
click to toggle source
Sort order for hierarchy shadowing queries
# File lib/through_hierarchy/hierarchicals/hierarchical.rb, line 59 def hierarchy_rank Arel.sql( "CASE `#{@source.name}`.`#{foreign_type_name}` " + hierarchy_models.map.with_index do |model, ii| "WHEN #{ThroughHierarchy::RailsUtils.sanitize_sql(model.base_class.to_s)} THEN #{ii} " end.join + "END" ) end
join_best_rank(group_by: nil)
click to toggle source
Join @model to @source only on best hierarchy matches
FASTER METHOD: join source to source alias on source.rank < alias.rank where alias does not exist
This performs OK. TODO: return arel once we know how to use the binds properly
# File lib/through_hierarchy/hierarchicals/hierarchical.rb, line 97 def join_best_rank(group_by: nil) better_rank = spawn(@source.alias("better_hierarchy")) join_condition_array = [ better_rank.filters, better_rank.hierarchy_rank.lt(hierarchy_rank) ] join_condition_array << better_rank.source[group_by].eq(@source[group_by]) if group_by.present? arel = @model.arel_table. join(@source).on(filters). join(better_rank.source, Arel::Nodes::OuterJoin). on(and_conditions(join_condition_array)). where(better_rank.source[:id].eq(nil)) result = @model.joins(@hierarchy).joins(arel.join_sources).order(arel.orders) arel.constraints.each{|cc| result = result.where(cc)} return result end
model_key(model)
click to toggle source
# File lib/through_hierarchy/hierarchicals/hierarchical.rb, line 89 def model_key(model) model.arel_table[model.primary_key] end
model_type(model)
click to toggle source
# File lib/through_hierarchy/hierarchicals/hierarchical.rb, line 85 def model_type(model) model.base_class.to_s end
or_conditions(conditions)
click to toggle source
# File lib/through_hierarchy/hierarchicals/hierarchical.rb, line 45 def or_conditions(conditions) conditions.reduce{|q, cond| q.or(cond)} end
set_target(target)
click to toggle source
# File lib/through_hierarchy/hierarchicals/hierarchical.rb, line 16 def set_target(target) @target = target @model = @target end
spawn(source)
click to toggle source
Intialize a copy of self with a new / derived source table
# File lib/through_hierarchy/hierarchicals/hierarchical.rb, line 28 def spawn(source) return self.class.new(source, @target, @hierarchy, as: @polymorphic_name, parent: self) end
with_instance(instance)
click to toggle source
Initialize a new copy of self bound to a specific instance
# File lib/through_hierarchy/hierarchicals/hierarchical.rb, line 22 def with_instance(instance) instance.is_a?(@model) or raise ThroughHierarchyInstanceError, "#{instance} is not an instance of #{@model}" Instance.new(@source, instance, @hierarchy, as: @polymorphic_name) end