Class: ThinkingSphinx::Association
- Inherits:
-
Object
- Object
- ThinkingSphinx::Association
- Defined in:
- lib/thinking_sphinx/association.rb
Overview
Association tracks a specific reflection and join to reference data that isn’t in the base model. Very much an internal class for Thinking Sphinx - perhaps because I feel it’s not as strong (or simple) as most of the rest.
Instance Attribute Summary collapse
-
#columns ⇒ Object
Returns the value of attribute columns.
-
#join ⇒ Object
Returns the value of attribute join.
-
#parent ⇒ Object
Returns the value of attribute parent.
-
#reflection ⇒ Object
Returns the value of attribute reflection.
Class Method Summary collapse
-
.children(klass, assoc, parent = nil) ⇒ Object
Get the children associations for a given class, association name and parent association.
Instance Method Summary collapse
- #adapter ⇒ Object
-
#ancestors ⇒ Object
Returns an array of all the associations that lead to this one - starting with the top level all the way to the current association object.
-
#children(assoc) ⇒ Object
Get the children associations for a given association name.
- #column_def_sql(column_name) ⇒ Object
- #column_sql(column) ⇒ Object
- #has_column?(column) ⇒ Boolean
-
#initialize(parent, reflection) ⇒ Association
constructor
Create a new association by passing in the parent association, and the corresponding reflection instance.
-
#is_many? ⇒ Boolean
Returns true if the association - or a parent - is a has_many or has_and_belongs_to_many.
-
#join_to(base_join) ⇒ Object
Link up the join for this model from a base join - and set parent associations’ joins recursively.
- #primary_key_from_reflection ⇒ Object
- #quote_column(column) ⇒ Object
- #quote_table_name(table_name) ⇒ Object
- #table ⇒ Object
-
#to_flat_sql ⇒ Object
Returns the association’s flattened columns as an indexed tempory table to speed up the joins and avoid a huge group by statement.
-
#to_sql ⇒ Object
- Returns the association’s join SQL statements - and it replaces ::ts_join_alias
-
with the aliased table name so the generated reflection join conditions avoid column name collisions.
Constructor Details
#initialize(parent, reflection) ⇒ Association
Create a new association by passing in the parent association, and the corresponding reflection instance. If there is no parent, pass in nil.
top = Association.new nil, top_reflection
child = Association.new top, child_reflection
15 16 17 18 19 |
# File 'lib/thinking_sphinx/association.rb', line 15 def initialize(parent, reflection) @parent, @reflection = parent, reflection @columns = [] @children = {} end |
Instance Attribute Details
#columns ⇒ Object
Returns the value of attribute columns.
7 8 9 |
# File 'lib/thinking_sphinx/association.rb', line 7 def columns @columns end |
#join ⇒ Object
Returns the value of attribute join.
7 8 9 |
# File 'lib/thinking_sphinx/association.rb', line 7 def join @join end |
#parent ⇒ Object
Returns the value of attribute parent.
7 8 9 |
# File 'lib/thinking_sphinx/association.rb', line 7 def parent @parent end |
#reflection ⇒ Object
Returns the value of attribute reflection.
7 8 9 |
# File 'lib/thinking_sphinx/association.rb', line 7 def reflection @reflection end |
Class Method Details
.children(klass, assoc, parent = nil) ⇒ Object
Get the children associations for a given class, association name and parent association. Much like the instance method of the same name, it will return an empty array if no associations have the name, and only have multiple association instances if the underlying relationship is polymorphic.
Association.children(User, :pages, user_association)
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/thinking_sphinx/association.rb', line 41 def self.children(klass, assoc, parent=nil) ref = klass.reflect_on_association(assoc) return [] if ref.nil? return [Association.new(parent, ref)] unless ref.[:polymorphic] # association is polymorphic - create associations for each # non-polymorphic reflection. polymorphic_classes(ref).collect { |klass| Association.new parent, ::ActiveRecord::Reflection::AssociationReflection.new( ref.macro, "#{ref.name}_#{klass.name}".to_sym, (klass, ref), ref.active_record ) } end |
Instance Method Details
#adapter ⇒ Object
153 154 155 |
# File 'lib/thinking_sphinx/association.rb', line 153 def adapter @adapter ||= @reflection.klass.sphinx_database_adapter end |
#ancestors ⇒ Object
Returns an array of all the associations that lead to this one - starting with the top level all the way to the current association object.
173 174 175 |
# File 'lib/thinking_sphinx/association.rb', line 173 def ancestors (parent ? parent.ancestors : []) << self end |
#children(assoc) ⇒ Object
Get the children associations for a given association name. The only time that there’ll actually be more than one association is when the relationship is polymorphic. To keep things simple though, it will always be an Array that gets returned (an empty one if no matches).
# where pages is an association on the class tied to the reflection.
association.children(:pages)
29 30 31 |
# File 'lib/thinking_sphinx/association.rb', line 29 def children(assoc) @children[assoc] ||= Association.children(@reflection.klass, assoc, self) end |
#column_def_sql(column_name) ⇒ Object
72 73 74 75 76 77 78 79 80 |
# File 'lib/thinking_sphinx/association.rb', line 72 def column_def_sql(column_name) if column_name.to_s =~ /_id$/ "#{quote_column(column_name)} int(11) NOT NULL" elsif column_name.to_s =~ /_ids$/ "#{quote_column(column_name)} BLOB default NULL" else "#{quote_column(column_name)} TEXT default NULL" end end |
#column_sql(column) ⇒ Object
157 158 159 160 |
# File 'lib/thinking_sphinx/association.rb', line 157 def column_sql(column) separator = column == :id ? ',' : ' ' "#{adapter.group_concatenate(column, separator)} AS #{quote_column(column)}" end |
#has_column?(column) ⇒ Boolean
177 178 179 |
# File 'lib/thinking_sphinx/association.rb', line 177 def has_column?(column) @reflection.klass.column_names.include?(column.to_s) end |
#is_many? ⇒ Boolean
Returns true if the association - or a parent - is a has_many or has_and_belongs_to_many.
144 145 146 147 148 149 150 151 |
# File 'lib/thinking_sphinx/association.rb', line 144 def is_many? case @reflection.macro when :has_many, :has_and_belongs_to_many true else @parent ? @parent.is_many? : false end end |
#join_to(base_join) ⇒ Object
Link up the join for this model from a base join - and set parent associations’ joins recursively.
62 63 64 65 66 67 68 69 70 |
# File 'lib/thinking_sphinx/association.rb', line 62 def join_to(base_join) parent.join_to(base_join) if parent && parent.join.nil? @join ||= ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation.new( @reflection, base_join, parent ? parent.join : base_join.joins.first ) @join.aliased_table_name << '_join' if is_many? and !(@join.aliased_table_name =~ /_join$/) end |
#primary_key_from_reflection ⇒ Object
181 182 183 184 185 186 187 188 189 190 |
# File 'lib/thinking_sphinx/association.rb', line 181 def primary_key_from_reflection if @reflection.[:through] @reflection.source_reflection.[:foreign_key] || @reflection.source_reflection.primary_key_name elsif @reflection.macro == :has_and_belongs_to_many @reflection.association_foreign_key else nil end end |
#quote_column(column) ⇒ Object
162 163 164 |
# File 'lib/thinking_sphinx/association.rb', line 162 def quote_column(column) @reflection.klass.connection.quote_column_name(column) end |
#quote_table_name(table_name) ⇒ Object
166 167 168 |
# File 'lib/thinking_sphinx/association.rb', line 166 def quote_table_name(table_name) @reflection.klass.connection.quote_table_name(table_name) end |
#table ⇒ Object
192 193 194 195 196 197 198 199 |
# File 'lib/thinking_sphinx/association.rb', line 192 def table if @reflection.[:through] || @reflection.macro == :has_and_belongs_to_many @join.aliased_join_table_name else @join.aliased_table_name end end |
#to_flat_sql ⇒ Object
Returns the association’s flattened columns as an indexed tempory table to speed up the joins and avoid a huge group by statement
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/thinking_sphinx/association.rb', line 85 def to_flat_sql primary_key = quote_column(@reflection.primary_key_name) temp_table_name = quote_table_name(@join.aliased_table_name) create = "CREATE TEMPORARY TABLE %s (%s, PRIMARY KEY (%s))" % [ temp_table_name, (columns.uniq.map(&:__name) << @reflection.primary_key_name).map { |column| column_def_sql(column) }.join(', '), primary_key ] insert = "INSERT INTO %s (%s)" % [ temp_table_name, (columns.uniq.map { |column| quote_column(column.__name) } << primary_key).join(', ') ] insert << " SELECT %s FROM %s" % [ (columns.uniq.map { |column| column_sql(column.__name) } << primary_key).join(', '), @reflection.quoted_table_name ] insert << " INNER JOIN %s ON %s.%s = %s.%s" % [ quote_table_name(@reflection.[:join_table]), quote_table_name(@reflection.[:join_table]), quote_column(@reflection.association_foreign_key), @reflection.quoted_table_name, quote_column(@join.primary_key) ] if @reflection.macro == :has_and_belongs_to_many insert << " GROUP BY %s" % [ primary_key ] [create, insert] end |
#to_sql ⇒ Object
Returns the association’s join SQL statements - and it replaces
- ::ts_join_alias
-
with the aliased table name so the generated reflection
join conditions avoid column name collisions.
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/thinking_sphinx/association.rb', line 124 def to_sql if is_many? temp_table_name = quote_table_name(@join.aliased_table_name) " LEFT OUTER JOIN %s ON %s.%s = %s.%s" % [ temp_table_name, temp_table_name, quote_column(@reflection.primary_key_name), quote_table_name(@join.parent.aliased_table_name), quote_column(@join.parent.primary_key) ] else @join.association_join.gsub(/::ts_join_alias::/, "#{@reflection.klass.connection.quote_table_name(@join.parent.aliased_table_name)}" ) end end |