elasticsearch-model 5.1.0 → 6.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (127) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -3
  3. data/Gemfile +5 -0
  4. data/README.md +18 -11
  5. data/Rakefile +27 -36
  6. data/elasticsearch-model.gemspec +6 -6
  7. data/examples/activerecord_custom_analyzer.rb +135 -0
  8. data/examples/activerecord_mapping_completion.rb +3 -18
  9. data/examples/datamapper_article.rb +11 -1
  10. data/gemfiles/3.0.gemfile +6 -1
  11. data/gemfiles/4.0.gemfile +8 -1
  12. data/gemfiles/5.0.gemfile +7 -1
  13. data/gemfiles/6.0.gemfile +18 -0
  14. data/lib/elasticsearch/model/adapters/active_record.rb +8 -24
  15. data/lib/elasticsearch/model/adapters/mongoid.rb +10 -3
  16. data/lib/elasticsearch/model/importing.rb +1 -1
  17. data/lib/elasticsearch/model/indexing.rb +6 -4
  18. data/lib/elasticsearch/model/naming.rb +9 -2
  19. data/lib/elasticsearch/model/response/aggregations.rb +1 -1
  20. data/lib/elasticsearch/model/response/base.rb +3 -2
  21. data/lib/elasticsearch/model/response/pagination/kaminari.rb +109 -0
  22. data/lib/elasticsearch/model/response/pagination/will_paginate.rb +95 -0
  23. data/lib/elasticsearch/model/response/pagination.rb +2 -192
  24. data/lib/elasticsearch/model/response/result.rb +1 -1
  25. data/lib/elasticsearch/model/response/suggestions.rb +1 -1
  26. data/lib/elasticsearch/model/response.rb +11 -10
  27. data/lib/elasticsearch/model/version.rb +1 -1
  28. data/lib/elasticsearch/model.rb +15 -8
  29. data/spec/elasticsearch/model/adapter_spec.rb +119 -0
  30. data/spec/elasticsearch/model/adapters/active_record/associations_spec.rb +334 -0
  31. data/spec/elasticsearch/model/adapters/active_record/basic_spec.rb +340 -0
  32. data/spec/elasticsearch/model/adapters/active_record/dynamic_index_name_spec.rb +18 -0
  33. data/spec/elasticsearch/model/adapters/active_record/import_spec.rb +187 -0
  34. data/spec/elasticsearch/model/adapters/active_record/multi_model_spec.rb +110 -0
  35. data/spec/elasticsearch/model/adapters/active_record/namespaced_model_spec.rb +38 -0
  36. data/spec/elasticsearch/model/adapters/active_record/pagination_spec.rb +315 -0
  37. data/spec/elasticsearch/model/adapters/active_record/parent_child_spec.rb +75 -0
  38. data/spec/elasticsearch/model/adapters/active_record/serialization_spec.rb +61 -0
  39. data/spec/elasticsearch/model/adapters/active_record_spec.rb +207 -0
  40. data/spec/elasticsearch/model/adapters/default_spec.rb +41 -0
  41. data/spec/elasticsearch/model/adapters/mongoid/basic_spec.rb +267 -0
  42. data/spec/elasticsearch/model/adapters/mongoid/multi_model_spec.rb +66 -0
  43. data/spec/elasticsearch/model/adapters/mongoid_spec.rb +235 -0
  44. data/spec/elasticsearch/model/adapters/multiple_spec.rb +125 -0
  45. data/spec/elasticsearch/model/callbacks_spec.rb +33 -0
  46. data/spec/elasticsearch/model/client_spec.rb +66 -0
  47. data/spec/elasticsearch/model/hash_wrapper_spec.rb +12 -0
  48. data/spec/elasticsearch/model/importing_spec.rb +214 -0
  49. data/spec/elasticsearch/model/indexing_spec.rb +918 -0
  50. data/spec/elasticsearch/model/module_spec.rb +101 -0
  51. data/spec/elasticsearch/model/multimodel_spec.rb +55 -0
  52. data/spec/elasticsearch/model/naming_inheritance_spec.rb +184 -0
  53. data/spec/elasticsearch/model/naming_spec.rb +186 -0
  54. data/spec/elasticsearch/model/proxy_spec.rb +107 -0
  55. data/spec/elasticsearch/model/response/aggregations_spec.rb +66 -0
  56. data/spec/elasticsearch/model/response/base_spec.rb +90 -0
  57. data/spec/elasticsearch/model/response/pagination/kaminari_spec.rb +410 -0
  58. data/spec/elasticsearch/model/response/pagination/will_paginate_spec.rb +262 -0
  59. data/spec/elasticsearch/model/response/records_spec.rb +118 -0
  60. data/spec/elasticsearch/model/response/response_spec.rb +131 -0
  61. data/spec/elasticsearch/model/response/result_spec.rb +122 -0
  62. data/spec/elasticsearch/model/response/results_spec.rb +56 -0
  63. data/spec/elasticsearch/model/searching_search_request_spec.rb +112 -0
  64. data/spec/elasticsearch/model/searching_spec.rb +49 -0
  65. data/spec/elasticsearch/model/serializing_spec.rb +22 -0
  66. data/spec/spec_helper.rb +161 -0
  67. data/spec/support/app/answer.rb +33 -0
  68. data/spec/support/app/article.rb +22 -0
  69. data/spec/support/app/article_for_pagination.rb +12 -0
  70. data/spec/support/app/article_with_custom_serialization.rb +13 -0
  71. data/spec/support/app/article_with_dynamic_index_name.rb +15 -0
  72. data/spec/support/app/author.rb +9 -0
  73. data/spec/support/app/authorship.rb +4 -0
  74. data/spec/support/app/category.rb +3 -0
  75. data/spec/support/app/comment.rb +3 -0
  76. data/spec/support/app/episode.rb +11 -0
  77. data/spec/support/app/image.rb +19 -0
  78. data/spec/support/app/import_article.rb +12 -0
  79. data/spec/support/app/mongoid_article.rb +21 -0
  80. data/spec/support/app/namespaced_book.rb +10 -0
  81. data/spec/support/app/parent_and_child_searchable.rb +24 -0
  82. data/spec/support/app/post.rb +14 -0
  83. data/spec/support/app/question.rb +27 -0
  84. data/spec/support/app/searchable.rb +48 -0
  85. data/spec/support/app/series.rb +11 -0
  86. data/spec/support/app.rb +21 -0
  87. data/spec/support/model.json +1 -0
  88. data/{test → spec}/support/model.yml +0 -0
  89. metadata +134 -89
  90. data/test/integration/active_record_associations_parent_child_test.rb +0 -147
  91. data/test/integration/active_record_associations_test.rb +0 -339
  92. data/test/integration/active_record_basic_test.rb +0 -251
  93. data/test/integration/active_record_custom_serialization_test.rb +0 -67
  94. data/test/integration/active_record_import_test.rb +0 -115
  95. data/test/integration/active_record_namespaced_model_test.rb +0 -54
  96. data/test/integration/active_record_pagination_test.rb +0 -149
  97. data/test/integration/dynamic_index_name_test.rb +0 -52
  98. data/test/integration/mongoid_basic_test.rb +0 -176
  99. data/test/integration/multiple_models_test.rb +0 -176
  100. data/test/support/model.json +0 -1
  101. data/test/test_helper.rb +0 -92
  102. data/test/unit/adapter_active_record_test.rb +0 -157
  103. data/test/unit/adapter_default_test.rb +0 -41
  104. data/test/unit/adapter_mongoid_test.rb +0 -104
  105. data/test/unit/adapter_multiple_test.rb +0 -106
  106. data/test/unit/adapter_test.rb +0 -69
  107. data/test/unit/callbacks_test.rb +0 -31
  108. data/test/unit/client_test.rb +0 -27
  109. data/test/unit/hash_wrapper_test.rb +0 -13
  110. data/test/unit/importing_test.rb +0 -203
  111. data/test/unit/indexing_test.rb +0 -687
  112. data/test/unit/module_test.rb +0 -68
  113. data/test/unit/multimodel_test.rb +0 -38
  114. data/test/unit/naming_inheritance_test.rb +0 -94
  115. data/test/unit/naming_test.rb +0 -103
  116. data/test/unit/proxy_test.rb +0 -98
  117. data/test/unit/response_aggregations_test.rb +0 -46
  118. data/test/unit/response_base_test.rb +0 -40
  119. data/test/unit/response_pagination_kaminari_test.rb +0 -433
  120. data/test/unit/response_pagination_will_paginate_test.rb +0 -398
  121. data/test/unit/response_records_test.rb +0 -91
  122. data/test/unit/response_result_test.rb +0 -90
  123. data/test/unit/response_results_test.rb +0 -31
  124. data/test/unit/response_test.rb +0 -104
  125. data/test/unit/searching_search_request_test.rb +0 -78
  126. data/test/unit/searching_test.rb +0 -41
  127. data/test/unit/serializing_test.rb +0 -17
@@ -0,0 +1,334 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Elasticsearch::Model::Adapter::ActiveRecord Associations' do
4
+
5
+ before(:all) do
6
+ ActiveRecord::Schema.define(version: 1) do
7
+ create_table :categories do |t|
8
+ t.string :title
9
+ t.timestamps null: false
10
+ end
11
+
12
+ create_table :categories_posts do |t|
13
+ t.references :post, :category
14
+ end
15
+
16
+ create_table :authors do |t|
17
+ t.string :first_name, :last_name
18
+ t.timestamps null: false
19
+ end
20
+
21
+ create_table :authorships do |t|
22
+ t.string :first_name, :last_name
23
+ t.references :post
24
+ t.references :author
25
+ t.timestamps null: false
26
+ end
27
+
28
+ create_table :comments do |t|
29
+ t.string :text
30
+ t.string :author
31
+ t.references :post
32
+ t.timestamps null: false
33
+ end
34
+
35
+ add_index(:comments, :post_id) unless index_exists?(:comments, :post_id)
36
+
37
+ create_table :posts do |t|
38
+ t.string :title
39
+ t.text :text
40
+ t.boolean :published
41
+ t.timestamps null: false
42
+ end
43
+ end
44
+
45
+ Comment.__send__ :include, Elasticsearch::Model
46
+ Comment.__send__ :include, Elasticsearch::Model::Callbacks
47
+ end
48
+
49
+ before do
50
+ clear_tables(:categories, :categories_posts, :authors, :authorships, :comments, :posts)
51
+ clear_indices(Post)
52
+ Post.__elasticsearch__.create_index!(force: true)
53
+ Comment.__elasticsearch__.create_index!(force: true)
54
+ end
55
+
56
+ after do
57
+ clear_tables(Post, Category)
58
+ clear_indices(Post)
59
+ end
60
+
61
+ context 'when a document is created' do
62
+
63
+ before do
64
+ Post.create!(title: 'Test')
65
+ Post.create!(title: 'Testing Coding')
66
+ Post.create!(title: 'Coding')
67
+ Post.__elasticsearch__.refresh_index!
68
+ end
69
+
70
+ let(:search_result) do
71
+ Post.search('title:test')
72
+ end
73
+
74
+ it 'indexes the document' do
75
+ expect(search_result.results.size).to eq(2)
76
+ expect(search_result.results.first.title).to eq('Test')
77
+ expect(search_result.records.size).to eq(2)
78
+ expect(search_result.records.first.title).to eq('Test')
79
+ end
80
+ end
81
+
82
+ describe 'has_many_and_belongs_to association' do
83
+
84
+ context 'when an association is updated' do
85
+
86
+ before do
87
+ post.categories = [category_a, category_b]
88
+ Post.__elasticsearch__.refresh_index!
89
+ end
90
+
91
+ let(:category_a) do
92
+ Category.where(title: "One").first_or_create!
93
+ end
94
+
95
+ let(:category_b) do
96
+ Category.where(title: "Two").first_or_create!
97
+ end
98
+
99
+ let(:post) do
100
+ Post.create! title: "First Post", text: "This is the first post..."
101
+ end
102
+
103
+ let(:search_result) do
104
+ Post.search(query: {
105
+ bool: {
106
+ must: {
107
+ multi_match: {
108
+ fields: ['title'],
109
+ query: 'first'
110
+ }
111
+ },
112
+ filter: {
113
+ terms: {
114
+ categories: ['One']
115
+ }
116
+ }
117
+ }
118
+ } )
119
+ end
120
+
121
+ it 'applies the update with' do
122
+ expect(search_result.results.size).to eq(1)
123
+ expect(search_result.results.first.title).to eq('First Post')
124
+ expect(search_result.records.size).to eq(1)
125
+ expect(search_result.records.first.title).to eq('First Post')
126
+ end
127
+ end
128
+
129
+ context 'when an association is deleted' do
130
+
131
+ before do
132
+ post.categories = [category_a, category_b]
133
+ post.categories = [category_b]
134
+ Post.__elasticsearch__.refresh_index!
135
+ end
136
+
137
+ let(:category_a) do
138
+ Category.where(title: "One").first_or_create!
139
+ end
140
+
141
+ let(:category_b) do
142
+ Category.where(title: "Two").first_or_create!
143
+ end
144
+
145
+ let(:post) do
146
+ Post.create! title: "First Post", text: "This is the first post..."
147
+ end
148
+
149
+ let(:search_result) do
150
+ Post.search(query: {
151
+ bool: {
152
+ must: {
153
+ multi_match: {
154
+ fields: ['title'],
155
+ query: 'first'
156
+ }
157
+ },
158
+ filter: {
159
+ terms: {
160
+ categories: ['One']
161
+ }
162
+ }
163
+ }
164
+ } )
165
+ end
166
+
167
+ it 'applies the update with a reindex' do
168
+ expect(search_result.results.size).to eq(0)
169
+ expect(search_result.records.size).to eq(0)
170
+ end
171
+ end
172
+ end
173
+
174
+ describe 'has_many through association' do
175
+
176
+ context 'when the association is updated' do
177
+
178
+ before do
179
+ author_a = Author.where(first_name: "John", last_name: "Smith").first_or_create!
180
+ author_b = Author.where(first_name: "Mary", last_name: "Smith").first_or_create!
181
+ author_c = Author.where(first_name: "Kobe", last_name: "Griss").first_or_create!
182
+
183
+ # Create posts
184
+ post_1 = Post.create!(title: "First Post", text: "This is the first post...")
185
+ post_2 = Post.create!(title: "Second Post", text: "This is the second post...")
186
+ post_3 = Post.create!(title: "Third Post", text: "This is the third post...")
187
+
188
+ # Assign authors
189
+ post_1.authors = [author_a, author_b]
190
+ post_2.authors = [author_a]
191
+ post_3.authors = [author_c]
192
+
193
+ Post.__elasticsearch__.refresh_index!
194
+ end
195
+
196
+ context 'if active record is at least 4' do
197
+
198
+ let(:search_result) do
199
+ Post.search('authors.full_name:john')
200
+ end
201
+
202
+ it 'applies the update', if: active_record_at_least_4? do
203
+ expect(search_result.results.size).to eq(2)
204
+ expect(search_result.records.size).to eq(2)
205
+ end
206
+ end
207
+
208
+ context 'if active record is less than 4' do
209
+
210
+ let(:search_result) do
211
+ Post.search('authors.author.full_name:john')
212
+ end
213
+
214
+ it 'applies the update', if: !active_record_at_least_4? do
215
+ expect(search_result.results.size).to eq(2)
216
+ expect(search_result.records.size).to eq(2)
217
+ end
218
+ end
219
+ end
220
+
221
+ context 'when an association is added', if: active_record_at_least_4? do
222
+
223
+ before do
224
+ author_a = Author.where(first_name: "John", last_name: "Smith").first_or_create!
225
+ author_b = Author.where(first_name: "Mary", last_name: "Smith").first_or_create!
226
+
227
+ # Create posts
228
+ post_1 = Post.create!(title: "First Post", text: "This is the first post...")
229
+
230
+ # Assign authors
231
+ post_1.authors = [author_a]
232
+ post_1.authors << author_b
233
+ Post.__elasticsearch__.refresh_index!
234
+ end
235
+
236
+ let(:search_result) do
237
+ Post.search('authors.full_name:john')
238
+ end
239
+
240
+ it 'adds the association' do
241
+ expect(search_result.results.size).to eq(1)
242
+ expect(search_result.records.size).to eq(1)
243
+ end
244
+ end
245
+ end
246
+
247
+ describe 'has_many association' do
248
+
249
+ context 'when an association is added', if: active_record_at_least_4? do
250
+
251
+ before do
252
+ # Create posts
253
+ post_1 = Post.create!(title: "First Post", text: "This is the first post...")
254
+ post_2 = Post.create!(title: "Second Post", text: "This is the second post...")
255
+
256
+ # Add comments
257
+ post_1.comments.create!(author: 'John', text: 'Excellent')
258
+ post_1.comments.create!(author: 'Abby', text: 'Good')
259
+
260
+ post_2.comments.create!(author: 'John', text: 'Terrible')
261
+
262
+ post_1.comments.create!(author: 'John', text: 'Or rather just good...')
263
+ Post.__elasticsearch__.refresh_index!
264
+ end
265
+
266
+ let(:search_result) do
267
+ Post.search(query: {
268
+ nested: {
269
+ path: 'comments',
270
+ query: {
271
+ bool: {
272
+ must: [
273
+ { match: { 'comments.author' => 'john' } },
274
+ { match: { 'comments.text' => 'good' } }
275
+ ]
276
+ }
277
+ }
278
+ }
279
+ })
280
+ end
281
+
282
+ it 'adds the association' do
283
+ expect(search_result.results.size).to eq(1)
284
+ end
285
+ end
286
+ end
287
+
288
+ describe '#touch' do
289
+
290
+ context 'when a touch callback is defined on the model' do
291
+
292
+ before do
293
+ # Create categories
294
+ category_a = Category.where(title: "One").first_or_create!
295
+
296
+ # Create post
297
+ post = Post.create!(title: "First Post", text: "This is the first post...")
298
+
299
+ # Assign category
300
+ post.categories << category_a
301
+ category_a.update_attribute(:title, "Updated")
302
+ category_a.posts.each { |p| p.touch }
303
+
304
+ Post.__elasticsearch__.refresh_index!
305
+ end
306
+
307
+ it 'executes the callback after #touch' do
308
+ expect(Post.search('categories:One').size).to eq(0)
309
+ expect(Post.search('categories:Updated').size).to eq(1)
310
+ end
311
+ end
312
+ end
313
+
314
+ describe '#includes' do
315
+
316
+ before do
317
+ post_1 = Post.create(title: 'One')
318
+ post_2 = Post.create(title: 'Two')
319
+ post_1.comments.create(text: 'First comment')
320
+ post_2.comments.create(text: 'Second comment')
321
+
322
+ Comment.__elasticsearch__.refresh_index!
323
+ end
324
+
325
+ let(:search_result) do
326
+ Comment.search('first').records(includes: :post)
327
+ end
328
+
329
+ it 'eager loads associations' do
330
+ expect(search_result.first.association(:post)).to be_loaded
331
+ expect(search_result.first.post.title).to eq('One')
332
+ end
333
+ end
334
+ end
@@ -0,0 +1,340 @@
1
+ require 'spec_helper'
2
+
3
+ describe Elasticsearch::Model::Adapter::ActiveRecord do
4
+
5
+ before(:all) do
6
+ ActiveRecord::Schema.define(:version => 1) do
7
+ create_table :articles do |t|
8
+ t.string :title
9
+ t.string :body
10
+ t.integer :clicks, :default => 0
11
+ t.datetime :created_at, :default => 'NOW()'
12
+ end
13
+ end
14
+
15
+ Article.delete_all
16
+ Article.__elasticsearch__.create_index!(force: true)
17
+
18
+ Article.create!(title: 'Test', body: '', clicks: 1)
19
+ Article.create!(title: 'Testing Coding', body: '', clicks: 2)
20
+ Article.create!(title: 'Coding', body: '', clicks: 3)
21
+
22
+ Article.__elasticsearch__.refresh_index!
23
+ end
24
+
25
+ describe 'indexing a document' do
26
+
27
+ let(:search_result) do
28
+ Article.search('title:test')
29
+ end
30
+
31
+ it 'allows searching for documents' do
32
+ expect(search_result.results.size).to be(2)
33
+ expect(search_result.records.size).to be(2)
34
+ end
35
+ end
36
+
37
+ describe '#results' do
38
+
39
+ let(:search_result) do
40
+ Article.search('title:test')
41
+ end
42
+
43
+ it 'returns an instance of Response::Result' do
44
+ expect(search_result.results.first).to be_a(Elasticsearch::Model::Response::Result)
45
+ end
46
+
47
+ it 'prooperly loads the document' do
48
+ expect(search_result.results.first.title).to eq('Test')
49
+ end
50
+
51
+ context 'when the result contains other data' do
52
+
53
+ let(:search_result) do
54
+ Article.search(query: { match: { title: 'test' } }, highlight: { fields: { title: {} } })
55
+ end
56
+
57
+ it 'allows access to the Elasticsearch result' do
58
+ expect(search_result.results.first.title).to eq('Test')
59
+ expect(search_result.results.first.title?).to be(true)
60
+ expect(search_result.results.first.boo?).to be(false)
61
+ expect(search_result.results.first.highlight?).to be(true)
62
+ expect(search_result.results.first.highlight.title?).to be(true)
63
+ expect(search_result.results.first.highlight.boo?).to be(false)
64
+ end
65
+ end
66
+ end
67
+
68
+ describe '#records' do
69
+
70
+ let(:search_result) do
71
+ Article.search('title:test')
72
+ end
73
+
74
+ it 'returns an instance of the model' do
75
+ expect(search_result.records.first).to be_a(Article)
76
+ end
77
+
78
+ it 'prooperly loads the document' do
79
+ expect(search_result.records.first.title).to eq('Test')
80
+ end
81
+ end
82
+
83
+ describe 'Enumerable' do
84
+
85
+ let(:search_result) do
86
+ Article.search('title:test')
87
+ end
88
+
89
+ it 'allows iteration over results' do
90
+ expect(search_result.results.map(&:_id)).to eq(['1', '2'])
91
+ end
92
+
93
+ it 'allows iteration over records' do
94
+ expect(search_result.records.map(&:id)).to eq([1, 2])
95
+ end
96
+ end
97
+
98
+ describe '#id' do
99
+
100
+ let(:search_result) do
101
+ Article.search('title:test')
102
+ end
103
+
104
+ it 'returns the id' do
105
+ expect(search_result.results.first.id).to eq('1')
106
+ end
107
+ end
108
+
109
+ describe '#id' do
110
+
111
+ let(:search_result) do
112
+ Article.search('title:test')
113
+ end
114
+
115
+ it 'returns the type' do
116
+ expect(search_result.results.first.type).to eq('article')
117
+ end
118
+ end
119
+
120
+ describe '#each_with_hit' do
121
+
122
+ let(:search_result) do
123
+ Article.search('title:test')
124
+ end
125
+
126
+ it 'returns the record with the Elasticsearch hit' do
127
+ search_result.records.each_with_hit do |r, h|
128
+ expect(h._score).not_to be_nil
129
+ expect(h._source.title).not_to be_nil
130
+ end
131
+ end
132
+ end
133
+
134
+ describe 'search results order' do
135
+
136
+ let(:search_result) do
137
+ Article.search(query: { match: { title: 'code' }}, sort: { clicks: :desc })
138
+ end
139
+
140
+ it 'preserves the search results order when accessing a single record' do
141
+ expect(search_result.records[0].clicks).to be(3)
142
+ expect(search_result.records[1].clicks).to be(2)
143
+ expect(search_result.records.first).to eq(search_result.records[0])
144
+ end
145
+
146
+ it 'preserves the search results order for the list of records' do
147
+ search_result.records.each_with_hit do |r, h|
148
+ expect(r.id.to_s).to eq(h._id)
149
+ end
150
+
151
+ search_result.records.map_with_hit do |r, h|
152
+ expect(r.id.to_s).to eq(h._id)
153
+ end
154
+ end
155
+ end
156
+
157
+ describe 'a paged collection' do
158
+
159
+ let(:search_result) do
160
+ Article.search(query: { match: { title: { query: 'test' } } },
161
+ size: 2,
162
+ from: 1)
163
+ end
164
+
165
+ it 'applies the paged options to the search' do
166
+ expect(search_result.results.size).to eq(1)
167
+ expect(search_result.results.first.title).to eq('Testing Coding')
168
+ expect(search_result.records.size).to eq(1)
169
+ expect(search_result.records.first.title).to eq('Testing Coding')
170
+ end
171
+ end
172
+
173
+ describe '#destroy' do
174
+
175
+ before do
176
+ Article.create!(title: 'destroy', body: '', clicks: 1)
177
+ Article.__elasticsearch__.refresh_index!
178
+ Article.where(title: 'destroy').first.destroy
179
+
180
+ Article.__elasticsearch__.refresh_index!
181
+ end
182
+
183
+ let(:search_result) do
184
+ Article.search('title:test')
185
+ end
186
+
187
+ it 'removes the document from the index' do
188
+ expect(Article.count).to eq(3)
189
+ expect(search_result.results.size).to eq(2)
190
+ expect(search_result.records.size).to eq(2)
191
+ end
192
+ end
193
+
194
+ describe 'full document updates' do
195
+
196
+ before do
197
+ article = Article.create!(title: 'update', body: '', clicks: 1)
198
+ Article.__elasticsearch__.refresh_index!
199
+ article.title = 'Writing'
200
+ article.save
201
+
202
+ Article.__elasticsearch__.refresh_index!
203
+ end
204
+
205
+ let(:search_result) do
206
+ Article.search('title:write')
207
+ end
208
+
209
+ it 'applies the update' do
210
+ expect(search_result.results.size).to eq(1)
211
+ expect(search_result.records.size).to eq(1)
212
+ end
213
+ end
214
+
215
+ describe 'attribute updates' do
216
+
217
+ before do
218
+ article = Article.create!(title: 'update', body: '', clicks: 1)
219
+ Article.__elasticsearch__.refresh_index!
220
+ article.title = 'special'
221
+ article.save
222
+
223
+ Article.__elasticsearch__.refresh_index!
224
+ end
225
+
226
+ let(:search_result) do
227
+ Article.search('title:special')
228
+ end
229
+
230
+ it 'applies the update' do
231
+ expect(search_result.results.size).to eq(1)
232
+ expect(search_result.records.size).to eq(1)
233
+ end
234
+ end
235
+
236
+ describe '#save' do
237
+
238
+ before do
239
+ article = Article.create!(title: 'save', body: '', clicks: 1)
240
+
241
+ ActiveRecord::Base.transaction do
242
+ article.body = 'dummy'
243
+ article.save
244
+
245
+ article.title = 'special'
246
+ article.save
247
+ end
248
+
249
+ article.__elasticsearch__.update_document
250
+ Article.__elasticsearch__.refresh_index!
251
+ end
252
+
253
+ let(:search_result) do
254
+ Article.search('body:dummy')
255
+ end
256
+
257
+ it 'applies the save' do
258
+ expect(search_result.results.size).to eq(1)
259
+ expect(search_result.records.size).to eq(1)
260
+ end
261
+ end
262
+
263
+ describe 'a DSL search' do
264
+
265
+ let(:search_result) do
266
+ Article.search(query: { match: { title: { query: 'test' } } })
267
+ end
268
+
269
+ it 'returns the results' do
270
+ expect(search_result.results.size).to eq(2)
271
+ expect(search_result.records.size).to eq(2)
272
+ end
273
+ end
274
+
275
+ describe 'chaining SQL queries on response.records' do
276
+
277
+ let(:search_result) do
278
+ Article.search(query: { match: { title: { query: 'test' } } })
279
+ end
280
+
281
+ it 'executes the SQL request with the chained query criteria' do
282
+ expect(search_result.records.size).to eq(2)
283
+ expect(search_result.records.where(title: 'Test').size).to eq(1)
284
+ expect(search_result.records.where(title: 'Test').first.title).to eq('Test')
285
+ end
286
+ end
287
+
288
+ describe 'ordering of SQL queries' do
289
+
290
+ context 'when order is called on the ActiveRecord query' do
291
+
292
+ let(:search_result) do
293
+ Article.search query: { match: { title: { query: 'test' } } }
294
+ end
295
+
296
+ it 'allows the SQL query to be ordered independent of the Elasticsearch results order', unless: active_record_at_least_4? do
297
+ expect(search_result.records.order('title DESC').first.title).to eq('Testing Coding')
298
+ expect(search_result.records.order('title DESC')[0].title).to eq('Testing Coding')
299
+ end
300
+
301
+ it 'allows the SQL query to be ordered independent of the Elasticsearch results order', if: active_record_at_least_4? do
302
+ expect(search_result.records.order(title: :desc).first.title).to eq('Testing Coding')
303
+ expect(search_result.records.order(title: :desc)[0].title).to eq('Testing Coding')
304
+ end
305
+ end
306
+
307
+ context 'when more methods are chained on the ActiveRecord query' do
308
+
309
+ let(:search_result) do
310
+ Article.search query: {match: {title: {query: 'test'}}}
311
+ end
312
+
313
+ it 'allows the SQL query to be ordered independent of the Elasticsearch results order', if: active_record_at_least_4? do
314
+ expect(search_result.records.distinct.order(title: :desc).first.title).to eq('Testing Coding')
315
+ expect(search_result.records.distinct.order(title: :desc)[0].title).to eq('Testing Coding')
316
+ end
317
+ end
318
+ end
319
+
320
+ describe 'access to the response via methods' do
321
+
322
+ let(:search_result) do
323
+ Article.search(query: { match: { title: { query: 'test' } } },
324
+ aggregations: {
325
+ dates: { date_histogram: { field: 'created_at', interval: 'hour' } },
326
+ clicks: { global: {}, aggregations: { min: { min: { field: 'clicks' } } } }
327
+ },
328
+ suggest: { text: 'tezt', title: { term: { field: 'title', suggest_mode: 'always' } } })
329
+ end
330
+
331
+ it 'allows document keys to be access via methods' do
332
+ expect(search_result.aggregations.dates.buckets.first.doc_count).to eq(2)
333
+ expect(search_result.aggregations.clicks.doc_count).to eq(6)
334
+ expect(search_result.aggregations.clicks.min.value).to eq(1.0)
335
+ expect(search_result.aggregations.clicks.max).to be_nil
336
+ expect(search_result.suggestions.title.first.options.size).to eq(1)
337
+ expect(search_result.suggestions.terms).to eq(['test'])
338
+ end
339
+ end
340
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Elasticsearch::Model::Adapter::ActiveRecord Dynamic Index naming' do
4
+
5
+ before do
6
+ ArticleWithDynamicIndexName.counter = 0
7
+ end
8
+
9
+ it 'exavlues the index_name value' do
10
+ expect(ArticleWithDynamicIndexName.index_name).to eq('articles-1')
11
+ end
12
+
13
+ it 'revaluates the index name with each call' do
14
+ expect(ArticleWithDynamicIndexName.index_name).to eq('articles-1')
15
+ expect(ArticleWithDynamicIndexName.index_name).to eq('articles-2')
16
+ expect(ArticleWithDynamicIndexName.index_name).to eq('articles-3')
17
+ end
18
+ end