elastictastic 0.10.9 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,28 +6,54 @@ module Elastictastic
6
6
 
7
7
  module ClassMethods
8
8
 
9
- def create_or_update(id, &block)
9
+ def create_or_update(*ids, &block)
10
10
  scope = current_scope
11
- new.tap do |instance|
12
- instance.id = id
13
- yield instance
14
- end.create do |e|
15
- case e
16
- when nil # chill
17
- when Elastictastic::ServerError::DocumentAlreadyExistsEngineException,
18
- Elastictastic::ServerError::DocumentAlreadyExistsException # 0.19+
19
- scope.update(id, &block)
11
+ ids.each do |id|
12
+ begin
13
+ new.tap do |instance|
14
+ instance.id = id
15
+ yield instance
16
+ end.create do |e|
17
+ case e
18
+ when nil # chill
19
+ when Elastictastic::ServerError::DocumentAlreadyExistsEngineException,
20
+ Elastictastic::ServerError::DocumentAlreadyExistsException # 0.19+
21
+ scope.update(id, &block)
22
+ else
23
+ raise e
24
+ end
25
+ end
26
+ rescue Elastictastic::CancelSave
27
+ # Do Nothing
28
+ end
29
+ end
30
+ end
31
+
32
+ def update(*ids, &block)
33
+ [].tap do |found|
34
+ case ids.length
35
+ when 0 then return
36
+ when 1
37
+ id = ids.first
38
+ instance = scoped({}).find_one(id, :preference => '_primary_first')
39
+ return unless instance
40
+ found << id
41
+ instances = [instance]
20
42
  else
21
- raise e
43
+ instances = scoped({}).
44
+ find_many(ids, :preference => '_primary_first')
45
+ found.concat(instances.map { |instance| instance.id })
46
+ end
47
+ instances.each do |instance|
48
+ instance.try_update(current_scope, &block)
22
49
  end
23
50
  end
24
- rescue Elastictastic::CancelSave
25
- # Do Nothing
26
51
  end
27
52
 
28
- def update(id, &block)
29
- instance = scoped({}).find_one(id, :preference => '_primary_first')
30
- instance.try_update(current_scope, &block) if instance
53
+ def update_or_create(*ids, &block)
54
+ updated_ids = update(*ids, &block)
55
+ create_ids = ids - updated_ids
56
+ create_or_update(*create_ids, &block) if create_ids.any?
31
57
  end
32
58
 
33
59
  def update_each(&block)
@@ -282,6 +282,19 @@ module Elastictastic
282
282
  end
283
283
  end
284
284
 
285
+ #
286
+ # @private
287
+ #
288
+ def find_many(ids, params = {})
289
+ docspec = ids.map do |id|
290
+ { '_id' => id }.merge!(params_for_find_many).
291
+ merge!(params.stringify_keys)
292
+ end
293
+ materialize_hits(
294
+ ::Elastictastic.client.mget(docspec, index, type)['docs']
295
+ ).map { |result, hit| result }
296
+ end
297
+
285
298
  def multi_get_params
286
299
  {
287
300
  '_type' => type,
@@ -380,16 +393,6 @@ module Elastictastic
380
393
  self.counts = search(params)
381
394
  end
382
395
 
383
- def find_many(ids, params = {})
384
- docspec = ids.map do |id|
385
- { '_id' => id }.merge!(params_for_find_many).
386
- merge!(params.stringify_keys)
387
- end
388
- materialize_hits(
389
- ::Elastictastic.client.mget(docspec, index, type)['docs']
390
- ).map { |result, hit| result }
391
- end
392
-
393
396
  def params_for_find_one
394
397
  params_for_find.tap do |params|
395
398
  params['fields'] &&= params['fields'].join(',')
@@ -1,3 +1,3 @@
1
1
  module Elastictastic
2
- VERSION = '0.10.9'
2
+ VERSION = '0.11.0'
3
3
  end
@@ -113,6 +113,52 @@ describe Elastictastic::OptimisticLocking do
113
113
  end
114
114
  end # describe '::update'
115
115
 
116
+ describe '::update with multiple arguments' do
117
+ let(:last_update_request) do
118
+ FakeWeb.requests.reverse.find { |req| req.method == 'PUT' }
119
+ end
120
+
121
+ before do
122
+ stub_es_mget(
123
+ index,
124
+ 'post',
125
+ '1' => {},
126
+ '2' => {}
127
+ )
128
+ stub_es_get(index, 'post', '2', { :title => 'Hey' }, 2)
129
+ stub_es_update(index, 'post', '1')
130
+ stub_request_json(
131
+ :put,
132
+ match_es_resource(index, 'post', '2'),
133
+ version_conflict,
134
+ generate_es_hit('post', :id => '2', :index => index, :version => 3)
135
+ )
136
+ scope.update('1', '2') do |post|
137
+ post.comments_count = 2
138
+ end
139
+ end
140
+
141
+ it 'should retry unsuccessful updates' do
142
+ FakeWeb.should have(5).requests # mget, update '1', update '2' (fail), get '2', update '2'
143
+ end
144
+
145
+ it 'should re-perform update on failed document' do
146
+ URI.parse(last_update_request.path).path.should == "/#{index}/post/2"
147
+ end
148
+
149
+ it 'should send data from latest version in persistence' do
150
+ Elastictastic.json_decode(last_update_request.body)['title'].should == 'Hey'
151
+ end
152
+
153
+ it 'should send data from update block' do
154
+ Elastictastic.json_decode(last_update_request.body)['comments_count'].should == 2
155
+ end
156
+
157
+ it 'should update with latest version' do
158
+ URI.parse(last_update_request.path).query.split('&').should include('version=2')
159
+ end
160
+ end # describe '::update with multiple requests'
161
+
116
162
  describe '::update_each' do
117
163
  let(:last_update_request) do
118
164
  FakeWeb.requests.reverse.find { |req| req.method == 'PUT' }
@@ -383,6 +429,46 @@ describe Elastictastic::OptimisticLocking do
383
429
  last_request_json['title'].should == 'hey'
384
430
  end
385
431
  end
432
+
433
+ context "with multiple arguments some of which exist" do
434
+ before do
435
+ stub_es_create('my_index', 'post', '1')
436
+ stub_request_json(
437
+ :put,
438
+ match_es_path('/my_index/post/2/_create'),
439
+ already_exists
440
+ )
441
+ stub_es_get('my_index', 'post', '2', :comments_count => 2)
442
+ stub_es_update('my_index', 'post', '2')
443
+ Post.in_index('my_index').create_or_update('1', '2') do |post|
444
+ post.title = "hey #{post.id}"
445
+ end
446
+ end
447
+
448
+ it 'should post to create endpoint for both documents' do
449
+ FakeWeb.requests.
450
+ should be_any { |request| request.path == '/my_index/post/1/_create' }
451
+ FakeWeb.requests.
452
+ should be_any { |request| request.path == '/my_index/post/2/_create' }
453
+ end
454
+
455
+ it 'should not send update request for successful create' do
456
+ FakeWeb.requests.
457
+ should_not be_any { |request| request.path == '/my_index/post/1?version=1' }
458
+ end
459
+
460
+ it 'should re-update existing data with correct version' do
461
+ last_request.path.should == '/my_index/post/2?version=1'
462
+ end
463
+
464
+ it 'should include data from storage' do
465
+ last_request_json['comments_count'].should == 2
466
+ end
467
+
468
+ it 'should include updated data from block' do
469
+ last_request_json['title'].should == 'hey 2'
470
+ end
471
+ end
386
472
  end
387
473
 
388
474
  context 'with bulk persistence' do
@@ -413,4 +499,44 @@ describe Elastictastic::OptimisticLocking do
413
499
  end
414
500
  end
415
501
  end
502
+
503
+ describe '::update_or_create' do
504
+ let(:scope) { Post }
505
+
506
+ before do
507
+ stub_es_mget(
508
+ 'default', 'post',
509
+ '1' => {title: 'Post 1'},
510
+ '2' => nil
511
+ )
512
+ stub_es_update('default', 'post', '1')
513
+ stub_es_create('default', 'post', '2')
514
+ scope.update_or_create('1', '2') do |post|
515
+ post.comments_count = 1
516
+ end
517
+ end
518
+
519
+ let :create_request do
520
+ FakeWeb.requests.
521
+ find { |request| request.path == "/default/post/2/_create" }
522
+ end
523
+
524
+ let :update_request do
525
+ FakeWeb.requests.
526
+ find { |request| request.path =~ %r(^/default/post/1\??) }
527
+ end
528
+
529
+ it 'should not send any extraneous requests' do
530
+ FakeWeb.should have(3).requests # multiget, create, update
531
+ end
532
+
533
+ it 'should send create request for nonexistent document' do
534
+ create_request.should be
535
+ end
536
+
537
+ it 'should send update request for existent document' do
538
+ update_request.should be
539
+ end
540
+ end
541
+
416
542
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elastictastic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.9
4
+ version: 0.11.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2013-01-09 00:00:00.000000000 Z
14
+ date: 2013-03-28 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: activesupport
@@ -250,7 +250,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
250
250
  requirements:
251
251
  - ElasticSearch
252
252
  rubyforge_project:
253
- rubygems_version: 1.8.24
253
+ rubygems_version: 1.8.25
254
254
  signing_key:
255
255
  specification_version: 3
256
256
  summary: Object-document mapper for ElasticSearch