elasticsearch-model 0.1.9 → 7.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +3 -2
  3. data/Gemfile +22 -0
  4. data/LICENSE.txt +199 -10
  5. data/README.md +96 -43
  6. data/Rakefile +49 -35
  7. data/elasticsearch-model.gemspec +53 -41
  8. data/examples/activerecord_article.rb +18 -1
  9. data/examples/activerecord_associations.rb +86 -17
  10. data/examples/activerecord_custom_analyzer.rb +152 -0
  11. data/examples/activerecord_mapping_completion.rb +33 -16
  12. data/examples/activerecord_mapping_edge_ngram.rb +118 -0
  13. data/examples/couchbase_article.rb +17 -0
  14. data/examples/datamapper_article.rb +28 -1
  15. data/examples/mongoid_article.rb +17 -0
  16. data/examples/ohm_article.rb +17 -0
  17. data/examples/riak_article.rb +17 -0
  18. data/gemfiles/3.0.gemfile +23 -1
  19. data/gemfiles/4.0.gemfile +25 -1
  20. data/gemfiles/5.0.gemfile +35 -0
  21. data/gemfiles/6.0.gemfile +36 -0
  22. data/lib/elasticsearch/model/adapter.rb +17 -0
  23. data/lib/elasticsearch/model/adapters/active_record.rb +31 -27
  24. data/lib/elasticsearch/model/adapters/default.rb +17 -0
  25. data/lib/elasticsearch/model/adapters/mongoid.rb +27 -3
  26. data/lib/elasticsearch/model/adapters/multiple.rb +29 -4
  27. data/lib/elasticsearch/model/callbacks.rb +17 -0
  28. data/lib/elasticsearch/model/client.rb +17 -0
  29. data/lib/elasticsearch/model/ext/active_record.rb +17 -0
  30. data/lib/elasticsearch/model/hash_wrapper.rb +32 -0
  31. data/lib/elasticsearch/model/importing.rb +61 -17
  32. data/lib/elasticsearch/model/indexing.rb +87 -49
  33. data/lib/elasticsearch/model/multimodel.rb +17 -0
  34. data/lib/elasticsearch/model/naming.rb +33 -2
  35. data/lib/elasticsearch/model/proxy.rb +61 -18
  36. data/lib/elasticsearch/model/response/aggregations.rb +55 -0
  37. data/lib/elasticsearch/model/response/base.rb +25 -3
  38. data/lib/elasticsearch/model/response/pagination/kaminari.rb +126 -0
  39. data/lib/elasticsearch/model/response/pagination/will_paginate.rb +112 -0
  40. data/lib/elasticsearch/model/response/pagination.rb +19 -192
  41. data/lib/elasticsearch/model/response/records.rb +17 -1
  42. data/lib/elasticsearch/model/response/result.rb +19 -2
  43. data/lib/elasticsearch/model/response/results.rb +17 -0
  44. data/lib/elasticsearch/model/response/suggestions.rb +20 -1
  45. data/lib/elasticsearch/model/response.rb +28 -10
  46. data/lib/elasticsearch/model/searching.rb +17 -0
  47. data/lib/elasticsearch/model/serializing.rb +17 -0
  48. data/lib/elasticsearch/model/version.rb +18 -1
  49. data/lib/elasticsearch/model.rb +36 -39
  50. data/spec/elasticsearch/model/adapter_spec.rb +136 -0
  51. data/spec/elasticsearch/model/adapters/active_record/associations_spec.rb +351 -0
  52. data/spec/elasticsearch/model/adapters/active_record/basic_spec.rb +395 -0
  53. data/spec/elasticsearch/model/adapters/active_record/dynamic_index_name_spec.rb +35 -0
  54. data/spec/elasticsearch/model/adapters/active_record/import_spec.rb +193 -0
  55. data/spec/elasticsearch/model/adapters/active_record/multi_model_spec.rb +127 -0
  56. data/spec/elasticsearch/model/adapters/active_record/namespaced_model_spec.rb +55 -0
  57. data/spec/elasticsearch/model/adapters/active_record/pagination_spec.rb +332 -0
  58. data/spec/elasticsearch/model/adapters/active_record/parent_child_spec.rb +92 -0
  59. data/spec/elasticsearch/model/adapters/active_record/serialization_spec.rb +78 -0
  60. data/spec/elasticsearch/model/adapters/active_record_spec.rb +224 -0
  61. data/spec/elasticsearch/model/adapters/default_spec.rb +58 -0
  62. data/spec/elasticsearch/model/adapters/mongoid/basic_spec.rb +284 -0
  63. data/spec/elasticsearch/model/adapters/mongoid/multi_model_spec.rb +83 -0
  64. data/spec/elasticsearch/model/adapters/mongoid_spec.rb +252 -0
  65. data/spec/elasticsearch/model/adapters/multiple_spec.rb +142 -0
  66. data/spec/elasticsearch/model/callbacks_spec.rb +50 -0
  67. data/spec/elasticsearch/model/client_spec.rb +83 -0
  68. data/spec/elasticsearch/model/hash_wrapper_spec.rb +29 -0
  69. data/spec/elasticsearch/model/importing_spec.rb +243 -0
  70. data/spec/elasticsearch/model/indexing_spec.rb +1014 -0
  71. data/spec/elasticsearch/model/module_spec.rb +94 -0
  72. data/spec/elasticsearch/model/multimodel_spec.rb +72 -0
  73. data/spec/elasticsearch/model/naming_spec.rb +203 -0
  74. data/spec/elasticsearch/model/proxy_spec.rb +124 -0
  75. data/spec/elasticsearch/model/response/aggregations_spec.rb +83 -0
  76. data/spec/elasticsearch/model/response/base_spec.rb +107 -0
  77. data/spec/elasticsearch/model/response/pagination/kaminari_spec.rb +472 -0
  78. data/spec/elasticsearch/model/response/pagination/will_paginate_spec.rb +279 -0
  79. data/spec/elasticsearch/model/response/records_spec.rb +135 -0
  80. data/spec/elasticsearch/model/response/response_spec.rb +148 -0
  81. data/spec/elasticsearch/model/response/result_spec.rb +139 -0
  82. data/spec/elasticsearch/model/response/results_spec.rb +73 -0
  83. data/spec/elasticsearch/model/searching_search_request_spec.rb +129 -0
  84. data/spec/elasticsearch/model/searching_spec.rb +66 -0
  85. data/spec/elasticsearch/model/serializing_spec.rb +39 -0
  86. data/spec/spec_helper.rb +193 -0
  87. data/spec/support/app/answer.rb +50 -0
  88. data/spec/support/app/article.rb +39 -0
  89. data/spec/support/app/article_for_pagination.rb +29 -0
  90. data/spec/support/app/article_no_type.rb +37 -0
  91. data/spec/support/app/article_with_custom_serialization.rb +30 -0
  92. data/spec/support/app/article_with_dynamic_index_name.rb +32 -0
  93. data/spec/support/app/author.rb +26 -0
  94. data/spec/support/app/authorship.rb +21 -0
  95. data/spec/support/app/category.rb +20 -0
  96. data/spec/support/app/comment.rb +20 -0
  97. data/spec/support/app/episode.rb +28 -0
  98. data/spec/support/app/image.rb +36 -0
  99. data/spec/support/app/import_article.rb +29 -0
  100. data/spec/support/app/mongoid_article.rb +38 -0
  101. data/spec/support/app/namespaced_book.rb +27 -0
  102. data/spec/support/app/parent_and_child_searchable.rb +41 -0
  103. data/spec/support/app/post.rb +31 -0
  104. data/spec/support/app/question.rb +44 -0
  105. data/spec/support/app/searchable.rb +65 -0
  106. data/spec/support/app/series.rb +28 -0
  107. data/spec/support/app.rb +46 -0
  108. data/spec/support/model.json +1 -0
  109. data/{test → spec}/support/model.yml +0 -0
  110. metadata +175 -121
  111. data/test/integration/active_record_associations_parent_child.rb +0 -139
  112. data/test/integration/active_record_associations_test.rb +0 -326
  113. data/test/integration/active_record_basic_test.rb +0 -234
  114. data/test/integration/active_record_custom_serialization_test.rb +0 -62
  115. data/test/integration/active_record_import_test.rb +0 -109
  116. data/test/integration/active_record_namespaced_model_test.rb +0 -49
  117. data/test/integration/active_record_pagination_test.rb +0 -145
  118. data/test/integration/dynamic_index_name_test.rb +0 -47
  119. data/test/integration/mongoid_basic_test.rb +0 -177
  120. data/test/integration/multiple_models_test.rb +0 -172
  121. data/test/support/model.json +0 -1
  122. data/test/test_helper.rb +0 -93
  123. data/test/unit/adapter_active_record_test.rb +0 -157
  124. data/test/unit/adapter_default_test.rb +0 -41
  125. data/test/unit/adapter_mongoid_test.rb +0 -104
  126. data/test/unit/adapter_multiple_test.rb +0 -106
  127. data/test/unit/adapter_test.rb +0 -69
  128. data/test/unit/callbacks_test.rb +0 -31
  129. data/test/unit/client_test.rb +0 -27
  130. data/test/unit/importing_test.rb +0 -203
  131. data/test/unit/indexing_test.rb +0 -650
  132. data/test/unit/module_test.rb +0 -57
  133. data/test/unit/multimodel_test.rb +0 -38
  134. data/test/unit/naming_test.rb +0 -103
  135. data/test/unit/proxy_test.rb +0 -100
  136. data/test/unit/response_base_test.rb +0 -40
  137. data/test/unit/response_pagination_kaminari_test.rb +0 -433
  138. data/test/unit/response_pagination_will_paginate_test.rb +0 -398
  139. data/test/unit/response_records_test.rb +0 -91
  140. data/test/unit/response_result_test.rb +0 -90
  141. data/test/unit/response_results_test.rb +0 -31
  142. data/test/unit/response_test.rb +0 -104
  143. data/test/unit/searching_search_request_test.rb +0 -78
  144. data/test/unit/searching_test.rb +0 -41
  145. data/test/unit/serializing_test.rb +0 -17
@@ -0,0 +1,395 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ require 'spec_helper'
19
+
20
+ describe Elasticsearch::Model::Adapter::ActiveRecord do
21
+
22
+ context 'when a document_type is not defined for the Model' do
23
+
24
+ before do
25
+ ActiveRecord::Schema.define(:version => 1) do
26
+ create_table :article_no_types do |t|
27
+ t.string :title
28
+ t.string :body
29
+ t.integer :clicks, :default => 0
30
+ t.datetime :created_at, :default => 'NOW()'
31
+ end
32
+ end
33
+
34
+ ArticleNoType.delete_all
35
+ ArticleNoType.__elasticsearch__.create_index!(force: true)
36
+
37
+ ArticleNoType.create!(title: 'Test', body: '', clicks: 1)
38
+ ArticleNoType.create!(title: 'Testing Coding', body: '', clicks: 2)
39
+ ArticleNoType.create!(title: 'Coding', body: '', clicks: 3)
40
+
41
+ ArticleNoType.__elasticsearch__.refresh_index!
42
+ end
43
+
44
+ describe 'indexing a document' do
45
+
46
+ let(:search_result) do
47
+ ArticleNoType.search('title:test')
48
+ end
49
+
50
+ it 'allows searching for documents' do
51
+ expect(search_result.results.size).to be(2)
52
+ expect(search_result.records.size).to be(2)
53
+ end
54
+ end
55
+ end
56
+
57
+ context 'when a document_type is defined for the Model' do
58
+
59
+ before(:all) do
60
+ ActiveRecord::Schema.define(:version => 1) do
61
+ create_table :articles do |t|
62
+ t.string :title
63
+ t.string :body
64
+ t.integer :clicks, :default => 0
65
+ t.datetime :created_at, :default => 'NOW()'
66
+ end
67
+ end
68
+
69
+ Article.delete_all
70
+ Article.__elasticsearch__.create_index!(force: true, include_type_name: true)
71
+
72
+ Article.create!(title: 'Test', body: '', clicks: 1)
73
+ Article.create!(title: 'Testing Coding', body: '', clicks: 2)
74
+ Article.create!(title: 'Coding', body: '', clicks: 3)
75
+
76
+ Article.__elasticsearch__.refresh_index!
77
+ end
78
+
79
+ describe 'indexing a document' do
80
+
81
+ let(:search_result) do
82
+ Article.search('title:test')
83
+ end
84
+
85
+ it 'allows searching for documents' do
86
+ expect(search_result.results.size).to be(2)
87
+ expect(search_result.records.size).to be(2)
88
+ end
89
+ end
90
+
91
+ describe '#results' do
92
+
93
+ let(:search_result) do
94
+ Article.search('title:test')
95
+ end
96
+
97
+ it 'returns an instance of Response::Result' do
98
+ expect(search_result.results.first).to be_a(Elasticsearch::Model::Response::Result)
99
+ end
100
+
101
+ it 'prooperly loads the document' do
102
+ expect(search_result.results.first.title).to eq('Test')
103
+ end
104
+
105
+ context 'when the result contains other data' do
106
+
107
+ let(:search_result) do
108
+ Article.search(query: { match: { title: 'test' } }, highlight: { fields: { title: {} } })
109
+ end
110
+
111
+ it 'allows access to the Elasticsearch result' do
112
+ expect(search_result.results.first.title).to eq('Test')
113
+ expect(search_result.results.first.title?).to be(true)
114
+ expect(search_result.results.first.boo?).to be(false)
115
+ expect(search_result.results.first.highlight?).to be(true)
116
+ expect(search_result.results.first.highlight.title?).to be(true)
117
+ expect(search_result.results.first.highlight.boo?).to be(false)
118
+ end
119
+ end
120
+ end
121
+
122
+ describe '#records' do
123
+
124
+ let(:search_result) do
125
+ Article.search('title:test')
126
+ end
127
+
128
+ it 'returns an instance of the model' do
129
+ expect(search_result.records.first).to be_a(Article)
130
+ end
131
+
132
+ it 'prooperly loads the document' do
133
+ expect(search_result.records.first.title).to eq('Test')
134
+ end
135
+ end
136
+
137
+ describe 'Enumerable' do
138
+
139
+ let(:search_result) do
140
+ Article.search('title:test')
141
+ end
142
+
143
+ it 'allows iteration over results' do
144
+ expect(search_result.results.map(&:_id)).to eq(['1', '2'])
145
+ end
146
+
147
+ it 'allows iteration over records' do
148
+ expect(search_result.records.map(&:id)).to eq([1, 2])
149
+ end
150
+ end
151
+
152
+ describe '#id' do
153
+
154
+ let(:search_result) do
155
+ Article.search('title:test')
156
+ end
157
+
158
+ it 'returns the id' do
159
+ expect(search_result.results.first.id).to eq('1')
160
+ end
161
+ end
162
+
163
+ describe '#id' do
164
+
165
+ let(:search_result) do
166
+ Article.search('title:test')
167
+ end
168
+
169
+ it 'returns the type' do
170
+ expect(search_result.results.first.type).to eq('article')
171
+ end
172
+ end
173
+
174
+ describe '#each_with_hit' do
175
+
176
+ let(:search_result) do
177
+ Article.search('title:test')
178
+ end
179
+
180
+ it 'returns the record with the Elasticsearch hit' do
181
+ search_result.records.each_with_hit do |r, h|
182
+ expect(h._score).not_to be_nil
183
+ expect(h._source.title).not_to be_nil
184
+ end
185
+ end
186
+ end
187
+
188
+ describe 'search results order' do
189
+
190
+ let(:search_result) do
191
+ Article.search(query: { match: { title: 'code' }}, sort: { clicks: :desc })
192
+ end
193
+
194
+ it 'preserves the search results order when accessing a single record' do
195
+ expect(search_result.records[0].clicks).to be(3)
196
+ expect(search_result.records[1].clicks).to be(2)
197
+ expect(search_result.records.first).to eq(search_result.records[0])
198
+ end
199
+
200
+ it 'preserves the search results order for the list of records' do
201
+ search_result.records.each_with_hit do |r, h|
202
+ expect(r.id.to_s).to eq(h._id)
203
+ end
204
+
205
+ search_result.records.map_with_hit do |r, h|
206
+ expect(r.id.to_s).to eq(h._id)
207
+ end
208
+ end
209
+ end
210
+
211
+ describe 'a paged collection' do
212
+
213
+ let(:search_result) do
214
+ Article.search(query: { match: { title: { query: 'test' } } },
215
+ size: 2,
216
+ from: 1)
217
+ end
218
+
219
+ it 'applies the paged options to the search' do
220
+ expect(search_result.results.size).to eq(1)
221
+ expect(search_result.results.first.title).to eq('Testing Coding')
222
+ expect(search_result.records.size).to eq(1)
223
+ expect(search_result.records.first.title).to eq('Testing Coding')
224
+ end
225
+ end
226
+
227
+ describe '#destroy' do
228
+
229
+ before do
230
+ Article.create!(title: 'destroy', body: '', clicks: 1)
231
+ Article.__elasticsearch__.refresh_index!
232
+ Article.where(title: 'destroy').first.destroy
233
+
234
+ Article.__elasticsearch__.refresh_index!
235
+ end
236
+
237
+ let(:search_result) do
238
+ Article.search('title:test')
239
+ end
240
+
241
+ it 'removes the document from the index' do
242
+ expect(Article.count).to eq(3)
243
+ expect(search_result.results.size).to eq(2)
244
+ expect(search_result.records.size).to eq(2)
245
+ end
246
+ end
247
+
248
+ describe 'full document updates' do
249
+
250
+ before do
251
+ article = Article.create!(title: 'update', body: '', clicks: 1)
252
+ Article.__elasticsearch__.refresh_index!
253
+ article.title = 'Writing'
254
+ article.save
255
+
256
+ Article.__elasticsearch__.refresh_index!
257
+ end
258
+
259
+ let(:search_result) do
260
+ Article.search('title:write')
261
+ end
262
+
263
+ it 'applies the update' do
264
+ expect(search_result.results.size).to eq(1)
265
+ expect(search_result.records.size).to eq(1)
266
+ end
267
+ end
268
+
269
+ describe 'attribute updates' do
270
+
271
+ before do
272
+ article = Article.create!(title: 'update', body: '', clicks: 1)
273
+ Article.__elasticsearch__.refresh_index!
274
+ article.title = 'special'
275
+ article.save
276
+
277
+ Article.__elasticsearch__.refresh_index!
278
+ end
279
+
280
+ let(:search_result) do
281
+ Article.search('title:special')
282
+ end
283
+
284
+ it 'applies the update' do
285
+ expect(search_result.results.size).to eq(1)
286
+ expect(search_result.records.size).to eq(1)
287
+ end
288
+ end
289
+
290
+ describe '#save' do
291
+
292
+ before do
293
+ article = Article.create!(title: 'save', body: '', clicks: 1)
294
+
295
+ ActiveRecord::Base.transaction do
296
+ article.body = 'dummy'
297
+ article.save
298
+
299
+ article.title = 'special'
300
+ article.save
301
+ end
302
+
303
+ article.__elasticsearch__.update_document
304
+ Article.__elasticsearch__.refresh_index!
305
+ end
306
+
307
+ let(:search_result) do
308
+ Article.search('body:dummy')
309
+ end
310
+
311
+ it 'applies the save' do
312
+ expect(search_result.results.size).to eq(1)
313
+ expect(search_result.records.size).to eq(1)
314
+ end
315
+ end
316
+
317
+ describe 'a DSL search' do
318
+
319
+ let(:search_result) do
320
+ Article.search(query: { match: { title: { query: 'test' } } })
321
+ end
322
+
323
+ it 'returns the results' do
324
+ expect(search_result.results.size).to eq(2)
325
+ expect(search_result.records.size).to eq(2)
326
+ end
327
+ end
328
+
329
+ describe 'chaining SQL queries on response.records' do
330
+
331
+ let(:search_result) do
332
+ Article.search(query: { match: { title: { query: 'test' } } })
333
+ end
334
+
335
+ it 'executes the SQL request with the chained query criteria' do
336
+ expect(search_result.records.size).to eq(2)
337
+ expect(search_result.records.where(title: 'Test').size).to eq(1)
338
+ expect(search_result.records.where(title: 'Test').first.title).to eq('Test')
339
+ end
340
+ end
341
+
342
+ describe 'ordering of SQL queries' do
343
+
344
+ context 'when order is called on the ActiveRecord query' do
345
+
346
+ let(:search_result) do
347
+ Article.search query: { match: { title: { query: 'test' } } }
348
+ end
349
+
350
+ it 'allows the SQL query to be ordered independent of the Elasticsearch results order', unless: active_record_at_least_4? do
351
+ expect(search_result.records.order('title DESC').first.title).to eq('Testing Coding')
352
+ expect(search_result.records.order('title DESC')[0].title).to eq('Testing Coding')
353
+ end
354
+
355
+ it 'allows the SQL query to be ordered independent of the Elasticsearch results order', if: active_record_at_least_4? do
356
+ expect(search_result.records.order(title: :desc).first.title).to eq('Testing Coding')
357
+ expect(search_result.records.order(title: :desc)[0].title).to eq('Testing Coding')
358
+ end
359
+ end
360
+
361
+ context 'when more methods are chained on the ActiveRecord query' do
362
+
363
+ let(:search_result) do
364
+ Article.search query: {match: {title: {query: 'test'}}}
365
+ end
366
+
367
+ it 'allows the SQL query to be ordered independent of the Elasticsearch results order', if: active_record_at_least_4? do
368
+ expect(search_result.records.distinct.order(title: :desc).first.title).to eq('Testing Coding')
369
+ expect(search_result.records.distinct.order(title: :desc)[0].title).to eq('Testing Coding')
370
+ end
371
+ end
372
+ end
373
+
374
+ describe 'access to the response via methods' do
375
+
376
+ let(:search_result) do
377
+ Article.search(query: { match: { title: { query: 'test' } } },
378
+ aggregations: {
379
+ dates: { date_histogram: { field: 'created_at', interval: 'hour' } },
380
+ clicks: { global: {}, aggregations: { min: { min: { field: 'clicks' } } } }
381
+ },
382
+ suggest: { text: 'tezt', title: { term: { field: 'title', suggest_mode: 'always' } } })
383
+ end
384
+
385
+ it 'allows document keys to be access via methods' do
386
+ expect(search_result.aggregations.dates.buckets.first.doc_count).to eq(2)
387
+ expect(search_result.aggregations.clicks.doc_count).to eq(6)
388
+ expect(search_result.aggregations.clicks.min.value).to eq(1.0)
389
+ expect(search_result.aggregations.clicks.max).to be_nil
390
+ expect(search_result.suggestions.title.first.options.size).to eq(1)
391
+ expect(search_result.suggestions.terms).to eq(['test'])
392
+ end
393
+ end
394
+ end
395
+ end
@@ -0,0 +1,35 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ require 'spec_helper'
19
+
20
+ describe 'Elasticsearch::Model::Adapter::ActiveRecord Dynamic Index naming' do
21
+
22
+ before do
23
+ ArticleWithDynamicIndexName.counter = 0
24
+ end
25
+
26
+ it 'exavlues the index_name value' do
27
+ expect(ArticleWithDynamicIndexName.index_name).to eq('articles-1')
28
+ end
29
+
30
+ it 'revaluates the index name with each call' do
31
+ expect(ArticleWithDynamicIndexName.index_name).to eq('articles-1')
32
+ expect(ArticleWithDynamicIndexName.index_name).to eq('articles-2')
33
+ expect(ArticleWithDynamicIndexName.index_name).to eq('articles-3')
34
+ end
35
+ end
@@ -0,0 +1,193 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ require 'spec_helper'
19
+
20
+ describe 'Elasticsearch::Model::Adapter::ActiveRecord Importing' do
21
+ before(:all) do
22
+ ActiveRecord::Schema.define(:version => 1) do
23
+ create_table :import_articles do |t|
24
+ t.string :title
25
+ t.integer :views
26
+ t.string :numeric # For the sake of invalid data sent to Elasticsearch
27
+ t.datetime :created_at, :default => 'NOW()'
28
+ end
29
+ end
30
+
31
+ ImportArticle.delete_all
32
+ ImportArticle.__elasticsearch__.client.cluster.health(wait_for_status: 'yellow')
33
+ end
34
+
35
+ before do
36
+ ImportArticle.__elasticsearch__.create_index!
37
+ end
38
+
39
+ after do
40
+ clear_indices(ImportArticle)
41
+ clear_tables(ImportArticle)
42
+ end
43
+
44
+ describe '#import' do
45
+ context 'when no search criteria is specified' do
46
+ before do
47
+ 10.times { |i| ImportArticle.create! title: 'Test', views: i.to_s }
48
+ ImportArticle.import
49
+ ImportArticle.__elasticsearch__.refresh_index!
50
+ end
51
+
52
+ it 'imports all documents' do
53
+ expect(ImportArticle.search('*').results.total).to eq(10)
54
+ end
55
+ end
56
+
57
+ context 'when batch size is specified' do
58
+ before do
59
+ 10.times { |i| ImportArticle.create! title: 'Test', views: "#{i}" }
60
+ end
61
+
62
+ let!(:batch_count) do
63
+ batches = 0
64
+ errors = ImportArticle.import(batch_size: 5) do |response|
65
+ batches += 1
66
+ end
67
+ ImportArticle.__elasticsearch__.refresh_index!
68
+ batches
69
+ end
70
+
71
+ it 'imports using the batch size' do
72
+ expect(batch_count).to eq(2)
73
+ end
74
+
75
+ it 'imports all the documents' do
76
+ expect(ImportArticle.search('*').results.total).to eq(10)
77
+ end
78
+ end
79
+
80
+ context 'when a scope is specified' do
81
+ before do
82
+ 10.times { |i| ImportArticle.create! title: 'Test', views: "#{i}" }
83
+ ImportArticle.import(scope: 'popular', force: true)
84
+ ImportArticle.__elasticsearch__.refresh_index!
85
+ end
86
+
87
+ it 'applies the scope' do
88
+ expect(ImportArticle.search('*').results.total).to eq(5)
89
+ end
90
+ end
91
+
92
+ context 'when a query is specified' do
93
+ before do
94
+ 10.times { |i| ImportArticle.create! title: 'Test', views: "#{i}" }
95
+ ImportArticle.import(query: -> { where('views >= 3') })
96
+ ImportArticle.__elasticsearch__.refresh_index!
97
+ end
98
+
99
+ it 'applies the query' do
100
+ expect(ImportArticle.search('*').results.total).to eq(7)
101
+ end
102
+ end
103
+
104
+ context 'when there are invalid documents' do
105
+ let!(:result) do
106
+ 10.times { |i| ImportArticle.create! title: 'Test', views: "#{i}" }
107
+ new_article
108
+ batches = 0
109
+ errors = ImportArticle.__elasticsearch__.import(batch_size: 5) do |response|
110
+ batches += 1
111
+ end
112
+ ImportArticle.__elasticsearch__.refresh_index!
113
+ { batch_size: batches, errors: errors}
114
+ end
115
+
116
+ let(:new_article) do
117
+ ImportArticle.create!(title: "Test INVALID", numeric: "INVALID")
118
+ end
119
+
120
+ it 'does not import them' do
121
+ expect(ImportArticle.search('*').results.total).to eq(10)
122
+ expect(result[:batch_size]).to eq(3)
123
+ expect(result[:errors]).to eq(1)
124
+ end
125
+ end
126
+
127
+ context 'when a transform proc is specified' do
128
+ before do
129
+ 10.times { |i| ImportArticle.create! title: 'Test', views: "#{i}" }
130
+ ImportArticle.import( transform: ->(a) {{ index: { data: { name: a.title, foo: 'BAR' } }}} )
131
+ ImportArticle.__elasticsearch__.refresh_index!
132
+ end
133
+
134
+ it 'transforms the documents' do
135
+ expect(ImportArticle.search('*').results.first._source.keys).to include('name')
136
+ expect(ImportArticle.search('*').results.first._source.keys).to include('foo')
137
+ end
138
+
139
+ it 'imports all documents' do
140
+ expect(ImportArticle.search('test').results.total).to eq(10)
141
+ expect(ImportArticle.search('bar').results.total).to eq(10)
142
+ end
143
+ end
144
+
145
+ context 'when the model has a default scope' do
146
+ around(:all) do |example|
147
+ 10.times { |i| ImportArticle.create! title: 'Test', views: "#{i}" }
148
+ ImportArticle.instance_eval { default_scope { where('views > 3') } }
149
+ example.run
150
+ ImportArticle.default_scopes.pop
151
+ end
152
+
153
+ before do
154
+ ImportArticle.__elasticsearch__.import
155
+ ImportArticle.__elasticsearch__.refresh_index!
156
+ end
157
+
158
+ it 'uses the default scope' do
159
+ expect(ImportArticle.search('*').results.total).to eq(6)
160
+ end
161
+ end
162
+
163
+ context 'when there is a default scope and a query specified' do
164
+ around(:all) do |example|
165
+ 10.times { |i| ImportArticle.create! title: 'Test', views: "#{i}" }
166
+ ImportArticle.instance_eval { default_scope { where('views > 3') } }
167
+ example.run
168
+ ImportArticle.default_scopes.pop
169
+ end
170
+
171
+ before do
172
+ ImportArticle.import(query: -> { where('views <= 4') })
173
+ ImportArticle.__elasticsearch__.refresh_index!
174
+ end
175
+
176
+ it 'combines the query and the default scope' do
177
+ expect(ImportArticle.search('*').results.total).to eq(1)
178
+ end
179
+ end
180
+
181
+ context 'when the batch is empty' do
182
+ before do
183
+ ImportArticle.delete_all
184
+ ImportArticle.import
185
+ ImportArticle.__elasticsearch__.refresh_index!
186
+ end
187
+
188
+ it 'does not make any requests to create documents' do
189
+ expect(ImportArticle.search('*').results.total).to eq(0)
190
+ end
191
+ end
192
+ end
193
+ end