elastic_searchable 1.5 → 1.6
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 +7 -0
- data/.gitignore +2 -0
- data/.rvmrc +1 -1
- data/.travis.yml +5 -0
- data/CONTRIBUTORS.txt +1 -0
- data/Rakefile +7 -9
- data/elastic_searchable.gemspec +5 -4
- data/lib/elastic_searchable/index.rb +7 -5
- data/lib/elastic_searchable/version.rb +1 -1
- data/spec/elastic_searchable_spec.rb +433 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/support/blog.rb +6 -0
- data/spec/support/book.rb +10 -0
- data/spec/support/database.yml +3 -0
- data/spec/support/friend.rb +4 -0
- data/spec/support/max_page_size_class.rb +6 -0
- data/spec/support/post.rb +26 -0
- data/{test → spec/support}/setup_database.rb +0 -0
- data/spec/support/user.rb +8 -0
- metadata +71 -64
- data/test/database.yml +0 -3
- data/test/helper.rb +0 -37
- data/test/test_elastic_searchable.rb +0 -626
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 07b8465cf211c71d51f8aae0a70050d764ca5b85
|
4
|
+
data.tar.gz: 22718204ae3d09fd1e969c1a8410b4d352946ff8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 64be3a3d8766e5a9d3a2d39523172703467572e496b96d92d3167686d04b8522b2aaf8203e32c60d8db4fe40ecedea7eb1fee945d49068ef0de7c47a51c4f490
|
7
|
+
data.tar.gz: f7791b7a15d83546061e34773e580d3d4a0fdee66d277f35c793d2515a20d0c0accc4c39f82b0d400a06a2dfd0ff35dc7910a1d3cb35f917c7481af867f1e737
|
data/.gitignore
CHANGED
data/.rvmrc
CHANGED
@@ -1 +1 @@
|
|
1
|
-
rvm use
|
1
|
+
rvm use default@elastic_searchable --create
|
data/.travis.yml
ADDED
data/CONTRIBUTORS.txt
CHANGED
data/Rakefile
CHANGED
@@ -1,13 +1,11 @@
|
|
1
|
-
require
|
2
|
-
Bundler::GemHelper.install_tasks
|
1
|
+
require "bundler/gem_tasks"
|
3
2
|
|
4
3
|
require 'rake'
|
5
4
|
|
6
|
-
require '
|
7
|
-
Rake::TestTask.new(:test) do |test|
|
8
|
-
test.libs << 'lib' << 'test'
|
9
|
-
test.pattern = 'test/**/test_*.rb'
|
10
|
-
test.verbose = true
|
11
|
-
end
|
12
|
-
task :default => :test
|
5
|
+
require 'rspec/core/rake_task'
|
13
6
|
|
7
|
+
desc "Run specs"
|
8
|
+
RSpec::Core::RakeTask.new do |t|
|
9
|
+
end
|
10
|
+
task :default => :spec
|
11
|
+
task :test => :spec
|
data/elastic_searchable.gemspec
CHANGED
@@ -23,9 +23,10 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.add_runtime_dependency(%q<httparty>, [">= 0.6.0"])
|
24
24
|
s.add_runtime_dependency(%q<backgrounded>, ["~> 0.7.0"])
|
25
25
|
s.add_runtime_dependency(%q<multi_json>, [">= 1.0.0"])
|
26
|
-
s.add_development_dependency(%q<rake
|
26
|
+
s.add_development_dependency(%q<rake>)
|
27
27
|
s.add_development_dependency(%q<sqlite3>)
|
28
|
-
s.add_development_dependency(%q<pry
|
29
|
-
s.add_development_dependency(%q<
|
30
|
-
s.add_development_dependency(%q<
|
28
|
+
s.add_development_dependency(%q<pry>)
|
29
|
+
s.add_development_dependency(%q<rspec>)
|
30
|
+
s.add_development_dependency(%q<byebug>)
|
31
|
+
s.add_development_dependency(%q<prefactory>)
|
31
32
|
end
|
@@ -111,15 +111,15 @@ module ElasticSearchable
|
|
111
111
|
# see http://www.elasticsearch.org/guide/reference/api/index_.html
|
112
112
|
def reindex(lifecycle = nil)
|
113
113
|
query = {}
|
114
|
-
|
115
|
-
response = ElasticSearchable.request :put, self.class.index_type_path(self.id), :query => query, :json_body => self.as_json_for_index
|
114
|
+
response = ElasticSearchable.request :put, self.class.index_type_path(id), :query => query, :json_body => as_json_for_index
|
116
115
|
|
117
116
|
self.index_lifecycle = lifecycle ? lifecycle.to_sym : nil
|
118
117
|
run_callbacks :index
|
119
118
|
|
120
|
-
self.
|
121
|
-
run_callbacks :percolate if
|
119
|
+
self.percolate if _percolate_callbacks.any?
|
120
|
+
run_callbacks :percolate if percolations.any?
|
122
121
|
end
|
122
|
+
|
123
123
|
# document to index in elasticsearch
|
124
124
|
def as_json_for_index
|
125
125
|
original_include_root_in_json = self.class.include_root_in_json
|
@@ -128,10 +128,12 @@ module ElasticSearchable
|
|
128
128
|
ensure
|
129
129
|
self.class.include_root_in_json = original_include_root_in_json
|
130
130
|
end
|
131
|
+
|
131
132
|
def should_index?
|
132
133
|
[self.class.elastic_options[:if]].flatten.compact.all? { |m| evaluate_elastic_condition(m) } &&
|
133
134
|
![self.class.elastic_options[:unless]].flatten.compact.any? { |m| evaluate_elastic_condition(m) }
|
134
135
|
end
|
136
|
+
|
135
137
|
# percolate this object to see what registered searches match
|
136
138
|
# can be done on transient/non-persisted objects!
|
137
139
|
# can be done automatically when indexing using :percolate => true config option
|
@@ -140,7 +142,7 @@ module ElasticSearchable
|
|
140
142
|
body = {:doc => self.as_json_for_index}
|
141
143
|
body[:query] = percolator_query if percolator_query
|
142
144
|
response = ElasticSearchable.request :get, self.class.index_type_path('_percolate'), :json_body => body
|
143
|
-
self.percolations = response['matches'] || []
|
145
|
+
self.percolations = (response['matches'] || []).map { |match| match['_id'] }
|
144
146
|
self.percolations
|
145
147
|
end
|
146
148
|
|
@@ -0,0 +1,433 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ElasticSearchable do
|
4
|
+
before do
|
5
|
+
begin
|
6
|
+
ElasticSearchable.delete '/elastic_searchable'
|
7
|
+
rescue
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'an ActiveRecord class that has not invoked elastic_searchable' do
|
12
|
+
before do
|
13
|
+
stub_const('Parent', Class.new(ActiveRecord::Base))
|
14
|
+
end
|
15
|
+
let(:clazz) { Parent }
|
16
|
+
let(:instance) { clazz.new }
|
17
|
+
it do
|
18
|
+
expect(clazz).to_not respond_to :elastic_options
|
19
|
+
expect(instance).to_not respond_to :percolations
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'with an ActiveRecord class with elastic_searchable config' do
|
24
|
+
let(:clazz) { Post }
|
25
|
+
let(:instance) { Post.new }
|
26
|
+
it do
|
27
|
+
expect(clazz).to respond_to :search
|
28
|
+
expect(clazz).to respond_to :elastic_options
|
29
|
+
expect(clazz.elastic_options[:unless]).to include :elasticsearch_offline?
|
30
|
+
expect(instance).to respond_to :percolations
|
31
|
+
expect(instance.percolations).to eq []
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '.request' do
|
35
|
+
subject(:sending_request) { ElasticSearchable.request method, url }
|
36
|
+
context 'GET' do
|
37
|
+
let(:method) { :get }
|
38
|
+
context 'with invalid url' do
|
39
|
+
let(:url) { '/elastic_searchable/foobar/notfound' }
|
40
|
+
it { expect { sending_request }.to raise_error ElasticSearchable::ElasticError }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '.create_index' do
|
46
|
+
let(:index_status) { ElasticSearchable.request :get, '/elastic_searchable/_status' }
|
47
|
+
context 'when it has not been called' do
|
48
|
+
it { expect { index_status }.to raise_error }
|
49
|
+
end
|
50
|
+
context 'when it has been called' do
|
51
|
+
before do
|
52
|
+
Post.create_index
|
53
|
+
Post.refresh_index
|
54
|
+
end
|
55
|
+
it { expect { index_status }.not_to raise_error }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe 'create callbacks' do
|
60
|
+
let!(:post) { Post.create :title => 'foo', :body => "bar" }
|
61
|
+
it 'fires index callbacks' do
|
62
|
+
expect(post).to be_indexed
|
63
|
+
expect(post).to be_indexed_on_create
|
64
|
+
expect(post).not_to be_indexed_on_update
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe 'update callbacks' do
|
69
|
+
before do
|
70
|
+
Post.create :title => 'foo', :body => 'bar'
|
71
|
+
end
|
72
|
+
let(:post) do
|
73
|
+
Post.last.tap do |post|
|
74
|
+
post.title = 'baz'
|
75
|
+
post.save
|
76
|
+
end
|
77
|
+
end
|
78
|
+
it do
|
79
|
+
expect(post).to be_indexed
|
80
|
+
expect(post).not_to be_indexed_on_create
|
81
|
+
expect(post).to be_indexed_on_update
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe 'ElasticSearchable.offline' do
|
86
|
+
let!(:post) do
|
87
|
+
ElasticSearchable.offline do
|
88
|
+
Post.create :title => 'foo', :body => "bar"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
it do
|
92
|
+
expect(post).not_to be_indexed
|
93
|
+
expect(post).not_to be_indexed_on_create
|
94
|
+
expect(post).not_to be_indexed_on_update
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'with an empty index and multiple database records' do
|
99
|
+
before do
|
100
|
+
Post.delete_all
|
101
|
+
Post.create_index
|
102
|
+
Post.create :title => 'foo', :body => "first bar"
|
103
|
+
Post.create :title => 'foo', :body => "second bar"
|
104
|
+
Post.delete_index
|
105
|
+
Post.create_index
|
106
|
+
Post.refresh_index
|
107
|
+
end
|
108
|
+
let!(:first_post) { Post.where(:body => "first bar").first }
|
109
|
+
let!(:second_post) { Post.where(:body => "second bar").first }
|
110
|
+
it 'does not raise error if an error occurs when reindexing model' do
|
111
|
+
expect_any_instance_of(Logger).to receive(:warn).at_least(:once)
|
112
|
+
expect(ElasticSearchable).to receive(:request).and_raise(ElasticSearchable::ElasticError.new('faux error'))
|
113
|
+
expect { Post.reindex }.not_to raise_error
|
114
|
+
end
|
115
|
+
it 'does not raise error when destroying one instance' do
|
116
|
+
expect_any_instance_of(Logger).to receive(:warn).at_least(:once)
|
117
|
+
expect { first_post.destroy }.not_to raise_error
|
118
|
+
end
|
119
|
+
describe ".reindex" do
|
120
|
+
before do
|
121
|
+
Post.reindex :per_page => 1, :scope => Post.order('body desc')
|
122
|
+
Post.refresh_index
|
123
|
+
end
|
124
|
+
it do
|
125
|
+
expect { ElasticSearchable.request :get, "/elastic_searchable/posts/#{first_post.id}" }.to_not raise_error
|
126
|
+
expect { ElasticSearchable.request :get, "/elastic_searchable/posts/#{second_post.id}" }.to_not raise_error
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'with the index containing multiple results' do
|
132
|
+
before do
|
133
|
+
Post.create_index
|
134
|
+
Post.create :title => 'foo', :body => "first bar"
|
135
|
+
Post.create :title => 'foo', :body => "second bar"
|
136
|
+
Post.refresh_index
|
137
|
+
end
|
138
|
+
let!(:first_post) { Post.where(:body => "first bar").first }
|
139
|
+
let!(:second_post) { Post.where(:body => "second bar").first }
|
140
|
+
|
141
|
+
context 'searching on a term that returns one result' do
|
142
|
+
subject(:results) { Post.search 'first' }
|
143
|
+
it do
|
144
|
+
is_expected.to include first_post
|
145
|
+
expect(results.current_page).to eq 1
|
146
|
+
expect(results.per_page).to eq Post.per_page
|
147
|
+
expect(results.previous_page).to be_nil
|
148
|
+
expect(results.next_page).to be_nil
|
149
|
+
expect(results.first.hit['_id']).to eq first_post.id.to_s
|
150
|
+
end
|
151
|
+
end
|
152
|
+
context 'searching on a term that returns multiple results' do
|
153
|
+
subject(:results) { Post.search 'foo' }
|
154
|
+
it do
|
155
|
+
is_expected.to include first_post
|
156
|
+
is_expected.to include second_post
|
157
|
+
expect(results.current_page).to eq 1
|
158
|
+
expect(results.per_page).to eq Post.per_page
|
159
|
+
expect(results.previous_page).to be_nil
|
160
|
+
expect(results.next_page).to be_nil
|
161
|
+
expect(results.first.hit['_id']).to eq first_post.id.to_s
|
162
|
+
expect(results.last.hit['_id']).to eq second_post.id.to_s
|
163
|
+
end
|
164
|
+
end
|
165
|
+
context 'searching for results using a query Hash' do
|
166
|
+
subject(:results) do
|
167
|
+
Post.search({
|
168
|
+
:filtered => {
|
169
|
+
:query => {
|
170
|
+
:term => {:title => 'foo'},
|
171
|
+
},
|
172
|
+
:filter => {
|
173
|
+
:or => [
|
174
|
+
{:term => {:body => 'second'}},
|
175
|
+
{:term => {:body => 'third'}}
|
176
|
+
]
|
177
|
+
}
|
178
|
+
}
|
179
|
+
})
|
180
|
+
end
|
181
|
+
it do
|
182
|
+
is_expected.to_not include first_post
|
183
|
+
is_expected.to include second_post
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
context 'when per_page is a string' do
|
188
|
+
subject(:results) { Post.search 'foo', :per_page => 1.to_s, :sort => 'id' }
|
189
|
+
it { expect(results).to include first_post }
|
190
|
+
end
|
191
|
+
|
192
|
+
context 'searching for second page using will_paginate params' do
|
193
|
+
subject(:results) { Post.search 'foo', :page => 2, :per_page => 1, :sort => 'id' }
|
194
|
+
it do
|
195
|
+
expect(results).not_to include first_post
|
196
|
+
expect(results).to include second_post
|
197
|
+
expect(results.current_page).to eq 2
|
198
|
+
expect(results.per_page).to eq 1
|
199
|
+
expect(results.previous_page).to eq 1
|
200
|
+
expect(results.next_page).to be_nil
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
context 'sorting search results' do
|
205
|
+
subject(:results) { Post.search 'foo', :sort => 'id:desc' }
|
206
|
+
it 'sorts results correctly' do
|
207
|
+
expect(results).to eq [second_post, first_post]
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
context 'advanced sort options' do
|
212
|
+
subject(:results) { Post.search 'foo', :sort => [{:id => 'desc'}] }
|
213
|
+
it 'sorts results correctly' do
|
214
|
+
expect(results).to eq [second_post, first_post]
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
context 'destroying one object' do
|
219
|
+
before do
|
220
|
+
first_post.destroy
|
221
|
+
Post.refresh_index
|
222
|
+
end
|
223
|
+
it 'is removed from the index' do
|
224
|
+
expect(ElasticSearchable.get("/elastic_searchable/posts/#{first_post.id}").response).to be_a Net::HTTPNotFound
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
context 'deleting a record without updating the index' do
|
230
|
+
|
231
|
+
context 'backfilling partial result pages' do
|
232
|
+
let!(:posts) do
|
233
|
+
posts = (1..8).map do |i|
|
234
|
+
Post.create :title => 'foo', :body => "#{i} bar"
|
235
|
+
end
|
236
|
+
Post.refresh_index
|
237
|
+
posts
|
238
|
+
end
|
239
|
+
subject(:results) { Post.search 'foo', :size => 4, :sort => 'id:desc' }
|
240
|
+
it 'backfills the first page with results from other pages' do
|
241
|
+
removed_posts = []
|
242
|
+
posts.each_with_index do |post, i|
|
243
|
+
if i % 2 == 1
|
244
|
+
removed_posts << post
|
245
|
+
expect(Post).to receive(:delete_id_from_index_backgrounded).with(post.id)
|
246
|
+
post.delete
|
247
|
+
end
|
248
|
+
end
|
249
|
+
expect(results).to match_array(posts - removed_posts)
|
250
|
+
expect(results.total_entries).to eq 4
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
context 'activerecord class with optional :if=>proc configuration' do
|
257
|
+
context 'when creating new instance' do
|
258
|
+
it do
|
259
|
+
expect_any_instance_of(Blog).to_not receive(:reindex)
|
260
|
+
blog = Blog.create! :title => 'foo'
|
261
|
+
expect(ElasticSearchable.get("/elastic_searchable/blogs/#{blog.id}").response).to be_a Net::HTTPNotFound
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
context 'activerecord class with :index_options and :mapping' do
|
267
|
+
context 'creating index' do
|
268
|
+
before do
|
269
|
+
User.create_index
|
270
|
+
end
|
271
|
+
it 'uses custom index_options' do
|
272
|
+
settings = ElasticSearchable.request(:get, '/elastic_searchable/_settings')['elastic_searchable']['settings']['index']
|
273
|
+
settings.delete('version')
|
274
|
+
settings.delete('uuid')
|
275
|
+
expect(settings).to eq(
|
276
|
+
"analysis" => {
|
277
|
+
"analyzer" => {
|
278
|
+
"default"=> {
|
279
|
+
"filter" => [ "standard", "lowercase", "porterStem"],
|
280
|
+
"tokenizer" => "standard"
|
281
|
+
}
|
282
|
+
}
|
283
|
+
},
|
284
|
+
"number_of_shards"=>"1",
|
285
|
+
"number_of_replicas"=>"0"
|
286
|
+
)
|
287
|
+
end
|
288
|
+
it 'has set mapping' do
|
289
|
+
status = ElasticSearchable.request :get, '/elastic_searchable/users/_mapping'
|
290
|
+
expect(status['elastic_searchable']['mappings']['users']['properties']).to eq(
|
291
|
+
"name"=> {"type"=>"string", "index"=>"not_analyzed"}
|
292
|
+
)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
context 'activerecord class with optional :json config' do
|
298
|
+
context 'creating index' do
|
299
|
+
let!(:friend) do
|
300
|
+
Friend.create_index
|
301
|
+
book = Book.create! :isbn => '123abc', :title => 'another world'
|
302
|
+
friend = Friend.new :name => 'bob', :favorite_color => 'red'
|
303
|
+
friend.book = book
|
304
|
+
friend.save!
|
305
|
+
Friend.refresh_index
|
306
|
+
friend
|
307
|
+
end
|
308
|
+
subject(:json) { ElasticSearchable.request(:get, "/elastic_searchable/friends/#{friend.id}")['_source'] }
|
309
|
+
it 'indexes json with configuration' do
|
310
|
+
expect(json['favorite_color']).to be_nil
|
311
|
+
expect(json['book'].key?('isbn')).to be_falsey
|
312
|
+
expect(json).to eq(
|
313
|
+
"name" => 'bob',
|
314
|
+
'book' => { 'title' => 'another world' }
|
315
|
+
)
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
context 'updating ElasticSearchable.default_index' do
|
321
|
+
before do
|
322
|
+
ElasticSearchable.default_index = 'my_new_index'
|
323
|
+
end
|
324
|
+
after do
|
325
|
+
ElasticSearchable.default_index = ElasticSearchable::DEFAULT_INDEX
|
326
|
+
end
|
327
|
+
it { expect(ElasticSearchable.default_index).to eq 'my_new_index' }
|
328
|
+
end
|
329
|
+
|
330
|
+
context 'Book class with after_percolate callback' do
|
331
|
+
context 'with created index and populated fields' do
|
332
|
+
before do
|
333
|
+
Book.create_index
|
334
|
+
Book.create! :title => 'baz'
|
335
|
+
end
|
336
|
+
context "when index has configured percolation" do
|
337
|
+
before do
|
338
|
+
ElasticSearchable.request :put, '/elastic_searchable/.percolator/myfilter', :json_body => {:query => {:query_string => {:query => 'foo' }}}
|
339
|
+
ElasticSearchable.request :post, '/elastic_searchable/_refresh'
|
340
|
+
end
|
341
|
+
context 'creating an object that does not match the percolation' do
|
342
|
+
it 'does not percolate the record' do
|
343
|
+
expect_any_instance_of(Book).to_not receive(:on_percolated)
|
344
|
+
Book.create! :title => 'bar'
|
345
|
+
end
|
346
|
+
end
|
347
|
+
context 'creating an object that matches the percolation' do
|
348
|
+
let!(:book) do
|
349
|
+
Book.create :title => "foo"
|
350
|
+
end
|
351
|
+
it do
|
352
|
+
expect(book.percolated).to eq ['myfilter']
|
353
|
+
end
|
354
|
+
end
|
355
|
+
context 'percolating a non-persisted object' do
|
356
|
+
let!(:matches) { Book.new(:title => 'foo').percolate }
|
357
|
+
it do
|
358
|
+
expect(matches).to eq ['myfilter']
|
359
|
+
end
|
360
|
+
end
|
361
|
+
context "with multiple percolators in the index" do
|
362
|
+
before do
|
363
|
+
ElasticSearchable.request :put, '/elastic_searchable/.percolator/greenfilter', :json_body => { :color => 'green', :query => {:query_string => {:query => 'foo' }}}
|
364
|
+
ElasticSearchable.request :put, '/elastic_searchable/.percolator/bluefilter', :json_body => { :color => 'blue', :query => {:query_string => {:query => 'foo' }}}
|
365
|
+
ElasticSearchable.request :post, '/elastic_searchable/_refresh'
|
366
|
+
end
|
367
|
+
context 'percolating a non-persisted object with no limitation' do
|
368
|
+
let!(:matches) { Book.new(:title => 'foo').percolate }
|
369
|
+
it 'returns all percolated matches' do
|
370
|
+
expect(matches).to match_array ['myfilter', 'greenfilter', 'bluefilter']
|
371
|
+
expect(matches.size).to eq 3
|
372
|
+
end
|
373
|
+
end
|
374
|
+
context 'percolating a non-persisted object with limitations' do
|
375
|
+
let!(:matches) { Book.new(:title => 'foo').percolate(:term => { :color => 'green' }) }
|
376
|
+
it 'returns limited percolated matches' do
|
377
|
+
expect(matches).to eq ['greenfilter']
|
378
|
+
end
|
379
|
+
end
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
context 'with 2 MaxPageSizeClass instances' do
|
386
|
+
before do
|
387
|
+
MaxPageSizeClass.create_index
|
388
|
+
MaxPageSizeClass.create! :name => 'foo one'
|
389
|
+
MaxPageSizeClass.create! :name => 'foo two'
|
390
|
+
MaxPageSizeClass.refresh_index
|
391
|
+
end
|
392
|
+
let!(:first) { MaxPageSizeClass.where(:name => 'foo one').first }
|
393
|
+
let!(:second) { MaxPageSizeClass.where(:name => 'foo two').first }
|
394
|
+
subject(:results) { MaxPageSizeClass.search 'foo' }
|
395
|
+
context 'MaxPageSizeClass.search with default options and WillPaginate' do
|
396
|
+
before do
|
397
|
+
ElasticSearchable::Paginator.handler = ElasticSearchable::Pagination::WillPaginate
|
398
|
+
end
|
399
|
+
it do
|
400
|
+
expect(results.per_page).to eq 1
|
401
|
+
expect(results.length).to eq 1
|
402
|
+
expect(results.total_entries).to eq 2
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
context 'MaxPageSizeClass.search with default options and Kaminari' do
|
407
|
+
before do
|
408
|
+
ElasticSearchable::Paginator.handler = ElasticSearchable::Pagination::Kaminari
|
409
|
+
@results = MaxPageSizeClass.search 'foo'
|
410
|
+
end
|
411
|
+
it do
|
412
|
+
expect(results.per_page).to eq 1
|
413
|
+
expect(results.length).to eq 1
|
414
|
+
expect(results.total_entries).to eq 2
|
415
|
+
expect(results.num_pages).to eq 2
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
describe '.escape_query' do
|
420
|
+
let(:backslash) { "\\" }
|
421
|
+
shared_examples_for "escaped" do
|
422
|
+
it { expect(ElasticSearchable.escape_query(queryString)).to eq(backslash + queryString) }
|
423
|
+
end
|
424
|
+
%w| ! ^ + - { } [ ] ~ * : ? ( ) "|.each do |mark|
|
425
|
+
context "escaping '#{mark}'" do
|
426
|
+
let(:queryString) { mark }
|
427
|
+
it_behaves_like "escaped"
|
428
|
+
end
|
429
|
+
end
|
430
|
+
end
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|