elasticsearch-persistence 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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