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
@@ -34,6 +34,59 @@ describe Elastictastic::Properties do
|
|
34
34
|
it 'should map embedded object fields' do
|
35
35
|
properties['author']['properties']['id']['type'].should == 'integer'
|
36
36
|
end
|
37
|
+
|
38
|
+
it 'should set boost field' do
|
39
|
+
mapping['post']['_boost'].should == { 'name' => 'score', 'null_value' => 1.0 }
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should set routing param if given' do
|
43
|
+
Photo.mapping['photo']['_routing'].should == {
|
44
|
+
'required' => true,
|
45
|
+
'path' => 'post_id'
|
46
|
+
}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe ':preset' do
|
51
|
+
before do
|
52
|
+
Elastictastic.config.presets[:silly] = { :type => 'integer', :store => 'yes', :index => 'no' }
|
53
|
+
end
|
54
|
+
|
55
|
+
let :clazz do
|
56
|
+
Class.new do
|
57
|
+
include Elastictastic::Document
|
58
|
+
|
59
|
+
def self.name
|
60
|
+
'Clazz'
|
61
|
+
end
|
62
|
+
|
63
|
+
field :title, :type => 'string', :preset => 'silly'
|
64
|
+
field :created, :preset => :silly
|
65
|
+
field :multi, :type => 'string' do
|
66
|
+
field :searchable, :preset => 'silly', :index => 'yes'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
let(:properties) { clazz.mapping.values.first['properties'] }
|
72
|
+
|
73
|
+
it 'should apply preset values' do
|
74
|
+
properties['created'].should == {
|
75
|
+
'type' => 'integer', 'store' => 'yes', 'index' => 'no'
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should override preset values with given values' do
|
80
|
+
properties['title'].should == {
|
81
|
+
'type' => 'string', 'store' => 'yes', 'index' => 'no'
|
82
|
+
}
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'should apply presets to field alternates' do
|
86
|
+
properties['multi']['fields']['searchable'].should == {
|
87
|
+
'store' => 'yes', 'index' => 'yes', 'type' => 'integer'
|
88
|
+
}
|
89
|
+
end
|
37
90
|
end
|
38
91
|
|
39
92
|
describe '#elasticsearch_doc' do
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe Elastictastic::Rotor do
|
4
|
+
let(:client) { Elastictastic::Client.new(config) }
|
5
|
+
let(:last_request) { FakeWeb.last_request }
|
6
|
+
|
7
|
+
context 'without backoff' do
|
8
|
+
let(:config) do
|
9
|
+
Elastictastic::Configuration.new.tap do |config|
|
10
|
+
config.hosts = ['http://es1.local', 'http://es2.local']
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should alternate requests between hosts' do
|
15
|
+
expect do
|
16
|
+
2.times do
|
17
|
+
1.upto 2 do |i|
|
18
|
+
host_status(i => true)
|
19
|
+
client.get('default', 'post', '1')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end.not_to raise_error # We can't check the hostname of last_request in Fakeweb
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'if one host fails' do
|
26
|
+
let!(:now) { Time.now.tap { |now| Time.stub(:now).and_return(now) }}
|
27
|
+
|
28
|
+
before do
|
29
|
+
host_status(1 => false, 2 => true)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should try the next host' do
|
33
|
+
client.get('default', 'post', '1').should == { 'success' => true }
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should pass PUT body to retry' do
|
37
|
+
client.update('default', 'post', '1', { 'title' => 'pizza' })
|
38
|
+
FakeWeb.last_request.body.should == { 'title' => 'pizza' }.to_json
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'if all hosts fail' do
|
43
|
+
let!(:now) { Time.now.tap { |now| Time.stub(:now).and_return(now) }}
|
44
|
+
|
45
|
+
before do
|
46
|
+
host_status(1 => false, 2 => false)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should raise error if no hosts respond' do
|
50
|
+
expect { client.get('default', 'post', '1') }.to(raise_error Elastictastic::NoServerAvailable)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'with backoff' do
|
56
|
+
let(:config) do
|
57
|
+
Elastictastic::Configuration.new.tap do |config|
|
58
|
+
config.hosts = ['http://es1.local', 'http://es2.local']
|
59
|
+
config.backoff_threshold = 2
|
60
|
+
config.backoff_start = 1
|
61
|
+
config.backoff_max = 4
|
62
|
+
end
|
63
|
+
end
|
64
|
+
let!(:time) { Time.now.tap { |time| Time.stub(:now).and_return(time) }}
|
65
|
+
|
66
|
+
before do
|
67
|
+
host_status(1 => false, 2 => true)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should retry immediately before reaching initial failure count' do
|
71
|
+
client.get('default', 'post', '1')
|
72
|
+
expect { client.get('default', 'post', '1') }.to change(FakeWeb.requests, :length).by(2)
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should back off after initial failure count reached' do
|
76
|
+
2.times { client.get('default', 'post', '1') }
|
77
|
+
expect { client.get('default', 'post', '1') }.to change(FakeWeb.requests, :length).by(1)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should retry after initial backoff period elapses' do
|
81
|
+
3.times { client.get('default', 'post', '1') }
|
82
|
+
Time.stub(:now).and_return(time + 1)
|
83
|
+
expect { client.get('default', 'post', '1') }.to change(FakeWeb.requests, :length).by(2)
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'should double backoff after another failure' do
|
87
|
+
3.times { client.get('default', 'post', '1') }
|
88
|
+
Time.stub(:now).and_return(time + 1)
|
89
|
+
client.get('default', 'post', '1')
|
90
|
+
Time.stub(:now).and_return(time + 2)
|
91
|
+
expect { client.get('default', 'post', '1') }.to change(FakeWeb.requests, :length).by(1)
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should cap backoff interval at backoff_max' do
|
95
|
+
2.times { client.get('default', 'post', '1') } # first backoff - 1 second
|
96
|
+
Time.stub(:now).and_return(time + 1)
|
97
|
+
client.get('default', 'post', '1') # second backoff - 2 seconds
|
98
|
+
Time.stub(:now).and_return(time + 3)
|
99
|
+
client.get('default', 'post', '1') # third backoff - 4 seconds
|
100
|
+
Time.stub(:now).and_return(time + 7)
|
101
|
+
client.get('default', 'post', '1') # fourth backoff - 4 seconds again
|
102
|
+
Time.stub(:now).and_return(time + 11)
|
103
|
+
expect { client.get('default', 'post', '1') }.to change(FakeWeb.requests, :length).by(2)
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'should reset backoff after a successful request' do
|
107
|
+
2.times { client.get('default', 'post', '1') } # initial backoff - 1 second
|
108
|
+
host_status(1 => true, 2 => true)
|
109
|
+
Time.stub(:now).and_return(time + 1)
|
110
|
+
2.times { client.get('default', 'post', '1') } # first one will go to es2 because of rotation. second one has success so es1 should reset
|
111
|
+
host_status(1 => false, 2 => true)
|
112
|
+
client.get('default', 'post', '1') # should be willing to immediately retry
|
113
|
+
host_status(1 => true, 2 => false)
|
114
|
+
expect { client.get('default', 'post', '1') }.to_not raise_error # only will succeed if it retries #1
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def host_status(statuses)
|
121
|
+
FakeWeb.clean_registry
|
122
|
+
statuses.each_pair do |i, healthy|
|
123
|
+
url = %r(^http://es#{i}.local/)
|
124
|
+
if healthy
|
125
|
+
options = { :body => '{"success":true}' }
|
126
|
+
else
|
127
|
+
options = { :exception => Errno::ECONNREFUSED }
|
128
|
+
end
|
129
|
+
FakeWeb.register_uri(:any, url, options)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
data/spec/examples/scope_spec.rb
CHANGED
@@ -7,7 +7,7 @@ describe Elastictastic::Scope do
|
|
7
7
|
include Elastictastic::TestHelpers
|
8
8
|
|
9
9
|
let(:last_request) { FakeWeb.last_request }
|
10
|
-
let(:last_request_body) {
|
10
|
+
let(:last_request_body) { Elastictastic.json_decode(last_request.body) }
|
11
11
|
let(:last_request_path) { last_request.path.split('?', 2)[0] }
|
12
12
|
let(:last_request_params) { last_request.path.split('?', 2)[1].try(:split, '&') }
|
13
13
|
|
@@ -20,7 +20,7 @@ describe Elastictastic::Scope do
|
|
20
20
|
let(:scroll_requests) { FakeWeb.requests[1..-1] }
|
21
21
|
|
22
22
|
before do
|
23
|
-
@scroll_ids =
|
23
|
+
@scroll_ids = stub_es_scan(
|
24
24
|
'default', 'post', 2, *make_hits(3)
|
25
25
|
)
|
26
26
|
end
|
@@ -41,7 +41,7 @@ describe Elastictastic::Scope do
|
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'should send query in data for initial search' do
|
44
|
-
scan_request.body.should == scope.params
|
44
|
+
scan_request.body.should == Elastictastic.json_encode(scope.params)
|
45
45
|
end
|
46
46
|
|
47
47
|
it 'should send POST request initially' do
|
@@ -81,7 +81,7 @@ describe Elastictastic::Scope do
|
|
81
81
|
let(:scope) { Post.from(10).size(10) }
|
82
82
|
|
83
83
|
before do
|
84
|
-
|
84
|
+
stub_es_search(
|
85
85
|
'default', 'post', 'hits' => {
|
86
86
|
'total' => 2,
|
87
87
|
'hits' => make_hits(2)
|
@@ -109,18 +109,35 @@ describe Elastictastic::Scope do
|
|
109
109
|
end
|
110
110
|
end # context 'with from/size'
|
111
111
|
|
112
|
+
describe 'with page out of range' do
|
113
|
+
let(:scope) { Post.from(10).size(10) }
|
114
|
+
|
115
|
+
before do
|
116
|
+
stub_es_search(
|
117
|
+
'default', 'post', 'hits' => {
|
118
|
+
'total' => 2,
|
119
|
+
'hits' => []
|
120
|
+
}
|
121
|
+
)
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'should return empty array of results' do
|
125
|
+
scope.to_a.should == []
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
112
129
|
context 'with sort but no from/size' do
|
113
130
|
let(:scope) { Post.sort(:title => 'asc') }
|
114
131
|
let(:requests) { FakeWeb.requests }
|
115
132
|
let(:request_bodies) do
|
116
133
|
requests.map do |request|
|
117
|
-
|
134
|
+
Elastictastic.json_decode(request.body)
|
118
135
|
end
|
119
136
|
end
|
120
137
|
|
121
138
|
before do
|
122
139
|
Elastictastic.config.default_batch_size = 2
|
123
|
-
|
140
|
+
stub_es_search(
|
124
141
|
'default', 'post',
|
125
142
|
make_hits(3).each_slice(2).map { |batch| { 'hits' => { 'hits' => batch, 'total' => 3 }} }
|
126
143
|
)
|
@@ -169,6 +186,38 @@ describe Elastictastic::Scope do
|
|
169
186
|
scope.each { |post| post.should be_persisted }
|
170
187
|
end
|
171
188
|
end # context 'with sort but no from/size'
|
189
|
+
|
190
|
+
describe 'with routing' do
|
191
|
+
it 'should send routing param in single-search query' do
|
192
|
+
stub_es_search(
|
193
|
+
'default', 'post',
|
194
|
+
'hits' => {'total' => 2, 'hits' => make_hits(2)}
|
195
|
+
)
|
196
|
+
Post.routing('7').size(10).to_a
|
197
|
+
last_request_uri.query.split('&').should include('routing=7')
|
198
|
+
end
|
199
|
+
|
200
|
+
it 'should send routing param in scan query' do
|
201
|
+
stub_es_scan(
|
202
|
+
'default', 'post', 2, *make_hits(3)
|
203
|
+
)
|
204
|
+
Post.routing('7').to_a
|
205
|
+
URI.parse(FakeWeb.requests.first.path).query.split('&').
|
206
|
+
should include('routing=7')
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'should send routing param in batch-search queries' do
|
210
|
+
Elastictastic.config.default_batch_size = 2
|
211
|
+
stub_es_search(
|
212
|
+
'default', 'post',
|
213
|
+
make_hits(3).each_slice(2).map { |batch| { 'hits' => { 'hits' => batch, 'total' => 3 }} }
|
214
|
+
)
|
215
|
+
Post.routing('7').sort(:score).to_a
|
216
|
+
FakeWeb.requests.each do |request|
|
217
|
+
URI.parse(request.path).query.split('&').should include('routing=7')
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
172
221
|
end # describe '#each'
|
173
222
|
|
174
223
|
describe 'hit metadata' do
|
@@ -203,7 +252,7 @@ describe Elastictastic::Scope do
|
|
203
252
|
let(:scope) { Post }
|
204
253
|
|
205
254
|
before do
|
206
|
-
|
255
|
+
stub_es_scan('default', 'post', 2, *hits)
|
207
256
|
end
|
208
257
|
|
209
258
|
it_should_behave_like 'enumerator with hit metadata'
|
@@ -214,7 +263,7 @@ describe Elastictastic::Scope do
|
|
214
263
|
|
215
264
|
before do
|
216
265
|
batches = hits.each_slice(2).map { |batch| { 'hits' => { 'hits' => batch, 'total' => 3 }} }
|
217
|
-
|
266
|
+
stub_es_search('default', 'post', batches)
|
218
267
|
end
|
219
268
|
|
220
269
|
it_should_behave_like 'enumerator with hit metadata'
|
@@ -224,7 +273,7 @@ describe Elastictastic::Scope do
|
|
224
273
|
let(:scope) { Post.size(3) }
|
225
274
|
|
226
275
|
before do
|
227
|
-
|
276
|
+
stub_es_search('default', 'post', 'hits' => { 'hits' => hits, 'total' => 3 })
|
228
277
|
end
|
229
278
|
|
230
279
|
it_should_behave_like 'enumerator with hit metadata'
|
@@ -234,7 +283,7 @@ describe Elastictastic::Scope do
|
|
234
283
|
describe '#count' do
|
235
284
|
context 'with no operations performed yet' do
|
236
285
|
let!(:count) do
|
237
|
-
|
286
|
+
stub_es_search('default', 'post', 'hits' => { 'total' => 3 })
|
238
287
|
Post.all.count
|
239
288
|
end
|
240
289
|
|
@@ -249,7 +298,7 @@ describe Elastictastic::Scope do
|
|
249
298
|
|
250
299
|
context 'with scan search performed' do
|
251
300
|
let!(:count) do
|
252
|
-
|
301
|
+
stub_es_scan(
|
253
302
|
'default', 'post', 2, *make_hits(3)
|
254
303
|
)
|
255
304
|
scope = Post.all
|
@@ -268,7 +317,7 @@ describe Elastictastic::Scope do
|
|
268
317
|
|
269
318
|
context 'with paginated search performed' do
|
270
319
|
let!(:count) do
|
271
|
-
|
320
|
+
stub_es_search(
|
272
321
|
'default', 'post', 'hits' => {
|
273
322
|
'hits' => make_hits(3),
|
274
323
|
'total' => 3
|
@@ -290,7 +339,7 @@ describe Elastictastic::Scope do
|
|
290
339
|
|
291
340
|
context 'with paginated scan performed' do
|
292
341
|
let!(:count) do
|
293
|
-
|
342
|
+
stub_es_search(
|
294
343
|
'default', 'post', 'hits' => {
|
295
344
|
'hits' => make_hits(2),
|
296
345
|
'total' => 2
|
@@ -309,6 +358,17 @@ describe Elastictastic::Scope do
|
|
309
358
|
FakeWeb.should have(1).request
|
310
359
|
end
|
311
360
|
end # context 'with paginated scan performed'
|
361
|
+
|
362
|
+
context 'with routing specified' do
|
363
|
+
let!(:count) do
|
364
|
+
stub_es_search('default', 'post', 'hits' => { 'total' => 3 })
|
365
|
+
Post.routing(7).count
|
366
|
+
end
|
367
|
+
|
368
|
+
it 'should send routing parameter' do
|
369
|
+
last_request_uri.query.split('&').should include('routing=7')
|
370
|
+
end
|
371
|
+
end
|
312
372
|
end # describe '#count'
|
313
373
|
|
314
374
|
describe '#all_facets' do
|
@@ -327,7 +387,7 @@ describe Elastictastic::Scope do
|
|
327
387
|
|
328
388
|
context 'with no requests performed' do
|
329
389
|
let!(:facets) do
|
330
|
-
|
390
|
+
stub_es_search(
|
331
391
|
'default', 'post',
|
332
392
|
'hits' => { 'hits' => [], 'total' => 2 },
|
333
393
|
'facets' => facet_response
|
@@ -346,7 +406,7 @@ describe Elastictastic::Scope do
|
|
346
406
|
|
347
407
|
context 'with count request performed' do
|
348
408
|
let!(:facets) do
|
349
|
-
|
409
|
+
stub_es_search(
|
350
410
|
'default', 'post',
|
351
411
|
'hits' => { 'hits' => [], 'total' => 2 },
|
352
412
|
'facets' => facet_response
|
@@ -366,7 +426,7 @@ describe Elastictastic::Scope do
|
|
366
426
|
|
367
427
|
context 'with single-page search performed' do
|
368
428
|
let!(:facets) do
|
369
|
-
|
429
|
+
stub_es_search(
|
370
430
|
'default', 'post',
|
371
431
|
'hits' => { 'hits' => make_hits(2), 'total' => 2 },
|
372
432
|
'facets' => facet_response
|
@@ -387,7 +447,7 @@ describe Elastictastic::Scope do
|
|
387
447
|
|
388
448
|
context 'with multi-page search performed' do
|
389
449
|
let!(:facets) do
|
390
|
-
|
450
|
+
stub_es_search(
|
391
451
|
'default', 'post',
|
392
452
|
'hits' => { 'hits' => make_hits(2), 'total' => 2 },
|
393
453
|
'facets' => facet_response
|
@@ -410,7 +470,7 @@ describe Elastictastic::Scope do
|
|
410
470
|
describe '#first' do
|
411
471
|
shared_examples_for 'first method' do
|
412
472
|
before do
|
413
|
-
|
473
|
+
stub_es_search(
|
414
474
|
index, 'post', 'hits' => {
|
415
475
|
'total' => 12,
|
416
476
|
'hits' => make_hits(1)
|
@@ -6,6 +6,8 @@ require File.expand_path('../spec_helper', __FILE__)
|
|
6
6
|
# search and dealing with the results
|
7
7
|
#
|
8
8
|
describe Elastictastic::Search do
|
9
|
+
include Elastictastic::TestHelpers
|
10
|
+
|
9
11
|
describe '#to_params' do
|
10
12
|
{
|
11
13
|
'query' => { 'match_all' => {} },
|
@@ -47,6 +49,30 @@ describe Elastictastic::Search do
|
|
47
49
|
end
|
48
50
|
end
|
49
51
|
|
52
|
+
describe '#[]' do
|
53
|
+
it 'should run #first query with an integer argument' do
|
54
|
+
stub_es_search('default', 'post', 'hits' => {
|
55
|
+
'total' => '2',
|
56
|
+
'hits' => [generate_es_hit('post', :id => '1')]
|
57
|
+
})
|
58
|
+
Post.all[4].id.should == '1'
|
59
|
+
last_request_json['from'].should == 4
|
60
|
+
last_request_json['size'].should == 1
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should add from/size to scope with a range argument' do
|
64
|
+
params = Post.all[2..4].params
|
65
|
+
params['from'].should == 2
|
66
|
+
params['size'].should == 3
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should add from/size to scope with an end-excluded range argument' do
|
70
|
+
params = Post.all[2...4].params
|
71
|
+
params['from'].should == 2
|
72
|
+
params['size'].should == 2
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
50
76
|
describe 'merging' do
|
51
77
|
let(:scope) { Post }
|
52
78
|
|
@@ -21,12 +21,18 @@ describe Elastictastic::Validations do
|
|
21
21
|
it 'should raise Elastictastic::RecordInvalid for save!' do
|
22
22
|
expect { post.save! }.to raise_error(Elastictastic::RecordInvalid)
|
23
23
|
end
|
24
|
+
|
25
|
+
it 'should save successfully if validations disabled' do
|
26
|
+
stub_es_create('default', 'post')
|
27
|
+
post.save(:validate => false)
|
28
|
+
FakeWeb.last_request.path.should == '/default/post'
|
29
|
+
end
|
24
30
|
end
|
25
31
|
|
26
32
|
describe 'with valid data' do
|
27
33
|
let(:post) { Post.new }
|
28
34
|
|
29
|
-
before {
|
35
|
+
before { stub_es_create('default', 'post') }
|
30
36
|
|
31
37
|
it 'should be valid' do
|
32
38
|
post.should be_valid
|
data/spec/models/author.rb
CHANGED
data/spec/models/blog.rb
CHANGED
data/spec/models/comment.rb
CHANGED
data/spec/models/post.rb
CHANGED
@@ -3,12 +3,15 @@ class Post
|
|
3
3
|
|
4
4
|
field :title
|
5
5
|
field :comments_count, :type => 'integer'
|
6
|
+
field :score, :type => 'integer'
|
6
7
|
field :tags, :index => 'analyzed' do
|
7
8
|
field :non_analyzed, :index => 'not_analyzed'
|
8
9
|
end
|
9
10
|
field :created_at, :type => 'date'
|
10
11
|
field :published_at, :type => 'date'
|
11
12
|
|
13
|
+
boost :score
|
14
|
+
|
12
15
|
embed :author
|
13
16
|
embed :comments
|
14
17
|
|