elastictastic 0.5.0 → 0.10.2
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.
- data/LICENSE +1 -1
- data/README.md +161 -10
- data/lib/elastictastic/adapter.rb +84 -0
- data/lib/elastictastic/association.rb +6 -0
- data/lib/elastictastic/basic_document.rb +213 -0
- data/lib/elastictastic/bulk_persistence_strategy.rb +64 -19
- data/lib/elastictastic/callbacks.rb +18 -12
- data/lib/elastictastic/child_collection_proxy.rb +15 -11
- data/lib/elastictastic/client.rb +47 -24
- data/lib/elastictastic/configuration.rb +59 -4
- data/lib/elastictastic/dirty.rb +43 -28
- data/lib/elastictastic/discrete_persistence_strategy.rb +48 -23
- data/lib/elastictastic/document.rb +1 -85
- data/lib/elastictastic/embedded_document.rb +34 -0
- data/lib/elastictastic/errors.rb +17 -5
- data/lib/elastictastic/field.rb +3 -0
- data/lib/elastictastic/mass_assignment_security.rb +2 -4
- data/lib/elastictastic/middleware.rb +66 -84
- data/lib/elastictastic/multi_get.rb +30 -0
- data/lib/elastictastic/multi_search.rb +70 -0
- data/lib/elastictastic/nested_document.rb +3 -27
- data/lib/elastictastic/new_relic_instrumentation.rb +8 -8
- data/lib/elastictastic/observing.rb +8 -6
- data/lib/elastictastic/optimistic_locking.rb +57 -0
- data/lib/elastictastic/parent_child.rb +56 -54
- data/lib/elastictastic/persistence.rb +16 -16
- data/lib/elastictastic/properties.rb +136 -96
- data/lib/elastictastic/railtie.rb +1 -1
- data/lib/elastictastic/rotor.rb +105 -0
- data/lib/elastictastic/scope.rb +186 -56
- data/lib/elastictastic/server_error.rb +20 -1
- data/lib/elastictastic/test_helpers.rb +152 -97
- data/lib/elastictastic/thrift/constants.rb +12 -0
- data/lib/elastictastic/thrift/rest.rb +83 -0
- data/lib/elastictastic/thrift/types.rb +124 -0
- data/lib/elastictastic/thrift_adapter.rb +61 -0
- data/lib/elastictastic/transport_methods.rb +27 -0
- data/lib/elastictastic/validations.rb +11 -13
- data/lib/elastictastic/version.rb +1 -1
- data/lib/elastictastic.rb +148 -27
- data/spec/environment.rb +1 -1
- data/spec/examples/bulk_persistence_strategy_spec.rb +151 -23
- data/spec/examples/callbacks_spec.rb +65 -34
- data/spec/examples/dirty_spec.rb +160 -1
- data/spec/examples/document_spec.rb +168 -106
- data/spec/examples/middleware_spec.rb +1 -61
- data/spec/examples/multi_get_spec.rb +127 -0
- data/spec/examples/multi_search_spec.rb +113 -0
- data/spec/examples/observing_spec.rb +24 -3
- data/spec/examples/optimistic_locking_spec.rb +417 -0
- data/spec/examples/parent_child_spec.rb +73 -33
- data/spec/examples/properties_spec.rb +53 -0
- data/spec/examples/rotor_spec.rb +132 -0
- data/spec/examples/scope_spec.rb +78 -18
- data/spec/examples/search_spec.rb +26 -0
- data/spec/examples/validation_spec.rb +7 -1
- data/spec/models/author.rb +1 -1
- data/spec/models/blog.rb +2 -0
- data/spec/models/comment.rb +1 -1
- data/spec/models/photo.rb +9 -0
- data/spec/models/post.rb +3 -0
- metadata +97 -78
- data/lib/elastictastic/resource.rb +0 -4
- data/spec/examples/active_model_lint_spec.rb +0 -20
@@ -0,0 +1,417 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
require 'ruby-debug'
|
3
|
+
|
4
|
+
describe Elastictastic::OptimisticLocking do
|
5
|
+
include Elastictastic::TestHelpers
|
6
|
+
|
7
|
+
shared_examples_for 'updatable scope' do
|
8
|
+
let :post do
|
9
|
+
scope.new.tap do |post|
|
10
|
+
post.id = '123abc'
|
11
|
+
post.version = 1
|
12
|
+
post.persisted!
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when save is cancelled' do
|
17
|
+
before do
|
18
|
+
stub_request_json(
|
19
|
+
:get,
|
20
|
+
match_es_resource(index, 'post', '123abc'),
|
21
|
+
generate_es_hit('post', :id => '123abc', :index => index, :version => 1).merge('exists' => true),
|
22
|
+
generate_es_hit('post', :id => '123abc', :index => index, :version => 2, :source => { :title => 'Hey' }).merge('exists' => true)
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '::update' do
|
27
|
+
before do
|
28
|
+
scope.update('123abc') do
|
29
|
+
raise Elastictastic::CancelSave
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should have 1 request for fetch' do
|
34
|
+
FakeWeb.should have(1).requests # 1 for fetch
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '::create_or_update' do
|
39
|
+
before do
|
40
|
+
scope.create_or_update('123abc') do
|
41
|
+
raise Elastictastic::CancelSave
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should make no requests' do
|
46
|
+
FakeWeb.should have(0).requests
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'when version conflict raised from discrete persistence' do
|
52
|
+
describe '#save' do
|
53
|
+
before do
|
54
|
+
stub_request_json(
|
55
|
+
:put,
|
56
|
+
match_es_resource(index, 'post', '123abc'),
|
57
|
+
version_conflict
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should raise VersionConflict' do
|
62
|
+
expect { post.save }.to raise_error(Elastictastic::ServerError::VersionConflictEngineException)
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should yield VersionConflict when called with block' do
|
66
|
+
ex = nil
|
67
|
+
post.save { |e| ex = e }
|
68
|
+
ex.should be_a(Elastictastic::ServerError::VersionConflictEngineException)
|
69
|
+
end
|
70
|
+
end # describe '#save'
|
71
|
+
|
72
|
+
describe '::update' do
|
73
|
+
before do
|
74
|
+
stub_request_json(
|
75
|
+
:get,
|
76
|
+
match_es_resource(index, 'post', '123abc'),
|
77
|
+
generate_es_hit('post', :id => '123abc', :index => index, :version => 1).merge('exists' => true),
|
78
|
+
generate_es_hit('post', :id => '123abc', :index => index, :version => 2, :source => { :title => 'Hey' }).merge('exists' => true)
|
79
|
+
)
|
80
|
+
stub_request_json(
|
81
|
+
:put,
|
82
|
+
match_es_resource(index, 'post', '123abc'),
|
83
|
+
version_conflict,
|
84
|
+
generate_es_hit('post', :id => '123abc', :version => 3, :index => index)
|
85
|
+
)
|
86
|
+
scope.update('123abc') do |post|
|
87
|
+
post.comments_count = 3
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should make four requests' do
|
92
|
+
FakeWeb.should have(4).requests
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'should add preference=_primary to get request' do
|
96
|
+
URI.parse(FakeWeb.requests.first.path).query.split('&').
|
97
|
+
should include('preference=_primary_first')
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'should make final update with modification in update block' do
|
101
|
+
last_request_json['comments_count'].should == 3
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'should make final update with data from latest version of doc' do
|
105
|
+
last_request_json['title'].should == 'Hey'
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should make final update with correct version' do
|
109
|
+
last_request_uri.query.split('&').should include('version=2')
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should send final update to correct index' do
|
113
|
+
last_request_uri.path.split('/')[1].should == index
|
114
|
+
end
|
115
|
+
end # describe '::update'
|
116
|
+
|
117
|
+
describe '::update_each' do
|
118
|
+
let(:last_update_request) do
|
119
|
+
FakeWeb.requests.reverse.find { |req| req.method == 'PUT' }
|
120
|
+
end
|
121
|
+
|
122
|
+
before do
|
123
|
+
stub_es_scan(
|
124
|
+
index, 'post', 100,
|
125
|
+
generate_es_hit('post', :index => index, :id => '1'),
|
126
|
+
generate_es_hit('post', :index => index, :id => '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_each do |post|
|
137
|
+
post.comments_count = 2
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'should retry unsuccessful updates' do
|
142
|
+
FakeWeb.should have(7).requests # initiate scan, 2 cursors, 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_each'
|
161
|
+
end # context 'when version conflict raised from discrete persistence'
|
162
|
+
|
163
|
+
context 'when version conflict raised from bulk persistence' do
|
164
|
+
describe '#save' do
|
165
|
+
before do
|
166
|
+
stub_es_bulk(
|
167
|
+
'index' => {
|
168
|
+
'_index' => index, '_type' => 'post', '_id' => '123abc',
|
169
|
+
'error' => version_conflict['error']
|
170
|
+
}
|
171
|
+
)
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'should raise error' do
|
175
|
+
expect { Elastictastic.bulk { post.save }}.to raise_error(Elastictastic::ServerError::VersionConflictEngineException)
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'should yield an error when called with block' do
|
179
|
+
ex = nil
|
180
|
+
Elastictastic.bulk { post.save { |e| ex = e }}
|
181
|
+
ex.should be_a(Elastictastic::ServerError::VersionConflictEngineException)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
describe '::update' do
|
186
|
+
before do
|
187
|
+
stub_request_json(
|
188
|
+
:get,
|
189
|
+
match_es_resource(index, 'post', 'abc123'),
|
190
|
+
generate_es_hit('post', :id => 'abc123', :index => index, :version => 1),
|
191
|
+
generate_es_hit('post', :id => 'abc123', :index => index, :version => 2, :source => { :title => 'Hey' })
|
192
|
+
)
|
193
|
+
stub_es_bulk(
|
194
|
+
'index' => {
|
195
|
+
'_index' => index, '_type' => 'post', '_id' => '123abc',
|
196
|
+
'error' => version_conflict['error']
|
197
|
+
}
|
198
|
+
)
|
199
|
+
stub_es_update(index, 'post', 'abc123')
|
200
|
+
|
201
|
+
Elastictastic.bulk do
|
202
|
+
scope.update('abc123') do |post|
|
203
|
+
post.comments_count = 2
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'should make 4 requests' do
|
209
|
+
FakeWeb.should have(4).requests
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'should send data from block in last request' do
|
213
|
+
last_request_json['comments_count'].should == 2
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'should send data from most recent version in last request' do
|
217
|
+
last_request_json['title'].should == 'Hey'
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'should send correct version in last request' do
|
221
|
+
last_request_uri.query.split('&').should include('version=2')
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'should send last request to correct index' do
|
225
|
+
last_request_uri.path.split('/')[1].should == index
|
226
|
+
end
|
227
|
+
end # describe '::update'
|
228
|
+
|
229
|
+
describe '::update_each' do
|
230
|
+
before do
|
231
|
+
stub_es_scan(
|
232
|
+
index, 'post', 100,
|
233
|
+
generate_es_hit('post', :index => index, :id => '1'),
|
234
|
+
generate_es_hit('post', :index => index, :id => '2')
|
235
|
+
)
|
236
|
+
stub_request_json(
|
237
|
+
:post,
|
238
|
+
match_es_path('/_bulk'),
|
239
|
+
'items' => [
|
240
|
+
{ 'index' => generate_es_hit('post', :index => index, :id => '1').except('_source').merge('ok' => true) },
|
241
|
+
{ 'index' => generate_es_hit('post', :index => index, :id => '2').except('_source').merge(version_conflict.slice('error')) }
|
242
|
+
]
|
243
|
+
)
|
244
|
+
stub_es_get(index, 'post', '2', { 'title' => 'Hey' }, 2)
|
245
|
+
stub_es_update(index, 'post', '2', 3)
|
246
|
+
Elastictastic.bulk do
|
247
|
+
scope.update_each { |post| post.comments_count = 2 }
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'should retry failed update' do
|
252
|
+
FakeWeb.should have(6).requests # start scan, 2 cursor reads, bulk update, reload '2', update '2'
|
253
|
+
end
|
254
|
+
|
255
|
+
it 'should update failed document' do
|
256
|
+
last_request_uri.path.should == "/#{index}/post/2"
|
257
|
+
end
|
258
|
+
|
259
|
+
it 'should update conflicted document with reloaded data' do
|
260
|
+
last_request_json['title'].should == 'Hey'
|
261
|
+
end
|
262
|
+
|
263
|
+
it 'should update conflicted document with data from block' do
|
264
|
+
last_request_json['comments_count'].should == 2
|
265
|
+
end
|
266
|
+
|
267
|
+
it 'should update conflicted document with proper version' do
|
268
|
+
last_request_uri.query.split('&').should include('version=2')
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end # context 'when version conflict raised from bulk persistence'
|
272
|
+
end # shared_examples_for 'updatable scope'
|
273
|
+
|
274
|
+
describe 'default scope' do
|
275
|
+
let(:scope) { Post }
|
276
|
+
let(:index) { 'default' }
|
277
|
+
let :version_conflict do
|
278
|
+
{
|
279
|
+
'error' => "VersionConflictEngineException: [[#{index}][3] [post][abc123]: version conflict, current[2], required[1]]",
|
280
|
+
'status' => 409
|
281
|
+
}
|
282
|
+
end
|
283
|
+
it_should_behave_like 'updatable scope'
|
284
|
+
end
|
285
|
+
|
286
|
+
describe 'scoped in index' do
|
287
|
+
let(:scope) { Post.in_index('my_index') }
|
288
|
+
let(:index) { 'my_index' }
|
289
|
+
let :version_conflict do
|
290
|
+
{
|
291
|
+
'error' => "VersionConflictEngineException: [[#{index}][3] [post][abc123]: version conflict, current[2], required[1]]",
|
292
|
+
'status' => 409
|
293
|
+
}
|
294
|
+
end
|
295
|
+
it_should_behave_like 'updatable scope'
|
296
|
+
end
|
297
|
+
|
298
|
+
describe 'default scope with nested exception' do
|
299
|
+
let(:scope) { Post }
|
300
|
+
let(:index) { 'default' }
|
301
|
+
let(:version_conflict) do
|
302
|
+
{
|
303
|
+
'error' => "RemoteTransportException: [[server][inet[/ip]][/index]]; nested: VersionConflictEngineException[[#{index}][0] [[post][abc123]: version conflict, current [2], required [1]]",
|
304
|
+
'status' => 409
|
305
|
+
}
|
306
|
+
end
|
307
|
+
it_should_behave_like 'updatable scope'
|
308
|
+
end
|
309
|
+
|
310
|
+
describe 'scoped in index with nested exception' do
|
311
|
+
let(:scope) { Post.in_index('my_index') }
|
312
|
+
let(:index) { 'my_index' }
|
313
|
+
let(:version_conflict) do
|
314
|
+
{
|
315
|
+
'error' => "RemoteTransportException: [[server][inet[/ip]][/index]]; nested: VersionConflictEngineException[[#{index}][0] [[post][abc123]: version conflict, current [2], required [1]]",
|
316
|
+
'status' => 409
|
317
|
+
}
|
318
|
+
end
|
319
|
+
it_should_behave_like 'updatable scope'
|
320
|
+
end
|
321
|
+
|
322
|
+
context '::update called on nonexistent document' do
|
323
|
+
before do
|
324
|
+
stub_es_get('default', 'post', '1', nil)
|
325
|
+
end
|
326
|
+
|
327
|
+
it 'should not do anything' do
|
328
|
+
expect { Post.update('1') { |post| post.title = 'bogus' }}.to_not raise_error
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
describe '::create_or_update' do
|
333
|
+
let :already_exists do
|
334
|
+
{
|
335
|
+
'error' => 'DocumentAlreadyExistsEngineException: [[my_index][2] [post][1]: document already exists]',
|
336
|
+
'status' => 409
|
337
|
+
}
|
338
|
+
end
|
339
|
+
|
340
|
+
let :version_conflict do
|
341
|
+
{
|
342
|
+
'error' => "VersionConflictEngineException: [[my_index][3] [post][1]: version conflict, current[2], required[1]]",
|
343
|
+
'status' => 409
|
344
|
+
}
|
345
|
+
end
|
346
|
+
|
347
|
+
context 'with discrete persistence' do
|
348
|
+
context "when document doesn't already exist" do
|
349
|
+
before do
|
350
|
+
stub_es_create('my_index', 'post', '1')
|
351
|
+
Post.in_index('my_index').create_or_update('1') { |post| post.title = 'hey' }
|
352
|
+
end
|
353
|
+
|
354
|
+
it 'should post to create endpoint' do
|
355
|
+
last_request.path.should == '/my_index/post/1/_create'
|
356
|
+
end
|
357
|
+
|
358
|
+
it 'should yield before saving' do
|
359
|
+
last_request_json['title'].should == 'hey'
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
context "when document already exists" do
|
364
|
+
before do
|
365
|
+
stub_request_json(
|
366
|
+
:put,
|
367
|
+
match_es_path('/my_index/post/1/_create'),
|
368
|
+
already_exists
|
369
|
+
)
|
370
|
+
stub_es_get('my_index', 'post', '1', :comments_count => 2)
|
371
|
+
stub_es_update('my_index', 'post', '1')
|
372
|
+
Post.in_index('my_index').create_or_update('1') { |post| post.title = 'hey' }
|
373
|
+
end
|
374
|
+
|
375
|
+
it 'should re-update data with correct version' do
|
376
|
+
last_request.path.should == '/my_index/post/1?version=1'
|
377
|
+
end
|
378
|
+
|
379
|
+
it 'should include data from storage' do
|
380
|
+
last_request_json['comments_count'].should == 2
|
381
|
+
end
|
382
|
+
|
383
|
+
it 'should include updated data from block' do
|
384
|
+
last_request_json['title'].should == 'hey'
|
385
|
+
end
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
context 'with bulk persistence' do
|
390
|
+
context 'when document already exists' do
|
391
|
+
before do
|
392
|
+
stub_es_bulk(
|
393
|
+
'create' => {
|
394
|
+
'_index' => 'my_index', '_type' => 'post', '_id' => '1',
|
395
|
+
'error' => already_exists['error']
|
396
|
+
}
|
397
|
+
)
|
398
|
+
stub_es_get('my_index', 'post', '1', 'comments_count' => 2)
|
399
|
+
stub_es_update('my_index', 'post', '1')
|
400
|
+
Elastictastic.bulk { Post.in_index('my_index').create_or_update('1') { |post| post.title = 'hey' } }
|
401
|
+
end
|
402
|
+
|
403
|
+
it 'should send update' do
|
404
|
+
last_request.path.should == '/my_index/post/1?version=1'
|
405
|
+
end
|
406
|
+
|
407
|
+
it 'should send data from existing document' do
|
408
|
+
last_request_json['comments_count'].should == 2
|
409
|
+
end
|
410
|
+
|
411
|
+
it 'should send data from block' do
|
412
|
+
last_request_json['title'].should == 'hey'
|
413
|
+
end
|
414
|
+
end
|
415
|
+
end
|
416
|
+
end
|
417
|
+
end
|
@@ -12,7 +12,7 @@ describe Elastictastic::ParentChild do
|
|
12
12
|
describe 'child instance' do
|
13
13
|
let(:post) { blog.posts.new }
|
14
14
|
let(:blog) do
|
15
|
-
|
15
|
+
stub_es_create('default', 'blog')
|
16
16
|
Blog.new.tap { |blog| blog.save }
|
17
17
|
end
|
18
18
|
|
@@ -24,40 +24,74 @@ describe Elastictastic::ParentChild do
|
|
24
24
|
blog.posts.from_hash('title' => 'hey').blog.should == blog
|
25
25
|
end
|
26
26
|
|
27
|
+
describe 'when retrieved directly' do
|
28
|
+
let(:post) { Post.in_index('my_index').fields('_source', '_parent').first }
|
29
|
+
|
30
|
+
before do
|
31
|
+
stub_es_search(
|
32
|
+
'my_index', 'post',
|
33
|
+
'hits' => {
|
34
|
+
'total' => 1,
|
35
|
+
'hits' => [{
|
36
|
+
'_id' => '2',
|
37
|
+
'_type' => 'post',
|
38
|
+
'_index' => 'my_index',
|
39
|
+
'_source' => {},
|
40
|
+
'fields' => { '_parent' => '1' }
|
41
|
+
}]
|
42
|
+
}
|
43
|
+
)
|
44
|
+
|
45
|
+
stub_es_get(
|
46
|
+
'my_index', 'blog', '1',
|
47
|
+
{ 'name' => 'Awesome Blog' }
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should retrieve parent via GET' do
|
52
|
+
post.blog.name.should == 'Awesome Blog'
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should lookup in correct index' do
|
56
|
+
post.blog
|
57
|
+
FakeWeb.last_request.path.split('?').first.should == '/my_index/blog/1'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
27
61
|
describe 'discrete persistence' do
|
28
62
|
it 'should pass parent param on create' do
|
29
|
-
|
63
|
+
stub_es_create('default', 'post')
|
30
64
|
post.save
|
31
65
|
URI.parse(FakeWeb.last_request.path).query.should == "parent=#{blog.id}"
|
32
66
|
end
|
33
67
|
|
34
68
|
it 'should pass parent param on update' do
|
35
|
-
|
69
|
+
stub_es_create('default', 'post')
|
36
70
|
post.save
|
37
|
-
|
71
|
+
stub_es_update('default', 'post', post.id)
|
38
72
|
post.save
|
39
|
-
URI.parse(FakeWeb.last_request.path).query.should
|
73
|
+
URI.parse(FakeWeb.last_request.path).query.split('&').should include("parent=#{blog.id}")
|
40
74
|
end
|
41
75
|
|
42
76
|
it 'should pass parent on delete' do
|
43
|
-
|
77
|
+
stub_es_create('default', 'post')
|
44
78
|
post = blog.posts.new
|
45
79
|
post.save
|
46
|
-
|
80
|
+
stub_es_destroy('default', 'post', post.id)
|
47
81
|
post.destroy
|
48
|
-
URI.parse(FakeWeb.last_request.path).query.should
|
82
|
+
URI.parse(FakeWeb.last_request.path).query.split('&').should include("parent=#{blog.id}")
|
49
83
|
end
|
50
84
|
end
|
51
85
|
|
52
86
|
describe 'bulk persistence' do
|
53
87
|
let(:bulk_requests) do
|
54
88
|
FakeWeb.last_request.body.split("\n").map do |line|
|
55
|
-
|
89
|
+
Elastictastic.json_decode(line)
|
56
90
|
end
|
57
91
|
end
|
58
92
|
|
59
93
|
before do
|
60
|
-
|
94
|
+
stub_es_bulk
|
61
95
|
end
|
62
96
|
|
63
97
|
it 'should pass parent param on create' do
|
@@ -102,7 +136,7 @@ describe Elastictastic::ParentChild do
|
|
102
136
|
end
|
103
137
|
|
104
138
|
it 'should set index' do
|
105
|
-
|
139
|
+
stub_es_create('my_index', 'blog')
|
106
140
|
blog = Blog.in_index('my_index').new
|
107
141
|
blog.save
|
108
142
|
post = blog.posts.new
|
@@ -112,7 +146,7 @@ describe Elastictastic::ParentChild do
|
|
112
146
|
|
113
147
|
describe 'collection proxies' do
|
114
148
|
let(:blog) do
|
115
|
-
|
149
|
+
stub_es_create('my_index', 'blog')
|
116
150
|
Blog.in_index('my_index').new.tap { |blog| blog.save }
|
117
151
|
end
|
118
152
|
let(:posts) { blog.posts }
|
@@ -137,20 +171,20 @@ describe Elastictastic::ParentChild do
|
|
137
171
|
end
|
138
172
|
|
139
173
|
it 'should search correct index' do
|
140
|
-
|
174
|
+
stub_es_scan('my_index', 'post', 100, { '_id' => '1' })
|
141
175
|
posts.to_a.first.id.should == '1'
|
142
176
|
end
|
143
177
|
|
144
178
|
it 'should set routing to parent ID on get' do
|
145
|
-
|
179
|
+
stub_es_get('my_index', 'post', 1)
|
146
180
|
blog.posts.find(1)
|
147
181
|
URI.parse(FakeWeb.last_request.path).query.should == "routing=#{blog.id}"
|
148
182
|
end
|
149
183
|
|
150
184
|
it 'should set routing to parent ID on multiget' do
|
151
|
-
|
185
|
+
stub_es_mget('my_index', 'post')
|
152
186
|
blog.posts.find(1, 2)
|
153
|
-
|
187
|
+
Elastictastic.json_decode(FakeWeb.last_request.body).should == {
|
154
188
|
'docs' => [
|
155
189
|
{ '_id' => 1, 'routing' => blog.id },
|
156
190
|
{ '_id' => 2, 'routing' => blog.id }
|
@@ -160,14 +194,14 @@ describe Elastictastic::ParentChild do
|
|
160
194
|
|
161
195
|
it 'should save transient instances when parent is saved' do
|
162
196
|
post = posts.new
|
163
|
-
|
164
|
-
|
197
|
+
stub_es_update('my_index', 'blog', blog.id)
|
198
|
+
stub_es_create('my_index', 'post')
|
165
199
|
blog.save
|
166
200
|
post.should be_persisted
|
167
201
|
end
|
168
202
|
|
169
203
|
it 'should not attempt to save transient instances that are pending for save in a bulk block' do
|
170
|
-
|
204
|
+
stub_es_bulk(
|
171
205
|
{ 'create' => { '_index' => 'my_index', '_type' => 'post', '_id' => '123', '_version' => 1, 'ok' => true }},
|
172
206
|
{ 'index' => { '_index' => 'my_index', '_type' => 'blog', '_id' => blog.id, '_version' => 2, 'ok' => true }}
|
173
207
|
)
|
@@ -177,34 +211,34 @@ describe Elastictastic::ParentChild do
|
|
177
211
|
blog.save
|
178
212
|
end
|
179
213
|
request_statements =
|
180
|
-
FakeWeb.last_request.body.each_line.map { |line|
|
214
|
+
FakeWeb.last_request.body.each_line.map { |line| Elastictastic.json_decode(line) }
|
181
215
|
request_statements.length.should == 4
|
182
216
|
end
|
183
217
|
|
184
218
|
it 'should not save transient instances again' do
|
185
219
|
post = posts.new
|
186
|
-
|
187
|
-
|
220
|
+
stub_es_update('my_index', 'blog', blog.id)
|
221
|
+
stub_es_create('my_index', 'post')
|
188
222
|
blog.save
|
189
223
|
FakeWeb.clean_registry
|
190
|
-
|
224
|
+
stub_es_update('my_index', 'blog', blog.id)
|
191
225
|
expect { blog.save }.to_not raise_error
|
192
226
|
end
|
193
227
|
|
194
228
|
it 'should populate parent when finding one' do
|
195
|
-
|
229
|
+
stub_es_get('my_index', 'post', '1')
|
196
230
|
blog.posts.find('1').blog.should == blog
|
197
231
|
end
|
198
232
|
|
199
233
|
it 'should populate parent when finding many' do
|
200
|
-
|
234
|
+
stub_es_mget('my_index', 'post', '1', '2')
|
201
235
|
blog.posts.find('1', '2').each do |post|
|
202
236
|
post.blog.should == blog
|
203
237
|
end
|
204
238
|
end
|
205
239
|
|
206
240
|
it 'should populate parent when retrieving first' do
|
207
|
-
|
241
|
+
stub_es_search(
|
208
242
|
'my_index', 'post',
|
209
243
|
'total' => 1,
|
210
244
|
'hits' => { 'hits' => [{ '_id' => '2', 'index' => 'my_index', '_type' => 'post' }]}
|
@@ -213,7 +247,7 @@ describe Elastictastic::ParentChild do
|
|
213
247
|
end
|
214
248
|
|
215
249
|
it 'should populate parent when iterating over cursor' do
|
216
|
-
|
250
|
+
stub_es_scan(
|
217
251
|
'my_index', 'post', 100,
|
218
252
|
'_id' => '1'
|
219
253
|
)
|
@@ -221,7 +255,7 @@ describe Elastictastic::ParentChild do
|
|
221
255
|
end
|
222
256
|
|
223
257
|
it 'should populate parent when paginating' do
|
224
|
-
|
258
|
+
stub_es_search(
|
225
259
|
'my_index', 'post',
|
226
260
|
'hits' => {
|
227
261
|
'total' => 1,
|
@@ -232,15 +266,21 @@ describe Elastictastic::ParentChild do
|
|
232
266
|
end
|
233
267
|
|
234
268
|
it 'should iterate over transient instances along with retrieved results' do
|
235
|
-
|
269
|
+
stub_es_scan('my_index', 'post', 100, '_id' => '1')
|
236
270
|
post = blog.posts.new
|
237
271
|
posts = blog.posts.to_a
|
238
272
|
posts[0].id.should == '1'
|
239
273
|
posts[1].should == post
|
240
274
|
end
|
241
275
|
|
276
|
+
it 'should iterate over only transient instances if parent is transient' do
|
277
|
+
blog = Blog.new
|
278
|
+
post = blog.posts.new
|
279
|
+
blog.posts.to_a.should == [post]
|
280
|
+
end
|
281
|
+
|
242
282
|
it 'should return transient instance as #first if no persisted results' do
|
243
|
-
|
283
|
+
stub_es_search(
|
244
284
|
'my_index', 'post', 'hits' => { 'total' => 0, 'hits' => [] })
|
245
285
|
post = blog.posts.new
|
246
286
|
blog.posts.first.should == post
|
@@ -274,7 +314,7 @@ describe Elastictastic::ParentChild do
|
|
274
314
|
|
275
315
|
describe 'searching children directly' do
|
276
316
|
before do
|
277
|
-
|
317
|
+
stub_es_search(
|
278
318
|
'default', 'post',
|
279
319
|
'hits' => {
|
280
320
|
'hits' => [
|
@@ -291,7 +331,7 @@ describe Elastictastic::ParentChild do
|
|
291
331
|
let(:post) { Post.first }
|
292
332
|
|
293
333
|
it 'should provide access to parent' do
|
294
|
-
|
334
|
+
stub_es_get('default', 'blog', '3')
|
295
335
|
post.blog.id.should == '3'
|
296
336
|
end
|
297
337
|
|
@@ -300,7 +340,7 @@ describe Elastictastic::ParentChild do
|
|
300
340
|
end
|
301
341
|
|
302
342
|
it 'should save post without dereferencing parent' do
|
303
|
-
|
343
|
+
stub_es_update('default', 'post', post.id)
|
304
344
|
post.save
|
305
345
|
URI.parse(FakeWeb.last_request.path).query.should == 'parent=3'
|
306
346
|
end
|