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
data/lib/elastictastic.rb
CHANGED
@@ -1,80 +1,201 @@
|
|
1
1
|
require 'active_support/core_ext'
|
2
2
|
require 'active_model'
|
3
|
+
|
4
|
+
require 'elastictastic/adapter'
|
5
|
+
require 'elastictastic/basic_document'
|
3
6
|
require 'elastictastic/errors'
|
7
|
+
require 'elastictastic/client'
|
8
|
+
require 'elastictastic/configuration'
|
9
|
+
require 'elastictastic/discrete_persistence_strategy'
|
10
|
+
require 'elastictastic/embedded_document'
|
11
|
+
require 'elastictastic/field'
|
12
|
+
require 'elastictastic/index'
|
13
|
+
require 'elastictastic/middleware'
|
14
|
+
require 'elastictastic/multi_get'
|
15
|
+
require 'elastictastic/multi_search'
|
16
|
+
require 'elastictastic/optimistic_locking'
|
17
|
+
require 'elastictastic/persistence'
|
18
|
+
require 'elastictastic/properties'
|
19
|
+
require 'elastictastic/scope'
|
20
|
+
require 'elastictastic/scope_builder'
|
21
|
+
require 'elastictastic/scoped'
|
22
|
+
require 'elastictastic/search'
|
23
|
+
require 'elastictastic/server_error'
|
24
|
+
require 'elastictastic/util'
|
4
25
|
|
5
26
|
module Elastictastic
|
6
27
|
autoload :Association, 'elastictastic/association'
|
7
28
|
autoload :BulkPersistenceStrategy, 'elastictastic/bulk_persistence_strategy'
|
8
29
|
autoload :Callbacks, 'elastictastic/callbacks'
|
9
30
|
autoload :ChildCollectionProxy, 'elastictastic/child_collection_proxy'
|
10
|
-
autoload :Client, 'elastictastic/client'
|
11
|
-
autoload :Configuration, 'elastictastic/configuration'
|
12
31
|
autoload :Dirty, 'elastictastic/dirty'
|
13
|
-
autoload :DiscretePersistenceStrategy, 'elastictastic/discrete_persistence_strategy'
|
14
32
|
autoload :Document, 'elastictastic/document'
|
15
|
-
autoload :Field, 'elastictastic/field'
|
16
|
-
autoload :Index, 'elastictastic/index'
|
17
33
|
autoload :MassAssignmentSecurity, 'elastictastic/mass_assignment_security'
|
18
|
-
autoload :Middleware, 'elastictastic/middleware'
|
19
34
|
autoload :NestedCollectionProxy, 'elastictastic/nested_collection_proxy'
|
20
|
-
autoload :NestedDocument, 'elastictastic/nested_document'
|
21
35
|
autoload :Observer, 'elastictastic/observer'
|
22
36
|
autoload :Observing, 'elastictastic/observing'
|
23
37
|
autoload :ParentChild, 'elastictastic/parent_child'
|
24
|
-
autoload :
|
25
|
-
autoload :Properties, 'elastictastic/properties'
|
26
|
-
autoload :Resource, 'elastictastic/resource'
|
27
|
-
autoload :Scope, 'elastictastic/scope'
|
28
|
-
autoload :ScopeBuilder, 'elastictastic/scope_builder'
|
29
|
-
autoload :Scoped, 'elastictastic/scoped'
|
30
|
-
autoload :Search, 'elastictastic/search'
|
31
|
-
autoload :ServerError, 'elastictastic/server_error'
|
38
|
+
autoload :Rotor, 'elastictastic/rotor'
|
32
39
|
autoload :TestHelpers, 'elastictastic/test_helpers'
|
33
|
-
autoload :
|
40
|
+
autoload :ThriftAdapter, 'elastictastic/thrift_adapter'
|
34
41
|
autoload :Validations, 'elastictastic/validations'
|
35
42
|
|
43
|
+
autoload :NestedDocument, 'elastictastic/nested_document' # Deprecated
|
44
|
+
|
36
45
|
class <<self
|
37
46
|
attr_writer :config
|
38
47
|
|
48
|
+
#
|
49
|
+
# Elastictastic global configuration. In a Rails environment, you can
|
50
|
+
# configure Elastictastic by creating a `config/elastictastic.yml` file,
|
51
|
+
# whose keys will be passed into the Configuration object when your
|
52
|
+
# application boots. In non-Rails environment, you can configure
|
53
|
+
# Elastictastic directly using the object returned by this method.
|
54
|
+
#
|
55
|
+
# @return [Configuration] global configuration object
|
56
|
+
#
|
39
57
|
def config
|
40
58
|
@config ||= Configuration.new
|
41
59
|
end
|
42
60
|
|
61
|
+
def multi_get(&block)
|
62
|
+
MultiGet.new.tap(&block).to_a
|
63
|
+
end
|
64
|
+
|
65
|
+
#
|
66
|
+
# Perform multiple searches in a single request to ElasticSearch. Each
|
67
|
+
# scope will be eagerly populated with results.
|
68
|
+
#
|
69
|
+
# @param [Scope, Array] collection of scopes to execute multisearch on
|
70
|
+
#
|
71
|
+
def multi_search(*scopes)
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
# Return a lower-level ElasticSearch client. This is likely to be extracted
|
76
|
+
# into a separate gem in the future.
|
77
|
+
#
|
78
|
+
# @return [Client] client
|
79
|
+
# @api private
|
80
|
+
#
|
43
81
|
def client
|
44
82
|
Thread.current['Elastictastic::client'] ||= Client.new(config)
|
45
83
|
end
|
46
84
|
|
85
|
+
#
|
86
|
+
# Set the current persistence strategy
|
87
|
+
#
|
88
|
+
# @param [DiscretePersistenceStrategy,BulkPersistenceStrategy] persistence strategy
|
89
|
+
# @api private
|
90
|
+
# @see ::persister
|
91
|
+
#
|
47
92
|
def persister=(persister)
|
48
93
|
Thread.current['Elastictastic::persister'] = persister
|
49
94
|
end
|
50
95
|
|
96
|
+
#
|
97
|
+
# The current persistence strategy for ElasticSearch. Usually this will
|
98
|
+
# be the DiscretePersistenceStrategy singleton; inside a ::bulk block, it
|
99
|
+
# will be an instance of BulkPersistenceStrategy
|
100
|
+
#
|
101
|
+
# @return [DiscretePersistenceStrategy,BulkPersistenceStrategy] current persistence strategy
|
102
|
+
# @api private
|
103
|
+
# @see ::bulk
|
104
|
+
#
|
51
105
|
def persister
|
52
106
|
Thread.current['Elastictastic::persister'] ||=
|
53
107
|
Elastictastic::DiscretePersistenceStrategy.instance
|
54
108
|
end
|
55
109
|
|
56
|
-
|
110
|
+
#
|
111
|
+
# Perform write operations in a single request to ElasticSearch. Highly
|
112
|
+
# recommended for any operation which writes a large quantity of data to
|
113
|
+
# ElasticSearch. Write operations (e.g. save/destroy documents) are buffered
|
114
|
+
# in the client and sent to ElasticSearch when the bulk operation exits
|
115
|
+
# (or when an auto-flush threshold is reached; see below).
|
116
|
+
#
|
117
|
+
# @example Create posts in bulk
|
118
|
+
# Elastictastic.bulk do
|
119
|
+
# params[:posts].each do |post_params|
|
120
|
+
# Post.new(post_params).save!
|
121
|
+
# end
|
122
|
+
# end # posts are actually persisted here
|
123
|
+
#
|
124
|
+
# Since write operations inside a bulk block are not performed
|
125
|
+
# synchronously, server-side errors will only be raised once the bulk block
|
126
|
+
# completes; you may pass a block into Document#save and Document#destroy
|
127
|
+
# that will be called once the operation completes. The block is passed an
|
128
|
+
# error param if the operation was not successful.
|
129
|
+
#
|
130
|
+
# @example Custom handling for conflicting IDs in a bulk block
|
131
|
+
# errors = []
|
132
|
+
# Elastictastic.bulk do
|
133
|
+
# params[:posts].each do |post_params|
|
134
|
+
# Post.new(post_params).save! do |e|
|
135
|
+
# case e
|
136
|
+
# when nil # success!
|
137
|
+
# when Elastictastic::ServerError::DocumentAlreadyExistsEngineException
|
138
|
+
# conflicting_ids << post_params[:id]
|
139
|
+
# else
|
140
|
+
# raise e
|
141
|
+
# end
|
142
|
+
# end
|
143
|
+
# end
|
144
|
+
# end
|
145
|
+
#
|
146
|
+
# @option options [Fixnum] :auto_flush Flush to ElasticSearch after this many operations performed.
|
147
|
+
# @yield Block during which all write operations are buffered for bulk
|
148
|
+
#
|
149
|
+
def bulk(options = {})
|
57
150
|
original_persister = self.persister
|
151
|
+
bulk_persister = self.persister =
|
152
|
+
Elastictastic::BulkPersistenceStrategy.new(options)
|
58
153
|
begin
|
59
|
-
self.persister = Elastictastic::BulkPersistenceStrategy.new
|
60
154
|
yield
|
61
|
-
self.persister.flush
|
62
|
-
rescue Elastictastic::CancelBulkOperation
|
63
|
-
# Nothing to see here...
|
64
155
|
ensure
|
65
156
|
self.persister = original_persister
|
66
157
|
end
|
158
|
+
bulk_persister.flush
|
67
159
|
end
|
68
160
|
|
69
|
-
|
70
|
-
|
161
|
+
#
|
162
|
+
# Use Elastictastic's configured JSON encoder to encode a JSON message.
|
163
|
+
#
|
164
|
+
# @param [Object] Object to encode to JSON
|
165
|
+
# @return JSON representation of object
|
166
|
+
# @api private
|
167
|
+
#
|
168
|
+
def json_encode(object)
|
169
|
+
if config.json_engine.respond_to?(:encode)
|
170
|
+
config.json_engine.encode(object)
|
171
|
+
else
|
172
|
+
config.json_engine.dump(object)
|
173
|
+
end
|
71
174
|
end
|
72
175
|
|
73
|
-
|
176
|
+
#
|
177
|
+
# Use Elastictastic's configured JSON decoder to decode a JSON message
|
178
|
+
#
|
179
|
+
# @param [String] JSON message to decode
|
180
|
+
# @return Ruby object represented by json param
|
181
|
+
# @api private
|
182
|
+
#
|
183
|
+
def json_decode(json)
|
184
|
+
if config.json_engine.respond_to?(:decode)
|
185
|
+
config.json_engine.decode(json)
|
186
|
+
else
|
187
|
+
config.json_engine.load(json)
|
188
|
+
end
|
189
|
+
end
|
74
190
|
|
75
|
-
|
76
|
-
|
77
|
-
|
191
|
+
#
|
192
|
+
# Coerce the argument to an Elastictastic index.
|
193
|
+
#
|
194
|
+
# @param [String,Elastictastic::Index] name_or_index Index name or object
|
195
|
+
# @api private
|
196
|
+
#
|
197
|
+
def Index(name_or_index)
|
198
|
+
Index === name_or_index ? name_or_index : Index.new(name_or_index)
|
78
199
|
end
|
79
200
|
end
|
80
201
|
end
|
data/spec/environment.rb
CHANGED
@@ -6,7 +6,7 @@ describe Elastictastic::BulkPersistenceStrategy do
|
|
6
6
|
let(:last_request) { FakeWeb.last_request }
|
7
7
|
let(:bulk_requests) do
|
8
8
|
last_request.body.split("\n").map do |request|
|
9
|
-
|
9
|
+
Elastictastic.json_decode(request)
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
@@ -14,7 +14,7 @@ describe Elastictastic::BulkPersistenceStrategy do
|
|
14
14
|
let(:post) { Post.new }
|
15
15
|
|
16
16
|
before do
|
17
|
-
|
17
|
+
stub_es_bulk(
|
18
18
|
'create' => { '_index' => 'default', '_type' => 'post', '_id' => '123', '_version' => 1, 'ok' => true }
|
19
19
|
)
|
20
20
|
Elastictastic.bulk do
|
@@ -38,6 +38,10 @@ describe Elastictastic::BulkPersistenceStrategy do
|
|
38
38
|
post.id.should == '123'
|
39
39
|
end
|
40
40
|
|
41
|
+
it 'should set version' do
|
42
|
+
post.version.should == 1
|
43
|
+
end
|
44
|
+
|
41
45
|
it 'should set persisted' do
|
42
46
|
post.should be_persisted
|
43
47
|
end
|
@@ -55,7 +59,7 @@ describe Elastictastic::BulkPersistenceStrategy do
|
|
55
59
|
example.run
|
56
60
|
# have to do this here because the before/after hooks run inside the
|
57
61
|
# around hook
|
58
|
-
|
62
|
+
stub_es_bulk(
|
59
63
|
'create' => { '_index' => 'default', '_type' => 'post', '_id' => '123', '_version' => 1, 'ok' => true }
|
60
64
|
)
|
61
65
|
end
|
@@ -80,7 +84,7 @@ describe Elastictastic::BulkPersistenceStrategy do
|
|
80
84
|
let(:posts) { Array.new(2) { Post.new }}
|
81
85
|
|
82
86
|
before do
|
83
|
-
|
87
|
+
stub_es_bulk(
|
84
88
|
{ 'create' => { '_index' => 'default', '_type' => 'post', '_id' => '123', '_version' => 1, 'ok' => true }},
|
85
89
|
{ 'create' => { '_index' => 'default', '_type' => 'post', '_id' => '124', '_version' => 1, 'ok' => true }}
|
86
90
|
)
|
@@ -99,6 +103,10 @@ describe Elastictastic::BulkPersistenceStrategy do
|
|
99
103
|
it 'should set IDs' do
|
100
104
|
posts.map { |post| post.id }.should == %w(123 124)
|
101
105
|
end
|
106
|
+
|
107
|
+
it 'should set versions' do
|
108
|
+
posts.each { |post| post.version.should == 1 }
|
109
|
+
end
|
102
110
|
end
|
103
111
|
|
104
112
|
describe 'create with ID set' do
|
@@ -110,7 +118,7 @@ describe Elastictastic::BulkPersistenceStrategy do
|
|
110
118
|
end
|
111
119
|
|
112
120
|
before do
|
113
|
-
|
121
|
+
stub_es_bulk(
|
114
122
|
'create' => { '_index' => 'default', '_type' => 'post', '_id' => '123', '_version' => 1, 'ok' => true }
|
115
123
|
)
|
116
124
|
Elastictastic.bulk { post.save }
|
@@ -130,30 +138,38 @@ describe Elastictastic::BulkPersistenceStrategy do
|
|
130
138
|
it 'should retain ID' do
|
131
139
|
post.id.should == '123'
|
132
140
|
end
|
141
|
+
|
142
|
+
it 'should set version' do
|
143
|
+
post.version.should == 1
|
144
|
+
end
|
133
145
|
end
|
134
146
|
|
135
147
|
describe '#update' do
|
136
148
|
let(:post) do
|
137
149
|
Post.new.tap do |post|
|
138
150
|
post.id = '123'
|
151
|
+
post.version = 1
|
139
152
|
post.persisted!
|
140
153
|
end
|
141
154
|
end
|
142
155
|
|
143
156
|
before do
|
144
|
-
|
145
|
-
'index' => { '_index' => 'default', '_type' => 'post', '_id' => '123', '_version' =>
|
157
|
+
stub_es_bulk(
|
158
|
+
'index' => { '_index' => 'default', '_type' => 'post', '_id' => '123', '_version' => 2, 'ok' => true }
|
146
159
|
)
|
160
|
+
Elastictastic.bulk { post.save }
|
147
161
|
end
|
148
162
|
|
149
163
|
it 'should send update' do
|
150
|
-
Elastictastic.bulk { post.save }
|
151
|
-
|
152
164
|
bulk_requests.should == [
|
153
|
-
{ 'index' => { '_index' => 'default', '_type' => 'post', '_id' => '123' }},
|
165
|
+
{ 'index' => { '_index' => 'default', '_type' => 'post', '_id' => '123', '_version' => 1 }},
|
154
166
|
post.elasticsearch_doc
|
155
167
|
]
|
156
168
|
end
|
169
|
+
|
170
|
+
it 'should set version' do
|
171
|
+
post.version.should == 2
|
172
|
+
end
|
157
173
|
end
|
158
174
|
|
159
175
|
describe 'destroy' do
|
@@ -161,20 +177,21 @@ describe Elastictastic::BulkPersistenceStrategy do
|
|
161
177
|
Post.new.tap do |post|
|
162
178
|
post.id = '123'
|
163
179
|
post.title = 'bulky'
|
180
|
+
post.version = 1
|
164
181
|
post.persisted!
|
165
182
|
end
|
166
183
|
end
|
167
184
|
|
168
185
|
before do
|
169
|
-
|
170
|
-
'
|
186
|
+
stub_es_bulk(
|
187
|
+
'delete' => { '_index' => 'default', '_type' => 'post', '_id' => '123', '_version' => 2, 'ok' => true }
|
171
188
|
)
|
172
189
|
Elastictastic.bulk { post.destroy }
|
173
190
|
end
|
174
191
|
|
175
192
|
it 'should send destroy' do
|
176
193
|
bulk_requests.should == [
|
177
|
-
{ 'delete' => { '_index' => 'default', '_type' => 'post', '_id' => '123' }}
|
194
|
+
{ 'delete' => { '_index' => 'default', '_type' => 'post', '_id' => '123', '_version' => 1 }}
|
178
195
|
]
|
179
196
|
end
|
180
197
|
|
@@ -191,7 +208,7 @@ describe Elastictastic::BulkPersistenceStrategy do
|
|
191
208
|
|
192
209
|
it 'should return to individual persistence strategy' do
|
193
210
|
error_proc.call rescue nil
|
194
|
-
|
211
|
+
stub_es_create('default', 'post')
|
195
212
|
Post.new.save
|
196
213
|
last_request.path.should == '/default/post'
|
197
214
|
end
|
@@ -214,20 +231,131 @@ describe Elastictastic::BulkPersistenceStrategy do
|
|
214
231
|
it_should_behave_like 'block with error'
|
215
232
|
end
|
216
233
|
|
217
|
-
describe '
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
234
|
+
describe 'with :auto_flush specified' do
|
235
|
+
before do
|
236
|
+
responses = Array.new(3) do
|
237
|
+
{ 'create' => generate_es_hit('post').except('_source').merge('ok' => true) }
|
238
|
+
end.each_slice(2).map { |slice| { 'items' => slice } }
|
239
|
+
stub_request_json(
|
240
|
+
:post,
|
241
|
+
match_es_path('/_bulk'),
|
242
|
+
*responses
|
243
|
+
)
|
244
|
+
Elastictastic.bulk(:auto_flush => 2) { 3.times { Post.new.save }}
|
245
|
+
end
|
246
|
+
|
247
|
+
it 'should perform multiple requests when auto-flush triggered' do
|
248
|
+
FakeWeb.should have(2).requests
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'should flush after specified number of operations' do
|
252
|
+
FakeWeb.requests.first.body.split("\n").should have(4).items
|
253
|
+
FakeWeb.requests.last.body.split("\n").should have(2).items
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
describe 'multiple operations on the same document' do
|
258
|
+
let(:post) do
|
259
|
+
Post.new.tap do |post|
|
260
|
+
post.id = '1'
|
261
|
+
post.version = 1
|
262
|
+
post.persisted!
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
before do
|
267
|
+
stub_es_bulk(
|
268
|
+
'delete' => generate_es_hit('post', :version => 2, :id => '1').merge('ok' => true)
|
269
|
+
)
|
270
|
+
Elastictastic.bulk do
|
271
|
+
post.save
|
272
|
+
post.destroy
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
it 'should only send one operation per document' do
|
277
|
+
bulk_requests.length.should == 1
|
278
|
+
end
|
279
|
+
|
280
|
+
it 'should send last operation for each document' do
|
281
|
+
bulk_requests.last.should == { 'delete' => generate_es_hit('post', :id => '1').except('_source') }
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
describe 'multiple creates' do
|
286
|
+
before do
|
287
|
+
stub_es_bulk(
|
288
|
+
{ 'create' => generate_es_hit('post', :id => '1').merge('ok' => true) },
|
289
|
+
{ 'create' => generate_es_hit('post', :id => '2').merge('ok' => true) }
|
290
|
+
)
|
291
|
+
Elastictastic.bulk { 2.times { |i| Post.new(:title => "post #{i}").save }}
|
292
|
+
end
|
293
|
+
|
294
|
+
it 'should create all documents' do
|
295
|
+
bulk_requests.length.should == 4
|
296
|
+
end
|
297
|
+
|
298
|
+
it 'should send correct info for each document' do
|
299
|
+
bulk_requests.each_slice(2).map do |commands|
|
300
|
+
commands.last['title']
|
301
|
+
end.should == ['post 0', 'post 1']
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
describe 'updating documents with same ID but different index' do
|
306
|
+
let(:posts) do
|
307
|
+
%w(default my_index).map do |index|
|
308
|
+
Post.in_index(index).new.tap do |post|
|
309
|
+
post.id = '1'
|
310
|
+
post.persisted!
|
223
311
|
end
|
224
312
|
end
|
225
313
|
end
|
226
314
|
|
227
|
-
|
228
|
-
|
315
|
+
before do
|
316
|
+
stub_es_bulk(
|
317
|
+
{ 'index' => generate_es_hit('post', :id => '1').merge('ok' => true) },
|
318
|
+
{ 'index' => generate_es_hit('post', :index => 'my_index', :id => '1').merge('ok' => true) }
|
319
|
+
)
|
320
|
+
Elastictastic.bulk { posts.map { |post| post.save }}
|
229
321
|
end
|
230
322
|
|
231
|
-
|
323
|
+
it 'should send updates for both documents' do
|
324
|
+
bulk_requests.length.should == 4
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
describe 'with routing' do
|
329
|
+
let(:photo) { Photo.new(:post_id => 1) }
|
330
|
+
|
331
|
+
it 'should include routing on create' do
|
332
|
+
stub_es_bulk(
|
333
|
+
'create' => { '_index' => 'default', '_type' => 'photo', '_id' => '123', '_version' => 1, 'ok' => true }
|
334
|
+
)
|
335
|
+
Elastictastic.bulk { photo.save }
|
336
|
+
bulk_requests.first['create']['_routing'].should == '1'
|
337
|
+
end
|
338
|
+
|
339
|
+
it 'should include routing on update' do
|
340
|
+
photo.id = '123'
|
341
|
+
photo.version = 1
|
342
|
+
photo.persisted!
|
343
|
+
stub_es_bulk(
|
344
|
+
'index' => { '_index' => 'default', '_type' => 'photo', '_id' => '123', '_version' => 2, 'ok' => true }
|
345
|
+
)
|
346
|
+
Elastictastic.bulk { photo.save }
|
347
|
+
bulk_requests.first['index']['_routing'].should == '1'
|
348
|
+
end
|
349
|
+
|
350
|
+
it 'should include routing on destroy' do
|
351
|
+
photo.id = '123'
|
352
|
+
photo.version = 1
|
353
|
+
photo.persisted!
|
354
|
+
stub_es_bulk(
|
355
|
+
'delete' => { '_index' => 'default', '_type' => 'post', '_id' => '123', '_version' => 2, 'ok' => true }
|
356
|
+
)
|
357
|
+
Elastictastic.bulk { photo.destroy }
|
358
|
+
bulk_requests.first['delete']['_routing'].should == '1'
|
359
|
+
end
|
232
360
|
end
|
233
361
|
end
|
@@ -15,6 +15,10 @@ describe Elastictastic::Callbacks do
|
|
15
15
|
before_create :before_create_ran!
|
16
16
|
before_update :before_update_ran!
|
17
17
|
before_destroy :before_destroy_ran!
|
18
|
+
after_save :after_save_ran!
|
19
|
+
after_create :after_create_ran!
|
20
|
+
after_update :after_update_ran!
|
21
|
+
after_destroy :after_destroy_ran!
|
18
22
|
|
19
23
|
def hooks_that_ran
|
20
24
|
@hooks_that_ran ||= Set[]
|
@@ -45,52 +49,79 @@ describe Elastictastic::Callbacks do
|
|
45
49
|
end
|
46
50
|
|
47
51
|
before do
|
48
|
-
|
49
|
-
|
50
|
-
|
52
|
+
stub_es_create('default', 'my_model')
|
53
|
+
stub_es_update('default', 'my_model', id)
|
54
|
+
stub_es_destroy('default', 'my_model', id)
|
51
55
|
end
|
52
56
|
|
53
|
-
|
57
|
+
%w(before after).each do |position|
|
58
|
+
describe "##{position}_save" do
|
54
59
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
60
|
+
it "should run #{position} create" do
|
61
|
+
instance.save
|
62
|
+
instance.should have_run_hook(:"#{position}_save")
|
63
|
+
end
|
59
64
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end
|
65
|
+
it 'should run before update' do
|
66
|
+
persisted_instance.save
|
67
|
+
persisted_instance.should have_run_hook(:"#{position}_save")
|
68
|
+
end
|
65
69
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
end
|
70
|
+
it 'should not run before create when callbacks disabled' do
|
71
|
+
instance.save(:callbacks => false)
|
72
|
+
instance.should_not have_run_hook(:"#{position}_save")
|
73
|
+
end
|
71
74
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
+
it 'should not run before update when hooks disabled' do
|
76
|
+
persisted_instance.save(:callbacks => false)
|
77
|
+
instance.should_not have_run_hook(:"#{position}_save")
|
78
|
+
end
|
75
79
|
end
|
76
|
-
end
|
77
80
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
81
|
+
describe "##{position}_create" do
|
82
|
+
it "should run #{position} create" do
|
83
|
+
instance.save
|
84
|
+
instance.should have_run_hook(:"#{position}_create")
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should not run #{position} update" do
|
88
|
+
persisted_instance.save
|
89
|
+
persisted_instance.should_not have_run_hook(:"#{position}_create")
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should not run #{position} create when callbacks disabled" do
|
93
|
+
instance.save(:callbacks => false)
|
94
|
+
instance.should_not have_run_hook(:"#{position}_create")
|
95
|
+
end
|
82
96
|
end
|
83
97
|
|
84
|
-
|
85
|
-
|
86
|
-
|
98
|
+
describe "##{position}_update" do
|
99
|
+
it "should not run #{position} create" do
|
100
|
+
instance.save
|
101
|
+
instance.should_not have_run_hook :"#{position}_update"
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should run #{position} update" do
|
105
|
+
persisted_instance.save
|
106
|
+
persisted_instance.should have_run_hook(:"#{position}_update")
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should not run #{position} update if callbacks disabled" do
|
110
|
+
persisted_instance.save(:callbacks => false)
|
111
|
+
persisted_instance.should_not have_run_hook(:"#{position}_update")
|
112
|
+
end
|
87
113
|
end
|
88
|
-
end
|
89
114
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
115
|
+
describe "##{position}_destroy" do
|
116
|
+
it "should run #{position} destroy" do
|
117
|
+
persisted_instance.destroy
|
118
|
+
persisted_instance.should have_run_hook(:"#{position}_destroy")
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should not run #{position} destroy if callbacks disabled" do
|
122
|
+
persisted_instance.destroy(:callbacks => false)
|
123
|
+
persisted_instance.should_not have_run_hook(:"#{position}_destroy")
|
124
|
+
end
|
94
125
|
end
|
95
126
|
end
|
96
127
|
end
|