elasticsearch-persistence 5.0.2 → 6.1.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 (81) hide show
  1. checksums.yaml +5 -5
  2. data/.rspec +2 -0
  3. data/Gemfile +9 -0
  4. data/README.md +206 -338
  5. data/Rakefile +15 -12
  6. data/elasticsearch-persistence.gemspec +6 -7
  7. data/examples/notes/application.rb +3 -4
  8. data/lib/elasticsearch/persistence.rb +2 -110
  9. data/lib/elasticsearch/persistence/repository.rb +212 -53
  10. data/lib/elasticsearch/persistence/repository/dsl.rb +94 -0
  11. data/lib/elasticsearch/persistence/repository/find.rb +27 -10
  12. data/lib/elasticsearch/persistence/repository/response/results.rb +21 -8
  13. data/lib/elasticsearch/persistence/repository/search.rb +30 -18
  14. data/lib/elasticsearch/persistence/repository/serialize.rb +65 -7
  15. data/lib/elasticsearch/persistence/repository/store.rb +38 -44
  16. data/lib/elasticsearch/persistence/version.rb +1 -1
  17. data/spec/repository/find_spec.rb +179 -0
  18. data/spec/repository/response/results_spec.rb +128 -0
  19. data/spec/repository/search_spec.rb +181 -0
  20. data/spec/repository/serialize_spec.rb +53 -0
  21. data/spec/repository/store_spec.rb +327 -0
  22. data/spec/repository_spec.rb +723 -0
  23. data/spec/spec_helper.rb +32 -0
  24. metadata +26 -104
  25. data/examples/music/album.rb +0 -54
  26. data/examples/music/artist.rb +0 -70
  27. data/examples/music/artists/_form.html.erb +0 -8
  28. data/examples/music/artists/artists_controller.rb +0 -67
  29. data/examples/music/artists/artists_controller_test.rb +0 -53
  30. data/examples/music/artists/index.html.erb +0 -60
  31. data/examples/music/artists/show.html.erb +0 -54
  32. data/examples/music/assets/application.css +0 -257
  33. data/examples/music/assets/autocomplete.css +0 -48
  34. data/examples/music/assets/blank_artist.png +0 -0
  35. data/examples/music/assets/blank_cover.png +0 -0
  36. data/examples/music/assets/form.css +0 -113
  37. data/examples/music/index_manager.rb +0 -73
  38. data/examples/music/search/index.html.erb +0 -95
  39. data/examples/music/search/search_controller.rb +0 -41
  40. data/examples/music/search/search_controller_test.rb +0 -12
  41. data/examples/music/search/search_helper.rb +0 -15
  42. data/examples/music/suggester.rb +0 -69
  43. data/examples/music/template.rb +0 -430
  44. data/examples/music/vendor/assets/jquery-ui-1.10.4.custom.min.css +0 -7
  45. data/examples/music/vendor/assets/jquery-ui-1.10.4.custom.min.js +0 -6
  46. data/examples/music/vendor/assets/stylesheets/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  47. data/lib/elasticsearch/persistence/client.rb +0 -51
  48. data/lib/elasticsearch/persistence/model.rb +0 -135
  49. data/lib/elasticsearch/persistence/model/base.rb +0 -87
  50. data/lib/elasticsearch/persistence/model/errors.rb +0 -8
  51. data/lib/elasticsearch/persistence/model/find.rb +0 -180
  52. data/lib/elasticsearch/persistence/model/rails.rb +0 -47
  53. data/lib/elasticsearch/persistence/model/store.rb +0 -254
  54. data/lib/elasticsearch/persistence/model/utils.rb +0 -0
  55. data/lib/elasticsearch/persistence/repository/class.rb +0 -71
  56. data/lib/elasticsearch/persistence/repository/naming.rb +0 -115
  57. data/lib/rails/generators/elasticsearch/model/model_generator.rb +0 -21
  58. data/lib/rails/generators/elasticsearch/model/templates/model.rb.tt +0 -9
  59. data/lib/rails/generators/elasticsearch_generator.rb +0 -2
  60. data/test/integration/model/model_basic_test.rb +0 -233
  61. data/test/integration/repository/custom_class_test.rb +0 -85
  62. data/test/integration/repository/customized_class_test.rb +0 -82
  63. data/test/integration/repository/default_class_test.rb +0 -116
  64. data/test/integration/repository/virtus_model_test.rb +0 -118
  65. data/test/test_helper.rb +0 -55
  66. data/test/unit/model_base_test.rb +0 -72
  67. data/test/unit/model_find_test.rb +0 -153
  68. data/test/unit/model_gateway_test.rb +0 -101
  69. data/test/unit/model_rails_test.rb +0 -112
  70. data/test/unit/model_store_test.rb +0 -576
  71. data/test/unit/persistence_test.rb +0 -32
  72. data/test/unit/repository_class_test.rb +0 -51
  73. data/test/unit/repository_client_test.rb +0 -32
  74. data/test/unit/repository_find_test.rb +0 -388
  75. data/test/unit/repository_indexing_test.rb +0 -37
  76. data/test/unit/repository_module_test.rb +0 -146
  77. data/test/unit/repository_naming_test.rb +0 -146
  78. data/test/unit/repository_response_results_test.rb +0 -98
  79. data/test/unit/repository_search_test.rb +0 -117
  80. data/test/unit/repository_serialize_test.rb +0 -57
  81. 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,723 @@
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
+
357
+ context 'when arguments are passed in' do
358
+
359
+ it 'passes the arguments to the request' do
360
+ expect(repository.index_exists?(index: 'other')).to be(false)
361
+ end
362
+ end
363
+ end
364
+
365
+ context 'when the method is called on the class' do
366
+
367
+ it 'raises a NotImplementedError' do
368
+ expect {
369
+ RepositoryWithDSL.index_exists?
370
+ }.to raise_exception(NotImplementedError)
371
+ end
372
+ end
373
+ end
374
+
375
+ describe '#mapping' do
376
+
377
+ let(:expected_mapping) do
378
+ { note: { dynamic: 'strict',
379
+ properties: { foo: { type: 'object',
380
+ properties: { bar: { type: 'text' } } },
381
+ baz: { type: 'text' } }
382
+ }
383
+ }
384
+ end
385
+
386
+ it 'sets the value at the class level' do
387
+ expect(RepositoryWithDSL.mapping.to_hash).to eq(expected_mapping)
388
+ end
389
+
390
+ it 'sets the value as the default at the instance level' do
391
+ expect(RepositoryWithDSL.new.mapping.to_hash).to eq(expected_mapping)
392
+ end
393
+
394
+ it 'allows the value to be overridden with options on the instance' do
395
+ expect(RepositoryWithDSL.new(mapping: double('mapping', to_hash: { note: {} })).mapping.to_hash).to eq(note: {})
396
+ end
397
+
398
+ context 'when the instance has a different document type' do
399
+
400
+ let(:expected_mapping) do
401
+ { other_note: { dynamic: 'strict',
402
+ properties: { foo: { type: 'object',
403
+ properties: { bar: { type: 'text' } } },
404
+ baz: { type: 'text' } }
405
+ }
406
+ }
407
+ end
408
+
409
+ it 'updates the mapping to use the document type' do
410
+ expect(RepositoryWithDSL.new(document_type: 'other_note').mapping.to_hash).to eq(expected_mapping)
411
+ end
412
+ end
413
+ end
414
+
415
+ describe '#settings' do
416
+
417
+ it 'sets the value at the class level' do
418
+ expect(RepositoryWithDSL.settings.to_hash).to eq(number_of_shards: 1, number_of_replicas: 0)
419
+ end
420
+
421
+ it 'sets the value as the default at the instance level' do
422
+ expect(RepositoryWithDSL.new.settings.to_hash).to eq(number_of_shards: 1, number_of_replicas: 0)
423
+ end
424
+
425
+ it 'allows the value to be overridden with options on the instance' do
426
+ expect(RepositoryWithDSL.new(settings: { number_of_shards: 3 }).settings.to_hash).to eq({number_of_shards: 3})
427
+ end
428
+ end
429
+ end
430
+
431
+ context 'when the DSL module is not included' do
432
+
433
+ before(:all) do
434
+ class RepositoryWithoutDSL
435
+ include Elasticsearch::Persistence::Repository
436
+ end
437
+ end
438
+
439
+ after(:all) do
440
+ if defined?(RepositoryWithoutDSL)
441
+ Object.send(:remove_const, RepositoryWithoutDSL.name)
442
+ end
443
+ end
444
+
445
+ context '#client' do
446
+
447
+ it 'does not define the method at the class level' do
448
+ expect {
449
+ RepositoryWithoutDSL.client
450
+ }.to raise_exception(NoMethodError)
451
+ end
452
+
453
+ it 'sets a default on the instance' do
454
+ expect(RepositoryWithoutDSL.new.client).to be_a(Elasticsearch::Transport::Client)
455
+ end
456
+
457
+ it 'allows the value to be overridden with options on the instance' do
458
+ expect(RepositoryWithoutDSL.new(client: double('client', object_id: 123)).client.object_id).to eq(123)
459
+ end
460
+ end
461
+
462
+ context '#klass' do
463
+
464
+ it 'does not define the method at the class level' do
465
+ expect {
466
+ RepositoryWithoutDSL.klass
467
+ }.to raise_exception(NoMethodError)
468
+ end
469
+
470
+ it 'does not set a default on an instance' do
471
+ expect(RepositoryWithoutDSL.new.klass).to be_nil
472
+ end
473
+
474
+ it 'allows the value to be overridden with options on the instance' do
475
+ expect(RepositoryWithoutDSL.new(klass: Array).klass).to eq(Array)
476
+ end
477
+ end
478
+
479
+ context '#document_type' do
480
+
481
+ it 'does not define the method at the class level' do
482
+ expect {
483
+ RepositoryWithoutDSL.document_type
484
+ }.to raise_exception(NoMethodError)
485
+ end
486
+
487
+ it 'sets a default on the instance' do
488
+ expect(RepositoryWithoutDSL.new.document_type).to eq('_doc')
489
+ end
490
+
491
+ it 'allows the value to be overridden with options on the instance' do
492
+ expect(RepositoryWithoutDSL.new(document_type: 'notes').document_type).to eq('notes')
493
+ end
494
+ end
495
+
496
+ context '#index_name' do
497
+
498
+ it 'does not define the method at the class level' do
499
+ expect {
500
+ RepositoryWithoutDSL.index_name
501
+ }.to raise_exception(NoMethodError)
502
+ end
503
+
504
+ it 'sets a default on the instance' do
505
+ expect(RepositoryWithoutDSL.new.index_name).to eq('repository')
506
+ end
507
+
508
+ it 'allows the value to be overridden with options on the instance' do
509
+ expect(RepositoryWithoutDSL.new(index_name: 'notes_repository').index_name).to eq('notes_repository')
510
+ end
511
+ end
512
+
513
+ describe '#create_index!' do
514
+
515
+ let(:repository) do
516
+ RepositoryWithoutDSL.new(client: DEFAULT_CLIENT)
517
+ end
518
+
519
+ after do
520
+ begin; repository.delete_index!; rescue; end
521
+ end
522
+
523
+ it 'does not define the method at the class level' do
524
+ expect {
525
+ RepositoryWithoutDSL.create_index!
526
+ }.to raise_exception(NoMethodError)
527
+ end
528
+
529
+ it 'creates an index' do
530
+ repository.create_index!
531
+ expect(repository.index_exists?).to eq(true)
532
+ end
533
+ end
534
+
535
+ describe '#delete_index!' do
536
+
537
+ let(:repository) do
538
+ RepositoryWithoutDSL.new(client: DEFAULT_CLIENT)
539
+ end
540
+
541
+ it 'does not define the method at the class level' do
542
+ expect {
543
+ RepositoryWithoutDSL.delete_index!
544
+ }.to raise_exception(NoMethodError)
545
+ end
546
+
547
+ it 'deletes an index' do
548
+ repository.create_index!
549
+ repository.delete_index!
550
+ expect(repository.index_exists?).to eq(false)
551
+ end
552
+ end
553
+
554
+ describe '#refresh_index!' do
555
+
556
+ let(:repository) do
557
+ RepositoryWithoutDSL.new(client: DEFAULT_CLIENT)
558
+ end
559
+
560
+ after do
561
+ begin; repository.delete_index!; rescue; end
562
+ end
563
+
564
+ it 'does not define the method at the class level' do
565
+ expect {
566
+ RepositoryWithoutDSL.refresh_index!
567
+ }.to raise_exception(NoMethodError)
568
+ end
569
+
570
+ it 'refreshes an index' do
571
+ repository.create_index!
572
+ expect(repository.refresh_index!['_shards']).to be_a(Hash)
573
+ end
574
+ end
575
+
576
+ describe '#index_exists?' do
577
+
578
+ let(:repository) do
579
+ RepositoryWithoutDSL.new(client: DEFAULT_CLIENT)
580
+ end
581
+
582
+ after do
583
+ begin; repository.delete_index!; rescue; end
584
+ end
585
+
586
+ it 'does not define the method at the class level' do
587
+ expect {
588
+ RepositoryWithoutDSL.index_exists?
589
+ }.to raise_exception(NoMethodError)
590
+ end
591
+
592
+ it 'returns whether the index exists' do
593
+ repository.create_index!
594
+ expect(repository.index_exists?).to be(true)
595
+ end
596
+ end
597
+
598
+ describe '#mapping' do
599
+
600
+ it 'does not define the method at the class level' do
601
+ expect {
602
+ RepositoryWithoutDSL.mapping
603
+ }.to raise_exception(NoMethodError)
604
+ end
605
+
606
+ it 'sets a default on an instance' do
607
+ expect(RepositoryWithoutDSL.new.mapping.to_hash).to eq(_doc: { properties: {} })
608
+ end
609
+
610
+ it 'allows the mapping to be set as an option' do
611
+ expect(RepositoryWithoutDSL.new(mapping: double('mapping', to_hash: { note: {} })).mapping.to_hash).to eq(note: {})
612
+ end
613
+
614
+ context 'when a block is passed to the create method' do
615
+
616
+ let(:expected_mapping) do
617
+ { note: { dynamic: 'strict',
618
+ properties: { foo: { type: 'object',
619
+ properties: { bar: { type: 'text' } } },
620
+ baz: { type: 'text' } }
621
+ }
622
+ }
623
+ end
624
+
625
+ let(:repository) do
626
+ RepositoryWithoutDSL.create(document_type: 'note') do
627
+ mapping dynamic: 'strict' do
628
+ indexes :foo do
629
+ indexes :bar
630
+ end
631
+ indexes :baz
632
+ end
633
+ end
634
+ end
635
+
636
+ it 'allows the mapping to be set in the block' do
637
+ expect(repository.mapping.to_hash).to eq(expected_mapping)
638
+ end
639
+
640
+ context 'when the mapping is set in the options' do
641
+
642
+ let(:repository) do
643
+ RepositoryWithoutDSL.create(mapping: double('mapping', to_hash: { note: {} })) do
644
+ mapping dynamic: 'strict' do
645
+ indexes :foo do
646
+ indexes :bar
647
+ end
648
+ indexes :baz
649
+ end
650
+ end
651
+ end
652
+
653
+ it 'uses the mapping from the options' do
654
+ expect(repository.mapping.to_hash).to eq(note: {})
655
+ end
656
+ end
657
+ end
658
+ end
659
+
660
+ describe '#settings' do
661
+
662
+ it 'does not define the method at the class level' do
663
+ expect {
664
+ RepositoryWithoutDSL.settings
665
+ }.to raise_exception(NoMethodError)
666
+ end
667
+
668
+ it 'sets a default on an instance' do
669
+ expect(RepositoryWithoutDSL.new.settings.to_hash).to eq({})
670
+ end
671
+
672
+ it 'allows the settings to be set as an option' do
673
+ expect(RepositoryWithoutDSL.new(settings: double('settings', to_hash: {})).settings.to_hash).to eq({})
674
+ end
675
+
676
+ context 'when a block is passed to the #create method' do
677
+
678
+ let(:repository) do
679
+ RepositoryWithoutDSL.create(document_type: 'note') do
680
+ settings number_of_shards: 1, number_of_replicas: 0
681
+ end
682
+ end
683
+
684
+ it 'allows the settings to be set with a block' do
685
+ expect(repository.settings.to_hash).to eq(number_of_shards: 1, number_of_replicas: 0)
686
+ end
687
+
688
+ context 'when a mapping is set in the block as well' do
689
+
690
+ let(:expected_mapping) do
691
+ { note: { dynamic: 'strict',
692
+ properties: { foo: { type: 'object',
693
+ properties: { bar: { type: 'text' } } },
694
+ baz: { type: 'text' } }
695
+ }
696
+ }
697
+ end
698
+
699
+ let(:repository) do
700
+ RepositoryWithoutDSL.create(document_type: 'note') do
701
+ settings number_of_shards: 1, number_of_replicas: 0 do
702
+ mapping dynamic: 'strict' do
703
+ indexes :foo do
704
+ indexes :bar
705
+ end
706
+ indexes :baz
707
+ end
708
+ end
709
+ end
710
+ end
711
+
712
+ it 'allows the settings to be set with a block' do
713
+ expect(repository.settings.to_hash).to eq(number_of_shards: 1, number_of_replicas: 0)
714
+ end
715
+
716
+ it 'allows the mapping to be set with a block' do
717
+ expect(repository.mappings.to_hash).to eq(expected_mapping)
718
+ end
719
+ end
720
+ end
721
+ end
722
+ end
723
+ end