elasticsearch-persistence 5.1.0 → 6.0.0.pre

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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +2 -0
  3. data/Gemfile +9 -0
  4. data/README.md +164 -323
  5. data/Rakefile +8 -8
  6. data/elasticsearch-persistence.gemspec +4 -5
  7. data/lib/elasticsearch/persistence.rb +2 -110
  8. data/lib/elasticsearch/persistence/repository.rb +212 -53
  9. data/lib/elasticsearch/persistence/repository/dsl.rb +94 -0
  10. data/lib/elasticsearch/persistence/repository/find.rb +27 -10
  11. data/lib/elasticsearch/persistence/repository/response/results.rb +17 -5
  12. data/lib/elasticsearch/persistence/repository/search.rb +15 -4
  13. data/lib/elasticsearch/persistence/repository/serialize.rb +65 -7
  14. data/lib/elasticsearch/persistence/repository/store.rb +38 -44
  15. data/lib/elasticsearch/persistence/version.rb +1 -1
  16. data/spec/repository/find_spec.rb +179 -0
  17. data/spec/repository/response/results_spec.rb +105 -0
  18. data/spec/repository/search_spec.rb +181 -0
  19. data/spec/repository/serialize_spec.rb +53 -0
  20. data/spec/repository/store_spec.rb +327 -0
  21. data/spec/repository_spec.rb +716 -0
  22. data/spec/spec_helper.rb +28 -0
  23. metadata +25 -80
  24. data/lib/elasticsearch/persistence/client.rb +0 -51
  25. data/lib/elasticsearch/persistence/model.rb +0 -153
  26. data/lib/elasticsearch/persistence/model/base.rb +0 -87
  27. data/lib/elasticsearch/persistence/model/errors.rb +0 -8
  28. data/lib/elasticsearch/persistence/model/find.rb +0 -180
  29. data/lib/elasticsearch/persistence/model/rails.rb +0 -47
  30. data/lib/elasticsearch/persistence/model/store.rb +0 -254
  31. data/lib/elasticsearch/persistence/model/utils.rb +0 -0
  32. data/lib/elasticsearch/persistence/repository/class.rb +0 -71
  33. data/lib/elasticsearch/persistence/repository/naming.rb +0 -115
  34. data/lib/rails/generators/elasticsearch/model/model_generator.rb +0 -21
  35. data/lib/rails/generators/elasticsearch/model/templates/model.rb.tt +0 -9
  36. data/lib/rails/generators/elasticsearch_generator.rb +0 -2
  37. data/test/integration/model/model_basic_test.rb +0 -238
  38. data/test/integration/repository/custom_class_test.rb +0 -85
  39. data/test/integration/repository/customized_class_test.rb +0 -82
  40. data/test/integration/repository/default_class_test.rb +0 -116
  41. data/test/integration/repository/virtus_model_test.rb +0 -118
  42. data/test/test_helper.rb +0 -55
  43. data/test/unit/model_base_test.rb +0 -72
  44. data/test/unit/model_find_test.rb +0 -153
  45. data/test/unit/model_gateway_test.rb +0 -101
  46. data/test/unit/model_rails_test.rb +0 -112
  47. data/test/unit/model_store_test.rb +0 -576
  48. data/test/unit/persistence_test.rb +0 -32
  49. data/test/unit/repository_class_test.rb +0 -51
  50. data/test/unit/repository_client_test.rb +0 -32
  51. data/test/unit/repository_find_test.rb +0 -388
  52. data/test/unit/repository_indexing_test.rb +0 -37
  53. data/test/unit/repository_module_test.rb +0 -146
  54. data/test/unit/repository_naming_test.rb +0 -146
  55. data/test/unit/repository_response_results_test.rb +0 -98
  56. data/test/unit/repository_search_test.rb +0 -117
  57. data/test/unit/repository_serialize_test.rb +0 -57
  58. data/test/unit/repository_store_test.rb +0 -303
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ describe Elasticsearch::Persistence::Repository::Serialize do
4
+
5
+ let(:repository) do
6
+ DEFAULT_REPOSITORY
7
+ end
8
+
9
+ describe '#serialize' do
10
+
11
+ before do
12
+ class MyDocument
13
+ def to_hash
14
+ { a: 1 }
15
+ end
16
+ end
17
+ end
18
+
19
+ it 'calls #to_hash on the object' do
20
+ expect(repository.serialize(MyDocument.new)).to eq(a: 1)
21
+ end
22
+ end
23
+
24
+ describe '#deserialize' do
25
+
26
+ context 'when klass is defined on the Repository' do
27
+
28
+ let(:repository) do
29
+ require 'set'
30
+ MyTestRepository.new(klass: Set)
31
+ end
32
+
33
+ it 'instantiates an object of the klass' do
34
+ expect(repository.deserialize('_source' => { a: 1 })).to be_a(Set)
35
+ end
36
+
37
+ it 'uses the source field to instantiate the object' do
38
+ expect(repository.deserialize('_source' => { a: 1 })).to eq(Set.new({ a: 1}))
39
+ end
40
+ end
41
+
42
+ context 'when klass is not defined on the Repository' do
43
+
44
+ it 'returns the raw Hash' do
45
+ expect(repository.deserialize('_source' => { a: 1 })).to be_a(Hash)
46
+ end
47
+
48
+ it 'uses the source field to instantiate the object' do
49
+ expect(repository.deserialize('_source' => { a: 1 })).to eq(a: 1)
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,327 @@
1
+ require 'spec_helper'
2
+
3
+ describe Elasticsearch::Persistence::Repository::Store do
4
+
5
+ let(:repository) do
6
+ DEFAULT_REPOSITORY
7
+ end
8
+
9
+ after do
10
+ begin; repository.delete_index!; rescue; end
11
+ end
12
+
13
+ describe '#save' do
14
+
15
+ let(:document) do
16
+ { a: 1 }
17
+ end
18
+
19
+ let(:response) do
20
+ repository.save(document)
21
+ end
22
+
23
+ it 'saves the document' do
24
+ expect(repository.find(response['_id'])).to eq('a' => 1)
25
+ end
26
+
27
+ context 'when the repository defines a custom serialize method' do
28
+
29
+ before do
30
+ class OtherNoteRepository
31
+ include Elasticsearch::Persistence::Repository
32
+ def serialize(document)
33
+ { b: 1 }
34
+ end
35
+ end
36
+ end
37
+
38
+ after do
39
+ if defined?(OtherNoteRepository)
40
+ Object.send(:remove_const, OtherNoteRepository.name)
41
+ end
42
+ end
43
+
44
+ let(:repository) do
45
+ OtherNoteRepository.new(client: DEFAULT_CLIENT)
46
+ end
47
+
48
+ let(:response) do
49
+ repository.save(document)
50
+ end
51
+
52
+ it 'saves the document' do
53
+ expect(repository.find(response['_id'])).to eq('b' => 1)
54
+ end
55
+ end
56
+
57
+ context 'when options are provided' do
58
+
59
+ let!(:response) do
60
+ repository.save(document, type: 'other_note')
61
+ end
62
+
63
+ it 'saves the document using the options' do
64
+ expect {
65
+ repository.find(response['_id'])
66
+ }.to raise_exception(Elasticsearch::Persistence::Repository::DocumentNotFound)
67
+ expect(repository.find(response['_id'], type: 'other_note')).to eq('a' => 1)
68
+ end
69
+ end
70
+ end
71
+
72
+ describe '#update' do
73
+
74
+ before(:all) do
75
+ class Note
76
+ def to_hash
77
+ { text: 'testing', views: 0 }
78
+ end
79
+ end
80
+ end
81
+
82
+ after(:all) do
83
+ if defined?(Note)
84
+ Object.send(:remove_const, :Note)
85
+ end
86
+ end
87
+
88
+ context 'when the document exists' do
89
+
90
+ let!(:id) do
91
+ repository.save(Note.new)['_id']
92
+ end
93
+
94
+ context 'when an id is provided' do
95
+
96
+ context 'when a doc is specified in the options' do
97
+
98
+ before do
99
+ repository.update(id, doc: { text: 'testing_2' })
100
+ end
101
+
102
+ it 'updates using the doc parameter' do
103
+ expect(repository.find(id)).to eq('text' => 'testing_2', 'views' => 0)
104
+ end
105
+ end
106
+
107
+ context 'when a script is specified in the options' do
108
+
109
+ before do
110
+ repository.update(id, script: { inline: 'ctx._source.views += 1' })
111
+ end
112
+
113
+ it 'updates using the script parameter' do
114
+ expect(repository.find(id)).to eq('text' => 'testing', 'views' => 1)
115
+ end
116
+ end
117
+
118
+ context 'when params are specified in the options' do
119
+
120
+ before do
121
+ repository.update(id, script: { inline: 'ctx._source.views += params.count',
122
+ params: { count: 2 } })
123
+ end
124
+
125
+ it 'updates using the script parameter' do
126
+ expect(repository.find(id)).to eq('text' => 'testing', 'views' => 2)
127
+ end
128
+ end
129
+
130
+ context 'when upsert is specified in the options' do
131
+
132
+ before do
133
+ repository.update(id, script: { inline: 'ctx._source.views += 1' },
134
+ upsert: { text: 'testing_2' })
135
+ end
136
+
137
+ it 'executes the script' do
138
+ expect(repository.find(id)).to eq('text' => 'testing', 'views' => 1)
139
+ end
140
+ end
141
+
142
+ context 'when doc_as_upsert is specified in the options' do
143
+
144
+ before do
145
+ repository.update(id, doc: { text: 'testing_2' },
146
+ doc_as_upsert: true)
147
+ end
148
+
149
+ it 'performs an upsert' do
150
+ expect(repository.find(id)).to eq('text' => 'testing_2', 'views' => 0)
151
+ end
152
+ end
153
+ end
154
+
155
+ context 'when a document is provided as the query criteria' do
156
+
157
+ context 'when no options are provided' do
158
+
159
+ before do
160
+ repository.update(id: id, text: 'testing_2')
161
+ end
162
+
163
+ it 'updates using the id and the document as the doc parameter' do
164
+ expect(repository.find(id)).to eq('text' => 'testing_2', 'views' => 0)
165
+ end
166
+ end
167
+
168
+ context 'when options are provided' do
169
+
170
+ context 'when a doc is specified in the options' do
171
+
172
+ before do
173
+ repository.update({ id: id, text: 'testing' }, doc: { text: 'testing_2' })
174
+ end
175
+
176
+ it 'updates using the id and the doc in the options' do
177
+ expect(repository.find(id)).to eq('text' => 'testing_2', 'views' => 0)
178
+ end
179
+ end
180
+
181
+ context 'when a script is specified in the options' do
182
+
183
+ before do
184
+ repository.update({ id: id, text: 'testing' },
185
+ script: { inline: 'ctx._source.views += 1' })
186
+ end
187
+
188
+ it 'updates using the id and script from the options' do
189
+ expect(repository.find(id)).to eq('text' => 'testing', 'views' => 1)
190
+ end
191
+ end
192
+
193
+ context 'when params are specified in the options' do
194
+
195
+ before do
196
+ repository.update({ id: id, text: 'testing' },
197
+ script: { inline: 'ctx._source.views += params.count',
198
+ params: { count: 2 } })
199
+ end
200
+
201
+ it 'updates using the id and script and params from the options' do
202
+ expect(repository.find(id)).to eq('text' => 'testing', 'views' => 2)
203
+ end
204
+ end
205
+
206
+ context 'when upsert is specified in the options' do
207
+
208
+ before do
209
+ repository.update({ id: id, text: 'testing_2' },
210
+ doc_as_upsert: true)
211
+ end
212
+
213
+ it 'updates using the id and script and params from the options' do
214
+ expect(repository.find(id)).to eq('text' => 'testing_2', 'views' => 0)
215
+ end
216
+ end
217
+ end
218
+ end
219
+ end
220
+
221
+ context 'when the document does not exist' do
222
+
223
+ context 'when an id is provided 'do
224
+
225
+ it 'raises an exception' do
226
+ expect {
227
+ repository.update(1, doc: { text: 'testing_2' })
228
+ }.to raise_exception(Elasticsearch::Transport::Transport::Errors::NotFound)
229
+ end
230
+
231
+ context 'when upsert is provided' do
232
+
233
+ before do
234
+ repository.update(1, doc: { text: 'testing' }, doc_as_upsert: true)
235
+ end
236
+
237
+ it 'upserts the document' do
238
+ expect(repository.find(1)).to eq('text' => 'testing')
239
+ end
240
+ end
241
+ end
242
+
243
+ context 'when a document is provided' do
244
+
245
+ it 'raises an exception' do
246
+ expect {
247
+ repository.update(id: 1, text: 'testing_2')
248
+ }.to raise_exception(Elasticsearch::Transport::Transport::Errors::NotFound)
249
+ end
250
+
251
+ context 'when upsert is provided' do
252
+
253
+ before do
254
+ repository.update({ id: 1, text: 'testing' }, doc_as_upsert: true)
255
+ end
256
+
257
+ it 'upserts the document' do
258
+ expect(repository.find(1)).to eq('text' => 'testing')
259
+ end
260
+ end
261
+ end
262
+ end
263
+ end
264
+
265
+ describe '#delete' do
266
+
267
+ before(:all) do
268
+ class Note
269
+ def to_hash
270
+ { text: 'testing', views: 0 }
271
+ end
272
+ end
273
+ end
274
+
275
+ after(:all) do
276
+ if defined?(Note)
277
+ Object.send(:remove_const, :Note)
278
+ end
279
+ end
280
+
281
+ context 'when the document exists' do
282
+
283
+ let!(:id) do
284
+ repository.save(Note.new)['_id']
285
+ end
286
+
287
+ context 'an id is provided' do
288
+
289
+ before do
290
+ repository.delete(id)
291
+ end
292
+
293
+ it 'deletes the document using the id' do
294
+ expect {
295
+ repository.find(id)
296
+ }.to raise_exception(Elasticsearch::Persistence::Repository::DocumentNotFound)
297
+ end
298
+ end
299
+
300
+ context 'when a document is provided' do
301
+
302
+ before do
303
+ repository.delete(id: id, text: 'testing')
304
+ end
305
+
306
+ it 'deletes the document using the document' do
307
+ expect {
308
+ repository.find(id)
309
+ }.to raise_exception(Elasticsearch::Persistence::Repository::DocumentNotFound)
310
+ end
311
+ end
312
+ end
313
+
314
+ context 'when the document does not exist' do
315
+
316
+ before do
317
+ repository.create_index!
318
+ end
319
+
320
+ it 'raises an exception' do
321
+ expect {
322
+ repository.delete(1)
323
+ }.to raise_exception(Elasticsearch::Transport::Transport::Errors::NotFound)
324
+ end
325
+ end
326
+ end
327
+ end
@@ -0,0 +1,716 @@
1
+ require 'spec_helper'
2
+
3
+ describe Elasticsearch::Persistence::Repository do
4
+
5
+ describe '#create' do
6
+
7
+ before(:all) do
8
+ class RepositoryWithoutDSL
9
+ include Elasticsearch::Persistence::Repository
10
+ end
11
+ end
12
+
13
+ after(:all) do
14
+ if defined?(RepositoryWithoutDSL)
15
+ Object.send(:remove_const, RepositoryWithoutDSL.name)
16
+ end
17
+ end
18
+
19
+ it 'creates a repository object' do
20
+ expect(RepositoryWithoutDSL.create).to be_a(RepositoryWithoutDSL)
21
+ end
22
+
23
+ context 'when options are provided' do
24
+
25
+ let(:repository) do
26
+ RepositoryWithoutDSL.create(document_type: 'note')
27
+ end
28
+
29
+ it 'sets the options on the instance' do
30
+ expect(repository.document_type).to eq('note')
31
+ end
32
+ end
33
+
34
+ context 'when a block is passed' do
35
+
36
+ let(:repository) do
37
+ RepositoryWithoutDSL.create(document_type: 'note') do
38
+ mapping dynamic: 'strict' do
39
+ indexes :foo
40
+ end
41
+ end
42
+ end
43
+
44
+ it 'executes the block on the instance' do
45
+ expect(repository.mapping.to_hash).to eq(note: { dynamic: 'strict', properties: { foo: { type: 'text' } } })
46
+ end
47
+
48
+ context 'when options are provided in the args and set in the block' do
49
+
50
+ let(:repository) do
51
+ RepositoryWithoutDSL.create(mapping: double('mapping', to_hash: {}), document_type: 'note') do
52
+ mapping dynamic: 'strict' do
53
+ indexes :foo
54
+ end
55
+ end
56
+ end
57
+
58
+ it 'uses the options from the args' do
59
+ expect(repository.mapping.to_hash).to eq({})
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ describe '#initialize' do
66
+
67
+ before(:all) do
68
+ class RepositoryWithoutDSL
69
+ include Elasticsearch::Persistence::Repository
70
+ end
71
+ end
72
+
73
+ after(:all) do
74
+ if defined?(RepositoryWithoutDSL)
75
+ Object.send(:remove_const, RepositoryWithoutDSL.name)
76
+ end
77
+ end
78
+
79
+ after do
80
+ begin; repository.delete_index!; rescue; end
81
+ end
82
+
83
+ context 'when options are not provided' do
84
+
85
+ let(:repository) do
86
+ RepositoryWithoutDSL.new
87
+ end
88
+
89
+ it 'sets a default client' do
90
+ expect(repository.client).to be_a(Elasticsearch::Transport::Client)
91
+ end
92
+
93
+ it 'sets a default document type' do
94
+ expect(repository.document_type).to eq('_doc')
95
+ end
96
+
97
+ it 'sets a default index name' do
98
+ expect(repository.index_name).to eq('repository')
99
+ end
100
+
101
+ it 'does not set a klass' do
102
+ expect(repository.klass).to be_nil
103
+ end
104
+ end
105
+
106
+ context 'when options are provided' do
107
+
108
+ let(:client) do
109
+ Elasticsearch::Client.new
110
+ end
111
+
112
+ let(:repository) do
113
+ RepositoryWithoutDSL.new(client: client, document_type: 'user', index_name: 'users', klass: Array)
114
+ end
115
+
116
+ it 'sets the client' do
117
+ expect(repository.client).to be(client)
118
+ end
119
+
120
+ it 'sets document type' do
121
+ expect(repository.document_type).to eq('user')
122
+ end
123
+
124
+ it 'sets index name' do
125
+ expect(repository.index_name).to eq('users')
126
+ end
127
+
128
+ it 'sets the klass' do
129
+ expect(repository.klass).to eq(Array)
130
+ end
131
+ end
132
+ end
133
+
134
+ context 'when the DSL module is included' do
135
+
136
+ before(:all) do
137
+ class RepositoryWithDSL
138
+ include Elasticsearch::Persistence::Repository
139
+ include Elasticsearch::Persistence::Repository::DSL
140
+
141
+ document_type 'note'
142
+ index_name 'notes_repo'
143
+ klass Hash
144
+ client DEFAULT_CLIENT
145
+
146
+ settings number_of_shards: 1, number_of_replicas: 0 do
147
+ mapping dynamic: 'strict' do
148
+ indexes :foo do
149
+ indexes :bar
150
+ end
151
+ indexes :baz
152
+ end
153
+ end
154
+ end
155
+ end
156
+
157
+ after(:all) do
158
+ if defined?(RepositoryWithDSL)
159
+ Object.send(:remove_const, RepositoryWithDSL.name)
160
+ end
161
+ end
162
+
163
+ after do
164
+ begin; repository.delete_index; rescue; end
165
+ end
166
+
167
+ context '#client' do
168
+
169
+ it 'allows the value to be set only once on the class' do
170
+ RepositoryWithDSL.client(double('client', class: 'other_client'))
171
+ expect(RepositoryWithDSL.client).to be(DEFAULT_CLIENT)
172
+ end
173
+
174
+ it 'sets the value at the class level' do
175
+ expect(RepositoryWithDSL.client).to be(DEFAULT_CLIENT)
176
+ end
177
+
178
+ it 'sets the value as the default at the instance level' do
179
+ expect(RepositoryWithDSL.new.client).to be(DEFAULT_CLIENT)
180
+ end
181
+
182
+ it 'allows the value to be overridden with options on the instance' do
183
+ expect(RepositoryWithDSL.new(client: double('client', instance: 'other')).client.instance).to eq('other')
184
+ end
185
+ end
186
+
187
+ context '#klass' do
188
+
189
+ it 'allows the value to be set only once on the class' do
190
+ RepositoryWithDSL.klass(Array)
191
+ expect(RepositoryWithDSL.klass).to eq(Hash)
192
+ end
193
+
194
+ it 'sets the value at the class level' do
195
+ expect(RepositoryWithDSL.klass).to eq(Hash)
196
+ end
197
+
198
+ it 'sets the value as the default at the instance level' do
199
+ expect(RepositoryWithDSL.new.klass).to eq(Hash)
200
+ end
201
+
202
+ it 'allows the value to be overridden with options on the instance' do
203
+ expect(RepositoryWithDSL.new(klass: Array).klass).to eq(Array)
204
+ end
205
+
206
+ context 'when nil is passed to the method' do
207
+
208
+ before do
209
+ RepositoryWithDSL.klass(nil)
210
+ end
211
+
212
+ it 'allows the value to be set only once' do
213
+ expect(RepositoryWithDSL.klass).to eq(Hash)
214
+ end
215
+ end
216
+ end
217
+
218
+ context '#document_type' do
219
+
220
+ it 'allows the value to be set only once on the class' do
221
+ RepositoryWithDSL.document_type('other_note')
222
+ expect(RepositoryWithDSL.document_type).to eq('note')
223
+ end
224
+
225
+ it 'sets the value at the class level' do
226
+ expect(RepositoryWithDSL.document_type).to eq('note')
227
+ end
228
+
229
+ it 'sets the value as the default at the instance level' do
230
+ expect(RepositoryWithDSL.new.document_type).to eq('note')
231
+ end
232
+
233
+ it 'allows the value to be overridden with options on the instance' do
234
+ expect(RepositoryWithDSL.new(document_type: 'other_note').document_type).to eq('other_note')
235
+ end
236
+ end
237
+
238
+ context '#index_name' do
239
+
240
+ it 'allows the value to be set only once on the class' do
241
+ RepositoryWithDSL.index_name('other_name')
242
+ expect(RepositoryWithDSL.index_name).to eq('notes_repo')
243
+ end
244
+
245
+ it 'sets the value at the class level' do
246
+ expect(RepositoryWithDSL.index_name).to eq('notes_repo')
247
+ end
248
+
249
+ it 'sets the value as the default at the instance level' do
250
+ expect(RepositoryWithDSL.new.index_name).to eq('notes_repo')
251
+ end
252
+
253
+ it 'allows the value to be overridden with options on the instance' do
254
+ expect(RepositoryWithDSL.new(index_name: 'other_notes_repo').index_name).to eq('other_notes_repo')
255
+ end
256
+ end
257
+
258
+ describe '#create_index!' do
259
+
260
+ context 'when the method is called on an instance' do
261
+
262
+ let(:repository) do
263
+ RepositoryWithDSL.new
264
+ end
265
+
266
+ before do
267
+ begin; repository.delete_index!; rescue; end
268
+ repository.create_index!
269
+ end
270
+
271
+ it 'creates the index' do
272
+ expect(repository.index_exists?).to be(true)
273
+ end
274
+ end
275
+
276
+ context 'when the method is called on the class' do
277
+
278
+ it 'raises a NotImplementedError' do
279
+ expect {
280
+ RepositoryWithDSL.create_index!
281
+ }.to raise_exception(NotImplementedError)
282
+ end
283
+ end
284
+ end
285
+
286
+ describe '#delete_index!' do
287
+
288
+ context 'when the method is called on an instance' do
289
+
290
+ let(:repository) do
291
+ RepositoryWithDSL.new
292
+ end
293
+
294
+ before do
295
+ repository.create_index!
296
+ begin; repository.delete_index!; rescue; end
297
+ end
298
+
299
+ it 'deletes the index' do
300
+ expect(repository.index_exists?).to be(false)
301
+ end
302
+ end
303
+
304
+ context 'when the method is called on the class' do
305
+
306
+ it 'raises a NotImplementedError' do
307
+ expect {
308
+ RepositoryWithDSL.delete_index!
309
+ }.to raise_exception(NotImplementedError)
310
+ end
311
+ end
312
+ end
313
+
314
+ describe '#refresh_index!' do
315
+
316
+ context 'when the method is called on an instance' do
317
+
318
+ let(:repository) do
319
+ RepositoryWithDSL.new
320
+ end
321
+
322
+ before do
323
+ repository.create_index!
324
+ end
325
+
326
+ it 'refreshes the index' do
327
+ expect(repository.refresh_index!['_shards']).to be_a(Hash)
328
+ end
329
+ end
330
+
331
+ context 'when the method is called on the class' do
332
+
333
+ it 'raises a NotImplementedError' do
334
+ expect {
335
+ RepositoryWithDSL.refresh_index!
336
+ }.to raise_exception(NotImplementedError)
337
+ end
338
+ end
339
+ end
340
+
341
+ describe '#index_exists?' do
342
+
343
+ context 'when the method is called on an instance' do
344
+
345
+ let(:repository) do
346
+ RepositoryWithDSL.new
347
+ end
348
+
349
+ before do
350
+ repository.create_index!
351
+ end
352
+
353
+ it 'determines if the index exists' do
354
+ expect(repository.index_exists?).to be(true)
355
+ end
356
+ end
357
+
358
+ context 'when the method is called on the class' do
359
+
360
+ it 'raises a NotImplementedError' do
361
+ expect {
362
+ RepositoryWithDSL.index_exists?
363
+ }.to raise_exception(NotImplementedError)
364
+ end
365
+ end
366
+ end
367
+
368
+ describe '#mapping' do
369
+
370
+ let(:expected_mapping) do
371
+ { note: { dynamic: 'strict',
372
+ properties: { foo: { type: 'object',
373
+ properties: { bar: { type: 'text' } } },
374
+ baz: { type: 'text' } }
375
+ }
376
+ }
377
+ end
378
+
379
+ it 'sets the value at the class level' do
380
+ expect(RepositoryWithDSL.mapping.to_hash).to eq(expected_mapping)
381
+ end
382
+
383
+ it 'sets the value as the default at the instance level' do
384
+ expect(RepositoryWithDSL.new.mapping.to_hash).to eq(expected_mapping)
385
+ end
386
+
387
+ it 'allows the value to be overridden with options on the instance' do
388
+ expect(RepositoryWithDSL.new(mapping: double('mapping', to_hash: { note: {} })).mapping.to_hash).to eq(note: {})
389
+ end
390
+
391
+ context 'when the instance has a different document type' do
392
+
393
+ let(:expected_mapping) do
394
+ { other_note: { dynamic: 'strict',
395
+ properties: { foo: { type: 'object',
396
+ properties: { bar: { type: 'text' } } },
397
+ baz: { type: 'text' } }
398
+ }
399
+ }
400
+ end
401
+
402
+ it 'updates the mapping to use the document type' do
403
+ expect(RepositoryWithDSL.new(document_type: 'other_note').mapping.to_hash).to eq(expected_mapping)
404
+ end
405
+ end
406
+ end
407
+
408
+ describe '#settings' do
409
+
410
+ it 'sets the value at the class level' do
411
+ expect(RepositoryWithDSL.settings.to_hash).to eq(number_of_shards: 1, number_of_replicas: 0)
412
+ end
413
+
414
+ it 'sets the value as the default at the instance level' do
415
+ expect(RepositoryWithDSL.new.settings.to_hash).to eq(number_of_shards: 1, number_of_replicas: 0)
416
+ end
417
+
418
+ it 'allows the value to be overridden with options on the instance' do
419
+ expect(RepositoryWithDSL.new(settings: { number_of_shards: 3 }).settings.to_hash).to eq({number_of_shards: 3})
420
+ end
421
+ end
422
+ end
423
+
424
+ context 'when the DSL module is not included' do
425
+
426
+ before(:all) do
427
+ class RepositoryWithoutDSL
428
+ include Elasticsearch::Persistence::Repository
429
+ end
430
+ end
431
+
432
+ after(:all) do
433
+ if defined?(RepositoryWithoutDSL)
434
+ Object.send(:remove_const, RepositoryWithoutDSL.name)
435
+ end
436
+ end
437
+
438
+ context '#client' do
439
+
440
+ it 'does not define the method at the class level' do
441
+ expect {
442
+ RepositoryWithoutDSL.client
443
+ }.to raise_exception(NoMethodError)
444
+ end
445
+
446
+ it 'sets a default on the instance' do
447
+ expect(RepositoryWithoutDSL.new.client).to be_a(Elasticsearch::Transport::Client)
448
+ end
449
+
450
+ it 'allows the value to be overridden with options on the instance' do
451
+ expect(RepositoryWithoutDSL.new(client: double('client', object_id: 123)).client.object_id).to eq(123)
452
+ end
453
+ end
454
+
455
+ context '#klass' do
456
+
457
+ it 'does not define the method at the class level' do
458
+ expect {
459
+ RepositoryWithoutDSL.klass
460
+ }.to raise_exception(NoMethodError)
461
+ end
462
+
463
+ it 'does not set a default on an instance' do
464
+ expect(RepositoryWithoutDSL.new.klass).to be_nil
465
+ end
466
+
467
+ it 'allows the value to be overridden with options on the instance' do
468
+ expect(RepositoryWithoutDSL.new(klass: Array).klass).to eq(Array)
469
+ end
470
+ end
471
+
472
+ context '#document_type' do
473
+
474
+ it 'does not define the method at the class level' do
475
+ expect {
476
+ RepositoryWithoutDSL.document_type
477
+ }.to raise_exception(NoMethodError)
478
+ end
479
+
480
+ it 'sets a default on the instance' do
481
+ expect(RepositoryWithoutDSL.new.document_type).to eq('_doc')
482
+ end
483
+
484
+ it 'allows the value to be overridden with options on the instance' do
485
+ expect(RepositoryWithoutDSL.new(document_type: 'notes').document_type).to eq('notes')
486
+ end
487
+ end
488
+
489
+ context '#index_name' do
490
+
491
+ it 'does not define the method at the class level' do
492
+ expect {
493
+ RepositoryWithoutDSL.index_name
494
+ }.to raise_exception(NoMethodError)
495
+ end
496
+
497
+ it 'sets a default on the instance' do
498
+ expect(RepositoryWithoutDSL.new.index_name).to eq('repository')
499
+ end
500
+
501
+ it 'allows the value to be overridden with options on the instance' do
502
+ expect(RepositoryWithoutDSL.new(index_name: 'notes_repository').index_name).to eq('notes_repository')
503
+ end
504
+ end
505
+
506
+ describe '#create_index!' do
507
+
508
+ let(:repository) do
509
+ RepositoryWithoutDSL.new(client: DEFAULT_CLIENT)
510
+ end
511
+
512
+ after do
513
+ begin; repository.delete_index!; rescue; end
514
+ end
515
+
516
+ it 'does not define the method at the class level' do
517
+ expect {
518
+ RepositoryWithoutDSL.create_index!
519
+ }.to raise_exception(NoMethodError)
520
+ end
521
+
522
+ it 'creates an index' do
523
+ repository.create_index!
524
+ expect(repository.index_exists?).to eq(true)
525
+ end
526
+ end
527
+
528
+ describe '#delete_index!' do
529
+
530
+ let(:repository) do
531
+ RepositoryWithoutDSL.new(client: DEFAULT_CLIENT)
532
+ end
533
+
534
+ it 'does not define the method at the class level' do
535
+ expect {
536
+ RepositoryWithoutDSL.delete_index!
537
+ }.to raise_exception(NoMethodError)
538
+ end
539
+
540
+ it 'deletes an index' do
541
+ repository.create_index!
542
+ repository.delete_index!
543
+ expect(repository.index_exists?).to eq(false)
544
+ end
545
+ end
546
+
547
+ describe '#refresh_index!' do
548
+
549
+ let(:repository) do
550
+ RepositoryWithoutDSL.new(client: DEFAULT_CLIENT)
551
+ end
552
+
553
+ after do
554
+ begin; repository.delete_index!; rescue; end
555
+ end
556
+
557
+ it 'does not define the method at the class level' do
558
+ expect {
559
+ RepositoryWithoutDSL.refresh_index!
560
+ }.to raise_exception(NoMethodError)
561
+ end
562
+
563
+ it 'refreshes an index' do
564
+ repository.create_index!
565
+ expect(repository.refresh_index!['_shards']).to be_a(Hash)
566
+ end
567
+ end
568
+
569
+ describe '#index_exists?' do
570
+
571
+ let(:repository) do
572
+ RepositoryWithoutDSL.new(client: DEFAULT_CLIENT)
573
+ end
574
+
575
+ after do
576
+ begin; repository.delete_index!; rescue; end
577
+ end
578
+
579
+ it 'does not define the method at the class level' do
580
+ expect {
581
+ RepositoryWithoutDSL.index_exists?
582
+ }.to raise_exception(NoMethodError)
583
+ end
584
+
585
+ it 'returns whether the index exists' do
586
+ repository.create_index!
587
+ expect(repository.index_exists?).to be(true)
588
+ end
589
+ end
590
+
591
+ describe '#mapping' do
592
+
593
+ it 'does not define the method at the class level' do
594
+ expect {
595
+ RepositoryWithoutDSL.mapping
596
+ }.to raise_exception(NoMethodError)
597
+ end
598
+
599
+ it 'sets a default on an instance' do
600
+ expect(RepositoryWithoutDSL.new.mapping.to_hash).to eq(_doc: { properties: {} })
601
+ end
602
+
603
+ it 'allows the mapping to be set as an option' do
604
+ expect(RepositoryWithoutDSL.new(mapping: double('mapping', to_hash: { note: {} })).mapping.to_hash).to eq(note: {})
605
+ end
606
+
607
+ context 'when a block is passed to the create method' do
608
+
609
+ let(:expected_mapping) do
610
+ { note: { dynamic: 'strict',
611
+ properties: { foo: { type: 'object',
612
+ properties: { bar: { type: 'text' } } },
613
+ baz: { type: 'text' } }
614
+ }
615
+ }
616
+ end
617
+
618
+ let(:repository) do
619
+ RepositoryWithoutDSL.create(document_type: 'note') do
620
+ mapping dynamic: 'strict' do
621
+ indexes :foo do
622
+ indexes :bar
623
+ end
624
+ indexes :baz
625
+ end
626
+ end
627
+ end
628
+
629
+ it 'allows the mapping to be set in the block' do
630
+ expect(repository.mapping.to_hash).to eq(expected_mapping)
631
+ end
632
+
633
+ context 'when the mapping is set in the options' do
634
+
635
+ let(:repository) do
636
+ RepositoryWithoutDSL.create(mapping: double('mapping', to_hash: { note: {} })) do
637
+ mapping dynamic: 'strict' do
638
+ indexes :foo do
639
+ indexes :bar
640
+ end
641
+ indexes :baz
642
+ end
643
+ end
644
+ end
645
+
646
+ it 'uses the mapping from the options' do
647
+ expect(repository.mapping.to_hash).to eq(note: {})
648
+ end
649
+ end
650
+ end
651
+ end
652
+
653
+ describe '#settings' do
654
+
655
+ it 'does not define the method at the class level' do
656
+ expect {
657
+ RepositoryWithoutDSL.settings
658
+ }.to raise_exception(NoMethodError)
659
+ end
660
+
661
+ it 'sets a default on an instance' do
662
+ expect(RepositoryWithoutDSL.new.settings.to_hash).to eq({})
663
+ end
664
+
665
+ it 'allows the settings to be set as an option' do
666
+ expect(RepositoryWithoutDSL.new(settings: double('settings', to_hash: {})).settings.to_hash).to eq({})
667
+ end
668
+
669
+ context 'when a block is passed to the #create method' do
670
+
671
+ let(:repository) do
672
+ RepositoryWithoutDSL.create(document_type: 'note') do
673
+ settings number_of_shards: 1, number_of_replicas: 0
674
+ end
675
+ end
676
+
677
+ it 'allows the settings to be set with a block' do
678
+ expect(repository.settings.to_hash).to eq(number_of_shards: 1, number_of_replicas: 0)
679
+ end
680
+
681
+ context 'when a mapping is set in the block as well' do
682
+
683
+ let(:expected_mapping) do
684
+ { note: { dynamic: 'strict',
685
+ properties: { foo: { type: 'object',
686
+ properties: { bar: { type: 'text' } } },
687
+ baz: { type: 'text' } }
688
+ }
689
+ }
690
+ end
691
+
692
+ let(:repository) do
693
+ RepositoryWithoutDSL.create(document_type: 'note') do
694
+ settings number_of_shards: 1, number_of_replicas: 0 do
695
+ mapping dynamic: 'strict' do
696
+ indexes :foo do
697
+ indexes :bar
698
+ end
699
+ indexes :baz
700
+ end
701
+ end
702
+ end
703
+ end
704
+
705
+ it 'allows the settings to be set with a block' do
706
+ expect(repository.settings.to_hash).to eq(number_of_shards: 1, number_of_replicas: 0)
707
+ end
708
+
709
+ it 'allows the mapping to be set with a block' do
710
+ expect(repository.mappings.to_hash).to eq(expected_mapping)
711
+ end
712
+ end
713
+ end
714
+ end
715
+ end
716
+ end