pixeltrix-thinking-sphinx 1.1.5 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/README.textile +147 -0
  2. data/lib/thinking_sphinx/active_record/attribute_updates.rb +48 -0
  3. data/lib/thinking_sphinx/active_record/delta.rb +14 -1
  4. data/lib/thinking_sphinx/active_record/scopes.rb +37 -0
  5. data/lib/thinking_sphinx/active_record.rb +46 -12
  6. data/lib/thinking_sphinx/adapters/abstract_adapter.rb +9 -1
  7. data/lib/thinking_sphinx/adapters/mysql_adapter.rb +3 -2
  8. data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +12 -5
  9. data/lib/thinking_sphinx/association.rb +20 -0
  10. data/lib/thinking_sphinx/attribute.rb +187 -116
  11. data/lib/thinking_sphinx/class_facet.rb +15 -0
  12. data/lib/thinking_sphinx/configuration.rb +46 -14
  13. data/lib/thinking_sphinx/core/string.rb +3 -10
  14. data/lib/thinking_sphinx/deltas/datetime_delta.rb +3 -3
  15. data/lib/thinking_sphinx/deltas/default_delta.rb +9 -6
  16. data/lib/thinking_sphinx/deltas/delayed_delta/delta_job.rb +1 -1
  17. data/lib/thinking_sphinx/deltas/delayed_delta.rb +4 -2
  18. data/lib/thinking_sphinx/deltas.rb +14 -6
  19. data/lib/thinking_sphinx/deploy/capistrano.rb +98 -0
  20. data/lib/thinking_sphinx/excerpter.rb +22 -0
  21. data/lib/thinking_sphinx/facet.rb +68 -18
  22. data/lib/thinking_sphinx/facet_search.rb +134 -0
  23. data/lib/thinking_sphinx/field.rb +7 -97
  24. data/lib/thinking_sphinx/index/builder.rb +255 -201
  25. data/lib/thinking_sphinx/index.rb +28 -343
  26. data/lib/thinking_sphinx/property.rb +160 -0
  27. data/lib/thinking_sphinx/rails_additions.rb +7 -4
  28. data/lib/thinking_sphinx/search.rb +593 -587
  29. data/lib/thinking_sphinx/search_methods.rb +421 -0
  30. data/lib/thinking_sphinx/source/internal_properties.rb +46 -0
  31. data/lib/thinking_sphinx/source/sql.rb +128 -0
  32. data/lib/thinking_sphinx/source.rb +150 -0
  33. data/lib/thinking_sphinx/tasks.rb +45 -11
  34. data/lib/thinking_sphinx.rb +88 -14
  35. data/rails/init.rb +14 -0
  36. data/spec/{unit → lib}/thinking_sphinx/active_record/delta_spec.rb +7 -7
  37. data/spec/{unit → lib}/thinking_sphinx/active_record/has_many_association_spec.rb +0 -0
  38. data/spec/lib/thinking_sphinx/active_record/scopes_spec.rb +92 -0
  39. data/spec/{unit → lib}/thinking_sphinx/active_record_spec.rb +115 -42
  40. data/spec/{unit → lib}/thinking_sphinx/association_spec.rb +4 -5
  41. data/spec/lib/thinking_sphinx/attribute_spec.rb +465 -0
  42. data/spec/{unit → lib}/thinking_sphinx/configuration_spec.rb +118 -7
  43. data/spec/{unit → lib}/thinking_sphinx/core/string_spec.rb +0 -0
  44. data/spec/lib/thinking_sphinx/excerpter_spec.rb +49 -0
  45. data/spec/lib/thinking_sphinx/facet_search_spec.rb +176 -0
  46. data/spec/lib/thinking_sphinx/facet_spec.rb +302 -0
  47. data/spec/{unit → lib}/thinking_sphinx/field_spec.rb +26 -17
  48. data/spec/lib/thinking_sphinx/index/builder_spec.rb +355 -0
  49. data/spec/{unit → lib}/thinking_sphinx/index/faux_column_spec.rb +0 -0
  50. data/spec/{unit → lib}/thinking_sphinx/index_spec.rb +3 -12
  51. data/spec/lib/thinking_sphinx/rails_additions_spec.rb +191 -0
  52. data/spec/lib/thinking_sphinx/search_methods_spec.rb +152 -0
  53. data/spec/lib/thinking_sphinx/search_spec.rb +887 -0
  54. data/spec/lib/thinking_sphinx/source_spec.rb +217 -0
  55. data/spec/{unit → lib}/thinking_sphinx_spec.rb +30 -8
  56. data/tasks/distribution.rb +20 -1
  57. data/tasks/testing.rb +7 -15
  58. data/vendor/after_commit/init.rb +3 -0
  59. data/vendor/after_commit/lib/after_commit/active_record.rb +27 -4
  60. data/vendor/after_commit/lib/after_commit/connection_adapters.rb +1 -1
  61. data/vendor/after_commit/lib/after_commit.rb +4 -1
  62. data/vendor/riddle/lib/riddle/client/message.rb +4 -3
  63. data/vendor/riddle/lib/riddle/client.rb +3 -0
  64. data/vendor/riddle/lib/riddle/configuration/section.rb +8 -2
  65. data/vendor/riddle/lib/riddle/controller.rb +1 -1
  66. data/vendor/riddle/lib/riddle.rb +1 -1
  67. metadata +75 -39
  68. data/README +0 -107
  69. data/lib/thinking_sphinx/active_record/search.rb +0 -57
  70. data/lib/thinking_sphinx/collection.rb +0 -142
  71. data/lib/thinking_sphinx/facet_collection.rb +0 -44
  72. data/spec/unit/thinking_sphinx/active_record/search_spec.rb +0 -107
  73. data/spec/unit/thinking_sphinx/attribute_spec.rb +0 -212
  74. data/spec/unit/thinking_sphinx/collection_spec.rb +0 -14
  75. data/spec/unit/thinking_sphinx/index/builder_spec.rb +0 -5
  76. data/spec/unit/thinking_sphinx/search_spec.rb +0 -59
data/README.textile ADDED
@@ -0,0 +1,147 @@
1
+ h1. Thinking Sphinx
2
+
3
+ h2. Usage
4
+
5
+ First, if you haven't done so already, check out the main "usage":http://ts.freelancing-gods.com/usage.html page. Once you've done that, the next place to look for information is the specific method docs - ThinkingSphinx::Search and ThinkingSphinx::Index::Builder in particular.
6
+
7
+ Keep in mind that while Thinking Sphinx works for ActiveRecord with Merb, it doesn't yet support DataMapper (although that is planned).
8
+
9
+ h2. Contributing
10
+
11
+ Fork on GitHub and after you've committed tested patches, send a pull request.
12
+
13
+ To quickly see if your system is ready to run the thinking sphinx specs, run the contribute.rb script found in the project root directory. Use the following instructions to install any missing requirements.
14
+
15
+ To get the spec suite running, you will need to install the not-a-mock gem if you don't already have it:
16
+
17
+ git clone git://github.com/freelancing-god/not-a-mock.git
18
+ cd not-a-mock
19
+ rake gem
20
+ gem install pkg/not_a_mock-1.1.0.gem
21
+
22
+ Then install the ginger gem. The steps are the same, except that you might need to sudo the gem install:
23
+
24
+ git clone git://github.com/freelancing-god/ginger.git
25
+ cd ginger
26
+ rake gem
27
+ sudo gem install pkg/ginger-1.1.0.gem
28
+
29
+ Alternatively, install the ginger gem directly from the freelancing-god github repository
30
+
31
+ sudo gem sources -a http://gems.github.com
32
+ sudo gem install freelancing-god-ginger
33
+
34
+ Then set up your database:
35
+
36
+ cp spec/fixtures/database.yml.default spec/fixtures/database.yml
37
+ mysqladmin -u root create thinking_sphinx
38
+
39
+ This last step can be done automatically by the contribute.rb script if all dependencies are met.
40
+
41
+ Make sure you don't have another Sphinx daemon (searchd) running. If you do, quit it with "rake ts:stop"
42
+ in the app root.
43
+
44
+ You should now have a passing test suite from which to build your patch on.
45
+
46
+ rake spec
47
+
48
+ If you get the message "Failed to start searchd daemon", run the spec with sudo:
49
+
50
+ sudo rake spec
51
+
52
+ If you quit the spec suite before it's completed, you may be left with data in the test
53
+ database, causing the next run to have failures. Let that run complete and then try again.
54
+
55
+ h2. Contributors
56
+
57
+ Since I first released this library, there's been quite a few people who have submitted patches, to my immense gratitude. Others have suggested syntax changes and general improvements. So my thanks to the following people:
58
+
59
+ * Joost Hietbrink
60
+ * Jonathan Conway
61
+ * Gregory Mirzayantz
62
+ * Tung Nguyen
63
+ * Sean Cribbs
64
+ * Benoit Caccinolo
65
+ * John Barton
66
+ * Oliver Beddows
67
+ * Arthur Zapparoli
68
+ * Dusty Doris
69
+ * Marcus Crafter
70
+ * Patrick Lenz
71
+ * Björn Andreasson
72
+ * James Healy
73
+ * Jae-Jun Hwang
74
+ * Xavier Shay
75
+ * Jason Rust
76
+ * Gopal Patel
77
+ * Chris Heald
78
+ * Peter Vandenberk
79
+ * Josh French
80
+ * Andrew Bennett
81
+ * Jordan Fowler
82
+ * Seth Walker
83
+ * Joe Noon
84
+ * Wolfgang Postler
85
+ * Rick Olson
86
+ * Killian Murphy
87
+ * Morten Primdahl
88
+ * Ryan Bates
89
+ * David Eisinger
90
+ * Shay Arnett
91
+ * Minh Tran
92
+ * Jeremy Durham
93
+ * Piotr Sarnacki
94
+ * Matt Johnson
95
+ * Nicolas Blanco
96
+ * Max Lapshin
97
+ * Josh Natanson
98
+ * Philip Hallstrom
99
+ * Christian Rishøj
100
+ * Mike Flester
101
+ * Jim Remsik
102
+ * Kennon Ballou
103
+ * Henrik Nyh
104
+ * Emil Tin
105
+ * Doug Cole
106
+ * Ed Hickey
107
+ * Evan Weaver
108
+ * Thibaut Barrere
109
+ * Kristopher Chambers
110
+ * Dmitrij Smalko
111
+ * Aleksey Yeschenko
112
+ * Lachie Cox
113
+ * Lourens Naude
114
+ * Tom Davies
115
+ * Dan Pickett
116
+ * Alex Caudill
117
+ * Jim Benton
118
+ * John Aughey
119
+ * Keith Pitty
120
+ * Jeff Talbot
121
+ * Dana Contreras
122
+ * Menno van der Sman
123
+ * Bill Harding
124
+ * Isaac Feliu
125
+ * Andrei Bocan
126
+ * László Bácsi
127
+ * Peter Wagenet
128
+ * Max Lapshin
129
+ * Martin Emde
130
+ * David Wennergren
131
+ * Mark Lane
132
+ * Eric Lindvall
133
+ * Lawrence Pit
134
+ * Mike Bailey
135
+ * Bill Leeper
136
+ * Michael Reinsch
137
+ * Anderson Dias
138
+ * Jerome Riga
139
+ * Tien Dung
140
+ * Johannes Kaefer
141
+ * Paul Campbell
142
+ * Matthew Beale
143
+ * Tom Simnett
144
+ * Erik Ostrom
145
+ * Ole Riesenberg
146
+ * Josh Kalderimis
147
+ * J.D. Hollis
@@ -0,0 +1,48 @@
1
+ module ThinkingSphinx
2
+ module ActiveRecord
3
+ module AttributeUpdates
4
+ def self.included(base)
5
+ base.class_eval do
6
+ after_commit :update_attribute_values
7
+ end
8
+ end
9
+
10
+ private
11
+
12
+ def update_attribute_values
13
+ return unless ThinkingSphinx.updates_enabled? && ThinkingSphinx.sphinx_running?
14
+
15
+ config = ThinkingSphinx::Configuration.instance
16
+ client = Riddle::Client.new config.address, config.port
17
+
18
+ self.sphinx_indexes.each do |index|
19
+ attribute_pairs = attribute_values_for_index(index)
20
+ attribute_names = attribute_pairs.keys
21
+ attribute_values = attribute_names.collect { |key|
22
+ attribute_pairs[key]
23
+ }
24
+
25
+ client.update "#{index.name}_core", attribute_names, {
26
+ sphinx_document_id => attribute_values
27
+ } if in_core_index?
28
+ end
29
+ end
30
+
31
+ def updatable_attributes(index)
32
+ index.attributes.select { |attrib| attrib.updatable? }
33
+ end
34
+
35
+ def attribute_values_for_index(index)
36
+ updatable_attributes(index).inject({}) { |hash, attrib|
37
+ if attrib.type == :datetime
38
+ hash[attrib.unique_name.to_s] = attrib.live_value(self).to_time.to_i
39
+ else
40
+ hash[attrib.unique_name.to_s] = attrib.live_value self
41
+ end
42
+
43
+ hash
44
+ }
45
+ end
46
+ end
47
+ end
48
+ end
@@ -50,6 +50,10 @@ module ThinkingSphinx
50
50
  end
51
51
  end
52
52
 
53
+ def toggled_delta?
54
+ self.class.delta_object.toggled(self)
55
+ end
56
+
53
57
  private
54
58
 
55
59
  # Set the delta value for the model to be true.
@@ -65,7 +69,16 @@ module ThinkingSphinx
65
69
  end
66
70
 
67
71
  def should_toggle_delta?
68
- !self.respond_to?(:changed?) || self.changed? || self.new_record?
72
+ self.new_record? || indexed_data_changed?
73
+ end
74
+
75
+ def indexed_data_changed?
76
+ sphinx_indexes.any? { |index|
77
+ index.fields.any? { |field| field.changed?(self) } ||
78
+ index.attributes.any? { |attrib|
79
+ attrib.public? && attrib.changed?(self) && !attrib.updatable?
80
+ }
81
+ }
69
82
  end
70
83
  end
71
84
  end
@@ -0,0 +1,37 @@
1
+ module ThinkingSphinx
2
+ module ActiveRecord
3
+ module Scopes
4
+ def self.included(base)
5
+ base.class_eval do
6
+ extend ThinkingSphinx::ActiveRecord::Scopes::ClassMethods
7
+ end
8
+ end
9
+
10
+ module ClassMethods
11
+ def sphinx_scope(method, &block)
12
+ @sphinx_scopes ||= []
13
+ @sphinx_scopes << method
14
+
15
+ metaclass.instance_eval do
16
+ define_method(method) do |*args|
17
+ options = block.call(*args)
18
+ ThinkingSphinx::Search.new(options)
19
+ end
20
+ end
21
+ end
22
+
23
+ def sphinx_scopes
24
+ @sphinx_scopes || []
25
+ end
26
+
27
+ def remove_sphinx_scopes
28
+ sphinx_scopes.each do |scope|
29
+ metaclass.send(:undef_method, scope)
30
+ end
31
+
32
+ sphinx_scopes.clear
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -1,6 +1,7 @@
1
+ require 'thinking_sphinx/active_record/attribute_updates'
1
2
  require 'thinking_sphinx/active_record/delta'
2
- require 'thinking_sphinx/active_record/search'
3
3
  require 'thinking_sphinx/active_record/has_many_association'
4
+ require 'thinking_sphinx/active_record/scopes'
4
5
 
5
6
  module ThinkingSphinx
6
7
  # Core additions to ActiveRecord models - define_index for creating indexes
@@ -65,7 +66,7 @@ module ThinkingSphinx
65
66
  return unless ThinkingSphinx.define_indexes?
66
67
 
67
68
  self.sphinx_indexes ||= []
68
- index = Index.new(self, &block)
69
+ index = ThinkingSphinx::Index::Builder.generate(self, &block)
69
70
 
70
71
  self.sphinx_indexes << index
71
72
  unless ThinkingSphinx.indexed_models.include?(self.name)
@@ -79,7 +80,22 @@ module ThinkingSphinx
79
80
 
80
81
  after_destroy :toggle_deleted
81
82
 
83
+ include ThinkingSphinx::SearchMethods
84
+ include ThinkingSphinx::ActiveRecord::AttributeUpdates
85
+ include ThinkingSphinx::ActiveRecord::Scopes
86
+
82
87
  index
88
+
89
+ # We want to make sure that if the database doesn't exist, then Thinking
90
+ # Sphinx doesn't mind when running non-TS tasks (like db:create, db:drop
91
+ # and db:migrate). It's a bit hacky, but I can't think of a better way.
92
+ rescue StandardError => err
93
+ case err.class.name
94
+ when "Mysql::Error", "Java::JavaSql::SQLException", "ActiveRecord::StatementInvalid"
95
+ return
96
+ else
97
+ raise err
98
+ end
83
99
  end
84
100
  alias_method :sphinx_index, :define_index
85
101
 
@@ -126,12 +142,12 @@ module ThinkingSphinx
126
142
  ThinkingSphinx::AbstractAdapter.detect(self)
127
143
  end
128
144
 
129
- private
130
-
131
145
  def sphinx_name
132
146
  self.name.underscore.tr(':/\\', '_')
133
147
  end
134
148
 
149
+ private
150
+
135
151
  def sphinx_delta?
136
152
  self.sphinx_indexes.any? { |index| index.delta? }
137
153
  end
@@ -148,7 +164,9 @@ module ThinkingSphinx
148
164
  self.sphinx_indexes.select { |ts_index|
149
165
  ts_index.model == self
150
166
  }.each_with_index do |ts_index, i|
151
- index.sources << ts_index.to_riddle_for_core(offset, i)
167
+ index.sources += ts_index.sources.collect { |source|
168
+ source.to_riddle_for_core(offset, i)
169
+ }
152
170
  end
153
171
 
154
172
  index
@@ -160,7 +178,9 @@ module ThinkingSphinx
160
178
  index.path = File.join(ThinkingSphinx::Configuration.instance.searchd_file_path, index.name)
161
179
 
162
180
  self.sphinx_indexes.each_with_index do |ts_index, i|
163
- index.sources << ts_index.to_riddle_for_delta(offset, i) if ts_index.delta?
181
+ index.sources += ts_index.sources.collect { |source|
182
+ source.to_riddle_for_delta(offset, i)
183
+ } if ts_index.delta?
164
184
  end
165
185
 
166
186
  index
@@ -197,7 +217,6 @@ module ThinkingSphinx
197
217
  end
198
218
 
199
219
  base.send(:include, ThinkingSphinx::ActiveRecord::Delta)
200
- base.send(:include, ThinkingSphinx::ActiveRecord::Search)
201
220
 
202
221
  ::ActiveRecord::Associations::HasManyAssociation.send(
203
222
  :include, ThinkingSphinx::ActiveRecord::HasManyAssociation
@@ -207,11 +226,20 @@ module ThinkingSphinx
207
226
  )
208
227
  end
209
228
 
229
+ def in_index?(suffix)
230
+ self.class.search_for_id self.sphinx_document_id, sphinx_index_name(suffix)
231
+ end
232
+
210
233
  def in_core_index?
211
- self.class.search_for_id(
212
- self.sphinx_document_id,
213
- "#{self.class.source_of_sphinx_index.name.underscore.tr(':/\\', '_')}_core"
214
- )
234
+ in_index? "core"
235
+ end
236
+
237
+ def in_delta_index?
238
+ in_index? "delta"
239
+ end
240
+
241
+ def in_both_indexes?
242
+ in_core_index? && in_delta_index?
215
243
  end
216
244
 
217
245
  def toggle_deleted
@@ -232,7 +260,7 @@ module ThinkingSphinx
232
260
  {self.sphinx_document_id => 1}
233
261
  ) if ThinkingSphinx.deltas_enabled? &&
234
262
  self.class.sphinx_indexes.any? { |index| index.delta? } &&
235
- self.delta
263
+ self.toggled_delta?
236
264
  rescue ::ThinkingSphinx::ConnectionError
237
265
  # nothing
238
266
  end
@@ -241,5 +269,11 @@ module ThinkingSphinx
241
269
  (self.id * ThinkingSphinx.indexed_models.size) +
242
270
  ThinkingSphinx.indexed_models.index(self.class.source_of_sphinx_index.name)
243
271
  end
272
+
273
+ private
274
+
275
+ def sphinx_index_name(suffix)
276
+ "#{self.class.source_of_sphinx_index.name.underscore.tr(':/\\', '_')}_#{suffix}"
277
+ end
244
278
  end
245
279
  end
@@ -16,8 +16,16 @@ module ThinkingSphinx
16
16
  ThinkingSphinx::MysqlAdapter.new model
17
17
  when "ActiveRecord::ConnectionAdapters::PostgreSQLAdapter"
18
18
  ThinkingSphinx::PostgreSQLAdapter.new model
19
+ when "ActiveRecord::ConnectionAdapters::JdbcAdapter"
20
+ if model.connection.config[:adapter] == "jdbcmysql"
21
+ ThinkingSphinx::MysqlAdapter.new model
22
+ elsif model.connection.config[:adapter] == "jdbcpostgresql"
23
+ ThinkingSphinx::PostgreSQLAdapter.new model
24
+ else
25
+ raise "Invalid Database Adapter: Sphinx only supports MySQL and PostgreSQL"
26
+ end
19
27
  else
20
- raise "Invalid Database Adapter: Sphinx only supports MySQL and PostgreSQL"
28
+ raise "Invalid Database Adapter: Sphinx only supports MySQL and PostgreSQL, not #{model.connection.class.name}"
21
29
  end
22
30
  end
23
31
 
@@ -13,7 +13,7 @@ module ThinkingSphinx
13
13
  end
14
14
 
15
15
  def group_concatenate(clause, separator = ' ')
16
- "GROUP_CONCAT(#{clause} SEPARATOR '#{separator}')"
16
+ "GROUP_CONCAT(DISTINCT #{clause} SEPARATOR '#{separator}')"
17
17
  end
18
18
 
19
19
  def cast_to_string(clause)
@@ -38,7 +38,8 @@ module ThinkingSphinx
38
38
  value ? 1 : 0
39
39
  end
40
40
 
41
- def crc(clause)
41
+ def crc(clause, blank_to_null = false)
42
+ clause = "NULLIF(#{clause},'')" if blank_to_null
42
43
  "CRC32(#{clause})"
43
44
  end
44
45
 
@@ -11,7 +11,12 @@ module ThinkingSphinx
11
11
 
12
12
  def concatenate(clause, separator = ' ')
13
13
  clause.split(', ').collect { |field|
14
- "COALESCE(CAST(#{field} as varchar), '')"
14
+ case field
15
+ when /COALESCE/, "'')"
16
+ field
17
+ else
18
+ "COALESCE(CAST(#{field} as varchar), '')"
19
+ end
15
20
  }.join(" || '#{separator}' || ")
16
21
  end
17
22
 
@@ -32,7 +37,8 @@ module ThinkingSphinx
32
37
  end
33
38
 
34
39
  def convert_nulls(clause, default = '')
35
- default = "'#{default}'" if default.is_a?(String)
40
+ default = "'#{default}'" if default.is_a?(String)
41
+ default = 'NULL' if default.nil?
36
42
 
37
43
  "COALESCE(#{clause}, #{default})"
38
44
  end
@@ -41,7 +47,8 @@ module ThinkingSphinx
41
47
  value ? 'TRUE' : 'FALSE'
42
48
  end
43
49
 
44
- def crc(clause)
50
+ def crc(clause, blank_to_null = false)
51
+ clause = "NULLIF(#{clause},'')" if blank_to_null
45
52
  "crc32(#{clause})"
46
53
  end
47
54
 
@@ -69,7 +76,7 @@ module ThinkingSphinx
69
76
  end
70
77
 
71
78
  def create_array_accum_function
72
- if connection.raw_connection.server_version > 80200
79
+ if connection.raw_connection.respond_to?(:server_version) && connection.raw_connection.server_version > 80200
73
80
  execute <<-SQL
74
81
  CREATE AGGREGATE array_accum (anyelement)
75
82
  (
@@ -126,4 +133,4 @@ module ThinkingSphinx
126
133
  execute function, true
127
134
  end
128
135
  end
129
- end
136
+ end
@@ -99,6 +99,26 @@ module ThinkingSphinx
99
99
  @reflection.klass.column_names.include?(column.to_s)
100
100
  end
101
101
 
102
+ def primary_key_from_reflection
103
+ if @reflection.options[:through]
104
+ @reflection.source_reflection.options[:foreign_key] ||
105
+ @reflection.source_reflection.primary_key_name
106
+ elsif @reflection.macro == :has_and_belongs_to_many
107
+ @reflection.association_foreign_key
108
+ else
109
+ nil
110
+ end
111
+ end
112
+
113
+ def table
114
+ if @reflection.options[:through] ||
115
+ @reflection.macro == :has_and_belongs_to_many
116
+ @join.aliased_join_table_name
117
+ else
118
+ @join.aliased_table_name
119
+ end
120
+ end
121
+
102
122
  private
103
123
 
104
124
  # Returns all the objects that could be currently instantiated from a