friendlyfashion-thinking-sphinx 2.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. data/HISTORY +244 -0
  2. data/LICENCE +20 -0
  3. data/README.textile +235 -0
  4. data/features/abstract_inheritance.feature +10 -0
  5. data/features/alternate_primary_key.feature +27 -0
  6. data/features/attribute_transformation.feature +22 -0
  7. data/features/attribute_updates.feature +77 -0
  8. data/features/deleting_instances.feature +67 -0
  9. data/features/direct_attributes.feature +11 -0
  10. data/features/excerpts.feature +21 -0
  11. data/features/extensible_delta_indexing.feature +9 -0
  12. data/features/facets.feature +88 -0
  13. data/features/facets_across_model.feature +29 -0
  14. data/features/field_sorting.feature +18 -0
  15. data/features/handling_edits.feature +94 -0
  16. data/features/retry_stale_indexes.feature +24 -0
  17. data/features/searching_across_models.feature +20 -0
  18. data/features/searching_by_index.feature +40 -0
  19. data/features/searching_by_model.feature +175 -0
  20. data/features/searching_with_find_arguments.feature +56 -0
  21. data/features/sphinx_detection.feature +25 -0
  22. data/features/sphinx_scopes.feature +68 -0
  23. data/features/step_definitions/alpha_steps.rb +16 -0
  24. data/features/step_definitions/beta_steps.rb +7 -0
  25. data/features/step_definitions/common_steps.rb +201 -0
  26. data/features/step_definitions/extensible_delta_indexing_steps.rb +7 -0
  27. data/features/step_definitions/facet_steps.rb +96 -0
  28. data/features/step_definitions/find_arguments_steps.rb +36 -0
  29. data/features/step_definitions/gamma_steps.rb +15 -0
  30. data/features/step_definitions/scope_steps.rb +19 -0
  31. data/features/step_definitions/search_steps.rb +94 -0
  32. data/features/step_definitions/sphinx_steps.rb +35 -0
  33. data/features/sti_searching.feature +19 -0
  34. data/features/support/env.rb +27 -0
  35. data/features/support/lib/generic_delta_handler.rb +8 -0
  36. data/features/thinking_sphinx/database.example.yml +3 -0
  37. data/features/thinking_sphinx/db/.gitignore +1 -0
  38. data/features/thinking_sphinx/db/fixtures/alphas.rb +8 -0
  39. data/features/thinking_sphinx/db/fixtures/authors.rb +1 -0
  40. data/features/thinking_sphinx/db/fixtures/betas.rb +11 -0
  41. data/features/thinking_sphinx/db/fixtures/boxes.rb +9 -0
  42. data/features/thinking_sphinx/db/fixtures/categories.rb +1 -0
  43. data/features/thinking_sphinx/db/fixtures/cats.rb +3 -0
  44. data/features/thinking_sphinx/db/fixtures/comments.rb +24 -0
  45. data/features/thinking_sphinx/db/fixtures/developers.rb +31 -0
  46. data/features/thinking_sphinx/db/fixtures/dogs.rb +3 -0
  47. data/features/thinking_sphinx/db/fixtures/extensible_betas.rb +10 -0
  48. data/features/thinking_sphinx/db/fixtures/foxes.rb +3 -0
  49. data/features/thinking_sphinx/db/fixtures/gammas.rb +10 -0
  50. data/features/thinking_sphinx/db/fixtures/music.rb +4 -0
  51. data/features/thinking_sphinx/db/fixtures/people.rb +1001 -0
  52. data/features/thinking_sphinx/db/fixtures/post_keywords.txt +1 -0
  53. data/features/thinking_sphinx/db/fixtures/posts.rb +10 -0
  54. data/features/thinking_sphinx/db/fixtures/robots.rb +8 -0
  55. data/features/thinking_sphinx/db/fixtures/tags.rb +27 -0
  56. data/features/thinking_sphinx/db/migrations/create_alphas.rb +8 -0
  57. data/features/thinking_sphinx/db/migrations/create_animals.rb +5 -0
  58. data/features/thinking_sphinx/db/migrations/create_authors.rb +3 -0
  59. data/features/thinking_sphinx/db/migrations/create_authors_posts.rb +6 -0
  60. data/features/thinking_sphinx/db/migrations/create_betas.rb +5 -0
  61. data/features/thinking_sphinx/db/migrations/create_boxes.rb +5 -0
  62. data/features/thinking_sphinx/db/migrations/create_categories.rb +3 -0
  63. data/features/thinking_sphinx/db/migrations/create_comments.rb +10 -0
  64. data/features/thinking_sphinx/db/migrations/create_developers.rb +7 -0
  65. data/features/thinking_sphinx/db/migrations/create_extensible_betas.rb +5 -0
  66. data/features/thinking_sphinx/db/migrations/create_gammas.rb +3 -0
  67. data/features/thinking_sphinx/db/migrations/create_genres.rb +3 -0
  68. data/features/thinking_sphinx/db/migrations/create_music.rb +6 -0
  69. data/features/thinking_sphinx/db/migrations/create_people.rb +13 -0
  70. data/features/thinking_sphinx/db/migrations/create_posts.rb +6 -0
  71. data/features/thinking_sphinx/db/migrations/create_robots.rb +4 -0
  72. data/features/thinking_sphinx/db/migrations/create_taggings.rb +5 -0
  73. data/features/thinking_sphinx/db/migrations/create_tags.rb +4 -0
  74. data/features/thinking_sphinx/models/alpha.rb +23 -0
  75. data/features/thinking_sphinx/models/andrew.rb +17 -0
  76. data/features/thinking_sphinx/models/animal.rb +5 -0
  77. data/features/thinking_sphinx/models/author.rb +3 -0
  78. data/features/thinking_sphinx/models/beta.rb +13 -0
  79. data/features/thinking_sphinx/models/box.rb +8 -0
  80. data/features/thinking_sphinx/models/cat.rb +3 -0
  81. data/features/thinking_sphinx/models/category.rb +4 -0
  82. data/features/thinking_sphinx/models/comment.rb +10 -0
  83. data/features/thinking_sphinx/models/developer.rb +21 -0
  84. data/features/thinking_sphinx/models/dog.rb +3 -0
  85. data/features/thinking_sphinx/models/extensible_beta.rb +9 -0
  86. data/features/thinking_sphinx/models/fox.rb +5 -0
  87. data/features/thinking_sphinx/models/gamma.rb +5 -0
  88. data/features/thinking_sphinx/models/genre.rb +3 -0
  89. data/features/thinking_sphinx/models/medium.rb +5 -0
  90. data/features/thinking_sphinx/models/music.rb +10 -0
  91. data/features/thinking_sphinx/models/person.rb +24 -0
  92. data/features/thinking_sphinx/models/post.rb +22 -0
  93. data/features/thinking_sphinx/models/robot.rb +12 -0
  94. data/features/thinking_sphinx/models/tag.rb +3 -0
  95. data/features/thinking_sphinx/models/tagging.rb +4 -0
  96. data/lib/cucumber/thinking_sphinx/external_world.rb +12 -0
  97. data/lib/cucumber/thinking_sphinx/internal_world.rb +137 -0
  98. data/lib/cucumber/thinking_sphinx/sql_logger.rb +28 -0
  99. data/lib/thinking-sphinx.rb +1 -0
  100. data/lib/thinking_sphinx/action_controller.rb +31 -0
  101. data/lib/thinking_sphinx/active_record/attribute_updates.rb +53 -0
  102. data/lib/thinking_sphinx/active_record/collection_proxy.rb +47 -0
  103. data/lib/thinking_sphinx/active_record/collection_proxy_with_scopes.rb +27 -0
  104. data/lib/thinking_sphinx/active_record/delta.rb +67 -0
  105. data/lib/thinking_sphinx/active_record/has_many_association.rb +44 -0
  106. data/lib/thinking_sphinx/active_record/has_many_association_with_scopes.rb +21 -0
  107. data/lib/thinking_sphinx/active_record/log_subscriber.rb +61 -0
  108. data/lib/thinking_sphinx/active_record/scopes.rb +110 -0
  109. data/lib/thinking_sphinx/active_record.rb +386 -0
  110. data/lib/thinking_sphinx/adapters/abstract_adapter.rb +87 -0
  111. data/lib/thinking_sphinx/adapters/mysql_adapter.rb +62 -0
  112. data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +188 -0
  113. data/lib/thinking_sphinx/association.rb +230 -0
  114. data/lib/thinking_sphinx/attribute.rb +405 -0
  115. data/lib/thinking_sphinx/auto_version.rb +40 -0
  116. data/lib/thinking_sphinx/bundled_search.rb +44 -0
  117. data/lib/thinking_sphinx/class_facet.rb +20 -0
  118. data/lib/thinking_sphinx/configuration.rb +375 -0
  119. data/lib/thinking_sphinx/context.rb +76 -0
  120. data/lib/thinking_sphinx/core/string.rb +15 -0
  121. data/lib/thinking_sphinx/deltas/default_delta.rb +62 -0
  122. data/lib/thinking_sphinx/deltas.rb +28 -0
  123. data/lib/thinking_sphinx/deploy/capistrano.rb +99 -0
  124. data/lib/thinking_sphinx/excerpter.rb +23 -0
  125. data/lib/thinking_sphinx/facet.rb +135 -0
  126. data/lib/thinking_sphinx/facet_search.rb +170 -0
  127. data/lib/thinking_sphinx/field.rb +98 -0
  128. data/lib/thinking_sphinx/index/builder.rb +315 -0
  129. data/lib/thinking_sphinx/index/faux_column.rb +118 -0
  130. data/lib/thinking_sphinx/index.rb +159 -0
  131. data/lib/thinking_sphinx/join.rb +37 -0
  132. data/lib/thinking_sphinx/property.rb +187 -0
  133. data/lib/thinking_sphinx/railtie.rb +43 -0
  134. data/lib/thinking_sphinx/search.rb +1061 -0
  135. data/lib/thinking_sphinx/search_methods.rb +439 -0
  136. data/lib/thinking_sphinx/sinatra.rb +7 -0
  137. data/lib/thinking_sphinx/source/internal_properties.rb +51 -0
  138. data/lib/thinking_sphinx/source/sql.rb +174 -0
  139. data/lib/thinking_sphinx/source.rb +194 -0
  140. data/lib/thinking_sphinx/tasks.rb +142 -0
  141. data/lib/thinking_sphinx/test.rb +55 -0
  142. data/lib/thinking_sphinx/version.rb +3 -0
  143. data/lib/thinking_sphinx.rb +297 -0
  144. data/spec/fixtures/data.sql +32 -0
  145. data/spec/fixtures/database.yml.default +3 -0
  146. data/spec/fixtures/models.rb +164 -0
  147. data/spec/fixtures/structure.sql +146 -0
  148. data/spec/spec_helper.rb +61 -0
  149. data/spec/sphinx_helper.rb +60 -0
  150. data/spec/support/rails.rb +25 -0
  151. data/spec/thinking_sphinx/active_record/delta_spec.rb +122 -0
  152. data/spec/thinking_sphinx/active_record/has_many_association_spec.rb +173 -0
  153. data/spec/thinking_sphinx/active_record/scopes_spec.rb +176 -0
  154. data/spec/thinking_sphinx/active_record_spec.rb +573 -0
  155. data/spec/thinking_sphinx/adapters/abstract_adapter_spec.rb +145 -0
  156. data/spec/thinking_sphinx/association_spec.rb +250 -0
  157. data/spec/thinking_sphinx/attribute_spec.rb +552 -0
  158. data/spec/thinking_sphinx/auto_version_spec.rb +103 -0
  159. data/spec/thinking_sphinx/configuration_spec.rb +326 -0
  160. data/spec/thinking_sphinx/context_spec.rb +126 -0
  161. data/spec/thinking_sphinx/core/array_spec.rb +9 -0
  162. data/spec/thinking_sphinx/core/string_spec.rb +9 -0
  163. data/spec/thinking_sphinx/excerpter_spec.rb +49 -0
  164. data/spec/thinking_sphinx/facet_search_spec.rb +176 -0
  165. data/spec/thinking_sphinx/facet_spec.rb +359 -0
  166. data/spec/thinking_sphinx/field_spec.rb +127 -0
  167. data/spec/thinking_sphinx/index/builder_spec.rb +532 -0
  168. data/spec/thinking_sphinx/index/faux_column_spec.rb +36 -0
  169. data/spec/thinking_sphinx/index_spec.rb +189 -0
  170. data/spec/thinking_sphinx/search_methods_spec.rb +156 -0
  171. data/spec/thinking_sphinx/search_spec.rb +1455 -0
  172. data/spec/thinking_sphinx/source_spec.rb +267 -0
  173. data/spec/thinking_sphinx/test_spec.rb +20 -0
  174. data/spec/thinking_sphinx_spec.rb +204 -0
  175. metadata +524 -0
@@ -0,0 +1,188 @@
1
+ module ThinkingSphinx
2
+ class PostgreSQLAdapter < AbstractAdapter
3
+ def setup
4
+ create_array_accum_function
5
+ create_crc32_function
6
+ end
7
+
8
+ def sphinx_identifier
9
+ "pgsql"
10
+ end
11
+
12
+ def concatenate(clause, separator = ' ')
13
+ if clause[/^COALESCE/]
14
+ clause.split('), ').join(") || '#{separator}' || ")
15
+ else
16
+ clause.split(', ').collect { |field|
17
+ "CAST(COALESCE(#{field}::varchar, '') as varchar)"
18
+ }.join(" || '#{separator}' || ")
19
+ end
20
+ end
21
+
22
+ def group_concatenate(clause, separator = ' ')
23
+ if server_version >= 80400
24
+ "array_to_string(array_agg(COALESCE(#{clause}, '0')), '#{separator}')"
25
+ else
26
+ "array_to_string(array_accum(COALESCE(#{clause}, '0')), '#{separator}')"
27
+ end
28
+ end
29
+
30
+ def cast_to_string(clause)
31
+ clause
32
+ end
33
+
34
+ def cast_to_datetime(clause)
35
+ if ThinkingSphinx::Configuration.instance.use_64_bit
36
+ "cast(floor(extract(epoch from #{clause})) as bigint)"
37
+ else
38
+ "cast(floor(extract(epoch from #{clause})) as int)"
39
+ end
40
+ end
41
+
42
+ def cast_to_unsigned(clause)
43
+ clause
44
+ end
45
+
46
+ def cast_to_int(clause)
47
+ "#{clause}::INT8"
48
+ end
49
+
50
+ def convert_nulls(clause, default = '')
51
+ default = case default
52
+ when String
53
+ "'#{default}'"
54
+ when NilClass
55
+ 'NULL'
56
+ when Fixnum
57
+ "#{default}::bigint"
58
+ else
59
+ default
60
+ end
61
+
62
+ "COALESCE(#{clause}, #{default})"
63
+ end
64
+
65
+ def boolean(value)
66
+ value ? 'TRUE' : 'FALSE'
67
+ end
68
+
69
+ def crc(clause, blank_to_null = false)
70
+ clause = "NULLIF(#{clause},'')" if blank_to_null
71
+ "crc32(#{clause})"
72
+ end
73
+
74
+ def utf8_query_pre
75
+ nil
76
+ end
77
+
78
+ def time_difference(diff)
79
+ "current_timestamp - interval '#{diff} seconds'"
80
+ end
81
+
82
+ def utc_query_pre
83
+ "SET TIME ZONE 'UTC'"
84
+ end
85
+
86
+ private
87
+
88
+ def execute(command, output_error = false)
89
+ if RUBY_PLATFORM == 'java'
90
+ connection.transaction do
91
+ execute_command command, output_error
92
+ end
93
+ else
94
+ execute_command command, output_error
95
+ end
96
+ end
97
+
98
+ def execute_command(command, output_error = false)
99
+ connection.execute "begin"
100
+ connection.execute "savepoint ts"
101
+ begin
102
+ connection.execute command
103
+ rescue StandardError => err
104
+ puts err if output_error
105
+ connection.execute "rollback to savepoint ts"
106
+ end
107
+ connection.execute "release savepoint ts"
108
+ connection.execute "commit"
109
+ end
110
+
111
+ def create_array_accum_function
112
+ if server_version >= 80311
113
+ return
114
+ elsif server_version > 80200
115
+ execute <<-SQL
116
+ CREATE AGGREGATE array_accum (anyelement)
117
+ (
118
+ sfunc = array_append,
119
+ stype = anyarray,
120
+ initcond = '{}'
121
+ );
122
+ SQL
123
+ else
124
+ execute <<-SQL
125
+ CREATE AGGREGATE array_accum
126
+ (
127
+ basetype = anyelement,
128
+ sfunc = array_append,
129
+ stype = anyarray,
130
+ initcond = '{}'
131
+ );
132
+ SQL
133
+ end
134
+ end
135
+
136
+ def create_crc32_function
137
+ execute "CREATE LANGUAGE 'plpgsql';"
138
+ function = <<-SQL
139
+ CREATE OR REPLACE FUNCTION crc32(word text)
140
+ RETURNS bigint AS $$
141
+ DECLARE tmp bigint;
142
+ DECLARE i int;
143
+ DECLARE j int;
144
+ DECLARE byte_length int;
145
+ DECLARE word_array bytea;
146
+ BEGIN
147
+ IF COALESCE(word, '') = '' THEN
148
+ return 0;
149
+ END IF;
150
+
151
+ i = 0;
152
+ tmp = 4294967295;
153
+ byte_length = bit_length(word) / 8;
154
+ word_array = decode(replace(word, E'\\\\', E'\\\\\\\\'), 'escape');
155
+ LOOP
156
+ tmp = (tmp # get_byte(word_array, i))::bigint;
157
+ i = i + 1;
158
+ j = 0;
159
+ LOOP
160
+ tmp = ((tmp >> 1) # (3988292384 * (tmp & 1)))::bigint;
161
+ j = j + 1;
162
+ IF j >= 8 THEN
163
+ EXIT;
164
+ END IF;
165
+ END LOOP;
166
+ IF i >= byte_length THEN
167
+ EXIT;
168
+ END IF;
169
+ END LOOP;
170
+ return (tmp # 4294967295);
171
+ END
172
+ $$ IMMUTABLE LANGUAGE plpgsql;
173
+ SQL
174
+ execute function, true
175
+ end
176
+
177
+ def server_version
178
+ if RUBY_PLATFORM == 'java'
179
+ (connection.raw_connection.connection.server_major_version * 10000) +
180
+ (connection.raw_connection.connection.server_minor_version * 100)
181
+ elsif connection.raw_connection.respond_to?(:server_version)
182
+ connection.raw_connection.server_version
183
+ else
184
+ 0
185
+ end
186
+ end
187
+ end
188
+ end
@@ -0,0 +1,230 @@
1
+ module ThinkingSphinx
2
+ # Association tracks a specific reflection and join to reference data that
3
+ # isn't in the base model. Very much an internal class for Thinking Sphinx -
4
+ # perhaps because I feel it's not as strong (or simple) as most of the rest.
5
+ #
6
+ class Association
7
+ attr_accessor :parent, :reflection, :join
8
+
9
+ # Create a new association by passing in the parent association, and the
10
+ # corresponding reflection instance. If there is no parent, pass in nil.
11
+ #
12
+ # top = Association.new nil, top_reflection
13
+ # child = Association.new top, child_reflection
14
+ #
15
+ def initialize(parent, reflection)
16
+ @parent, @reflection = parent, reflection
17
+ @children = {}
18
+ end
19
+
20
+ # Get the children associations for a given association name. The only time
21
+ # that there'll actually be more than one association is when the
22
+ # relationship is polymorphic. To keep things simple though, it will always
23
+ # be an Array that gets returned (an empty one if no matches).
24
+ #
25
+ # # where pages is an association on the class tied to the reflection.
26
+ # association.children(:pages)
27
+ #
28
+ def children(assoc)
29
+ @children[assoc] ||= Association.children(@reflection.klass, assoc, self)
30
+ end
31
+
32
+ # Get the children associations for a given class, association name and
33
+ # parent association. Much like the instance method of the same name, it
34
+ # will return an empty array if no associations have the name, and only
35
+ # have multiple association instances if the underlying relationship is
36
+ # polymorphic.
37
+ #
38
+ # Association.children(User, :pages, user_association)
39
+ #
40
+ def self.children(klass, assoc, parent=nil)
41
+ ref = klass.reflect_on_association(assoc)
42
+
43
+ return [] if ref.nil?
44
+ return [Association.new(parent, ref)] unless ref.options[:polymorphic]
45
+
46
+ # association is polymorphic - create associations for each
47
+ # non-polymorphic reflection.
48
+ polymorphic_classes(ref).collect { |poly_class|
49
+ Association.new parent, depolymorphic_reflection(ref, klass, poly_class)
50
+ }
51
+ end
52
+
53
+ # Link up the join for this model from a base join - and set parent
54
+ # associations' joins recursively.
55
+ #
56
+ def join_to(base_join)
57
+ parent.join_to(base_join) if parent && parent.join.nil?
58
+
59
+ @join ||= join_association_class.new(
60
+ @reflection, base_join, parent ? parent.join : join_parent(base_join)
61
+ )
62
+ end
63
+
64
+ def arel_join
65
+ @join.join_type = Arel::OuterJoin
66
+ rewrite_conditions
67
+
68
+ @join
69
+ end
70
+
71
+ # Returns true if the association - or a parent - is a has_many or
72
+ # has_and_belongs_to_many.
73
+ #
74
+ def is_many?
75
+ case @reflection.macro
76
+ when :has_many, :has_and_belongs_to_many
77
+ true
78
+ else
79
+ @parent ? @parent.is_many? : false
80
+ end
81
+ end
82
+
83
+ # Returns an array of all the associations that lead to this one - starting
84
+ # with the top level all the way to the current association object.
85
+ #
86
+ def ancestors
87
+ (parent ? parent.ancestors : []) << self
88
+ end
89
+
90
+ def has_column?(column)
91
+ @reflection.klass.column_names.include?(column.to_s)
92
+ end
93
+
94
+ def primary_key_from_reflection
95
+ if @reflection.options[:through]
96
+ if ThinkingSphinx.rails_3_1?
97
+ @reflection.source_reflection.foreign_key
98
+ else
99
+ @reflection.source_reflection.options[:foreign_key] ||
100
+ @reflection.source_reflection.primary_key_name
101
+ end
102
+ elsif @reflection.macro == :has_and_belongs_to_many
103
+ @reflection.association_foreign_key
104
+ else
105
+ nil
106
+ end
107
+ end
108
+
109
+ def table
110
+ if @reflection.options[:through] ||
111
+ @reflection.macro == :has_and_belongs_to_many
112
+ if ThinkingSphinx.rails_3_1?
113
+ @join.tables.first.name
114
+ else
115
+ @join.aliased_join_table_name
116
+ end
117
+ else
118
+ @join.aliased_table_name
119
+ end
120
+ end
121
+
122
+ private
123
+
124
+ def self.depolymorphic_reflection(reflection, source_class, poly_class)
125
+ name = "#{reflection.name}_#{poly_class.name}".to_sym
126
+
127
+ source_class.reflections[name] ||=
128
+ ::ActiveRecord::Reflection::AssociationReflection.new(
129
+ reflection.macro, name, casted_options(poly_class, reflection),
130
+ reflection.active_record
131
+ )
132
+ end
133
+
134
+ # Returns all the objects that could be currently instantiated from a
135
+ # polymorphic association. This is pretty damn fast if there's an index on
136
+ # the foreign type column - but if there isn't, it can take a while if you
137
+ # have a lot of data.
138
+ #
139
+ def self.polymorphic_classes(ref)
140
+ ref.active_record.connection.select_all(
141
+ "SELECT DISTINCT #{foreign_type(ref)} " +
142
+ "FROM #{ref.active_record.table_name} " +
143
+ "WHERE #{foreign_type(ref)} IS NOT NULL"
144
+ ).collect { |row|
145
+ row[foreign_type(ref)].constantize
146
+ }
147
+ end
148
+
149
+ # Returns a new set of options for an association that mimics an existing
150
+ # polymorphic relationship for a specific class. It adds a condition to
151
+ # filter by the appropriate object.
152
+ #
153
+ def self.casted_options(klass, ref)
154
+ options = ref.options.clone
155
+ options[:polymorphic] = nil
156
+ options[:class_name] = klass.name
157
+ options[:foreign_key] ||= "#{ref.name}_id"
158
+
159
+ quoted_foreign_type = klass.connection.quote_column_name foreign_type(ref)
160
+ case options[:conditions]
161
+ when nil
162
+ options[:conditions] = "::ts_join_alias::.#{quoted_foreign_type} = '#{klass.name}'"
163
+ when Array
164
+ options[:conditions] << "::ts_join_alias::.#{quoted_foreign_type} = '#{klass.name}'"
165
+ when Hash
166
+ options[:conditions].merge!(foreign_type(ref) => klass.name)
167
+ else
168
+ options[:conditions] << " AND ::ts_join_alias::.#{quoted_foreign_type} = '#{klass.name}'"
169
+ end
170
+
171
+ options
172
+ end
173
+
174
+ def join_association_class
175
+ if ThinkingSphinx.rails_3_1?
176
+ ::ActiveRecord::Associations::JoinDependency::JoinAssociation
177
+ else
178
+ ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation
179
+ end
180
+ end
181
+
182
+ def join_parent(join)
183
+ if ThinkingSphinx.rails_3_1?
184
+ join.join_parts.first
185
+ else
186
+ join.joins.first
187
+ end
188
+ end
189
+
190
+ def self.foreign_type(ref)
191
+ if ThinkingSphinx.rails_3_1?
192
+ ref.foreign_type
193
+ else
194
+ ref.options[:foreign_type]
195
+ end
196
+ end
197
+
198
+ def rewrite_conditions
199
+ @join.options[:conditions] = case @join.options[:conditions]
200
+ when String
201
+ rewrite_condition @join.options[:conditions]
202
+ when Array
203
+ @join.options[:conditions].collect { |condition|
204
+ rewrite_condition condition
205
+ }
206
+ else
207
+ @join.options[:conditions]
208
+ end
209
+ end
210
+
211
+ def rewrite_condition(condition)
212
+ return condition unless condition.is_a?(String)
213
+
214
+ if defined?(ActsAsTaggableOn) &&
215
+ @reflection.klass == ActsAsTaggableOn::Tagging &&
216
+ @reflection.name.to_s[/_taggings$/]
217
+ condition.gsub! /taggings\.tag_id = tags\.id AND/, "" if ThinkingSphinx.rails_3_1?
218
+ condition = condition.gsub /taggings\./, "#{quoted_alias @join}."
219
+ end
220
+
221
+ condition.gsub /::ts_join_alias::/, quoted_alias(@join.parent)
222
+ end
223
+
224
+ def quoted_alias(join)
225
+ @reflection.klass.connection.quote_table_name(
226
+ join.aliased_table_name
227
+ )
228
+ end
229
+ end
230
+ end