elasticsearch-persistence 5.0.2 → 6.1.1

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