thinking-sphinx 3.1.0 → 3.1.1
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.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/.travis.yml +4 -7
- data/HISTORY +27 -0
- data/README.textile +38 -218
- data/gemfiles/rails_3_2.gemfile +2 -3
- data/gemfiles/rails_4_0.gemfile +2 -3
- data/gemfiles/rails_4_1.gemfile +2 -3
- data/lib/thinking_sphinx.rb +1 -0
- data/lib/thinking_sphinx/active_record.rb +1 -0
- data/lib/thinking_sphinx/active_record/association_proxy.rb +1 -0
- data/lib/thinking_sphinx/active_record/association_proxy/attribute_finder.rb +5 -10
- data/lib/thinking_sphinx/active_record/association_proxy/attribute_matcher.rb +38 -0
- data/lib/thinking_sphinx/active_record/attribute/type.rb +19 -8
- data/lib/thinking_sphinx/active_record/base.rb +3 -1
- data/lib/thinking_sphinx/active_record/callbacks/delta_callbacks.rb +1 -1
- data/lib/thinking_sphinx/active_record/callbacks/update_callbacks.rb +4 -1
- data/lib/thinking_sphinx/active_record/index.rb +4 -4
- data/lib/thinking_sphinx/active_record/property_query.rb +57 -27
- data/lib/thinking_sphinx/active_record/simple_many_query.rb +35 -0
- data/lib/thinking_sphinx/capistrano/v3.rb +11 -10
- data/lib/thinking_sphinx/configuration.rb +23 -6
- data/lib/thinking_sphinx/connection.rb +8 -9
- data/lib/thinking_sphinx/errors.rb +7 -2
- data/lib/thinking_sphinx/facet.rb +2 -2
- data/lib/thinking_sphinx/facet_search.rb +4 -2
- data/lib/thinking_sphinx/logger.rb +7 -0
- data/lib/thinking_sphinx/masks/group_enumerators_mask.rb +4 -4
- data/lib/thinking_sphinx/middlewares/inquirer.rb +2 -2
- data/lib/thinking_sphinx/middlewares/sphinxql.rb +6 -2
- data/lib/thinking_sphinx/middlewares/stale_id_filter.rb +1 -1
- data/lib/thinking_sphinx/real_time/callbacks/real_time_callbacks.rb +6 -1
- data/lib/thinking_sphinx/real_time/property.rb +2 -1
- data/lib/thinking_sphinx/real_time/transcriber.rb +7 -3
- data/lib/thinking_sphinx/search.rb +14 -4
- data/lib/thinking_sphinx/search/context.rb +0 -6
- data/lib/thinking_sphinx/test.rb +11 -2
- data/lib/thinking_sphinx/wildcard.rb +7 -1
- data/spec/acceptance/association_scoping_spec.rb +55 -15
- data/spec/acceptance/geosearching_spec.rb +8 -2
- data/spec/acceptance/real_time_updates_spec.rb +9 -0
- data/spec/acceptance/specifying_sql_spec.rb +31 -17
- data/spec/internal/app/indices/car_index.rb +5 -0
- data/spec/internal/app/models/car.rb +5 -0
- data/spec/internal/app/models/category.rb +2 -1
- data/spec/internal/app/models/manufacturer.rb +3 -0
- data/spec/internal/db/schema.rb +9 -0
- data/spec/thinking_sphinx/active_record/attribute/type_spec.rb +7 -0
- data/spec/thinking_sphinx/active_record/base_spec.rb +17 -0
- data/spec/thinking_sphinx/active_record/callbacks/update_callbacks_spec.rb +2 -1
- data/spec/thinking_sphinx/configuration_spec.rb +40 -2
- data/spec/thinking_sphinx/errors_spec.rb +21 -0
- data/spec/thinking_sphinx/facet_search_spec.rb +6 -6
- data/spec/thinking_sphinx/middlewares/inquirer_spec.rb +0 -4
- data/spec/thinking_sphinx/middlewares/sphinxql_spec.rb +25 -0
- data/spec/thinking_sphinx/middlewares/stale_id_filter_spec.rb +2 -2
- data/spec/thinking_sphinx/real_time/callbacks/real_time_callbacks_spec.rb +2 -1
- data/spec/thinking_sphinx/search_spec.rb +56 -0
- data/spec/thinking_sphinx/wildcard_spec.rb +5 -0
- data/thinking-sphinx.gemspec +2 -2
- metadata +40 -32
- data/sketchpad.rb +0 -58
- data/spec/internal/log/.gitignore +0 -1
@@ -175,7 +175,7 @@ describe 'separate queries for MVAs' do
|
|
175
175
|
declaration, query = attribute.split(/;\s+/)
|
176
176
|
|
177
177
|
declaration.should == 'uint tag_ids from query'
|
178
|
-
query.should match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .taggings.\..tag_id. AS .tag_ids. FROM .taggings.\s
|
178
|
+
query.should match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .taggings.\..tag_id. AS .tag_ids. FROM .taggings.\s? WHERE \(.taggings.\..article_id. IS NOT NULL\)$/)
|
179
179
|
end
|
180
180
|
|
181
181
|
it "generates a SQL query with joins when appropriate for MVAs" do
|
@@ -191,7 +191,7 @@ describe 'separate queries for MVAs' do
|
|
191
191
|
declaration, query = attribute.split(/;\s+/)
|
192
192
|
|
193
193
|
declaration.should == 'uint tag_ids from query'
|
194
|
-
query.should match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..id. AS .tag_ids. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id
|
194
|
+
query.should match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..id. AS .tag_ids. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id. WHERE \(.taggings.\..article_id. IS NOT NULL\)\s?$/)
|
195
195
|
end
|
196
196
|
|
197
197
|
it "respects has_many :through joins for MVA queries" do
|
@@ -207,7 +207,7 @@ describe 'separate queries for MVAs' do
|
|
207
207
|
declaration, query = attribute.split(/;\s+/)
|
208
208
|
|
209
209
|
declaration.should == 'uint tag_ids from query'
|
210
|
-
query.should match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..id. AS .tag_ids. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id
|
210
|
+
query.should match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..id. AS .tag_ids. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id. WHERE \(.taggings.\..article_id. IS NOT NULL\)\s?$/)
|
211
211
|
end
|
212
212
|
|
213
213
|
it "can handle multiple joins for MVA queries" do
|
@@ -225,15 +225,10 @@ describe 'separate queries for MVAs' do
|
|
225
225
|
declaration, query = attribute.split(/;\s+/)
|
226
226
|
|
227
227
|
declaration.should == 'uint tag_ids from query'
|
228
|
-
query.should match(/^SELECT .articles.\..user_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..id. AS .tag_ids. FROM .articles. INNER JOIN .taggings. ON .taggings.\..article_id. = .articles.\..id. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id
|
228
|
+
query.should match(/^SELECT .articles.\..user_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..id. AS .tag_ids. FROM .articles. INNER JOIN .taggings. ON .taggings.\..article_id. = .articles.\..id. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id. WHERE \(.articles.\..user_id. IS NOT NULL\)\s?$/)
|
229
229
|
end
|
230
230
|
|
231
|
-
it "can handle HABTM joins for MVA queries" do
|
232
|
-
pending "Efficient HABTM queries are tricky."
|
233
|
-
# We don't really have any need for other tables, but that doesn't lend
|
234
|
-
# itself nicely to Thinking Sphinx's DSL, nor ARel SQL generation. This is
|
235
|
-
# a low priority - manual SQL queries for this situation may work better.
|
236
|
-
|
231
|
+
it "can handle simple HABTM joins for MVA queries" do
|
237
232
|
index = ThinkingSphinx::ActiveRecord::Index.new(:book)
|
238
233
|
index.definition_block = Proc.new {
|
239
234
|
indexes title
|
@@ -248,7 +243,7 @@ describe 'separate queries for MVAs' do
|
|
248
243
|
declaration, query = attribute.split(/;\s+/)
|
249
244
|
|
250
245
|
declaration.should == 'uint genre_ids from query'
|
251
|
-
query.should match(/^SELECT .books_genres.\..book_id. \* #{count} \+ #{source.offset} AS .id., .
|
246
|
+
query.should match(/^SELECT .books_genres.\..book_id. \* #{count} \+ #{source.offset} AS .id., .books_genres.\..genre_id. AS .genre_ids. FROM .books_genres.\s?$/)
|
252
247
|
end
|
253
248
|
|
254
249
|
it "generates an appropriate range SQL queries for an MVA" do
|
@@ -264,7 +259,7 @@ describe 'separate queries for MVAs' do
|
|
264
259
|
declaration, query, range = attribute.split(/;\s+/)
|
265
260
|
|
266
261
|
declaration.should == 'uint tag_ids from ranged-query'
|
267
|
-
query.should match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .taggings.\..tag_id. AS .tag_ids. FROM .taggings. \s?WHERE \(.taggings.\..article_id. BETWEEN \$start AND \$end\)$/)
|
262
|
+
query.should match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .taggings.\..tag_id. AS .tag_ids. FROM .taggings. \s?WHERE \(.taggings.\..article_id. BETWEEN \$start AND \$end\) AND \(.taggings.\..article_id. IS NOT NULL\)$/)
|
268
263
|
range.should match(/^SELECT MIN\(.taggings.\..article_id.\), MAX\(.taggings.\..article_id.\) FROM .taggings.\s?$/)
|
269
264
|
end
|
270
265
|
|
@@ -281,10 +276,29 @@ describe 'separate queries for MVAs' do
|
|
281
276
|
declaration, query, range = attribute.split(/;\s+/)
|
282
277
|
|
283
278
|
declaration.should == 'uint tag_ids from ranged-query'
|
284
|
-
query.should match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..id. AS .tag_ids. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id. \s?WHERE \(.taggings.\..article_id. BETWEEN \$start AND \$end\)$/)
|
279
|
+
query.should match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..id. AS .tag_ids. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id. \s?WHERE \(.taggings.\..article_id. BETWEEN \$start AND \$end\) AND \(.taggings.\..article_id. IS NOT NULL\)$/)
|
285
280
|
range.should match(/^SELECT MIN\(.taggings.\..article_id.\), MAX\(.taggings.\..article_id.\) FROM .taggings.\s?$/)
|
286
281
|
end
|
287
282
|
|
283
|
+
it "can handle ranged queries for simple HABTM joins for MVA queries" do
|
284
|
+
index = ThinkingSphinx::ActiveRecord::Index.new(:book)
|
285
|
+
index.definition_block = Proc.new {
|
286
|
+
indexes title
|
287
|
+
has genres.id, :as => :genre_ids, :source => :ranged_query
|
288
|
+
}
|
289
|
+
index.render
|
290
|
+
source = index.sources.first
|
291
|
+
|
292
|
+
attribute = source.sql_attr_multi.detect { |attribute|
|
293
|
+
attribute[/genre_ids/]
|
294
|
+
}
|
295
|
+
declaration, query, range = attribute.split(/;\s+/)
|
296
|
+
|
297
|
+
declaration.should == 'uint genre_ids from ranged-query'
|
298
|
+
query.should match(/^SELECT .books_genres.\..book_id. \* #{count} \+ #{source.offset} AS .id., .books_genres.\..genre_id. AS .genre_ids. FROM .books_genres. WHERE \(.books_genres.\..book_id. BETWEEN \$start AND \$end\)$/)
|
299
|
+
range.should match(/^SELECT MIN\(.books_genres.\..book_id.\), MAX\(.books_genres.\..book_id.\) FROM .books_genres.$/)
|
300
|
+
end
|
301
|
+
|
288
302
|
it "respects custom SQL snippets as the query value" do
|
289
303
|
index.definition_block = Proc.new {
|
290
304
|
indexes title
|
@@ -355,7 +369,7 @@ describe 'separate queries for field' do
|
|
355
369
|
declaration, query = field.split(/;\s+/)
|
356
370
|
|
357
371
|
declaration.should == 'tags from query'
|
358
|
-
query.should match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..name. AS .tags. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id.\s? ORDER BY .taggings.\..article_id. ASC\s?$/)
|
372
|
+
query.should match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..name. AS .tags. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id.\s? WHERE \(.taggings.\..article_id. IS NOT NULL\)\s? ORDER BY .taggings.\..article_id. ASC\s?$/)
|
359
373
|
end
|
360
374
|
|
361
375
|
it "respects has_many :through joins for MVF queries" do
|
@@ -368,7 +382,7 @@ describe 'separate queries for field' do
|
|
368
382
|
declaration, query = field.split(/;\s+/)
|
369
383
|
|
370
384
|
declaration.should == 'tags from query'
|
371
|
-
query.should match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..name. AS .tags. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id.\s? ORDER BY .taggings.\..article_id. ASC\s?$/)
|
385
|
+
query.should match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..name. AS .tags. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id.\s? WHERE \(.taggings.\..article_id. IS NOT NULL\)\s? ORDER BY .taggings.\..article_id. ASC\s?$/)
|
372
386
|
end
|
373
387
|
|
374
388
|
it "can handle multiple joins for MVF queries" do
|
@@ -383,7 +397,7 @@ describe 'separate queries for field' do
|
|
383
397
|
declaration, query = field.split(/;\s+/)
|
384
398
|
|
385
399
|
declaration.should == 'tags from query'
|
386
|
-
query.should match(/^SELECT .articles.\..user_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..name. AS .tags. FROM .articles. INNER JOIN .taggings. ON .taggings.\..article_id. = .articles.\..id. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id.\s? ORDER BY .articles.\..user_id. ASC\s?$/)
|
400
|
+
query.should match(/^SELECT .articles.\..user_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..name. AS .tags. FROM .articles. INNER JOIN .taggings. ON .taggings.\..article_id. = .articles.\..id. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id.\s? WHERE \(.articles.\..user_id. IS NOT NULL\)\s? ORDER BY .articles.\..user_id. ASC\s?$/)
|
387
401
|
end
|
388
402
|
|
389
403
|
it "generates a SQL query with joins when appropriate for MVFs" do
|
@@ -396,7 +410,7 @@ describe 'separate queries for field' do
|
|
396
410
|
declaration, query, range = field.split(/;\s+/)
|
397
411
|
|
398
412
|
declaration.should == 'tags from ranged-query'
|
399
|
-
query.should match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..name. AS .tags. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id. \s?WHERE \(.taggings.\..article_id. BETWEEN \$start AND \$end\)\s? ORDER BY .taggings.\..article_id. ASC$/)
|
413
|
+
query.should match(/^SELECT .taggings.\..article_id. \* #{count} \+ #{source.offset} AS .id., .tags.\..name. AS .tags. FROM .taggings. INNER JOIN .tags. ON .tags.\..id. = .taggings.\..tag_id. \s?WHERE \(.taggings.\..article_id. BETWEEN \$start AND \$end\) AND \(.taggings.\..article_id. IS NOT NULL\)\s? ORDER BY .taggings.\..article_id. ASC$/)
|
400
414
|
range.should match(/^SELECT MIN\(.taggings.\..article_id.\), MAX\(.taggings.\..article_id.\) FROM .taggings.\s?$/)
|
401
415
|
end
|
402
416
|
|
data/spec/internal/db/schema.rb
CHANGED
@@ -17,6 +17,15 @@ ActiveRecord::Schema.define do
|
|
17
17
|
t.timestamps
|
18
18
|
end
|
19
19
|
|
20
|
+
create_table(:manufacturers, :force => true) do |t|
|
21
|
+
t.string :name
|
22
|
+
end
|
23
|
+
|
24
|
+
create_table(:cars, :force => true) do |t|
|
25
|
+
t.integer :manufacturer_id
|
26
|
+
t.string :name
|
27
|
+
end
|
28
|
+
|
20
29
|
create_table(:books, :force => true) do |t|
|
21
30
|
t.string :title
|
22
31
|
t.string :author
|
@@ -4,6 +4,7 @@ module ThinkingSphinx
|
|
4
4
|
end
|
5
5
|
end
|
6
6
|
|
7
|
+
require 'thinking_sphinx/errors'
|
7
8
|
require 'thinking_sphinx/active_record/attribute/type'
|
8
9
|
|
9
10
|
describe ThinkingSphinx::ActiveRecord::Attribute::Type do
|
@@ -143,5 +144,11 @@ describe ThinkingSphinx::ActiveRecord::Attribute::Type do
|
|
143
144
|
|
144
145
|
type.type.should == :timestamp
|
145
146
|
end
|
147
|
+
|
148
|
+
it 'raises an error if the database column does not exist' do
|
149
|
+
model.columns.clear
|
150
|
+
|
151
|
+
expect { type.type }.to raise_error(ThinkingSphinx::MissingColumnError)
|
152
|
+
end
|
146
153
|
end
|
147
154
|
end
|
@@ -48,6 +48,12 @@ describe ThinkingSphinx::ActiveRecord::Base do
|
|
48
48
|
end
|
49
49
|
|
50
50
|
describe '.search' do
|
51
|
+
let(:stack) { double('stack', :call => true) }
|
52
|
+
|
53
|
+
before :each do
|
54
|
+
stub_const 'ThinkingSphinx::Middlewares::DEFAULT', stack
|
55
|
+
end
|
56
|
+
|
51
57
|
it "returns a new search object" do
|
52
58
|
model.search.should be_a(ThinkingSphinx::Search)
|
53
59
|
end
|
@@ -60,6 +66,17 @@ describe ThinkingSphinx::ActiveRecord::Base do
|
|
60
66
|
model.search('pancakes').options[:classes].should == [model]
|
61
67
|
end
|
62
68
|
|
69
|
+
it "passes through options to the search object" do
|
70
|
+
model.search('pancakes', populate: true).
|
71
|
+
options[:populate].should be_true
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should automatically populate when :populate is set to true" do
|
75
|
+
stack.should_receive(:call).and_return(true)
|
76
|
+
|
77
|
+
model.search('pancakes', populate: true)
|
78
|
+
end
|
79
|
+
|
63
80
|
it "merges the :classes option with the model" do
|
64
81
|
model.search('pancakes', :classes => [sub_model]).
|
65
82
|
options[:classes].should == [sub_model, model]
|
@@ -20,7 +20,8 @@ describe ThinkingSphinx::ActiveRecord::Callbacks::UpdateCallbacks do
|
|
20
20
|
:indices_for_references => [index]) }
|
21
21
|
let(:connection) { double('connection', :execute => '') }
|
22
22
|
let(:index) { double 'index', :name => 'article_core',
|
23
|
-
:sources => [source], :document_id_for_key => 3, :distributed? => false
|
23
|
+
:sources => [source], :document_id_for_key => 3, :distributed? => false,
|
24
|
+
:type => 'plain'}
|
24
25
|
let(:source) { double('source', :attributes => []) }
|
25
26
|
|
26
27
|
before :each do
|
@@ -128,6 +128,10 @@ describe ThinkingSphinx::Configuration do
|
|
128
128
|
end
|
129
129
|
|
130
130
|
describe '#initialize' do
|
131
|
+
before :each do
|
132
|
+
FileUtils.rm_rf Rails.root.join('log')
|
133
|
+
end
|
134
|
+
|
131
135
|
it "sets the daemon pid file within log for the Rails app" do
|
132
136
|
config.searchd.pid_file.
|
133
137
|
should == File.join(Rails.root, 'log', 'test.sphinx.pid')
|
@@ -154,6 +158,19 @@ describe ThinkingSphinx::Configuration do
|
|
154
158
|
|
155
159
|
config.searchd.workers.should == 'none'
|
156
160
|
end
|
161
|
+
|
162
|
+
it 'adds settings to indexer without common section' do
|
163
|
+
write_configuration 'lemmatizer_base' => 'foo'
|
164
|
+
|
165
|
+
expect(config.indexer.lemmatizer_base).to eq('foo')
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'adds settings to common section if requested' do
|
169
|
+
write_configuration 'lemmatizer_base' => 'foo',
|
170
|
+
'common_sphinx_configuration' => true
|
171
|
+
|
172
|
+
expect(config.common.lemmatizer_base).to eq('foo')
|
173
|
+
end
|
157
174
|
end
|
158
175
|
|
159
176
|
describe '#next_offset' do
|
@@ -176,6 +193,13 @@ describe ThinkingSphinx::Configuration do
|
|
176
193
|
end
|
177
194
|
|
178
195
|
describe '#preload_indices' do
|
196
|
+
let(:distributor) { double :reconcile => true }
|
197
|
+
|
198
|
+
before :each do
|
199
|
+
stub_const 'ThinkingSphinx::Configuration::DistributedIndices',
|
200
|
+
double(:new => distributor)
|
201
|
+
end
|
202
|
+
|
179
203
|
it "searches each index path for ruby files" do
|
180
204
|
config.index_paths.replace ['/path/to/indices', '/path/to/other/indices']
|
181
205
|
|
@@ -217,6 +241,20 @@ describe ThinkingSphinx::Configuration do
|
|
217
241
|
config.preload_indices
|
218
242
|
config.preload_indices
|
219
243
|
end
|
244
|
+
|
245
|
+
it 'adds distributed indices' do
|
246
|
+
distributor.should_receive(:reconcile)
|
247
|
+
|
248
|
+
config.preload_indices
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'does not add distributed indices if disabled' do
|
252
|
+
write_configuration('distributed_indices' => false)
|
253
|
+
|
254
|
+
distributor.should_not_receive(:reconcile)
|
255
|
+
|
256
|
+
config.preload_indices
|
257
|
+
end
|
220
258
|
end
|
221
259
|
|
222
260
|
describe '#render' do
|
@@ -373,8 +411,8 @@ describe ThinkingSphinx::Configuration do
|
|
373
411
|
end
|
374
412
|
|
375
413
|
describe '#version' do
|
376
|
-
it "defaults to 2.
|
377
|
-
config.version.should == '2.
|
414
|
+
it "defaults to 2.1.4" do
|
415
|
+
config.version.should == '2.1.4'
|
378
416
|
end
|
379
417
|
|
380
418
|
it "respects supplied YAML versions" do
|
@@ -33,6 +33,27 @@ describe ThinkingSphinx::SphinxError do
|
|
33
33
|
should be_a(ThinkingSphinx::ConnectionError)
|
34
34
|
end
|
35
35
|
|
36
|
+
it 'prefixes the connection error message' do
|
37
|
+
error.stub :message => "Can't connect to MySQL server on '127.0.0.1' (61)"
|
38
|
+
|
39
|
+
ThinkingSphinx::SphinxError.new_from_mysql(error).message.
|
40
|
+
should == "Error connecting to Sphinx via the MySQL protocol. Can't connect to MySQL server on '127.0.0.1' (61)"
|
41
|
+
end
|
42
|
+
|
43
|
+
it "translates jdbc connection errors" do
|
44
|
+
error.stub :message => "Communications link failure"
|
45
|
+
|
46
|
+
ThinkingSphinx::SphinxError.new_from_mysql(error).
|
47
|
+
should be_a(ThinkingSphinx::ConnectionError)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'prefixes the jdbc connection error message' do
|
51
|
+
error.stub :message => "Communications link failure"
|
52
|
+
|
53
|
+
ThinkingSphinx::SphinxError.new_from_mysql(error).message.
|
54
|
+
should == "Error connecting to Sphinx via the MySQL protocol. Communications link failure"
|
55
|
+
end
|
56
|
+
|
36
57
|
it "defaults to sphinx errors" do
|
37
58
|
error.stub :message => 'index foo: unknown error: something is wrong'
|
38
59
|
|
@@ -26,12 +26,12 @@ describe ThinkingSphinx::FacetSearch do
|
|
26
26
|
DumbSearch = ::Struct.new(:query, :options) do
|
27
27
|
def raw
|
28
28
|
[{
|
29
|
-
'sphinx_internal_class'
|
30
|
-
'price_bracket'
|
31
|
-
'tag_ids'
|
32
|
-
'category_id'
|
33
|
-
|
34
|
-
|
29
|
+
'sphinx_internal_class' => 'Foo',
|
30
|
+
'price_bracket' => 3,
|
31
|
+
'tag_ids' => '1,2',
|
32
|
+
'category_id' => 11,
|
33
|
+
'sphinx_internal_count' => 5,
|
34
|
+
'sphinx_internal_group' => 2
|
35
35
|
}]
|
36
36
|
end
|
37
37
|
end
|
@@ -15,10 +15,6 @@ describe ThinkingSphinx::Middlewares::Inquirer do
|
|
15
15
|
:results => [[:raw], [{'Variable_name' => 'meta', 'Value' => 'value'}]]) }
|
16
16
|
|
17
17
|
before :each do
|
18
|
-
context.stub(:log) do |notification, message, &block|
|
19
|
-
block.call unless block.nil?
|
20
|
-
end
|
21
|
-
|
22
18
|
batch_class = double
|
23
19
|
batch_class.stub(:new).and_return(batch_inquirer)
|
24
20
|
|
@@ -6,6 +6,9 @@ module ActiveRecord
|
|
6
6
|
class Base; end
|
7
7
|
end
|
8
8
|
|
9
|
+
class SphinxQLSubclass
|
10
|
+
end
|
11
|
+
|
9
12
|
require 'active_support/core_ext/module/attribute_accessors'
|
10
13
|
require 'active_support/core_ext/module/delegation'
|
11
14
|
require 'active_support/core_ext/object/blank'
|
@@ -185,6 +188,28 @@ describe ThinkingSphinx::Middlewares::SphinxQL do
|
|
185
188
|
middleware.call [context]
|
186
189
|
end
|
187
190
|
|
191
|
+
it "ignores blank subclasses" do
|
192
|
+
db_connection = double('db connection', :select_values => [''],
|
193
|
+
:schema_cache => double('cache', :table_exists? => false))
|
194
|
+
supermodel = Class.new(ActiveRecord::Base) do
|
195
|
+
def self.name; 'Cat'; end
|
196
|
+
def self.inheritance_column; 'type'; end
|
197
|
+
end
|
198
|
+
supermodel.stub :connection => db_connection, :column_names => ['type']
|
199
|
+
submodel = Class.new(supermodel) do
|
200
|
+
def self.name; 'Lion'; end
|
201
|
+
def self.inheritance_column; 'type'; end
|
202
|
+
def self.table_name; 'cats'; end
|
203
|
+
end
|
204
|
+
submodel.stub :connection => db_connection, :column_names => ['type'],
|
205
|
+
:descendants => []
|
206
|
+
index_set.first.stub :reference => :cat
|
207
|
+
|
208
|
+
search.options[:classes] = [submodel]
|
209
|
+
|
210
|
+
expect { middleware.call [context] }.to_not raise_error
|
211
|
+
end
|
212
|
+
|
188
213
|
it "filters out deleted values by default" do
|
189
214
|
sphinx_sql.should_receive(:where).with(:sphinx_deleted => false).
|
190
215
|
and_return(sphinx_sql)
|
@@ -15,7 +15,7 @@ describe ThinkingSphinx::Middlewares::StaleIdFilter do
|
|
15
15
|
|
16
16
|
describe '#call' do
|
17
17
|
before :each do
|
18
|
-
context.stub :search => search
|
18
|
+
context.stub :search => search
|
19
19
|
end
|
20
20
|
|
21
21
|
context 'one stale ids exception' do
|
@@ -88,4 +88,4 @@ describe ThinkingSphinx::Middlewares::StaleIdFilter do
|
|
88
88
|
end
|
89
89
|
end
|
90
90
|
end
|
91
|
-
end
|
91
|
+
end
|
@@ -5,7 +5,8 @@ describe ThinkingSphinx::RealTime::Callbacks::RealTimeCallbacks do
|
|
5
5
|
ThinkingSphinx::RealTime::Callbacks::RealTimeCallbacks.new :article
|
6
6
|
}
|
7
7
|
let(:instance) { double('instance', :id => 12) }
|
8
|
-
let(:config) { double('config', :indices_for_references => [index]
|
8
|
+
let(:config) { double('config', :indices_for_references => [index],
|
9
|
+
:settings => {}) }
|
9
10
|
let(:index) { double('index', :name => 'my_index', :is_a? => true,
|
10
11
|
:document_id_for_key => 123, :fields => [], :attributes => [],
|
11
12
|
:conditions => []) }
|
@@ -5,6 +5,34 @@ describe ThinkingSphinx::Search do
|
|
5
5
|
let(:context) { {:results => []} }
|
6
6
|
let(:stack) { double('stack', :call => true) }
|
7
7
|
|
8
|
+
let(:pagination_mask_methods) do
|
9
|
+
[:first_page?,
|
10
|
+
:last_page?,
|
11
|
+
:next_page,
|
12
|
+
:next_page?,
|
13
|
+
:page,
|
14
|
+
:per,
|
15
|
+
:previous_page,
|
16
|
+
:total_entries,
|
17
|
+
:total_count,
|
18
|
+
:count,
|
19
|
+
:total_pages,
|
20
|
+
:page_count,
|
21
|
+
:num_pages]
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:scopes_mask_methods) do
|
25
|
+
[:facets,
|
26
|
+
:search,
|
27
|
+
:search_for_ids]
|
28
|
+
end
|
29
|
+
|
30
|
+
let(:group_enumerator_mask_methods) do
|
31
|
+
[:each_with_count,
|
32
|
+
:each_with_group,
|
33
|
+
:each_with_group_and_count]
|
34
|
+
end
|
35
|
+
|
8
36
|
before :each do
|
9
37
|
ThinkingSphinx::Search::Context.stub :new => context
|
10
38
|
|
@@ -141,6 +169,24 @@ describe ThinkingSphinx::Search do
|
|
141
169
|
it "should respond to Search methods" do
|
142
170
|
search.respond_to?(:per_page).should be_true
|
143
171
|
end
|
172
|
+
|
173
|
+
it "should return true for methods delegated to pagination mask by method_missing" do
|
174
|
+
pagination_mask_methods.each do |method|
|
175
|
+
expect(search).to respond_to method
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should return true for methods delegated to scopes mask by method_missing" do
|
180
|
+
scopes_mask_methods.each do |method|
|
181
|
+
expect(search).to respond_to method
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should return true for methods delegated to group enumerators mask by method_missing" do
|
186
|
+
group_enumerator_mask_methods.each do |method|
|
187
|
+
expect(search).to respond_to method
|
188
|
+
end
|
189
|
+
end
|
144
190
|
end
|
145
191
|
|
146
192
|
describe '#to_a' do
|
@@ -153,4 +199,14 @@ describe ThinkingSphinx::Search do
|
|
153
199
|
search.to_a.first.__id__.should == unglazed.__id__
|
154
200
|
end
|
155
201
|
end
|
202
|
+
|
203
|
+
it "correctly handles access to methods delegated to masks through 'method' call" do
|
204
|
+
[
|
205
|
+
pagination_mask_methods,
|
206
|
+
scopes_mask_methods,
|
207
|
+
group_enumerator_mask_methods
|
208
|
+
].flatten.each do |method|
|
209
|
+
expect { search.method method }.to_not raise_exception
|
210
|
+
end
|
211
|
+
end
|
156
212
|
end
|