sunspot 2.1.1 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/sunspot.rb +13 -9
- data/lib/sunspot/dsl.rb +4 -3
- data/lib/sunspot/dsl/fields.rb +11 -16
- data/lib/sunspot/dsl/paginatable.rb +4 -1
- data/lib/sunspot/dsl/spellcheckable.rb +14 -0
- data/lib/sunspot/dsl/standard_query.rb +63 -35
- data/lib/sunspot/field.rb +54 -8
- data/lib/sunspot/field_factory.rb +2 -4
- data/lib/sunspot/indexer.rb +1 -2
- data/lib/sunspot/query.rb +2 -2
- data/lib/sunspot/query/abstract_fulltext.rb +69 -0
- data/lib/sunspot/query/common_query.rb +13 -2
- data/lib/sunspot/query/composite_fulltext.rb +58 -8
- data/lib/sunspot/query/dismax.rb +14 -67
- data/lib/sunspot/query/function_query.rb +1 -2
- data/lib/sunspot/query/geo.rb +1 -1
- data/lib/sunspot/query/join.rb +90 -0
- data/lib/sunspot/query/pagination.rb +12 -4
- data/lib/sunspot/query/restriction.rb +3 -4
- data/lib/sunspot/query/sort.rb +6 -0
- data/lib/sunspot/query/sort_composite.rb +7 -0
- data/lib/sunspot/query/spellcheck.rb +19 -0
- data/lib/sunspot/query/standard_query.rb +24 -2
- data/lib/sunspot/query/text_field_boost.rb +1 -3
- data/lib/sunspot/search/abstract_search.rb +10 -1
- data/lib/sunspot/search/cursor_paginated_collection.rb +32 -0
- data/lib/sunspot/search/paginated_collection.rb +1 -0
- data/lib/sunspot/search/standard_search.rb +71 -3
- data/lib/sunspot/session.rb +6 -6
- data/lib/sunspot/setup.rb +6 -1
- data/lib/sunspot/util.rb +46 -13
- data/lib/sunspot/version.rb +1 -1
- data/spec/api/query/fulltext_examples.rb +150 -1
- data/spec/api/query/geo_examples.rb +2 -6
- data/spec/api/query/join_spec.rb +3 -3
- data/spec/api/query/ordering_pagination_examples.rb +14 -0
- data/spec/api/query/spellcheck_examples.rb +20 -0
- data/spec/api/query/standard_spec.rb +1 -0
- data/spec/api/search/cursor_paginated_collection_spec.rb +35 -0
- data/spec/api/search/paginated_collection_spec.rb +1 -0
- data/spec/api/session_spec.rb +36 -2
- data/spec/integration/spellcheck_spec.rb +74 -0
- data/spec/mocks/connection.rb +5 -3
- data/spec/mocks/photo.rb +12 -4
- data/spec/spec_helper.rb +4 -0
- metadata +24 -5
- checksums.yaml +0 -7
data/lib/sunspot/version.rb
CHANGED
@@ -188,7 +188,8 @@ shared_examples_for 'fulltext query' do
|
|
188
188
|
search Photo do
|
189
189
|
keywords 'great pizza'
|
190
190
|
end
|
191
|
-
|
191
|
+
# Hashes in 1.8 aren't ordered
|
192
|
+
connection.searches.last[:qf].split(" ").sort.join(" ").should eq 'caption_text^1.5 description_text'
|
192
193
|
end
|
193
194
|
|
194
195
|
it 'sets default boost with fields specified in options' do
|
@@ -310,4 +311,152 @@ shared_examples_for 'fulltext query' do
|
|
310
311
|
end
|
311
312
|
end.should raise_error(Sunspot::UnrecognizedFieldError)
|
312
313
|
end
|
314
|
+
|
315
|
+
describe 'connective examples' do
|
316
|
+
it 'creates a disjunction between two subqueries' do
|
317
|
+
search Post do
|
318
|
+
any do
|
319
|
+
fulltext 'keywords1', :fields => :title
|
320
|
+
fulltext 'keyword2', :fields => :body
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
connection.searches.last[:q].should eq "(_query_:\"{!edismax qf='title_text'}keywords1\" OR _query_:\"{!edismax qf='body_textsv'}keyword2\")"
|
325
|
+
end
|
326
|
+
|
327
|
+
it 'creates a conjunction inside of a disjunction' do
|
328
|
+
search do
|
329
|
+
any do
|
330
|
+
fulltext 'keywords1', :fields => :body
|
331
|
+
|
332
|
+
all do
|
333
|
+
fulltext 'keyword2', :fields => :body
|
334
|
+
fulltext 'keyword3', :fields => :body
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
connection.searches.last[:q].should eq "(_query_:\"{!edismax qf='body_textsv'}keywords1\" OR (_query_:\"{!edismax qf='body_textsv'}keyword2\" AND _query_:\"{!edismax qf='body_textsv'}keyword3\"))"
|
340
|
+
end
|
341
|
+
|
342
|
+
it 'does nothing special if #all/#any called from the top level or called multiple times' do
|
343
|
+
search Post do
|
344
|
+
all do
|
345
|
+
fulltext 'keywords1', :fields => :title
|
346
|
+
fulltext 'keyword2', :fields => :body
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
connection.searches.last[:q].should eq "(_query_:\"{!edismax qf='title_text'}keywords1\" AND _query_:\"{!edismax qf='body_textsv'}keyword2\")"
|
351
|
+
end
|
352
|
+
|
353
|
+
it 'does nothing special if #all/#any are mixed and called multiple times' do
|
354
|
+
search Post do
|
355
|
+
all do
|
356
|
+
any do
|
357
|
+
all do
|
358
|
+
fulltext 'keywords1', :fields => :title
|
359
|
+
fulltext 'keyword2', :fields => :body
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
connection.searches.last[:q].should eq "(_query_:\"{!edismax qf='title_text'}keywords1\" AND _query_:\"{!edismax qf='body_textsv'}keyword2\")"
|
366
|
+
|
367
|
+
search Post do
|
368
|
+
any do
|
369
|
+
all do
|
370
|
+
any do
|
371
|
+
fulltext 'keywords1', :fields => :title
|
372
|
+
fulltext 'keyword2', :fields => :body
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
connection.searches.last[:q].should eq "(_query_:\"{!edismax qf='title_text'}keywords1\" OR _query_:\"{!edismax qf='body_textsv'}keyword2\")"
|
379
|
+
end
|
380
|
+
|
381
|
+
it "does not add empty parentheses" do
|
382
|
+
search Post do
|
383
|
+
any do
|
384
|
+
all do
|
385
|
+
end
|
386
|
+
|
387
|
+
any do
|
388
|
+
fulltext 'keywords1', :fields => :title
|
389
|
+
all do
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
395
|
+
connection.searches.last[:q].should eq "_query_:\"{!edismax qf='title_text'}keywords1\""
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
describe "joins" do
|
400
|
+
it "should search by join" do
|
401
|
+
srch = search PhotoContainer do
|
402
|
+
any do
|
403
|
+
fulltext 'keyword1', :fields => :caption
|
404
|
+
fulltext 'keyword2', :fields => :description
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
obj_id = find_ob_id(srch)
|
409
|
+
q_name = "qPhoto#{obj_id}"
|
410
|
+
fq_name = "f#{q_name}"
|
411
|
+
|
412
|
+
connection.searches.last[:q].should eq "(_query_:\"{!join from=photo_container_id_i to=id_i v=$#{q_name} fq=$#{fq_name}}\" OR _query_:\"{!edismax qf='description_text^1.2'}keyword2\")"
|
413
|
+
connection.searches.last[q_name].should eq "_query_:\"{!edismax qf='caption_text'}keyword1\""
|
414
|
+
connection.searches.last[fq_name].should eq "type:Photo"
|
415
|
+
end
|
416
|
+
|
417
|
+
it "should be able to resolve name conflicts with the :prefix option" do
|
418
|
+
srch = search PhotoContainer do
|
419
|
+
any do
|
420
|
+
fulltext 'keyword1', :fields => :description
|
421
|
+
fulltext 'keyword2', :fields => :photo_description
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
obj_id = find_ob_id(srch)
|
426
|
+
q_name = "qPhoto#{obj_id}"
|
427
|
+
fq_name = "f#{q_name}"
|
428
|
+
|
429
|
+
connection.searches.last[:q].should eq "(_query_:\"{!edismax qf='description_text^1.2'}keyword1\" OR _query_:\"{!join from=photo_container_id_i to=id_i v=$#{q_name} fq=$#{fq_name}}\")"
|
430
|
+
connection.searches.last[q_name].should eq "_query_:\"{!edismax qf='description_text'}keyword2\""
|
431
|
+
connection.searches.last[fq_name].should eq "type:Photo"
|
432
|
+
end
|
433
|
+
|
434
|
+
it "should recognize fields when adding from DSL, e.g. when calling boost_fields" do
|
435
|
+
srch = search PhotoContainer do
|
436
|
+
any do
|
437
|
+
fulltext 'keyword1', :fields => [:photo_description, :description] do
|
438
|
+
boost_fields(:photo_description => 1.3, :description => 1.5)
|
439
|
+
end
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
obj_id = find_ob_id(srch)
|
444
|
+
q_name = "qPhoto#{obj_id}"
|
445
|
+
fq_name = "f#{q_name}"
|
446
|
+
|
447
|
+
connection.searches.last[:q].should eq "(_query_:\"{!edismax qf='description_text^1.5'}keyword1\" OR _query_:\"{!join from=photo_container_id_i to=id_i v=$#{q_name} fq=$#{fq_name}}\")"
|
448
|
+
connection.searches.last[q_name].should eq "_query_:\"{!edismax qf='description_text^1.3'}keyword1\""
|
449
|
+
connection.searches.last[fq_name].should eq "type:Photo"
|
450
|
+
end
|
451
|
+
|
452
|
+
private
|
453
|
+
|
454
|
+
def find_ob_id(search)
|
455
|
+
search.query.
|
456
|
+
instance_variable_get("@components").find { |c| c.is_a?(Sunspot::Query::Conjunction) }.
|
457
|
+
instance_variable_get("@components").find { |c| c.is_a?(Sunspot::Query::Disjunction) }.
|
458
|
+
instance_variable_get("@components").find { |c| c.is_a?(Sunspot::Query::Join) }.
|
459
|
+
object_id
|
460
|
+
end
|
461
|
+
end
|
313
462
|
end
|
@@ -41,12 +41,8 @@ shared_examples_for 'geohash query' do
|
|
41
41
|
fulltext 'pizza', :fields => :title
|
42
42
|
with(:coordinates).near(40.7, -73.5)
|
43
43
|
end
|
44
|
-
expected =
|
45
|
-
|
46
|
-
connection.should have_last_search_including(
|
47
|
-
:q,
|
48
|
-
%Q(_query_:"{!edismax qf='title_text'}pizza" (#{build_geo_query}))
|
49
|
-
)
|
44
|
+
expected = %Q((_query_:"{!edismax qf='title_text'}pizza" AND (#{build_geo_query})))
|
45
|
+
connection.should have_last_search_including(:q, expected)
|
50
46
|
end
|
51
47
|
|
52
48
|
private
|
data/spec/api/query/join_spec.rb
CHANGED
@@ -6,7 +6,7 @@ describe 'join' do
|
|
6
6
|
with(:caption, 'blah')
|
7
7
|
end
|
8
8
|
connection.should have_last_search_including(
|
9
|
-
:fq, "{!join from=
|
9
|
+
:fq, "{!join from=photo_container_id_i to=id_i}caption_s:blah")
|
10
10
|
end
|
11
11
|
|
12
12
|
it 'should greater_than search by join' do
|
@@ -14,6 +14,6 @@ describe 'join' do
|
|
14
14
|
with(:photo_rating).greater_than(3)
|
15
15
|
end
|
16
16
|
connection.should have_last_search_including(
|
17
|
-
:fq, "{!join from=
|
17
|
+
:fq, "{!join from=photo_container_id_i to=id_i}average_rating_ft:{3\\.0 TO *}")
|
18
18
|
end
|
19
|
-
end
|
19
|
+
end
|
@@ -46,6 +46,20 @@ shared_examples_for 'sortable query' do
|
|
46
46
|
connection.should have_last_search_with(:rows => 15, :start => 30)
|
47
47
|
end
|
48
48
|
|
49
|
+
it 'paginates with initial cursor' do
|
50
|
+
search do
|
51
|
+
paginate :cursor => '*', :per_page => 15
|
52
|
+
end
|
53
|
+
connection.should have_last_search_with(:rows => 15, :cursorMark => '*')
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'paginates with given cursor' do
|
57
|
+
search do
|
58
|
+
paginate :cursor => 'AoIIP4AAACxQcm9maWxlIDEwMTk='
|
59
|
+
end
|
60
|
+
connection.should have_last_search_with(:cursorMark => 'AoIIP4AAACxQcm9maWxlIDEwMTk=')
|
61
|
+
end
|
62
|
+
|
49
63
|
it 'orders by a single field' do
|
50
64
|
search do
|
51
65
|
order_by :average_rating, :desc
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
shared_examples_for 'spellcheck query' do
|
4
|
+
|
5
|
+
it 'sends spellcheck parameters to solr' do
|
6
|
+
search do
|
7
|
+
spellcheck
|
8
|
+
end
|
9
|
+
connection.should have_last_search_including(:spellcheck, true)
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
it "sends additional spellcheck parameters with camel casing" do
|
14
|
+
search do
|
15
|
+
spellcheck :only_more_popular => true, :count => 5
|
16
|
+
end
|
17
|
+
connection.should have_last_search_including('spellcheck.onlyMorePopular', true)
|
18
|
+
connection.should have_last_search_including('spellcheck.count', 5)
|
19
|
+
end
|
20
|
+
end
|
@@ -13,6 +13,7 @@ describe 'standard query', :type => :query do
|
|
13
13
|
it_should_behave_like "geohash query"
|
14
14
|
it_should_behave_like "spatial query"
|
15
15
|
it_should_behave_like "stats query"
|
16
|
+
it_should_behave_like "spellcheck query"
|
16
17
|
|
17
18
|
it 'adds a no-op query to :q parameter when no :q provided' do
|
18
19
|
session.search Post do
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe "CursorPaginatedCollection" do
|
4
|
+
subject { Sunspot::Search::CursorPaginatedCollection.new [], 10, 20, '*', 'AoIIP4AAACxQcm9maWxlIDEwMTk=' }
|
5
|
+
|
6
|
+
it { subject.should be_an(Array) }
|
7
|
+
|
8
|
+
describe "#send" do
|
9
|
+
it 'should allow send' do
|
10
|
+
expect { subject.send(:current_cursor) }.to_not raise_error
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#respond_to?" do
|
15
|
+
it 'should return true for current_cursor' do
|
16
|
+
subject.respond_to?(:current_cursor).should be_true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "behaves like a WillPaginate::Collection" do
|
21
|
+
it { subject.total_entries.should eql(20) }
|
22
|
+
it { subject.total_pages.should eql(2) }
|
23
|
+
it { subject.current_cursor.should eql('*') }
|
24
|
+
it { subject.per_page.should eql(10) }
|
25
|
+
it { subject.next_page_cursor.should eql('AoIIP4AAACxQcm9maWxlIDEwMTk=') }
|
26
|
+
end
|
27
|
+
|
28
|
+
context "behaves like Kaminari" do
|
29
|
+
it { subject.total_count.should eql(20) }
|
30
|
+
it { subject.num_pages.should eql(2) }
|
31
|
+
it { subject.limit_value.should eql(10) }
|
32
|
+
it { subject.first_page?.should be_true }
|
33
|
+
it { subject.last_page?.should be_true }
|
34
|
+
end
|
35
|
+
end
|
@@ -23,6 +23,7 @@ describe "PaginatedCollection" do
|
|
23
23
|
it { subject.current_page.should eql(1) }
|
24
24
|
it { subject.per_page.should eql(10) }
|
25
25
|
it { subject.previous_page.should be_nil }
|
26
|
+
it { subject.prev_page.should be_nil }
|
26
27
|
it { subject.next_page.should eql(2) }
|
27
28
|
it { subject.out_of_bounds?.should_not be_true }
|
28
29
|
it { subject.offset.should eql(0) }
|
data/spec/api/session_spec.rb
CHANGED
@@ -35,6 +35,26 @@ shared_examples_for 'all sessions' do
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
+
context '#commit(bool)' do
|
39
|
+
it 'should soft-commit if bool=true' do
|
40
|
+
@session.commit(true)
|
41
|
+
connection.should have(1).commits
|
42
|
+
connection.should have(1).soft_commits
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should hard-commit if bool=false' do
|
46
|
+
@session.commit(false)
|
47
|
+
connection.should have(1).commits
|
48
|
+
connection.should have(0).soft_commits
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should hard-commit if bool is not specified' do
|
52
|
+
@session.commit
|
53
|
+
connection.should have(1).commits
|
54
|
+
connection.should have(0).soft_commits
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
38
58
|
context '#optimize()' do
|
39
59
|
before :each do
|
40
60
|
@session.optimize
|
@@ -202,17 +222,31 @@ describe 'Session' do
|
|
202
222
|
connection.should have(0).commits
|
203
223
|
end
|
204
224
|
|
205
|
-
it 'should commit when commit_if_dirty called on dirty session' do
|
225
|
+
it 'should hard commit when commit_if_dirty called on dirty session' do
|
206
226
|
@session.index(Post.new)
|
207
227
|
@session.commit_if_dirty
|
208
228
|
connection.should have(1).commits
|
209
229
|
end
|
210
230
|
|
211
|
-
it 'should commit when
|
231
|
+
it 'should soft commit when commit_if_dirty called on dirty session' do
|
232
|
+
@session.index(Post.new)
|
233
|
+
@session.commit_if_dirty(true)
|
234
|
+
connection.should have(1).commits
|
235
|
+
connection.should have(1).soft_commits
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'should hard commit when commit_if_delete_dirty called on delete_dirty session' do
|
212
239
|
@session.remove(Post.new)
|
213
240
|
@session.commit_if_delete_dirty
|
214
241
|
connection.should have(1).commits
|
215
242
|
end
|
243
|
+
|
244
|
+
it 'should soft commit when commit_if_delete_dirty called on delete_dirty session' do
|
245
|
+
@session.remove(Post.new)
|
246
|
+
@session.commit_if_delete_dirty(true)
|
247
|
+
connection.should have(1).commits
|
248
|
+
connection.should have(1).soft_commits
|
249
|
+
end
|
216
250
|
end
|
217
251
|
|
218
252
|
context 'session proxy' do
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
2
|
+
include SearchHelper
|
3
|
+
|
4
|
+
describe 'spellcheck' do
|
5
|
+
before :each do
|
6
|
+
Sunspot.remove_all
|
7
|
+
|
8
|
+
@posts = [
|
9
|
+
Post.new(:title => 'Clojure Developer'),
|
10
|
+
Post.new(:title => 'Conjure Flow'),
|
11
|
+
Post.new(:title => 'Clojure Analyst'),
|
12
|
+
Post.new(:title => 'C++ Developer'),
|
13
|
+
Post.new(:title => 'C++ Developing')
|
14
|
+
]
|
15
|
+
|
16
|
+
Sunspot.index!(*@posts)
|
17
|
+
Sunspot.commit
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'has no spellchecking by default' do
|
21
|
+
search = Sunspot.search(Post) do
|
22
|
+
keywords 'Closure'
|
23
|
+
end
|
24
|
+
search.spellcheck_suggestions.should == {}
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'returns the list of suggestions' do
|
28
|
+
search = Sunspot.search(Post) do
|
29
|
+
keywords 'Closure'
|
30
|
+
spellcheck :count => 3
|
31
|
+
end
|
32
|
+
search.spellcheck_suggestions['closure']['suggestion'].should == [
|
33
|
+
{'word'=>'clojure', 'freq'=>2}, {'word'=>'conjure', 'freq'=>1}
|
34
|
+
]
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'returns suggestion with highest frequency' do
|
38
|
+
search = Sunspot.search(Post) do
|
39
|
+
keywords 'Closure'
|
40
|
+
spellcheck :count => 3
|
41
|
+
end
|
42
|
+
search.spellcheck_suggestion_for('closure').should == 'clojure'
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'returns suggestion without collation when only more popular is true' do
|
46
|
+
search = Sunspot.search(Post) do
|
47
|
+
keywords 'Closure'
|
48
|
+
spellcheck :count => 3, :only_more_popular => true, :collate => false
|
49
|
+
end
|
50
|
+
|
51
|
+
search.spellcheck_suggestion_for('closure').should == 'clojure'
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'spellcheck collation' do
|
55
|
+
it 'replaces terms that are not in the index if terms are provided' do
|
56
|
+
|
57
|
+
search = Sunspot.search(Post) do
|
58
|
+
keywords 'lojure developing'
|
59
|
+
spellcheck :count => 3, :only_more_popular => true
|
60
|
+
end
|
61
|
+
search.spellcheck_collation('lojure', 'developing').should == 'clojure developing'
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'returns Solr collation if terms are not provided' do
|
65
|
+
|
66
|
+
search = Sunspot.search(Post) do
|
67
|
+
keywords 'lojure developing'
|
68
|
+
spellcheck :count => 3, :only_more_popular => true
|
69
|
+
end
|
70
|
+
search.spellcheck_collation.should == 'clojure developer'
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
data/spec/mocks/connection.rb
CHANGED
@@ -22,7 +22,7 @@ module Mock
|
|
22
22
|
end
|
23
23
|
|
24
24
|
class Connection
|
25
|
-
attr_reader :adds, :commits, :optims, :searches, :message, :opts, :deletes_by_query
|
25
|
+
attr_reader :adds, :commits, :soft_commits, :optims, :searches, :message, :opts, :deletes_by_query
|
26
26
|
attr_accessor :response
|
27
27
|
attr_writer :expected_handler
|
28
28
|
undef_method :select # annoyingly defined on Object
|
@@ -30,7 +30,7 @@ module Mock
|
|
30
30
|
def initialize(opts = {})
|
31
31
|
@opts = opts
|
32
32
|
@message = OpenStruct.new
|
33
|
-
@adds, @deletes, @deletes_by_query, @commits, @optims, @searches = Array.new(
|
33
|
+
@adds, @deletes, @deletes_by_query, @commits, @soft_commits, @optims, @searches = Array.new(7) { [] }
|
34
34
|
@expected_handler = :select
|
35
35
|
end
|
36
36
|
|
@@ -46,8 +46,10 @@ module Mock
|
|
46
46
|
@deletes_by_query << query
|
47
47
|
end
|
48
48
|
|
49
|
-
def commit
|
49
|
+
def commit(opts = {})
|
50
|
+
commit_attrs = opts.delete(:commit_attributes) || {}
|
50
51
|
@commits << Time.now
|
52
|
+
@soft_commits << Time.now if commit_attrs[:softCommit]
|
51
53
|
end
|
52
54
|
|
53
55
|
def optimize
|