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,279 @@
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::Response::Response WillPaginate' do
21
+
22
+ before(:all) do
23
+ class ModelClass
24
+ def self.index_name; 'foo'; end
25
+ def self.document_type; 'bar'; end
26
+
27
+ def self.per_page
28
+ 33
29
+ end
30
+ end
31
+
32
+ # Subclass Response so we can include WillPaginate module without conflicts with Kaminari.
33
+ class WillPaginateResponse < Elasticsearch::Model::Response::Response
34
+ include Elasticsearch::Model::Response::Pagination::WillPaginate
35
+ end
36
+ end
37
+
38
+ after(:all) do
39
+ remove_classes(ModelClass, WillPaginateResponse)
40
+ end
41
+
42
+ let(:response_document) do
43
+ { 'took' => '5', 'timed_out' => false, '_shards' => {'one' => 'OK'},
44
+ 'hits' => { 'total' => 100, 'hits' => (1..100).to_a.map { |i| { _id: i } } } }
45
+ end
46
+
47
+ let(:search) do
48
+ Elasticsearch::Model::Searching::SearchRequest.new(model, '*')
49
+ end
50
+
51
+ let(:response) do
52
+ allow(model).to receive(:client).and_return(client)
53
+ WillPaginateResponse.new(model, search, response_document).tap do |resp|
54
+ allow(resp).to receive(:client).and_return(client)
55
+ end
56
+ end
57
+
58
+ let(:client) do
59
+ double('client')
60
+ end
61
+
62
+ shared_examples_for 'a search request that can be paginated' do
63
+
64
+ describe '#offset' do
65
+
66
+ context 'when per_page and page are set' do
67
+
68
+ before do
69
+ response.per_page(3).page(3)
70
+ end
71
+
72
+ it 'sets the correct offset' do
73
+ expect(response.offset).to eq(6)
74
+ end
75
+ end
76
+ end
77
+
78
+ describe '#length' do
79
+
80
+ context 'when per_page and page are set' do
81
+
82
+ before do
83
+ response.per_page(3).page(3)
84
+ end
85
+
86
+ it 'sets the correct offset' do
87
+ expect(response.length).to eq(3)
88
+ end
89
+ end
90
+ end
91
+
92
+ describe '#paginate' do
93
+
94
+ context 'when there are no settings' do
95
+
96
+ context 'when page is set to nil' do
97
+
98
+ before do
99
+ response.paginate(page: nil)
100
+ end
101
+
102
+ it 'uses the defaults' do
103
+ expect(response.search.definition[:size]).to eq(default_per_page)
104
+ expect(response.search.definition[:from]).to eq(0)
105
+ end
106
+ end
107
+
108
+ context 'when page is set to a value' do
109
+
110
+ before do
111
+ response.paginate(page: 2)
112
+ end
113
+
114
+ it 'uses the defaults' do
115
+ expect(response.search.definition[:size]).to eq(default_per_page)
116
+ expect(response.search.definition[:from]).to eq(default_per_page)
117
+ end
118
+ end
119
+
120
+ context 'when a custom page and per_page is set' do
121
+
122
+ before do
123
+ response.paginate(page: 3, per_page: 9)
124
+ end
125
+
126
+ it 'uses the custom values' do
127
+ expect(response.search.definition[:size]).to eq(9)
128
+ expect(response.search.definition[:from]).to eq(18)
129
+ end
130
+ end
131
+
132
+ context 'fall back to first page if invalid value is provided' do
133
+
134
+ before do
135
+ response.paginate(page: -1)
136
+ end
137
+
138
+ it 'uses the custom values' do
139
+ expect(response.search.definition[:size]).to eq(default_per_page)
140
+ expect(response.search.definition[:from]).to eq(0)
141
+ end
142
+ end
143
+ end
144
+ end
145
+
146
+ describe '#page' do
147
+
148
+ context 'when a value is provided for page' do
149
+
150
+ before do
151
+ response.page(5)
152
+ end
153
+
154
+ it 'calculates the correct :size and :from' do
155
+ expect(response.search.definition[:size]).to eq(default_per_page)
156
+ expect(response.search.definition[:from]).to eq(default_per_page * 4)
157
+ end
158
+ end
159
+
160
+ context 'when a value is provided for page and per_page' do
161
+
162
+ before do
163
+ response.page(5).per_page(3)
164
+ end
165
+
166
+ it 'calculates the correct :size and :from' do
167
+ expect(response.search.definition[:size]).to eq(3)
168
+ expect(response.search.definition[:from]).to eq(12)
169
+ end
170
+ end
171
+
172
+ context 'when a value is provided for per_page and page' do
173
+
174
+ before do
175
+ response.per_page(3).page(5)
176
+ end
177
+
178
+ it 'calculates the correct :size and :from' do
179
+ expect(response.search.definition[:size]).to eq(3)
180
+ expect(response.search.definition[:from]).to eq(12)
181
+ end
182
+ end
183
+ end
184
+
185
+ describe '#current_page' do
186
+
187
+ context 'when no values are set' do
188
+
189
+ before do
190
+ response.paginate({})
191
+ end
192
+
193
+ it 'returns the first page' do
194
+ expect(response.current_page).to eq(1)
195
+ end
196
+ end
197
+
198
+ context 'when values are provided for per_page and page' do
199
+
200
+ before do
201
+ response.paginate(page: 3, per_page: 9)
202
+ end
203
+
204
+ it 'calculates the correct current page' do
205
+ expect(response.current_page).to eq(3)
206
+ end
207
+ end
208
+
209
+ context 'when #paginate has not been called on the response' do
210
+
211
+ it 'returns nil' do
212
+ expect(response.current_page).to be_nil
213
+ end
214
+ end
215
+ end
216
+
217
+ describe '#per_page' do
218
+
219
+ context 'when a value is set via the #paginate method' do
220
+
221
+ before do
222
+ response.paginate(per_page: 8)
223
+ end
224
+
225
+ it 'returns the per_page value' do
226
+ expect(response.per_page).to eq(8)
227
+ end
228
+ end
229
+
230
+ context 'when a value is set via the #per_page method' do
231
+
232
+ before do
233
+ response.per_page(8)
234
+ end
235
+
236
+ it 'returns the per_page value' do
237
+ expect(response.per_page).to eq(8)
238
+ end
239
+ end
240
+ end
241
+
242
+ describe '#total_entries' do
243
+
244
+ before do
245
+ allow(response).to receive(:results).and_return(double('results', total: 100))
246
+ end
247
+
248
+ it 'returns the total results' do
249
+ expect(response.total_entries).to eq(100)
250
+ end
251
+ end
252
+ end
253
+
254
+ context 'when the model is a single one' do
255
+
256
+ let(:model) do
257
+ ModelClass
258
+ end
259
+
260
+ let(:default_per_page) do
261
+ 33
262
+ end
263
+
264
+ it_behaves_like 'a search request that can be paginated'
265
+ end
266
+
267
+ context 'when the model is a multimodel' do
268
+
269
+ let(:model) do
270
+ Elasticsearch::Model::Multimodel.new(ModelClass)
271
+ end
272
+
273
+ let(:default_per_page) do
274
+ ::WillPaginate.per_page
275
+ end
276
+
277
+ it_behaves_like 'a search request that can be paginated'
278
+ end
279
+ end
@@ -0,0 +1,135 @@
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::Response::Records do
21
+
22
+ before(:all) do
23
+ class DummyCollection
24
+ include Enumerable
25
+
26
+ def each(&block); ['FOO'].each(&block); end
27
+ def size; ['FOO'].size; end
28
+ def empty?; ['FOO'].empty?; end
29
+ def foo; 'BAR'; end
30
+ end
31
+
32
+ class DummyModel
33
+ def self.index_name; 'foo'; end
34
+ def self.document_type; 'bar'; end
35
+
36
+ def self.find(*args)
37
+ DummyCollection.new
38
+ end
39
+ end
40
+ end
41
+
42
+ after(:all) do
43
+ remove_classes(DummyCollection, DummyModel)
44
+ end
45
+
46
+ let(:response_document) do
47
+ { 'hits' => { 'total' => 123, 'max_score' => 456, 'hits' => [{'_id' => '1', 'foo' => 'bar'}] } }
48
+ end
49
+
50
+ let(:results) do
51
+ Elasticsearch::Model::Response::Results.new(DummyModel, response_document)
52
+ end
53
+
54
+ let(:search) do
55
+ Elasticsearch::Model::Searching::SearchRequest.new(DummyModel, '*').tap do |request|
56
+ allow(request).to receive(:execute!).and_return(response_document)
57
+ end
58
+ end
59
+
60
+ let(:response) do
61
+ Elasticsearch::Model::Response::Response.new(DummyModel, search)
62
+ end
63
+
64
+ let(:records) do
65
+ described_class.new(DummyModel, response)
66
+ end
67
+
68
+ context 'when the records are accessed' do
69
+
70
+ it 'returns the records' do
71
+ expect(records.records.size).to eq(1)
72
+ expect(records.records.first).to eq('FOO')
73
+ end
74
+
75
+ it 'delegates methods to records' do
76
+ expect(records.foo).to eq('BAR')
77
+ end
78
+ end
79
+
80
+ describe '#each_with_hit' do
81
+
82
+ it 'returns each record with its Elasticsearch hit' do
83
+ records.each_with_hit do |record, hit|
84
+ expect(record).to eq('FOO')
85
+ expect(hit.foo).to eq('bar')
86
+ end
87
+ end
88
+ end
89
+
90
+ describe '#map_with_hit' do
91
+
92
+ let(:value) do
93
+ records.map_with_hit { |record, hit| "#{record}---#{hit.foo}" }
94
+ end
95
+
96
+ it 'returns each record with its Elasticsearch hit' do
97
+ expect(value).to eq(['FOO---bar'])
98
+ end
99
+ end
100
+
101
+ describe '#ids' do
102
+
103
+ it 'returns the ids' do
104
+ expect(records.ids).to eq(['1'])
105
+ end
106
+ end
107
+
108
+ context 'when an adapter is used' do
109
+
110
+ before do
111
+ module DummyAdapter
112
+ module RecordsMixin
113
+ def records
114
+ ['FOOBAR']
115
+ end
116
+ end
117
+
118
+ def records_mixin
119
+ RecordsMixin
120
+ end; module_function :records_mixin
121
+ end
122
+
123
+ allow(Elasticsearch::Model::Adapter).to receive(:from_class).and_return(DummyAdapter)
124
+ end
125
+
126
+ after do
127
+ Elasticsearch::Model::Adapter::Adapter.adapters.delete(DummyAdapter)
128
+ Object.send(:remove_const, :DummyAdapter) if defined?(DummyAdapter)
129
+ end
130
+
131
+ it 'delegates the records method to the adapter' do
132
+ expect(records.records).to eq(['FOOBAR'])
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,148 @@
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::Response::Response do
21
+
22
+ before(:all) do
23
+ class OriginClass
24
+ def self.index_name; 'foo'; end
25
+ def self.document_type; 'bar'; end
26
+ end
27
+ end
28
+
29
+ after(:all) do
30
+ remove_classes(OriginClass)
31
+ end
32
+
33
+ let(:response_document) do
34
+ { 'took' => '5', 'timed_out' => false, '_shards' => {'one' => 'OK'}, 'hits' => { 'hits' => [] },
35
+ 'aggregations' => {'foo' => {'bar' => 10}},
36
+ 'suggest' => {'my_suggest' => [ { 'text' => 'foo', 'options' => [ { 'text' => 'Foo', 'score' => 2.0 },
37
+ { 'text' => 'Bar', 'score' => 1.0 } ] } ]}}
38
+
39
+ end
40
+
41
+ let(:search) do
42
+ Elasticsearch::Model::Searching::SearchRequest.new(OriginClass, '*').tap do |request|
43
+ allow(request).to receive(:execute!).and_return(response_document)
44
+ end
45
+ end
46
+
47
+ let(:response) do
48
+ Elasticsearch::Model::Response::Response.new(OriginClass, search)
49
+ end
50
+
51
+ it 'performs the Elasticsearch request lazily' do
52
+ expect(search).not_to receive(:execute!)
53
+ response
54
+ end
55
+
56
+ describe '#klass' do
57
+
58
+ it 'returns the class' do
59
+ expect(response.klass).to be(OriginClass)
60
+ end
61
+ end
62
+
63
+ describe '#search' do
64
+
65
+ it 'returns the search object' do
66
+ expect(response.search).to eq(search)
67
+ end
68
+ end
69
+
70
+ describe '#took' do
71
+
72
+ it 'returns the took field' do
73
+ expect(response.took).to eq('5')
74
+ end
75
+ end
76
+
77
+ describe '#timed_out' do
78
+
79
+ it 'returns the timed_out field' do
80
+ expect(response.timed_out).to eq(false)
81
+ end
82
+ end
83
+
84
+ describe '#shards' do
85
+
86
+ it 'returns a Hashie::Mash' do
87
+ expect(response.shards.one).to eq('OK')
88
+ end
89
+ end
90
+
91
+ describe '#response' do
92
+
93
+ it 'returns the response document' do
94
+ expect(response.response).to eq(response_document)
95
+ end
96
+ end
97
+
98
+ describe '#results' do
99
+
100
+ it 'provides access to the results' do
101
+ expect(response.results).to be_a(Elasticsearch::Model::Response::Results)
102
+ expect(response.size).to be(0)
103
+ end
104
+ end
105
+
106
+ describe '#records' do
107
+
108
+ it 'provides access to the records' do
109
+ expect(response.records).to be_a(Elasticsearch::Model::Response::Records)
110
+ expect(response.size).to be(0)
111
+ end
112
+ end
113
+
114
+ describe 'enumerable methods' do
115
+
116
+ it 'delegates the methods to the results' do
117
+ expect(response.empty?).to be(true)
118
+ end
119
+ end
120
+
121
+ describe 'aggregations' do
122
+
123
+ it 'provides access to the aggregations' do
124
+ expect(response.aggregations).to be_a(Hashie::Mash)
125
+ expect(response.aggregations.foo.bar).to eq(10)
126
+ end
127
+ end
128
+
129
+ describe 'suggestions' do
130
+
131
+ it 'provides access to the suggestions' do
132
+ expect(response.suggestions).to be_a(Hashie::Mash)
133
+ expect(response.suggestions.my_suggest.first.options.first.text).to eq('Foo')
134
+ expect(response.suggestions.terms).to eq([ 'Foo', 'Bar' ])
135
+ end
136
+
137
+ context 'when there are no suggestions' do
138
+
139
+ let(:response_document) do
140
+ { }
141
+ end
142
+
143
+ it 'returns an empty list' do
144
+ expect(response.suggestions.terms).to eq([ ])
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,139 @@
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
+ require 'active_support/json/encoding'
20
+
21
+ describe Elasticsearch::Model::Response::Result do
22
+
23
+ let(:result) do
24
+ described_class.new(foo: 'bar', bar: { bam: 'baz' })
25
+ end
26
+
27
+ it 'provides access to the properties' do
28
+ expect(result.foo).to eq('bar')
29
+ expect(result.bar.bam).to eq('baz')
30
+ expect { result.xoxo }.to raise_exception(NoMethodError)
31
+ end
32
+
33
+ describe '#id' do
34
+
35
+ let(:result) do
36
+ described_class.new(foo: 'bar', _id: 42, _source: { id: 12 })
37
+ end
38
+
39
+ it 'returns the _id field' do
40
+ expect(result.id).to eq(42)
41
+ end
42
+
43
+ it 'provides access to the source id field' do
44
+ expect(result._source.id).to eq(12)
45
+ end
46
+ end
47
+
48
+ describe '#type' do
49
+
50
+ let(:result) do
51
+ described_class.new(foo: 'bar', _type: 'baz', _source: { type: 'BAM' })
52
+ end
53
+
54
+ it 'returns the _type field' do
55
+ expect(result.type).to eq('baz')
56
+ end
57
+
58
+ it 'provides access to the source type field' do
59
+ expect(result._source.type).to eq('BAM')
60
+ end
61
+ end
62
+
63
+ describe 'method delegation' do
64
+
65
+ let(:result) do
66
+ described_class.new(foo: 'bar', _source: { bar: { bam: 'baz' } })
67
+ end
68
+
69
+ it 'provides access to the _source field via a method' do
70
+ expect(result._source).to eq('bar' => { 'bam' => 'baz' })
71
+ end
72
+
73
+ it 'is recognized by #method' do
74
+ expect(result.method :bar).to be_a Method
75
+ end
76
+
77
+ it 'respond_to? still works' do
78
+ expect(result.respond_to? :bar).to be true
79
+ end
80
+
81
+ context 'when methods map to keys in subdocuments of the response from Elasticsearch' do
82
+
83
+ it 'provides access to top level fields via a method' do
84
+ expect(result.foo).to eq('bar')
85
+ expect(result.fetch(:foo)).to eq('bar')
86
+ expect(result.fetch(:does_not_exist, 'moo')).to eq('moo')
87
+ end
88
+
89
+ it 'responds to hash methods' do
90
+ expect(result.keys).to eq(['foo', '_source'])
91
+ expect(result.to_hash).to eq('foo' => 'bar', '_source' => { 'bar' => { 'bam' => 'baz' } })
92
+ end
93
+
94
+ it 'provides access to fields in the _source subdocument via a method' do
95
+ expect(result.bar).to eq('bam' => 'baz')
96
+ expect(result.bar.bam).to eq('baz')
97
+ expect(result._source.bar).to eq('bam' => 'baz')
98
+ expect(result._source.bar.bam).to eq('baz')
99
+ end
100
+
101
+ context 'when boolean methods are called' do
102
+
103
+ it 'provides access to top level fields via a method' do
104
+ expect(result.foo?).to eq(true)
105
+ expect(result.boo?).to eq(false)
106
+ end
107
+
108
+ it 'delegates to fields in the _source subdocument via a method' do
109
+ expect(result.bar?).to eq(true)
110
+ expect(result.bar.bam?).to eq(true)
111
+ expect(result.boo?).to eq(false)
112
+ expect(result.bar.boo?).to eq(false)
113
+ expect(result._source.bar?).to eq(true)
114
+ expect(result._source.bar.bam?).to eq(true)
115
+ expect(result._source.boo?).to eq(false)
116
+ expect(result._source.bar.boo?).to eq(false)
117
+ end
118
+ end
119
+ end
120
+
121
+ context 'when methods do not map to keys in subdocuments of the response from Elasticsearch' do
122
+
123
+ it 'raises a NoMethodError' do
124
+ expect { result.does_not_exist }.to raise_exception(NoMethodError)
125
+ end
126
+ end
127
+ end
128
+
129
+ describe '#as_json' do
130
+
131
+ let(:result) do
132
+ described_class.new(foo: 'bar', _source: { bar: { bam: 'baz' } })
133
+ end
134
+
135
+ it 'returns a json string' do
136
+ expect(result.as_json(except: 'foo')).to eq({'_source'=>{'bar'=>{'bam'=>'baz'}}})
137
+ end
138
+ end
139
+ end