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
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
require 'yaml'
|
4
|
+
require 'byebug'
|
5
|
+
|
6
|
+
begin
|
7
|
+
Bundler.setup
|
8
|
+
rescue Bundler::BundlerError => e
|
9
|
+
$stderr.puts e.message
|
10
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
11
|
+
exit e.status_code
|
12
|
+
end
|
13
|
+
require 'rspec/matchers'
|
14
|
+
|
15
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
16
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
17
|
+
|
18
|
+
require 'elastic_searchable'
|
19
|
+
require 'prefactory'
|
20
|
+
|
21
|
+
SINGLE_NODE_CLUSTER_CONFIG = {
|
22
|
+
'number_of_replicas' => 0,
|
23
|
+
'number_of_shards' => 1
|
24
|
+
}
|
25
|
+
|
26
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
27
|
+
|
28
|
+
RSpec.configure do |config|
|
29
|
+
config.include Prefactory
|
30
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Post < ActiveRecord::Base
|
2
|
+
Post.class_eval do
|
3
|
+
elastic_searchable :index_options => SINGLE_NODE_CLUSTER_CONFIG
|
4
|
+
after_index :indexed
|
5
|
+
after_index :indexed_on_create, :on => :create
|
6
|
+
after_index :indexed_on_update, :on => :update
|
7
|
+
def indexed
|
8
|
+
@indexed = true
|
9
|
+
end
|
10
|
+
def indexed?
|
11
|
+
@indexed
|
12
|
+
end
|
13
|
+
def indexed_on_create
|
14
|
+
@indexed_on_create = true
|
15
|
+
end
|
16
|
+
def indexed_on_create?
|
17
|
+
@indexed_on_create
|
18
|
+
end
|
19
|
+
def indexed_on_update
|
20
|
+
@indexed_on_update = true
|
21
|
+
end
|
22
|
+
def indexed_on_update?
|
23
|
+
@indexed_on_update
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
File without changes
|
@@ -0,0 +1,8 @@
|
|
1
|
+
class User < ActiveRecord::Base
|
2
|
+
elastic_searchable :index_options => {
|
3
|
+
'number_of_replicas' => 0,
|
4
|
+
'number_of_shards' => 1,
|
5
|
+
"analysis.analyzer.default.tokenizer" => 'standard',
|
6
|
+
"analysis.analyzer.default.filter" => ["standard", "lowercase", 'porterStem']},
|
7
|
+
:mapping => {:properties => {:name => {:type => 'string', :index => 'not_analyzed'}}}
|
8
|
+
end
|
metadata
CHANGED
@@ -1,158 +1,153 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: elastic_searchable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '1.
|
5
|
-
prerelease:
|
4
|
+
version: '1.6'
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Ryan Sonnek
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2014-09-09 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: activerecord
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - ">="
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: 3.0.5
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - ">="
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: 3.0.5
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: httparty
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - ">="
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: 0.6.0
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - ">="
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: 0.6.0
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: backgrounded
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- - ~>
|
45
|
+
- - "~>"
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: 0.7.0
|
54
48
|
type: :runtime
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- - ~>
|
52
|
+
- - "~>"
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: 0.7.0
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: multi_json
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
|
-
- -
|
59
|
+
- - ">="
|
68
60
|
- !ruby/object:Gem::Version
|
69
61
|
version: 1.0.0
|
70
62
|
type: :runtime
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
|
-
- -
|
66
|
+
- - ">="
|
76
67
|
- !ruby/object:Gem::Version
|
77
68
|
version: 1.0.0
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: rake
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
|
-
- -
|
73
|
+
- - ">="
|
84
74
|
- !ruby/object:Gem::Version
|
85
|
-
version: 0
|
75
|
+
version: '0'
|
86
76
|
type: :development
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
|
-
- -
|
80
|
+
- - ">="
|
92
81
|
- !ruby/object:Gem::Version
|
93
|
-
version: 0
|
82
|
+
version: '0'
|
94
83
|
- !ruby/object:Gem::Dependency
|
95
84
|
name: sqlite3
|
96
85
|
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
86
|
requirements:
|
99
|
-
- -
|
87
|
+
- - ">="
|
100
88
|
- !ruby/object:Gem::Version
|
101
89
|
version: '0'
|
102
90
|
type: :development
|
103
91
|
prerelease: false
|
104
92
|
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
none: false
|
106
93
|
requirements:
|
107
|
-
- -
|
94
|
+
- - ">="
|
108
95
|
- !ruby/object:Gem::Version
|
109
96
|
version: '0'
|
110
97
|
- !ruby/object:Gem::Dependency
|
111
98
|
name: pry
|
112
99
|
requirement: !ruby/object:Gem::Requirement
|
113
|
-
none: false
|
114
100
|
requirements:
|
115
|
-
- -
|
101
|
+
- - ">="
|
116
102
|
- !ruby/object:Gem::Version
|
117
|
-
version: 0
|
103
|
+
version: '0'
|
118
104
|
type: :development
|
119
105
|
prerelease: false
|
120
106
|
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
none: false
|
122
107
|
requirements:
|
123
|
-
- -
|
108
|
+
- - ">="
|
124
109
|
- !ruby/object:Gem::Version
|
125
|
-
version: 0
|
110
|
+
version: '0'
|
126
111
|
- !ruby/object:Gem::Dependency
|
127
|
-
name:
|
112
|
+
name: rspec
|
128
113
|
requirement: !ruby/object:Gem::Requirement
|
129
|
-
none: false
|
130
114
|
requirements:
|
131
|
-
- -
|
115
|
+
- - ">="
|
132
116
|
- !ruby/object:Gem::Version
|
133
|
-
version:
|
117
|
+
version: '0'
|
134
118
|
type: :development
|
135
119
|
prerelease: false
|
136
120
|
version_requirements: !ruby/object:Gem::Requirement
|
137
|
-
none: false
|
138
121
|
requirements:
|
139
|
-
- -
|
122
|
+
- - ">="
|
140
123
|
- !ruby/object:Gem::Version
|
141
|
-
version:
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: byebug
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
142
139
|
- !ruby/object:Gem::Dependency
|
143
|
-
name:
|
140
|
+
name: prefactory
|
144
141
|
requirement: !ruby/object:Gem::Requirement
|
145
|
-
none: false
|
146
142
|
requirements:
|
147
|
-
- -
|
143
|
+
- - ">="
|
148
144
|
- !ruby/object:Gem::Version
|
149
145
|
version: '0'
|
150
146
|
type: :development
|
151
147
|
prerelease: false
|
152
148
|
version_requirements: !ruby/object:Gem::Requirement
|
153
|
-
none: false
|
154
149
|
requirements:
|
155
|
-
- -
|
150
|
+
- - ">="
|
156
151
|
- !ruby/object:Gem::Version
|
157
152
|
version: '0'
|
158
153
|
description: integrate the elastic search engine with rails
|
@@ -162,9 +157,10 @@ executables: []
|
|
162
157
|
extensions: []
|
163
158
|
extra_rdoc_files: []
|
164
159
|
files:
|
165
|
-
- .document
|
166
|
-
- .gitignore
|
167
|
-
- .rvmrc
|
160
|
+
- ".document"
|
161
|
+
- ".gitignore"
|
162
|
+
- ".rvmrc"
|
163
|
+
- ".travis.yml"
|
168
164
|
- CONTRIBUTORS.txt
|
169
165
|
- Gemfile
|
170
166
|
- LICENSE.txt
|
@@ -180,36 +176,47 @@ files:
|
|
180
176
|
- lib/elastic_searchable/paginator.rb
|
181
177
|
- lib/elastic_searchable/queries.rb
|
182
178
|
- lib/elastic_searchable/version.rb
|
183
|
-
-
|
184
|
-
-
|
185
|
-
-
|
186
|
-
-
|
179
|
+
- spec/elastic_searchable_spec.rb
|
180
|
+
- spec/spec_helper.rb
|
181
|
+
- spec/support/blog.rb
|
182
|
+
- spec/support/book.rb
|
183
|
+
- spec/support/database.yml
|
184
|
+
- spec/support/friend.rb
|
185
|
+
- spec/support/max_page_size_class.rb
|
186
|
+
- spec/support/post.rb
|
187
|
+
- spec/support/setup_database.rb
|
188
|
+
- spec/support/user.rb
|
187
189
|
homepage: http://github.com/socialcast/elastic_searchable
|
188
190
|
licenses: []
|
191
|
+
metadata: {}
|
189
192
|
post_install_message:
|
190
193
|
rdoc_options: []
|
191
194
|
require_paths:
|
192
195
|
- lib
|
193
196
|
required_ruby_version: !ruby/object:Gem::Requirement
|
194
|
-
none: false
|
195
197
|
requirements:
|
196
|
-
- -
|
198
|
+
- - ">="
|
197
199
|
- !ruby/object:Gem::Version
|
198
200
|
version: '0'
|
199
201
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
200
|
-
none: false
|
201
202
|
requirements:
|
202
|
-
- -
|
203
|
+
- - ">="
|
203
204
|
- !ruby/object:Gem::Version
|
204
205
|
version: '0'
|
205
206
|
requirements: []
|
206
207
|
rubyforge_project: elastic_searchable
|
207
|
-
rubygems_version:
|
208
|
+
rubygems_version: 2.2.2
|
208
209
|
signing_key:
|
209
|
-
specification_version:
|
210
|
+
specification_version: 4
|
210
211
|
summary: elastic search for activerecord
|
211
212
|
test_files:
|
212
|
-
-
|
213
|
-
-
|
214
|
-
-
|
215
|
-
-
|
213
|
+
- spec/elastic_searchable_spec.rb
|
214
|
+
- spec/spec_helper.rb
|
215
|
+
- spec/support/blog.rb
|
216
|
+
- spec/support/book.rb
|
217
|
+
- spec/support/database.yml
|
218
|
+
- spec/support/friend.rb
|
219
|
+
- spec/support/max_page_size_class.rb
|
220
|
+
- spec/support/post.rb
|
221
|
+
- spec/support/setup_database.rb
|
222
|
+
- spec/support/user.rb
|
data/test/database.yml
DELETED
data/test/helper.rb
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'bundler'
|
3
|
-
begin
|
4
|
-
Bundler.setup(:default, :development)
|
5
|
-
rescue Bundler::BundlerError => e
|
6
|
-
$stderr.puts e.message
|
7
|
-
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
-
exit e.status_code
|
9
|
-
end
|
10
|
-
require 'test/unit'
|
11
|
-
require 'shoulda'
|
12
|
-
require 'mocha/setup'
|
13
|
-
require 'pry'
|
14
|
-
|
15
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
16
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
17
|
-
require 'elastic_searchable'
|
18
|
-
require 'setup_database'
|
19
|
-
|
20
|
-
class DeprecationLogger < Logger
|
21
|
-
def format_message(severity, timestamp, progname, msg)
|
22
|
-
"#{severity} #{msg}\n"
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
DEPRECATION_LOGGER = DeprecationLogger.new(File.join(File.dirname(__FILE__), "/deprecations.log"))
|
27
|
-
ActiveSupport::Deprecation.debug = false
|
28
|
-
ActiveSupport::Deprecation::DEFAULT_BEHAVIORS[:deprecation_log] = lambda { |message, callstack|
|
29
|
-
DEPRECATION_LOGGER.warn(message)
|
30
|
-
}
|
31
|
-
ActiveSupport::Deprecation.behavior = :deprecation_log
|
32
|
-
|
33
|
-
class Test::Unit::TestCase
|
34
|
-
def delete_index
|
35
|
-
ElasticSearchable.delete '/elastic_searchable' rescue nil
|
36
|
-
end
|
37
|
-
end
|
@@ -1,626 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'helper')
|
2
|
-
|
3
|
-
class TestElasticSearchable < Test::Unit::TestCase
|
4
|
-
def setup
|
5
|
-
delete_index
|
6
|
-
end
|
7
|
-
# ElasticSearchable.debug_output
|
8
|
-
SINGLE_NODE_CLUSTER_CONFIG = {'number_of_replicas' => 0, 'number_of_shards' => 1}
|
9
|
-
|
10
|
-
context 'non elastic activerecord class' do
|
11
|
-
class Parent < ActiveRecord::Base
|
12
|
-
end
|
13
|
-
setup do
|
14
|
-
@clazz = Parent
|
15
|
-
end
|
16
|
-
should 'not respond to elastic_options' do
|
17
|
-
assert !@clazz.respond_to?(:elastic_options)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
context 'instance of non-elastic_searchable activerecord class' do
|
21
|
-
class Parent < ActiveRecord::Base
|
22
|
-
end
|
23
|
-
setup do
|
24
|
-
@instance = Parent.new
|
25
|
-
end
|
26
|
-
should 'not respond to percolations' do
|
27
|
-
assert !@instance.respond_to?(:percolations)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
class Post < ActiveRecord::Base
|
32
|
-
elastic_searchable :index_options => SINGLE_NODE_CLUSTER_CONFIG
|
33
|
-
after_index :indexed
|
34
|
-
after_index :indexed_on_create, :on => :create
|
35
|
-
after_index :indexed_on_update, :on => :update
|
36
|
-
def indexed
|
37
|
-
@indexed = true
|
38
|
-
end
|
39
|
-
def indexed?
|
40
|
-
@indexed
|
41
|
-
end
|
42
|
-
def indexed_on_create
|
43
|
-
@indexed_on_create = true
|
44
|
-
end
|
45
|
-
def indexed_on_create?
|
46
|
-
@indexed_on_create
|
47
|
-
end
|
48
|
-
def indexed_on_update
|
49
|
-
@indexed_on_update = true
|
50
|
-
end
|
51
|
-
def indexed_on_update?
|
52
|
-
@indexed_on_update
|
53
|
-
end
|
54
|
-
end
|
55
|
-
context 'activerecord class with default elastic_searchable config' do
|
56
|
-
setup do
|
57
|
-
@clazz = Post
|
58
|
-
end
|
59
|
-
should 'respond to :search' do
|
60
|
-
assert @clazz.respond_to?(:search)
|
61
|
-
end
|
62
|
-
should 'define elastic_options' do
|
63
|
-
assert @clazz.elastic_options
|
64
|
-
end
|
65
|
-
should 'respond to :percolations' do
|
66
|
-
assert @clazz.new.respond_to?(:percolations)
|
67
|
-
assert_equal [], @clazz.new.percolations
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
context 'Model.request with invalid url' do
|
72
|
-
should 'raise error' do
|
73
|
-
assert_raises ElasticSearchable::ElasticError do
|
74
|
-
ElasticSearchable.request :get, '/elastic_searchable/foobar/notfound'
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
context 'Model.create_index' do
|
80
|
-
setup do
|
81
|
-
Post.create_index
|
82
|
-
Post.refresh_index
|
83
|
-
@status = ElasticSearchable.request :get, '/elastic_searchable/_status'
|
84
|
-
end
|
85
|
-
should 'have created index' do
|
86
|
-
assert @status['ok']
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
context 'Model.create' do
|
91
|
-
setup do
|
92
|
-
@post = Post.create :title => 'foo', :body => "bar"
|
93
|
-
end
|
94
|
-
should 'have fired after_index callback' do
|
95
|
-
assert @post.indexed?
|
96
|
-
end
|
97
|
-
should 'have fired after_index_on_create callback' do
|
98
|
-
assert @post.indexed_on_create?
|
99
|
-
end
|
100
|
-
should 'not have fired after_index_on_update callback' do
|
101
|
-
assert !@post.indexed_on_update?
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
context 'Model.update' do
|
106
|
-
setup do
|
107
|
-
Post.create :title => 'foo', :body => 'bar'
|
108
|
-
@post = Post.last
|
109
|
-
@post.title = 'baz'
|
110
|
-
@post.save
|
111
|
-
end
|
112
|
-
should 'have fired after_index callback' do
|
113
|
-
assert @post.indexed?
|
114
|
-
end
|
115
|
-
should 'not have fired after_index_on_create callback' do
|
116
|
-
assert !@post.indexed_on_create?
|
117
|
-
end
|
118
|
-
should 'have fired after_index_on_update callback' do
|
119
|
-
assert @post.indexed_on_update?
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
context 'Model.create within ElasticSearchable.offline block' do
|
124
|
-
setup do
|
125
|
-
ElasticSearchable.offline do
|
126
|
-
@post = Post.create :title => 'foo', :body => "bar"
|
127
|
-
end
|
128
|
-
end
|
129
|
-
should 'not have fired after_index callback' do
|
130
|
-
assert !@post.indexed?
|
131
|
-
end
|
132
|
-
should 'not have fired after_index_on_create callback' do
|
133
|
-
assert !@post.indexed_on_create?
|
134
|
-
end
|
135
|
-
should 'not have fired after_index_on_update callback' do
|
136
|
-
assert !@post.indexed_on_update?
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
context 'with empty index when multiple database records' do
|
141
|
-
setup do
|
142
|
-
Post.delete_all
|
143
|
-
Post.create_index
|
144
|
-
@first_post = Post.create :title => 'foo', :body => "first bar"
|
145
|
-
@second_post = Post.create :title => 'foo', :body => "second bar"
|
146
|
-
Post.delete_index
|
147
|
-
Post.create_index
|
148
|
-
end
|
149
|
-
should 'not raise error if error occurs reindexing model' do
|
150
|
-
ElasticSearchable.expects(:request).raises(ElasticSearchable::ElasticError.new('faux error'))
|
151
|
-
assert_nothing_raised do
|
152
|
-
Post.reindex
|
153
|
-
end
|
154
|
-
end
|
155
|
-
should 'not raise error if destroying one instance' do
|
156
|
-
Logger.any_instance.expects(:warn)
|
157
|
-
assert_nothing_raised do
|
158
|
-
@first_post.destroy
|
159
|
-
end
|
160
|
-
end
|
161
|
-
context 'Model.reindex' do
|
162
|
-
setup do
|
163
|
-
Post.reindex :per_page => 1, :scope => Post.order('body desc')
|
164
|
-
Post.refresh_index
|
165
|
-
end
|
166
|
-
should 'have reindexed both records' do
|
167
|
-
assert_nothing_raised do
|
168
|
-
ElasticSearchable.request :get, "/elastic_searchable/posts/#{@first_post.id}"
|
169
|
-
ElasticSearchable.request :get, "/elastic_searchable/posts/#{@second_post.id}"
|
170
|
-
end
|
171
|
-
end
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
context 'with index containing multiple results' do
|
176
|
-
setup do
|
177
|
-
Post.create_index
|
178
|
-
@first_post = Post.create :title => 'foo', :body => "first bar"
|
179
|
-
@second_post = Post.create :title => 'foo', :body => "second bar"
|
180
|
-
Post.refresh_index
|
181
|
-
end
|
182
|
-
|
183
|
-
context 'searching on a term that returns one result' do
|
184
|
-
setup do
|
185
|
-
@results = Post.search 'first'
|
186
|
-
end
|
187
|
-
should 'find created object' do
|
188
|
-
assert_contains @results, @first_post
|
189
|
-
end
|
190
|
-
should 'be paginated' do
|
191
|
-
assert_equal 1, @results.current_page
|
192
|
-
assert_equal Post.per_page, @results.per_page
|
193
|
-
assert_nil @results.previous_page
|
194
|
-
assert_nil @results.next_page
|
195
|
-
end
|
196
|
-
should 'have populated hit' do
|
197
|
-
assert_equal @results.first.hit['_id'], @first_post.id.to_s
|
198
|
-
end
|
199
|
-
end
|
200
|
-
context 'searching on a term that returns multiple results' do
|
201
|
-
setup do
|
202
|
-
@results = Post.search 'foo'
|
203
|
-
end
|
204
|
-
should 'have populated hit on each record with the correct hit json' do
|
205
|
-
assert_equal @results.first.hit['_id'], @first_post.id.to_s
|
206
|
-
assert_equal @results.last.hit['_id'], @second_post.id.to_s
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
context 'searching for results using a query Hash' do
|
211
|
-
setup do
|
212
|
-
@results = Post.search({
|
213
|
-
:filtered => {
|
214
|
-
:query => {
|
215
|
-
:term => {:title => 'foo'},
|
216
|
-
},
|
217
|
-
:filter => {
|
218
|
-
:or => [
|
219
|
-
{:term => {:body => 'second'}},
|
220
|
-
{:term => {:body => 'third'}}
|
221
|
-
]
|
222
|
-
}
|
223
|
-
}
|
224
|
-
})
|
225
|
-
end
|
226
|
-
should 'find only the object which ' do
|
227
|
-
assert_does_not_contain @results, @first_post
|
228
|
-
assert_contains @results, @second_post
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
|
-
context 'when per_page is a string' do
|
233
|
-
setup do
|
234
|
-
@results = Post.search 'foo', :per_page => 1.to_s, :sort => 'id'
|
235
|
-
end
|
236
|
-
should 'find first object' do
|
237
|
-
assert_contains @results, @first_post
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
|
-
context 'searching for second page using will_paginate params' do
|
242
|
-
setup do
|
243
|
-
@results = Post.search 'foo', :page => 2, :per_page => 1, :sort => 'id'
|
244
|
-
end
|
245
|
-
should 'not find objects from first page' do
|
246
|
-
assert_does_not_contain @results, @first_post
|
247
|
-
end
|
248
|
-
should 'find second object' do
|
249
|
-
assert_contains @results, @second_post
|
250
|
-
end
|
251
|
-
should 'be paginated' do
|
252
|
-
assert_equal 2, @results.current_page
|
253
|
-
assert_equal 1, @results.per_page
|
254
|
-
assert_equal 1, @results.previous_page
|
255
|
-
assert_nil @results.next_page
|
256
|
-
end
|
257
|
-
end
|
258
|
-
|
259
|
-
context 'sorting search results' do
|
260
|
-
setup do
|
261
|
-
@results = Post.search 'foo', :sort => 'id:desc'
|
262
|
-
end
|
263
|
-
should 'sort results correctly' do
|
264
|
-
assert_equal @second_post, @results.first
|
265
|
-
assert_equal @first_post, @results.last
|
266
|
-
end
|
267
|
-
end
|
268
|
-
|
269
|
-
context 'advanced sort options' do
|
270
|
-
setup do
|
271
|
-
@results = Post.search 'foo', :sort => [{:id => 'desc'}]
|
272
|
-
end
|
273
|
-
should 'sort results correctly' do
|
274
|
-
assert_equal @second_post, @results.first
|
275
|
-
assert_equal @first_post, @results.last
|
276
|
-
end
|
277
|
-
end
|
278
|
-
|
279
|
-
context 'destroying one object' do
|
280
|
-
setup do
|
281
|
-
@first_post.destroy
|
282
|
-
Post.refresh_index
|
283
|
-
end
|
284
|
-
should 'be removed from the index' do
|
285
|
-
@request = ElasticSearchable.get "/elastic_searchable/posts/#{@first_post.id}"
|
286
|
-
assert @request.response.is_a?(Net::HTTPNotFound), @request.inspect
|
287
|
-
end
|
288
|
-
end
|
289
|
-
end
|
290
|
-
|
291
|
-
context 'deleting a record without updating the index' do
|
292
|
-
|
293
|
-
context 'backfilling partial result pages' do
|
294
|
-
setup do
|
295
|
-
@posts = (1..8).map do |i|
|
296
|
-
Post.create :title => 'foo', :body => "#{i} bar"
|
297
|
-
end
|
298
|
-
Post.refresh_index
|
299
|
-
|
300
|
-
@removed_posts = []
|
301
|
-
@posts.each_with_index do |post, i|
|
302
|
-
if i % 2 == 1
|
303
|
-
@removed_posts << post
|
304
|
-
post.delete
|
305
|
-
Post.expects(:delete_id_from_index_backgrounded).with(post.id)
|
306
|
-
end
|
307
|
-
end
|
308
|
-
|
309
|
-
assert_nothing_raised do
|
310
|
-
@results = Post.search 'foo', :size => 4, :sort => 'id:desc'
|
311
|
-
end
|
312
|
-
end
|
313
|
-
# should 'not raise an exception' do end
|
314
|
-
# should 'trigger deletion of bad index records' do end
|
315
|
-
should 'backfill the first page with results from other pages' do
|
316
|
-
assert_equal((@posts - @removed_posts).reverse, @results)
|
317
|
-
end
|
318
|
-
should 'adjust total hit count to exclude invalid results encountered from repaging' do
|
319
|
-
assert_equal 4, @results.total_entries
|
320
|
-
end
|
321
|
-
end
|
322
|
-
|
323
|
-
end
|
324
|
-
|
325
|
-
class Blog < ActiveRecord::Base
|
326
|
-
elastic_searchable :if => proc {|b| b.should_index? }, :index_options => SINGLE_NODE_CLUSTER_CONFIG
|
327
|
-
def should_index?
|
328
|
-
false
|
329
|
-
end
|
330
|
-
end
|
331
|
-
context 'activerecord class with optional :if=>proc configuration' do
|
332
|
-
context 'when creating new instance' do
|
333
|
-
setup do
|
334
|
-
Blog.any_instance.expects(:reindex).never
|
335
|
-
@blog = Blog.create! :title => 'foo'
|
336
|
-
end
|
337
|
-
should 'not index record' do end #see expectations
|
338
|
-
should 'not be found in elasticsearch' do
|
339
|
-
@request = ElasticSearchable.get "/elastic_searchable/blogs/#{@blog.id}"
|
340
|
-
assert @request.response.is_a?(Net::HTTPNotFound), @request.inspect
|
341
|
-
end
|
342
|
-
end
|
343
|
-
end
|
344
|
-
|
345
|
-
class User < ActiveRecord::Base
|
346
|
-
elastic_searchable :index_options => {
|
347
|
-
'number_of_replicas' => 0,
|
348
|
-
'number_of_shards' => 1,
|
349
|
-
"analysis.analyzer.default.tokenizer" => 'standard',
|
350
|
-
"analysis.analyzer.default.filter" => ["standard", "lowercase", 'porterStem']},
|
351
|
-
:mapping => {:properties => {:name => {:type => 'string', :index => 'not_analyzed'}}}
|
352
|
-
end
|
353
|
-
context 'activerecord class with :index_options and :mapping' do
|
354
|
-
context 'creating index' do
|
355
|
-
setup do
|
356
|
-
User.create_index
|
357
|
-
end
|
358
|
-
should 'have used custom index_options' do
|
359
|
-
@status = ElasticSearchable.request :get, '/elastic_searchable/_settings'
|
360
|
-
@status['elastic_searchable']['settings'].delete('index.version.created')
|
361
|
-
expected = {
|
362
|
-
"index.number_of_replicas" => "0",
|
363
|
-
"index.number_of_shards" => "1",
|
364
|
-
"index.analysis.analyzer.default.tokenizer" => "standard",
|
365
|
-
"index.analysis.analyzer.default.filter.0" => "standard",
|
366
|
-
"index.analysis.analyzer.default.filter.1" => "lowercase",
|
367
|
-
"index.analysis.analyzer.default.filter.2" => "porterStem"
|
368
|
-
}
|
369
|
-
assert_equal expected, @status['elastic_searchable']['settings'], @status.inspect
|
370
|
-
end
|
371
|
-
should 'have set mapping' do
|
372
|
-
@status = ElasticSearchable.request :get, '/elastic_searchable/users/_mapping'
|
373
|
-
expected = {
|
374
|
-
"name"=> {"type"=>"string", "index"=>"not_analyzed"}
|
375
|
-
}
|
376
|
-
assert_equal expected, @status['users']['properties'], @status.inspect
|
377
|
-
end
|
378
|
-
end
|
379
|
-
end
|
380
|
-
|
381
|
-
class Friend < ActiveRecord::Base
|
382
|
-
belongs_to :book
|
383
|
-
elastic_searchable :json => {:include => {:book => {:only => :title}}, :only => :name}, :index_options => SINGLE_NODE_CLUSTER_CONFIG
|
384
|
-
end
|
385
|
-
context 'activerecord class with optional :json config' do
|
386
|
-
context 'creating index' do
|
387
|
-
setup do
|
388
|
-
Friend.create_index
|
389
|
-
@book = Book.create! :isbn => '123abc', :title => 'another world'
|
390
|
-
@friend = Friend.new :name => 'bob', :favorite_color => 'red'
|
391
|
-
@friend.book = @book
|
392
|
-
@friend.save!
|
393
|
-
Friend.refresh_index
|
394
|
-
end
|
395
|
-
should 'index json with configuration' do
|
396
|
-
@response = ElasticSearchable.request :get, "/elastic_searchable/friends/#{@friend.id}"
|
397
|
-
# should not index:
|
398
|
-
# friend.favorite_color
|
399
|
-
# book.isbn
|
400
|
-
expected = {
|
401
|
-
"name" => 'bob',
|
402
|
-
'book' => {'title' => 'another world'}
|
403
|
-
}
|
404
|
-
assert_equal expected, @response['_source'], @response.inspect
|
405
|
-
end
|
406
|
-
end
|
407
|
-
end
|
408
|
-
|
409
|
-
context 'updating ElasticSearchable.default_index' do
|
410
|
-
setup do
|
411
|
-
ElasticSearchable.default_index = 'my_new_index'
|
412
|
-
end
|
413
|
-
teardown do
|
414
|
-
ElasticSearchable.default_index = ElasticSearchable::DEFAULT_INDEX
|
415
|
-
end
|
416
|
-
should 'change default index' do
|
417
|
-
assert_equal 'my_new_index', ElasticSearchable.default_index
|
418
|
-
end
|
419
|
-
end
|
420
|
-
|
421
|
-
class Book < ActiveRecord::Base
|
422
|
-
elastic_searchable
|
423
|
-
after_percolate :on_percolated
|
424
|
-
def on_percolated
|
425
|
-
@percolated = percolations
|
426
|
-
end
|
427
|
-
def percolated
|
428
|
-
@percolated
|
429
|
-
end
|
430
|
-
end
|
431
|
-
context 'Book class with after_percolate callback' do
|
432
|
-
context 'with created index' do
|
433
|
-
setup do
|
434
|
-
Book.create_index
|
435
|
-
end
|
436
|
-
context "when index has configured percolation" do
|
437
|
-
setup do
|
438
|
-
ElasticSearchable.request :put, '/_percolator/elastic_searchable/myfilter', :json_body => {:query => {:query_string => {:query => 'foo' }}}
|
439
|
-
ElasticSearchable.request :post, '/_percolator/_refresh'
|
440
|
-
end
|
441
|
-
context 'creating an object that does not match the percolation' do
|
442
|
-
setup do
|
443
|
-
Book.any_instance.expects(:on_percolated).never
|
444
|
-
@book = Book.create! :title => 'bar'
|
445
|
-
end
|
446
|
-
should 'not percolate the record' do end #see expectations
|
447
|
-
end
|
448
|
-
context 'creating an object that matches the percolation' do
|
449
|
-
setup do
|
450
|
-
@book = Book.create :title => "foo"
|
451
|
-
end
|
452
|
-
should 'return percolated matches in the callback' do
|
453
|
-
assert_equal ['myfilter'], @book.percolated
|
454
|
-
end
|
455
|
-
end
|
456
|
-
context 'percolating a non-persisted object' do
|
457
|
-
setup do
|
458
|
-
@matches = Book.new(:title => 'foo').percolate
|
459
|
-
end
|
460
|
-
should 'return percolated matches' do
|
461
|
-
assert_equal ['myfilter'], @matches
|
462
|
-
end
|
463
|
-
end
|
464
|
-
context "with multiple percolators" do
|
465
|
-
setup do
|
466
|
-
ElasticSearchable.request :put, '/_percolator/elastic_searchable/greenfilter', :json_body => { :color => 'green', :query => {:query_string => {:query => 'foo' }}}
|
467
|
-
ElasticSearchable.request :put, '/_percolator/elastic_searchable/bluefilter', :json_body => { :color => 'blue', :query => {:query_string => {:query => 'foo' }}}
|
468
|
-
ElasticSearchable.request :post, '/_percolator/_refresh'
|
469
|
-
end
|
470
|
-
context 'percolating a non-persisted object with no limitation' do
|
471
|
-
setup do
|
472
|
-
@matches = Book.new(:title => 'foo').percolate
|
473
|
-
end
|
474
|
-
should 'return all percolated matches' do
|
475
|
-
assert_equal ['bluefilter','greenfilter','myfilter'], @matches.sort
|
476
|
-
end
|
477
|
-
end
|
478
|
-
context 'percolating a non-persisted object with limitations' do
|
479
|
-
setup do
|
480
|
-
@matches = Book.new(:title => 'foo').percolate( { :term => { :color => 'green' }} )
|
481
|
-
end
|
482
|
-
should 'return limited percolated matches' do
|
483
|
-
assert_equal ['greenfilter'], @matches
|
484
|
-
end
|
485
|
-
end
|
486
|
-
end
|
487
|
-
end
|
488
|
-
end
|
489
|
-
end
|
490
|
-
|
491
|
-
class MaxPageSizeClass < ActiveRecord::Base
|
492
|
-
elastic_searchable :index_options => SINGLE_NODE_CLUSTER_CONFIG
|
493
|
-
def self.max_per_page
|
494
|
-
1
|
495
|
-
end
|
496
|
-
end
|
497
|
-
context 'with 2 MaxPageSizeClass instances' do
|
498
|
-
setup do
|
499
|
-
MaxPageSizeClass.create_index
|
500
|
-
@first = MaxPageSizeClass.create! :name => 'foo one'
|
501
|
-
@second = MaxPageSizeClass.create! :name => 'foo two'
|
502
|
-
MaxPageSizeClass.refresh_index
|
503
|
-
end
|
504
|
-
context 'MaxPageSizeClass.search with default options and WillPaginate' do
|
505
|
-
setup do
|
506
|
-
ElasticSearchable::Paginator.handler = ElasticSearchable::Pagination::WillPaginate
|
507
|
-
@results = MaxPageSizeClass.search 'foo'
|
508
|
-
end
|
509
|
-
should 'have one per page' do
|
510
|
-
assert_equal 1, @results.per_page
|
511
|
-
end
|
512
|
-
should 'return one instance' do
|
513
|
-
assert_equal 1, @results.length
|
514
|
-
end
|
515
|
-
should 'have second page' do
|
516
|
-
assert_equal 2, @results.total_entries
|
517
|
-
end
|
518
|
-
end
|
519
|
-
|
520
|
-
context 'MaxPageSizeClass.search with default options and Kaminari' do
|
521
|
-
setup do
|
522
|
-
ElasticSearchable::Paginator.handler = ElasticSearchable::Pagination::Kaminari
|
523
|
-
@results = MaxPageSizeClass.search 'foo'
|
524
|
-
end
|
525
|
-
should 'have one per page' do
|
526
|
-
assert_equal 1, @results.per_page
|
527
|
-
end
|
528
|
-
should 'return one instance' do
|
529
|
-
assert_equal 1, @results.length
|
530
|
-
end
|
531
|
-
should 'have second page' do
|
532
|
-
assert_equal 2, @results.total_entries
|
533
|
-
end
|
534
|
-
should 'have a total of 2 pages' do
|
535
|
-
assert_equal 2, @results.num_pages
|
536
|
-
end
|
537
|
-
end
|
538
|
-
|
539
|
-
context "escape_query" do
|
540
|
-
should "escape exclamation marks" do
|
541
|
-
queryString = '!'
|
542
|
-
result = ElasticSearchable.escape_query(queryString)
|
543
|
-
assert_equal '\!', result
|
544
|
-
end
|
545
|
-
|
546
|
-
should "escape ^" do
|
547
|
-
queryString = '^'
|
548
|
-
result = ElasticSearchable.escape_query(queryString)
|
549
|
-
assert_equal '\^', result
|
550
|
-
end
|
551
|
-
|
552
|
-
should "escape +" do
|
553
|
-
queryString = '+'
|
554
|
-
result = ElasticSearchable.escape_query(queryString)
|
555
|
-
assert_equal '\+', result
|
556
|
-
end
|
557
|
-
|
558
|
-
should "escape -" do
|
559
|
-
queryString = '-'
|
560
|
-
result = ElasticSearchable.escape_query(queryString)
|
561
|
-
assert_equal '\-', result
|
562
|
-
end
|
563
|
-
|
564
|
-
should "escape (" do
|
565
|
-
queryString = '('
|
566
|
-
result = ElasticSearchable.escape_query(queryString)
|
567
|
-
assert_equal '\(', result
|
568
|
-
end
|
569
|
-
|
570
|
-
should "escape )" do
|
571
|
-
queryString = ')'
|
572
|
-
result = ElasticSearchable.escape_query(queryString)
|
573
|
-
assert_equal '\)', result
|
574
|
-
end
|
575
|
-
|
576
|
-
should "escape {" do
|
577
|
-
queryString = '}'
|
578
|
-
result = ElasticSearchable.escape_query(queryString)
|
579
|
-
assert_equal '\}', result
|
580
|
-
end
|
581
|
-
|
582
|
-
should "escape [" do
|
583
|
-
queryString = '['
|
584
|
-
result = ElasticSearchable.escape_query(queryString)
|
585
|
-
assert_equal '\[', result
|
586
|
-
end
|
587
|
-
|
588
|
-
should "escape ]" do
|
589
|
-
queryString = ']'
|
590
|
-
result = ElasticSearchable.escape_query(queryString)
|
591
|
-
assert_equal '\]', result
|
592
|
-
end
|
593
|
-
|
594
|
-
should 'escape "' do
|
595
|
-
queryString = '"'
|
596
|
-
result = ElasticSearchable.escape_query(queryString)
|
597
|
-
assert_equal '\"', result
|
598
|
-
end
|
599
|
-
|
600
|
-
should "escape ~" do
|
601
|
-
queryString = '~'
|
602
|
-
result = ElasticSearchable.escape_query(queryString)
|
603
|
-
assert_equal '\~', result
|
604
|
-
end
|
605
|
-
|
606
|
-
should "escape *" do
|
607
|
-
queryString = '*'
|
608
|
-
result = ElasticSearchable.escape_query(queryString)
|
609
|
-
assert_equal '\*', result
|
610
|
-
end
|
611
|
-
|
612
|
-
should "escape :" do
|
613
|
-
queryString = ':'
|
614
|
-
result = ElasticSearchable.escape_query(queryString)
|
615
|
-
assert_equal '\:', result
|
616
|
-
end
|
617
|
-
|
618
|
-
should "escape ?" do
|
619
|
-
queryString = '?'
|
620
|
-
result = ElasticSearchable.escape_query(queryString)
|
621
|
-
assert_equal '\?', result
|
622
|
-
end
|
623
|
-
end
|
624
|
-
end
|
625
|
-
end
|
626
|
-
|