elasticsearch-persistence 0.0.0 → 0.0.1

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.
Files changed (39) hide show
  1. checksums.yaml +15 -0
  2. data/LICENSE.txt +10 -19
  3. data/README.md +432 -14
  4. data/Rakefile +56 -0
  5. data/elasticsearch-persistence.gemspec +45 -17
  6. data/examples/sinatra/.gitignore +7 -0
  7. data/examples/sinatra/Gemfile +28 -0
  8. data/examples/sinatra/README.markdown +36 -0
  9. data/examples/sinatra/application.rb +238 -0
  10. data/examples/sinatra/config.ru +7 -0
  11. data/examples/sinatra/test.rb +118 -0
  12. data/lib/elasticsearch/persistence.rb +88 -2
  13. data/lib/elasticsearch/persistence/client.rb +51 -0
  14. data/lib/elasticsearch/persistence/repository.rb +75 -0
  15. data/lib/elasticsearch/persistence/repository/class.rb +71 -0
  16. data/lib/elasticsearch/persistence/repository/find.rb +73 -0
  17. data/lib/elasticsearch/persistence/repository/naming.rb +115 -0
  18. data/lib/elasticsearch/persistence/repository/response/results.rb +90 -0
  19. data/lib/elasticsearch/persistence/repository/search.rb +60 -0
  20. data/lib/elasticsearch/persistence/repository/serialize.rb +31 -0
  21. data/lib/elasticsearch/persistence/repository/store.rb +95 -0
  22. data/lib/elasticsearch/persistence/version.rb +1 -1
  23. data/test/integration/repository/custom_class_test.rb +85 -0
  24. data/test/integration/repository/customized_class_test.rb +82 -0
  25. data/test/integration/repository/default_class_test.rb +108 -0
  26. data/test/integration/repository/virtus_model_test.rb +114 -0
  27. data/test/test_helper.rb +46 -0
  28. data/test/unit/persistence_test.rb +32 -0
  29. data/test/unit/repository_class_test.rb +51 -0
  30. data/test/unit/repository_client_test.rb +32 -0
  31. data/test/unit/repository_find_test.rb +375 -0
  32. data/test/unit/repository_indexing_test.rb +37 -0
  33. data/test/unit/repository_module_test.rb +144 -0
  34. data/test/unit/repository_naming_test.rb +146 -0
  35. data/test/unit/repository_response_results_test.rb +98 -0
  36. data/test/unit/repository_search_test.rb +97 -0
  37. data/test/unit/repository_serialize_test.rb +57 -0
  38. data/test/unit/repository_store_test.rb +287 -0
  39. metadata +288 -20
@@ -0,0 +1,375 @@
1
+ require 'test_helper'
2
+
3
+ class Elasticsearch::Persistence::RepositoryFindTest < Test::Unit::TestCase
4
+ class MyDocument; end
5
+
6
+ context "The repository" do
7
+ setup do
8
+ @shoulda_subject = Class.new() { include Elasticsearch::Persistence::Repository::Find }.new
9
+
10
+ @client = mock
11
+ @shoulda_subject.stubs(:document_type).returns(nil)
12
+ @shoulda_subject.stubs(:klass).returns(nil)
13
+ @shoulda_subject.stubs(:index_name).returns('my_index')
14
+ @shoulda_subject.stubs(:client).returns(@client)
15
+ end
16
+
17
+ context "find method" do
18
+ should "find one document when passed a single, literal ID" do
19
+ subject.expects(:__find_one).with(1, {})
20
+ subject.find(1)
21
+ end
22
+
23
+ should "find multiple documents when passed multiple IDs" do
24
+ subject.expects(:__find_many).with([1, 2], {})
25
+ subject.find(1, 2)
26
+ end
27
+
28
+ should "find multiple documents when passed an array of IDs" do
29
+ subject.expects(:__find_many).with([1, 2], {})
30
+ subject.find([1, 2])
31
+ end
32
+
33
+ should "pass the options" do
34
+ subject.expects(:__find_one).with(1, { foo: 'bar' })
35
+ subject.find(1, foo: 'bar')
36
+
37
+ subject.expects(:__find_many).with([1, 2], { foo: 'bar' })
38
+ subject.find([1, 2], foo: 'bar')
39
+
40
+ subject.expects(:__find_many).with([1, 2], { foo: 'bar' })
41
+ subject.find(1, 2, foo: 'bar')
42
+ end
43
+ end
44
+
45
+ context "'exists?' method" do
46
+ should "return false when the document does not exist" do
47
+ @client.expects(:exists).returns(false)
48
+ assert_equal false, subject.exists?('1')
49
+ end
50
+
51
+ should "return whether document for klass exists" do
52
+ subject.expects(:document_type).returns(nil)
53
+ subject.expects(:klass).returns(MyDocument).at_least_once
54
+ subject.expects(:__get_type_from_class).with(MyDocument).returns('my_document')
55
+
56
+ @client
57
+ .expects(:exists)
58
+ .with do |arguments|
59
+ assert_equal 'my_document', arguments[:type]
60
+ assert_equal '1', arguments[:id]
61
+ end
62
+ .returns(true)
63
+
64
+ assert_equal true, subject.exists?('1')
65
+ end
66
+
67
+ should "return whether document for document_type exists" do
68
+ subject.expects(:document_type).returns('my_document')
69
+ subject.expects(:klass).returns(MyDocument).at_most_once
70
+ subject.expects(:__get_type_from_class).never
71
+
72
+ @client
73
+ .expects(:exists)
74
+ .with do |arguments|
75
+ assert_equal 'my_document', arguments[:type]
76
+ assert_equal '1', arguments[:id]
77
+ end
78
+ .returns(true)
79
+
80
+ assert_equal true, subject.exists?('1')
81
+ end
82
+
83
+ should "return whether document exists" do
84
+ subject.expects(:klass).returns(nil)
85
+ subject.expects(:__get_type_from_class).never
86
+
87
+ @client
88
+ .expects(:exists)
89
+ .with do |arguments|
90
+ assert_equal '_all', arguments[:type]
91
+ assert_equal '1', arguments[:id]
92
+ end
93
+ .returns(true)
94
+
95
+ assert_equal true, subject.exists?('1')
96
+ end
97
+
98
+ should "pass options to the client" do
99
+ @client.expects(:exists).with do |arguments|
100
+ assert_equal 'foobarbam', arguments[:index]
101
+ assert_equal 'bambam', arguments[:routing]
102
+ end
103
+
104
+ subject.exists? '1', index: 'foobarbam', routing: 'bambam'
105
+ end
106
+ end
107
+
108
+ context "'__find_one' method" do
109
+ should "find document based on klass and return a deserialized object" do
110
+ subject.expects(:document_type).returns(nil)
111
+ subject.expects(:klass).returns(MyDocument).at_least_once
112
+ subject.expects(:__get_type_from_class).with(MyDocument).returns('my_document')
113
+
114
+ subject.expects(:deserialize).with({'_source' => {'foo' => 'bar'}}).returns(MyDocument.new)
115
+
116
+ @client
117
+ .expects(:get)
118
+ .with do |arguments|
119
+ assert_equal 'my_document', arguments[:type]
120
+ assert_equal '1', arguments[:id]
121
+ end
122
+ .returns({'_source' => { 'foo' => 'bar' }})
123
+
124
+ assert_instance_of MyDocument, subject.__find_one('1')
125
+ end
126
+
127
+ should "find document based on document_type and return a deserialized object" do
128
+ subject.expects(:document_type).returns('my_document')
129
+ subject.expects(:klass).returns(MyDocument).at_most_once
130
+ subject.expects(:__get_type_from_class).never
131
+
132
+ subject.expects(:deserialize).with({'_source' => {'foo' => 'bar'}}).returns(MyDocument.new)
133
+
134
+ @client
135
+ .expects(:get)
136
+ .with do |arguments|
137
+ assert_equal 'my_document', arguments[:type]
138
+ assert_equal '1', arguments[:id]
139
+ end
140
+ .returns({'_source' => { 'foo' => 'bar' }})
141
+
142
+ assert_instance_of MyDocument, subject.__find_one('1')
143
+ end
144
+
145
+ should "find document and return a deserialized object" do
146
+ subject.expects(:document_type).returns(nil)
147
+ subject.expects(:klass).returns(nil).at_least_once
148
+ subject.expects(:__get_type_from_class).never
149
+
150
+ subject.expects(:deserialize).with({'_source' => {'foo' => 'bar'}}).returns(MyDocument.new)
151
+
152
+ @client
153
+ .expects(:get)
154
+ .with do |arguments|
155
+ assert_equal '_all', arguments[:type]
156
+ assert_equal '1', arguments[:id]
157
+ end
158
+ .returns({'_source' => { 'foo' => 'bar' }})
159
+
160
+ assert_instance_of MyDocument, subject.__find_one('1')
161
+ end
162
+
163
+ should "raise DocumentNotFound exception when the document cannot be found" do
164
+ subject.expects(:document_type).returns(nil)
165
+ subject.expects(:klass).returns(nil).at_least_once
166
+
167
+ subject.expects(:deserialize).never
168
+
169
+ @client
170
+ .expects(:get)
171
+ .raises(Elasticsearch::Transport::Transport::Errors::NotFound)
172
+
173
+ assert_raise Elasticsearch::Persistence::Repository::DocumentNotFound do
174
+ subject.__find_one('foobar')
175
+ end
176
+ end
177
+
178
+ should "pass other exceptions" do
179
+ subject.expects(:klass).returns(nil).at_least_once
180
+
181
+ subject.expects(:deserialize).never
182
+
183
+ @client
184
+ .expects(:get)
185
+ .raises(RuntimeError)
186
+
187
+ assert_raise RuntimeError do
188
+ subject.__find_one('foobar')
189
+ end
190
+ end
191
+
192
+ should "pass options to the client" do
193
+ subject.expects(:klass).returns(nil).at_least_once
194
+ subject.expects(:deserialize)
195
+
196
+ @client
197
+ .expects(:get)
198
+ .with do |arguments|
199
+ assert_equal 'foobarbam', arguments[:index]
200
+ assert_equal 'bambam', arguments[:routing]
201
+ end
202
+ .returns({'_source' => { 'foo' => 'bar' }})
203
+
204
+ subject.__find_one '1', index: 'foobarbam', routing: 'bambam'
205
+ end
206
+ end
207
+
208
+ context "'__find_many' method" do
209
+ setup do
210
+ @response = {"docs"=>
211
+ [ {"_index"=>"my_index",
212
+ "_type"=>"note",
213
+ "_id"=>"1",
214
+ "_version"=>1,
215
+ "found"=>true,
216
+ "_source"=>{"id"=>"1", "title"=>"Test 1"}},
217
+
218
+ {"_index"=>"my_index",
219
+ "_type"=>"note",
220
+ "_id"=>"2",
221
+ "_version"=>1,
222
+ "found"=>true,
223
+ "_source"=>{"id"=>"2", "title"=>"Test 2"}}
224
+ ]}
225
+ end
226
+
227
+ should "find documents based on klass and return an Array of deserialized objects" do
228
+ subject.expects(:document_type).returns(nil)
229
+ subject.expects(:klass).returns(MyDocument).at_least_once
230
+ subject.expects(:__get_type_from_class).with(MyDocument).returns('my_document')
231
+
232
+ subject
233
+ .expects(:deserialize)
234
+ .with(@response['docs'][0])
235
+ .returns(MyDocument.new)
236
+
237
+ subject
238
+ .expects(:deserialize)
239
+ .with(@response['docs'][1])
240
+ .returns(MyDocument.new)
241
+
242
+ @client
243
+ .expects(:mget)
244
+ .with do |arguments|
245
+ assert_equal 'my_document', arguments[:type]
246
+ assert_equal ['1', '2'], arguments[:body][:ids]
247
+ end
248
+ .returns(@response)
249
+
250
+ results = subject.__find_many(['1', '2'])
251
+ assert_instance_of MyDocument, results[0]
252
+ assert_instance_of MyDocument, results[1]
253
+ end
254
+
255
+ should "find documents based on document_type and return an Array of deserialized objects" do
256
+ subject.expects(:document_type).returns('my_document')
257
+ subject.expects(:klass).returns(MyDocument).at_most_once
258
+ subject.expects(:__get_type_from_class).never
259
+
260
+ subject.expects(:deserialize).twice
261
+
262
+ @client
263
+ .expects(:mget)
264
+ .with do |arguments|
265
+ assert_equal 'my_document', arguments[:type]
266
+ assert_equal ['1', '2'], arguments[:body][:ids]
267
+ end
268
+ .returns(@response)
269
+
270
+ subject.__find_many(['1', '2'])
271
+ end
272
+
273
+ should "find documents and return an Array of deserialized objects" do
274
+ subject.expects(:document_type).returns(nil)
275
+ subject.expects(:klass).returns(nil).at_least_once
276
+ subject.expects(:__get_type_from_class).never
277
+
278
+ subject
279
+ .expects(:deserialize)
280
+ .with(@response['docs'][0])
281
+ .returns(MyDocument.new)
282
+
283
+ subject
284
+ .expects(:deserialize)
285
+ .with(@response['docs'][1])
286
+ .returns(MyDocument.new)
287
+
288
+ @client
289
+ .expects(:mget)
290
+ .with do |arguments|
291
+ assert_equal '_all', arguments[:type]
292
+ assert_equal ['1', '2'], arguments[:body][:ids]
293
+ end
294
+ .returns(@response)
295
+
296
+ results = subject.__find_many(['1', '2'])
297
+
298
+ assert_equal 2, results.size
299
+
300
+ assert_instance_of MyDocument, results[0]
301
+ assert_instance_of MyDocument, results[1]
302
+ end
303
+
304
+ should "find keep missing documents in the result as nil" do
305
+ @response = {"docs"=>
306
+ [ {"_index"=>"my_index",
307
+ "_type"=>"note",
308
+ "_id"=>"1",
309
+ "_version"=>1,
310
+ "found"=>true,
311
+ "_source"=>{"id"=>"1", "title"=>"Test 1"}},
312
+
313
+ {"_index"=>"my_index",
314
+ "_type"=>"note",
315
+ "_id"=>"3",
316
+ "_version"=>1,
317
+ "found"=>false},
318
+
319
+ {"_index"=>"my_index",
320
+ "_type"=>"note",
321
+ "_id"=>"2",
322
+ "_version"=>1,
323
+ "found"=>true,
324
+ "_source"=>{"id"=>"2", "title"=>"Test 2"}}
325
+ ]}
326
+
327
+ subject.expects(:document_type).returns(nil)
328
+ subject.expects(:klass).returns(MyDocument).at_least_once
329
+ subject.expects(:__get_type_from_class).with(MyDocument).returns('my_document')
330
+
331
+ subject
332
+ .expects(:deserialize)
333
+ .with(@response['docs'][0])
334
+ .returns(MyDocument.new)
335
+
336
+ subject
337
+ .expects(:deserialize)
338
+ .with(@response['docs'][2])
339
+ .returns(MyDocument.new)
340
+
341
+ @client
342
+ .expects(:mget)
343
+ .with do |arguments|
344
+ assert_equal 'my_document', arguments[:type]
345
+ assert_equal ['1', '3', '2'], arguments[:body][:ids]
346
+ end
347
+ .returns(@response)
348
+
349
+ results = subject.__find_many(['1', '3', '2'])
350
+
351
+ assert_equal 3, results.size
352
+
353
+ assert_instance_of MyDocument, results[0]
354
+ assert_instance_of NilClass, results[1]
355
+ assert_instance_of MyDocument, results[2]
356
+ end
357
+
358
+ should "pass options to the client" do
359
+ subject.expects(:klass).returns(nil).at_least_once
360
+ subject.expects(:deserialize).twice
361
+
362
+ @client
363
+ .expects(:mget)
364
+ .with do |arguments|
365
+ assert_equal 'foobarbam', arguments[:index]
366
+ assert_equal 'bambam', arguments[:routing]
367
+ end
368
+ .returns(@response)
369
+
370
+ subject.__find_many ['1', '2'], index: 'foobarbam', routing: 'bambam'
371
+ end
372
+ end
373
+
374
+ end
375
+ end
@@ -0,0 +1,37 @@
1
+ require 'test_helper'
2
+
3
+ class Elasticsearch::Persistence::RepositoryIndexingTest < Test::Unit::TestCase
4
+ context "The repository index methods" do
5
+ class MyDocument; end
6
+
7
+ setup do
8
+ @shoulda_subject = Class.new() { include Elasticsearch::Model::Indexing::ClassMethods }.new
9
+ @shoulda_subject.stubs(:index_name).returns('my_index')
10
+ @shoulda_subject.stubs(:document_type).returns('my_document')
11
+ end
12
+
13
+ should "have the convenience index management methods" do
14
+ %w( create_index! delete_index! refresh_index! ).each do |method|
15
+ assert_respond_to subject, method
16
+ end
17
+ end
18
+
19
+ context "mappings" do
20
+ should "configure the mappings for the type" do
21
+ subject.mappings do
22
+ indexes :title
23
+ end
24
+
25
+ assert_equal( {:"my_document"=>{:properties=>{:title=>{:type=>"string"}}}}, subject.mappings.to_hash )
26
+ end
27
+ end
28
+
29
+ context "settings" do
30
+ should "configure the settings for the index" do
31
+ subject.settings foo: 'bar'
32
+ assert_equal( {foo: 'bar'}, subject.settings.to_hash)
33
+ end
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,144 @@
1
+ require 'test_helper'
2
+
3
+ class Elasticsearch::Persistence::RepositoryModuleTest < Test::Unit::TestCase
4
+ context "The repository module" do
5
+
6
+ class DummyModel
7
+ def initialize(attributes={})
8
+ @attributes = attributes
9
+ end
10
+
11
+ def to_hash
12
+ @attributes
13
+ end
14
+
15
+ def inspect
16
+ "<Note #{@attributes.inspect}>"
17
+ end
18
+ end
19
+
20
+ setup do
21
+ class DummyRepository
22
+ include Elasticsearch::Persistence::Repository
23
+ end
24
+ end
25
+
26
+ teardown do
27
+ Elasticsearch::Persistence::RepositoryModuleTest.__send__ :remove_const, :DummyRepository
28
+ end
29
+
30
+ context "when included" do
31
+ should "set up the gateway for the class and instance" do
32
+ assert_respond_to DummyRepository, :gateway
33
+ assert_respond_to DummyRepository.new, :gateway
34
+
35
+ assert_instance_of Elasticsearch::Persistence::Repository::Class, DummyRepository.gateway
36
+ assert_instance_of Elasticsearch::Persistence::Repository::Class, DummyRepository.new.gateway
37
+ end
38
+
39
+ should "proxy repository methods from the class to the gateway" do
40
+ class DummyRepository
41
+ include Elasticsearch::Persistence::Repository
42
+
43
+ index :foobar
44
+ klass DummyModel
45
+ type :my_dummy_model
46
+ mapping { indexes :title, analyzer: 'snowball' }
47
+ end
48
+
49
+ repository = DummyRepository.new
50
+
51
+ assert_equal :foobar, DummyRepository.index
52
+ assert_equal DummyModel, DummyRepository.klass
53
+ assert_equal :my_dummy_model, DummyRepository.type
54
+ assert_equal 'snowball', DummyRepository.mappings.to_hash[:my_dummy_model][:properties][:title][:analyzer]
55
+
56
+ assert_equal :foobar, repository.index
57
+ assert_equal DummyModel, repository.klass
58
+ assert_equal :my_dummy_model, repository.type
59
+ assert_equal 'snowball', repository.mappings.to_hash[:my_dummy_model][:properties][:title][:analyzer]
60
+ end
61
+
62
+ should "correctly delegate to the gateway" do
63
+ repository = DummyRepository.new
64
+ assert_instance_of Method, repository.method(:index)
65
+ end
66
+
67
+ should "proxy repository methods from the instance to the gateway" do
68
+ class DummyRepository
69
+ include Elasticsearch::Persistence::Repository
70
+ end
71
+
72
+ repository = DummyRepository.new
73
+ repository.index :foobar
74
+ repository.klass DummyModel
75
+ repository.type :my_dummy_model
76
+ repository.mapping { indexes :title, analyzer: 'snowball' }
77
+
78
+ assert_equal :foobar, DummyRepository.index
79
+ assert_equal DummyModel, DummyRepository.klass
80
+ assert_equal :my_dummy_model, DummyRepository.type
81
+ assert_equal 'snowball', DummyRepository.mappings.to_hash[:my_dummy_model][:properties][:title][:analyzer]
82
+
83
+ assert_equal :foobar, repository.index
84
+ assert_equal DummyModel, repository.klass
85
+ assert_equal :my_dummy_model, repository.type
86
+ assert_equal 'snowball', repository.mappings.to_hash[:my_dummy_model][:properties][:title][:analyzer]
87
+ end
88
+
89
+ should "allow to define gateway methods in the class definition via block passed to the gateway method" do
90
+ class DummyRepositoryWithGatewaySerialize
91
+ include Elasticsearch::Persistence::Repository
92
+
93
+ gateway do
94
+ def serialize(document)
95
+ 'FAKE!'
96
+ end
97
+ end
98
+ end
99
+
100
+ repository = DummyRepositoryWithGatewaySerialize.new
101
+ repository.client.transport.logger = Logger.new(STDERR)
102
+
103
+ client = mock
104
+ client.expects(:index).with do |arguments|
105
+ assert_equal('xxx', arguments[:id])
106
+ assert_equal('FAKE!', arguments[:body])
107
+ end
108
+ repository.gateway.expects(:client).returns(client)
109
+
110
+ repository.gateway.expects(:__get_id_from_document).returns('xxx')
111
+
112
+ repository.save( id: '123', foo: 'bar' )
113
+ end
114
+ end
115
+
116
+ should "allow to define gateway methods in the class definition via regular method definition" do
117
+ class DummyRepositoryWithDirectSerialize
118
+ include Elasticsearch::Persistence::Repository
119
+
120
+ def serialize(document)
121
+ 'FAKE IN CLASS!'
122
+ end
123
+ end
124
+
125
+ repository = DummyRepositoryWithDirectSerialize.new
126
+ repository.client.transport.logger = Logger.new(STDERR)
127
+
128
+ client = mock
129
+ client.expects(:index).with do |arguments|
130
+ assert_equal('xxx', arguments[:id])
131
+ assert_equal('FAKE IN CLASS!', arguments[:body])
132
+ end
133
+ repository.gateway.expects(:client).returns(client)
134
+
135
+ repository.gateway.expects(:__get_id_from_document).returns('xxx')
136
+
137
+ repository.save( id: '123', foo: 'bar' )
138
+ end
139
+
140
+ should "configure the index name in the shortcut initializer" do
141
+ assert_equal 'repository', Elasticsearch::Persistence::Repository.new.index_name
142
+ end
143
+ end
144
+ end