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,573 @@
1
+ require 'spec_helper'
2
+
3
+ describe ThinkingSphinx::ActiveRecord do
4
+ before :each do
5
+ @existing_alpha_indexes = Alpha.sphinx_indexes.clone
6
+ @existing_beta_indexes = Beta.sphinx_indexes.clone
7
+
8
+ Alpha.send :defined_indexes=, false
9
+ Beta.send :defined_indexes=, false
10
+
11
+ Alpha.sphinx_indexes.clear
12
+ Beta.sphinx_indexes.clear
13
+ end
14
+
15
+ after :each do
16
+ Alpha.sphinx_indexes.replace @existing_alpha_indexes
17
+ Beta.sphinx_indexes.replace @existing_beta_indexes
18
+
19
+ Alpha.send :defined_indexes=, true
20
+ Beta.send :defined_indexes=, true
21
+
22
+ Alpha.sphinx_index_blocks.clear
23
+ Beta.sphinx_index_blocks.clear
24
+ end
25
+
26
+ describe '.define_index' do
27
+ it "should do nothing if indexes are disabled" do
28
+ ThinkingSphinx.define_indexes = false
29
+ ThinkingSphinx::Index.should_not_receive(:new)
30
+
31
+ Alpha.define_index { }
32
+ Alpha.define_indexes
33
+
34
+ ThinkingSphinx.define_indexes = true
35
+ end
36
+
37
+ it "should not evaluate the index block automatically" do
38
+ lambda {
39
+ Alpha.define_index { raise StandardError }
40
+ }.should_not raise_error
41
+ end
42
+
43
+ it "should add the model to the context collection" do
44
+ Alpha.define_index { indexes :name }
45
+
46
+ ThinkingSphinx.context.indexed_models.should include("Alpha")
47
+ end
48
+
49
+ it "should die quietly if there is a database error" do
50
+ ThinkingSphinx::Index::Builder.stub(:generate).
51
+ and_raise(Mysql2::Error.new(''))
52
+ Alpha.define_index { indexes :name }
53
+
54
+ lambda {
55
+ Alpha.define_indexes
56
+ }.should_not raise_error
57
+ end unless RUBY_PLATFORM == 'java'
58
+
59
+ it "should die noisily if there is a non-database error" do
60
+ ThinkingSphinx::Index::Builder.stub(:generate) { raise StandardError }
61
+ Alpha.define_index { indexes :name }
62
+
63
+ lambda {
64
+ Alpha.define_indexes
65
+ }.should raise_error
66
+ end
67
+
68
+ it "should set the index's name using the parameter if provided" do
69
+ Alpha.define_index('custom') { indexes :name }
70
+ Alpha.define_indexes
71
+
72
+ Alpha.sphinx_indexes.first.name.should == 'custom'
73
+ end
74
+
75
+ context 'callbacks' do
76
+ it "should add a before_validation callback to define_indexes" do
77
+ Alpha.should_receive(:before_validation).with(:define_indexes)
78
+
79
+ Alpha.define_index { }
80
+ end
81
+
82
+ it "should not add a before_validation callback twice" do
83
+ Alpha.should_receive(:before_validation).with(:define_indexes).once
84
+
85
+ Alpha.define_index { }
86
+ Alpha.define_index { }
87
+ end
88
+
89
+ it "should add a before_destroy callback to define_indexes" do
90
+ Alpha.should_receive(:before_destroy).with(:define_indexes)
91
+
92
+ Alpha.define_index { }
93
+ end
94
+
95
+ it "should not add a before_destroy callback twice" do
96
+ Alpha.should_receive(:before_destroy).with(:define_indexes).once
97
+
98
+ Alpha.define_index { }
99
+ Alpha.define_index { }
100
+ end
101
+
102
+ it "should add a toggle_deleted callback when defined" do
103
+ Alpha.should_receive(:after_destroy).with(:toggle_deleted)
104
+
105
+ Alpha.define_index { indexes :name }
106
+ Alpha.define_indexes
107
+ end
108
+
109
+ it "should not add toggle_deleted callback more than once" do
110
+ Alpha.should_receive(:after_destroy).with(:toggle_deleted).once
111
+
112
+ Alpha.define_index { indexes :name }
113
+ Alpha.define_index { indexes :name }
114
+ Alpha.define_indexes
115
+ end
116
+
117
+ it "should add a update_attribute_values callback when defined" do
118
+ Alpha.should_receive(:after_save).with(:update_attribute_values)
119
+
120
+ Alpha.define_index { indexes :name }
121
+ Alpha.define_indexes
122
+ end
123
+
124
+ it "should not add update_attribute_values callback more than once" do
125
+ Alpha.should_receive(:after_save).with(:update_attribute_values).once
126
+
127
+ Alpha.define_index { indexes :name }
128
+ Alpha.define_index { indexes :name }
129
+ Alpha.define_indexes
130
+ end
131
+
132
+ it "should add a toggle_delta callback if deltas are enabled" do
133
+ Beta.should_receive(:before_save).with(:toggle_delta)
134
+
135
+ Beta.define_index {
136
+ indexes :name
137
+ set_property :delta => true
138
+ }
139
+ Beta.define_indexes
140
+ end
141
+
142
+ it "should not add a toggle_delta callback if deltas are disabled" do
143
+ Alpha.should_not_receive(:before_save).with(:toggle_delta)
144
+
145
+ Alpha.define_index { indexes :name }
146
+ Alpha.define_indexes
147
+ end
148
+
149
+ it "should add the toggle_delta callback if deltas are disabled in other indexes" do
150
+ Beta.should_receive(:before_save).with(:toggle_delta).once
151
+
152
+ Beta.define_index { indexes :name }
153
+ Beta.define_index('foo') {
154
+ indexes :name
155
+ set_property :delta => true
156
+ }
157
+ Beta.define_indexes
158
+ end
159
+
160
+ it "should only add the toggle_delta callback once" do
161
+ Beta.should_receive(:before_save).with(:toggle_delta).once
162
+
163
+ Beta.define_index {
164
+ indexes :name
165
+ set_property :delta => true
166
+ }
167
+ Beta.define_index {
168
+ indexes :name
169
+ set_property :delta => true
170
+ }
171
+ Beta.define_indexes
172
+ end
173
+
174
+ it "should add an index_delta callback if deltas are enabled" do
175
+ Beta.stub!(:after_save => true)
176
+ Beta.should_receive(:after_commit).with(:index_delta)
177
+
178
+ Beta.define_index {
179
+ indexes :name
180
+ set_property :delta => true
181
+ }
182
+ Beta.define_indexes
183
+ end
184
+
185
+ it "should not add an index_delta callback if deltas are disabled" do
186
+ Alpha.should_not_receive(:after_commit).with(:index_delta)
187
+
188
+ Alpha.define_index { indexes :name }
189
+ Alpha.define_indexes
190
+ end
191
+
192
+ it "should add the index_delta callback if deltas are disabled in other indexes" do
193
+ Beta.stub!(:after_commit => true)
194
+ Beta.should_receive(:after_commit).with(:index_delta).once
195
+
196
+ Beta.define_index { indexes :name }
197
+ Beta.define_index('foo') {
198
+ indexes :name
199
+ set_property :delta => true
200
+ }
201
+ Beta.define_indexes
202
+ end
203
+
204
+ it "should only add the index_delta callback once" do
205
+ Beta.stub!(:after_commit => true)
206
+ Beta.should_receive(:after_commit).with(:index_delta).once
207
+
208
+ Beta.define_index {
209
+ indexes :name
210
+ set_property :delta => true
211
+ }
212
+ Beta.define_index {
213
+ indexes :name
214
+ set_property :delta => true
215
+ }
216
+ Beta.define_indexes
217
+ end
218
+ end
219
+ end
220
+
221
+ describe '.define_indexes' do
222
+ it "should process define_index blocks" do
223
+ Beta.define_index { indexes :name }
224
+ Beta.sphinx_indexes.length.should == 0
225
+
226
+ Beta.define_indexes
227
+ Beta.sphinx_indexes.length.should == 1
228
+ end
229
+
230
+ it "should not re-add indexes" do
231
+ Beta.define_index { indexes :name }
232
+ Beta.define_indexes
233
+ Beta.define_indexes
234
+
235
+ Beta.sphinx_indexes.length.should == 1
236
+ end
237
+ end
238
+
239
+ describe '.source_of_sphinx_index' do
240
+ it "should return self if model defines an index" do
241
+ Person.source_of_sphinx_index.should == Person
242
+ end
243
+
244
+ it "should return the parent if model inherits an index" do
245
+ Admin::Person.source_of_sphinx_index.should == Person
246
+ end
247
+ end
248
+
249
+ describe '.to_crc32' do
250
+ it "should return an integer" do
251
+ Person.to_crc32.should be_a_kind_of(Integer)
252
+ end
253
+ end
254
+
255
+ describe '.to_crc32s' do
256
+ it "should return an array" do
257
+ Person.to_crc32s.should be_a_kind_of(Array)
258
+ end
259
+ end
260
+
261
+ describe "toggle_deleted method" do
262
+ before :each do
263
+ ThinkingSphinx.stub!(:sphinx_running? => true)
264
+
265
+ @configuration = ThinkingSphinx::Configuration.instance
266
+ @configuration.stub!(
267
+ :address => "an address",
268
+ :port => 123
269
+ )
270
+ @client = Riddle::Client.new
271
+ @client.stub!(:update => true)
272
+ @person = Person.find(:first)
273
+
274
+ @configuration.stub!(:client => @client)
275
+ Person.sphinx_indexes.each { |index| index.stub!(:delta? => false) }
276
+ end
277
+
278
+ it "should update the core index's deleted flag if in core index" do
279
+ @client.should_receive(:update).with(
280
+ "person_core", ["sphinx_deleted"], {@person.sphinx_document_id => [1]}
281
+ )
282
+
283
+ @person.toggle_deleted
284
+ end
285
+
286
+ it "shouldn't attempt to update the deleted flag if sphinx isn't running" do
287
+ ThinkingSphinx.stub!(:sphinx_running? => false)
288
+ @client.should_not_receive(:update)
289
+
290
+ @person.toggle_deleted
291
+ end
292
+
293
+ it "should update the delta index's deleted flag if delta indexes are enabled and the instance's delta is true" do
294
+ ThinkingSphinx.deltas_enabled = true
295
+ Person.sphinx_indexes.each { |index| index.stub!(:delta? => true) }
296
+ @person.delta = true
297
+ @client.should_receive(:update).with(
298
+ "person_delta", ["sphinx_deleted"], {@person.sphinx_document_id => [1]}
299
+ )
300
+
301
+ @person.toggle_deleted
302
+ end
303
+
304
+ it "should not update the delta index's deleted flag if delta indexes are enabled and the instance's delta is false" do
305
+ ThinkingSphinx.deltas_enabled = true
306
+ Person.sphinx_indexes.each { |index| index.stub!(:delta? => true) }
307
+ @person.delta = false
308
+ @client.should_not_receive(:update).with(
309
+ "person_delta", ["sphinx_deleted"], {@person.sphinx_document_id => [1]}
310
+ )
311
+
312
+ @person.toggle_deleted
313
+ end
314
+
315
+ it "should not update the delta index's deleted flag if delta indexes are enabled and the instance's delta is equivalent to false" do
316
+ ThinkingSphinx.deltas_enabled = true
317
+ Person.sphinx_indexes.each { |index| index.stub!(:delta? => true) }
318
+ @person.delta = 0
319
+ @client.should_not_receive(:update).with(
320
+ "person_delta", ["sphinx_deleted"], {@person.sphinx_document_id => [1]}
321
+ )
322
+
323
+ @person.toggle_deleted
324
+ end
325
+
326
+ it "shouldn't update the delta index if delta indexes are disabled" do
327
+ ThinkingSphinx.deltas_enabled = true
328
+ @client.should_not_receive(:update).with(
329
+ "person_delta", ["sphinx_deleted"], {@person.sphinx_document_id => [1]}
330
+ )
331
+
332
+ @person.toggle_deleted
333
+ end
334
+
335
+ it "should not update either index if updates are disabled" do
336
+ ThinkingSphinx.updates_enabled = false
337
+ ThinkingSphinx.deltas_enabled = true
338
+ Person.sphinx_indexes.each { |index| index.stub!(:delta? => true) }
339
+ @person.delta = true
340
+ @client.should_not_receive(:update)
341
+
342
+ @person.toggle_deleted
343
+ end
344
+ end
345
+
346
+ describe "sphinx_indexes in the inheritance chain (STI)" do
347
+ it "should hand defined indexes on a class down to its child classes" do
348
+ Child.sphinx_indexes.should include(*Person.sphinx_indexes)
349
+ end
350
+
351
+ it "should allow associations to other STI models" do
352
+ source = Child.sphinx_indexes.last.sources.first
353
+ sql = source.to_riddle_for_core(0, 0).sql_query
354
+ sql.gsub!('$start', '0').gsub!('$end', '100')
355
+ lambda {
356
+ Child.connection.execute(sql)
357
+ }.should_not raise_error(ActiveRecord::StatementInvalid)
358
+ end
359
+ end
360
+
361
+ describe '#sphinx_document_id' do
362
+ before :each do
363
+ Alpha.define_index { indexes :name }
364
+ Beta.define_index { indexes :name }
365
+ end
366
+
367
+ it "should return values with the expected offset" do
368
+ person = Person.find(:first)
369
+ model_count = ThinkingSphinx.context.indexed_models.length
370
+ Person.stub!(:sphinx_offset => 3)
371
+
372
+ (person.id * model_count + 3).should == person.sphinx_document_id
373
+ end
374
+ end
375
+
376
+ describe '#primary_key_for_sphinx' do
377
+ before :each do
378
+ @person = Person.find(:first)
379
+ end
380
+
381
+ after :each do
382
+ Person.clear_primary_key_for_sphinx
383
+ end
384
+
385
+ after :each do
386
+ Person.set_sphinx_primary_key nil
387
+ end
388
+
389
+ it "should return the id by default" do
390
+ @person.primary_key_for_sphinx.should == @person.id
391
+ end
392
+
393
+ it "should use the sphinx primary key to determine the value" do
394
+ Person.set_sphinx_primary_key :first_name
395
+ @person.primary_key_for_sphinx.should == @person.first_name
396
+ end
397
+
398
+ it "should not use accessor methods but the attributes hash" do
399
+ id = @person.id
400
+ @person.stub!(:id => 'unique_hash')
401
+ @person.primary_key_for_sphinx.should == id
402
+ end
403
+
404
+ it "should be inherited by subclasses" do
405
+ Person.set_sphinx_primary_key :first_name
406
+ Parent.superclass.custom_primary_key_for_sphinx?
407
+ Parent.primary_key_for_sphinx.should == Person.primary_key_for_sphinx
408
+ end
409
+ end
410
+
411
+ describe '#types_for_sphinx' do
412
+ after :each do
413
+ Person.set_sphinx_types nil
414
+ end
415
+
416
+ it "should return nil by default" do
417
+ Person.sphinx_types.should == nil
418
+ end
419
+
420
+ it "should return the specified value" do
421
+ Person.set_sphinx_types %w(Person Parent)
422
+ Person.sphinx_types.should == %w(Person Parent)
423
+ end
424
+ end
425
+
426
+ describe '.sphinx_index_names' do
427
+ it "should return the core index" do
428
+ Alpha.define_index { indexes :name }
429
+ Alpha.define_indexes
430
+ Alpha.sphinx_index_names.should == ['alpha_core']
431
+ end
432
+
433
+ it "should return the delta index if enabled" do
434
+ Beta.define_index {
435
+ indexes :name
436
+ set_property :delta => true
437
+ }
438
+ Beta.define_indexes
439
+
440
+ Beta.sphinx_index_names.should == ['beta_core', 'beta_delta']
441
+ end
442
+
443
+ it "should return the superclass with an index definition" do
444
+ Parent.sphinx_index_names.should == ['person_core', 'person_delta']
445
+ end
446
+ end
447
+
448
+ describe '.indexed_by_sphinx?' do
449
+ it "should return true if there is at least one index on the model" do
450
+ Alpha.define_index { indexes :name }
451
+ Alpha.define_indexes
452
+
453
+ Alpha.should be_indexed_by_sphinx
454
+ end
455
+
456
+ it "should return false if there are no indexes on the model" do
457
+ Gamma.should_not be_indexed_by_sphinx
458
+ end
459
+ end
460
+
461
+ describe '.delta_indexed_by_sphinx?' do
462
+ it "should return true if there is at least one delta index on the model" do
463
+ Beta.define_index {
464
+ indexes :name
465
+ set_property :delta => true
466
+ }
467
+ Beta.define_indexes
468
+
469
+ Beta.should be_delta_indexed_by_sphinx
470
+ end
471
+
472
+ it "should return false if there are no delta indexes on the model" do
473
+ Alpha.define_index { indexes :name }
474
+ Alpha.define_indexes
475
+
476
+ Alpha.should_not be_delta_indexed_by_sphinx
477
+ end
478
+ end
479
+
480
+ describe '.delete_in_index' do
481
+ before :each do
482
+ @client = stub('client')
483
+ ThinkingSphinx.stub!(:sphinx_running? => true)
484
+ ThinkingSphinx::Configuration.instance.stub!(:client => @client)
485
+ end
486
+
487
+ it "should direct the update to the supplied index" do
488
+ @client.should_receive(:update) do |index, attributes, values|
489
+ index.should == 'custom_index_core'
490
+ end
491
+
492
+ Alpha.delete_in_index('custom_index_core', 42)
493
+ end
494
+
495
+ it "should set the sphinx_deleted flag to true" do
496
+ @client.should_receive(:update) do |index, attributes, values|
497
+ attributes.should == ['sphinx_deleted']
498
+ values.should == {42 => [1]}
499
+ end
500
+
501
+ Alpha.delete_in_index('alpha_core', 42)
502
+ end
503
+ end
504
+
505
+ describe '.core_index_names' do
506
+ it "should return each index's core name" do
507
+ Alpha.define_index('foo') { indexes :name }
508
+ Alpha.define_index('bar') { indexes :name }
509
+ Alpha.define_indexes
510
+
511
+ Alpha.core_index_names.should == ['foo_core', 'bar_core']
512
+ end
513
+ end
514
+
515
+ describe '.delta_index_names' do
516
+ it "should return index delta names, for indexes with deltas enabled" do
517
+ Alpha.define_index('foo') { indexes :name }
518
+ Alpha.define_index('bar') { indexes :name }
519
+ Alpha.define_indexes
520
+ Alpha.sphinx_indexes.first.delta_object = stub('delta')
521
+
522
+ Alpha.delta_index_names.should == ['foo_delta']
523
+ end
524
+ end
525
+
526
+ describe '.sphinx_offset' do
527
+ before :each do
528
+ @context = ThinkingSphinx.context
529
+ end
530
+
531
+ it "should return the index of the model's name in all known indexed models" do
532
+ @context.stub!(:indexed_models => ['Alpha', 'Beta'])
533
+
534
+ Alpha.sphinx_offset.should == 0
535
+ Beta.sphinx_offset.should == 1
536
+ end
537
+
538
+ it "should ignore classes that have indexed superclasses" do
539
+ @context.stub!(:indexed_models => ['Alpha', 'Parent', 'Person'])
540
+
541
+ Person.sphinx_offset.should == 1
542
+ end
543
+
544
+ it "should respect first known indexed parents" do
545
+ @context.stub!(:indexed_models => ['Alpha', 'Parent', 'Person'])
546
+
547
+ Parent.sphinx_offset.should == 1
548
+ end
549
+ end
550
+
551
+ describe '.has_sphinx_indexes?' do
552
+ it "should return true if there are sphinx indexes defined" do
553
+ Alpha.sphinx_indexes.replace [stub('index')]
554
+ Alpha.sphinx_index_blocks.replace []
555
+
556
+ Alpha.should have_sphinx_indexes
557
+ end
558
+
559
+ it "should return true if there are sphinx index blocks defined" do
560
+ Alpha.sphinx_indexes.replace []
561
+ Alpha.sphinx_index_blocks.replace [stub('lambda')]
562
+
563
+ Alpha.should have_sphinx_indexes
564
+ end
565
+
566
+ it "should return false if there are no sphinx indexes or blocks" do
567
+ Alpha.sphinx_indexes.clear
568
+ Alpha.sphinx_index_blocks.clear
569
+
570
+ Alpha.should_not have_sphinx_indexes
571
+ end
572
+ end
573
+ end
@@ -0,0 +1,145 @@
1
+ require 'spec_helper'
2
+
3
+ class CustomAdapter < ThinkingSphinx::AbstractAdapter
4
+ #
5
+ end
6
+
7
+ describe ThinkingSphinx::AbstractAdapter do
8
+ describe '.detect' do
9
+ let(:model) { stub('model') }
10
+
11
+ it "returns a MysqlAdapter object for :mysql" do
12
+ ThinkingSphinx::AbstractAdapter.stub(:adapter_for_model => :mysql)
13
+
14
+ adapter = ThinkingSphinx::AbstractAdapter.detect(model)
15
+ adapter.should be_a(ThinkingSphinx::MysqlAdapter)
16
+ end
17
+
18
+ it "returns a PostgreSQLAdapter object for :postgresql" do
19
+ ThinkingSphinx::AbstractAdapter.stub(:adapter_for_model => :postgresql)
20
+
21
+ adapter = ThinkingSphinx::AbstractAdapter.detect(model)
22
+ adapter.should be_a(ThinkingSphinx::PostgreSQLAdapter)
23
+ end
24
+
25
+ it "instantiates the provided class if one is provided" do
26
+ ThinkingSphinx::AbstractAdapter.stub(:adapter_for_model => CustomAdapter)
27
+ CustomAdapter.should_receive(:new).and_return(stub('adapter'))
28
+
29
+ ThinkingSphinx::AbstractAdapter.detect(model)
30
+ end
31
+
32
+ it "raises an exception for other responses" do
33
+ ThinkingSphinx::AbstractAdapter.stub(:adapter_for_model => :sqlite)
34
+
35
+ lambda {
36
+ ThinkingSphinx::AbstractAdapter.detect(model)
37
+ }.should raise_error
38
+ end
39
+ end
40
+
41
+ describe '.adapter_for_model' do
42
+ let(:model) { stub('model') }
43
+
44
+ after :each do
45
+ ThinkingSphinx.database_adapter = nil
46
+ end
47
+
48
+ it "translates strings to symbols" do
49
+ ThinkingSphinx.database_adapter = 'foo'
50
+
51
+ ThinkingSphinx::AbstractAdapter.adapter_for_model(model).should == :foo
52
+ end
53
+
54
+ it "passes through symbols unchanged" do
55
+ ThinkingSphinx.database_adapter = :bar
56
+
57
+ ThinkingSphinx::AbstractAdapter.adapter_for_model(model).should == :bar
58
+ end
59
+
60
+ it "returns standard_adapter_for_model if database_adapter is not set" do
61
+ ThinkingSphinx.database_adapter = nil
62
+ ThinkingSphinx::AbstractAdapter.stub!(:standard_adapter_for_model => :baz)
63
+
64
+ ThinkingSphinx::AbstractAdapter.adapter_for_model(model).should == :baz
65
+ end
66
+
67
+ it "calls the lambda and returns it if one is provided" do
68
+ ThinkingSphinx.database_adapter = lambda { |model| :foo }
69
+
70
+ ThinkingSphinx::AbstractAdapter.adapter_for_model(model).should == :foo
71
+ end
72
+ end
73
+
74
+ describe '.standard_adapter_for_model' do
75
+ let(:klass) { stub('connection class') }
76
+ let(:connection) { stub('connection', :class => klass) }
77
+ let(:model) { stub('model', :connection => connection) }
78
+
79
+ it "translates a normal MySQL adapter" do
80
+ klass.stub(:name => 'ActiveRecord::ConnectionAdapters::MysqlAdapter')
81
+
82
+ ThinkingSphinx::AbstractAdapter.standard_adapter_for_model(model).
83
+ should == :mysql
84
+ end
85
+
86
+ it "translates a MySQL plus adapter" do
87
+ klass.stub(:name => 'ActiveRecord::ConnectionAdapters::MysqlplusAdapter')
88
+
89
+ ThinkingSphinx::AbstractAdapter.standard_adapter_for_model(model).
90
+ should == :mysql
91
+ end
92
+
93
+ it "translates a MySQL2 adapter" do
94
+ klass.stub(:name => 'ActiveRecord::ConnectionAdapters::Mysql2Adapter')
95
+
96
+ ThinkingSphinx::AbstractAdapter.standard_adapter_for_model(model).
97
+ should == :mysql
98
+ end
99
+
100
+ it "translates a NullDB adapter to MySQL" do
101
+ klass.stub(:name => 'ActiveRecord::ConnectionAdapters::NullDBAdapter')
102
+
103
+ ThinkingSphinx::AbstractAdapter.standard_adapter_for_model(model).
104
+ should == :mysql
105
+ end
106
+
107
+ it "translates a normal PostgreSQL adapter" do
108
+ klass.stub(:name => 'ActiveRecord::ConnectionAdapters::PostgreSQLAdapter')
109
+
110
+ ThinkingSphinx::AbstractAdapter.standard_adapter_for_model(model).
111
+ should == :postgresql
112
+ end
113
+
114
+ it "translates a JDBC MySQL adapter to MySQL" do
115
+ klass.stub(:name => 'ActiveRecord::ConnectionAdapters::JdbcAdapter')
116
+ connection.stub(:config => {:adapter => 'jdbcmysql'})
117
+
118
+ ThinkingSphinx::AbstractAdapter.standard_adapter_for_model(model).
119
+ should == :mysql
120
+ end
121
+
122
+ it "translates a JDBC PostgreSQL adapter to PostgreSQL" do
123
+ klass.stub(:name => 'ActiveRecord::ConnectionAdapters::JdbcAdapter')
124
+ connection.stub(:config => {:adapter => 'jdbcpostgresql'})
125
+
126
+ ThinkingSphinx::AbstractAdapter.standard_adapter_for_model(model).
127
+ should == :postgresql
128
+ end
129
+
130
+ it "returns other JDBC adapters without translation" do
131
+ klass.stub(:name => 'ActiveRecord::ConnectionAdapters::JdbcAdapter')
132
+ connection.stub(:config => {:adapter => 'jdbcmssql'})
133
+
134
+ ThinkingSphinx::AbstractAdapter.standard_adapter_for_model(model).
135
+ should == :jdbcmssql
136
+ end
137
+
138
+ it "returns other unknown adapters without translation" do
139
+ klass.stub(:name => 'ActiveRecord::ConnectionAdapters::FooAdapter')
140
+
141
+ ThinkingSphinx::AbstractAdapter.standard_adapter_for_model(model).
142
+ should == 'ActiveRecord::ConnectionAdapters::FooAdapter'
143
+ end
144
+ end
145
+ end