Class: ThroughHierarchy::Hierarchicals::Hierarchical
- Inherits:
-
Object
- Object
- ThroughHierarchy::Hierarchicals::Hierarchical
- Defined in:
- lib/through_hierarchy/hierarchicals/hierarchical.rb
Direct Known Subclasses
Instance Attribute Summary collapse
-
#source ⇒ Object
readonly
Returns the value of attribute source.
Instance Method Summary collapse
- #and_conditions(conditions) ⇒ Object
- #filter(model) ⇒ Object
- #filters ⇒ Object
- #foreign_key_column ⇒ Object
- #foreign_key_name ⇒ Object
- #foreign_type_column ⇒ Object
- #foreign_type_name ⇒ Object
-
#hierarchy_joins ⇒ Object
TODO: some of these may be :through others, so this may generate redundant joins.
- #hierarchy_models ⇒ Object
-
#hierarchy_rank ⇒ Object
Sort order for hierarchy shadowing queries.
-
#initialize(source, target, hierarchy, as:, parent: nil) ⇒ Hierarchical
constructor
source should be an Arel::Table or Arel::TableAlias TODO: parent only on derived tables.
-
#join_best_rank(group_by: nil) ⇒ Object
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.
- #model_key(model) ⇒ Object
- #model_type(model) ⇒ Object
- #or_conditions(conditions) ⇒ Object
- #set_target(target) ⇒ Object
-
#spawn(source) ⇒ Object
Intialize a copy of self with a new / derived source table.
-
#with_instance(instance) ⇒ Object
Initialize a new copy of self bound to a specific instance.
Constructor Details
#initialize(source, target, hierarchy, as:, parent: nil) ⇒ Hierarchical
source should be an Arel::Table or Arel::TableAlias TODO: parent only on derived tables. Make that a separate class or module.
8 9 10 11 12 13 14 |
# 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 |
Instance Attribute Details
#source ⇒ Object (readonly)
Returns the value of attribute source.
4 5 6 |
# File 'lib/through_hierarchy/hierarchicals/hierarchical.rb', line 4 def source @source end |
Instance Method Details
#and_conditions(conditions) ⇒ Object
41 42 43 |
# File 'lib/through_hierarchy/hierarchicals/hierarchical.rb', line 41 def and_conditions(conditions) conditions.reduce{|q, cond| q.and(cond)} end |
#filter(model) ⇒ Object
53 54 55 56 |
# 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 ⇒ Object
49 50 51 |
# File 'lib/through_hierarchy/hierarchicals/hierarchical.rb', line 49 def filters or_conditions(hierarchy_models.map{|model| filter(model)}) end |
#foreign_key_column ⇒ Object
77 78 79 |
# File 'lib/through_hierarchy/hierarchicals/hierarchical.rb', line 77 def foreign_key_column @source[foreign_key_name] end |
#foreign_key_name ⇒ Object
69 70 71 |
# File 'lib/through_hierarchy/hierarchicals/hierarchical.rb', line 69 def foreign_key_name @polymorphic_name.foreign_key end |
#foreign_type_column ⇒ Object
81 82 83 |
# File 'lib/through_hierarchy/hierarchicals/hierarchical.rb', line 81 def foreign_type_column @source[foreign_type_name] end |
#foreign_type_name ⇒ Object
73 74 75 |
# File 'lib/through_hierarchy/hierarchicals/hierarchical.rb', line 73 def foreign_type_name @polymorphic_name + "_type" end |
#hierarchy_joins ⇒ Object
TODO: some of these may be :through others, so this may generate redundant joins
37 38 39 |
# File 'lib/through_hierarchy/hierarchicals/hierarchical.rb', line 37 def hierarchy_joins @hierarchy end |
#hierarchy_models ⇒ Object
32 33 34 |
# 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 ⇒ Object
Sort order for hierarchy shadowing queries
59 60 61 62 63 64 65 66 67 |
# 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) ⇒ Object
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
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# 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) ⇒ Object
89 90 91 |
# File 'lib/through_hierarchy/hierarchicals/hierarchical.rb', line 89 def model_key(model) model.arel_table[model.primary_key] end |
#model_type(model) ⇒ Object
85 86 87 |
# File 'lib/through_hierarchy/hierarchicals/hierarchical.rb', line 85 def model_type(model) model.base_class.to_s end |
#or_conditions(conditions) ⇒ Object
45 46 47 |
# File 'lib/through_hierarchy/hierarchicals/hierarchical.rb', line 45 def or_conditions(conditions) conditions.reduce{|q, cond| q.or(cond)} end |
#set_target(target) ⇒ Object
16 17 18 19 |
# File 'lib/through_hierarchy/hierarchicals/hierarchical.rb', line 16 def set_target(target) @target = target @model = @target end |
#spawn(source) ⇒ Object
Intialize a copy of self with a new / derived source table
28 29 30 |
# 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) ⇒ Object
Initialize a new copy of self bound to a specific instance
22 23 24 25 |
# 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 |