elastic_adapter 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +41 -0
  7. data/Rakefile +24 -0
  8. data/elastic_adapter.gemspec +30 -0
  9. data/example.env +4 -0
  10. data/lib/elastic_adapter/decoration/count_response.rb +18 -0
  11. data/lib/elastic_adapter/decoration/decorator.rb +39 -0
  12. data/lib/elastic_adapter/decoration/hit_decorator.rb +25 -0
  13. data/lib/elastic_adapter/decoration/response_decorator_factory.rb +51 -0
  14. data/lib/elastic_adapter/decoration/search_response.rb +29 -0
  15. data/lib/elastic_adapter/decoration/suggestion_response.rb +25 -0
  16. data/lib/elastic_adapter/decoration/validation_response.rb +16 -0
  17. data/lib/elastic_adapter/document_type.rb +21 -0
  18. data/lib/elastic_adapter/index.rb +108 -0
  19. data/lib/elastic_adapter/response.rb +57 -0
  20. data/lib/elastic_adapter/version.rb +3 -0
  21. data/lib/elastic_adapter.rb +21 -0
  22. data/spec/cassettes/ElasticAdapter_Index/_count/empty_index/is_a_response.yml +30 -0
  23. data/spec/cassettes/ElasticAdapter_Index/_count/empty_index/returs_the_amount_of_all_documents.yml +30 -0
  24. data/spec/cassettes/ElasticAdapter_Index/_count/not_empty_index/is_a_response.yml +30 -0
  25. data/spec/cassettes/ElasticAdapter_Index/_count/not_empty_index/returns_1.yml +30 -0
  26. data/spec/cassettes/ElasticAdapter_Index/_create_index/index_is_present/response/has_an_exception.yml +30 -0
  27. data/spec/cassettes/ElasticAdapter_Index/_create_index/index_is_present/response/is_a_Response.yml +30 -0
  28. data/spec/cassettes/ElasticAdapter_Index/_create_index/index_not_present/response/has_no_exception.yml +57 -0
  29. data/spec/cassettes/ElasticAdapter_Index/_create_index/index_not_present/response/is_a_Response.yml +57 -0
  30. data/spec/cassettes/ElasticAdapter_Index/_delete_index/index_not_present/repsonse/has_an_exception.yml +30 -0
  31. data/spec/cassettes/ElasticAdapter_Index/_delete_index/index_not_present/repsonse/is_a_Response.yml +30 -0
  32. data/spec/cassettes/ElasticAdapter_Index/_delete_index/index_present/repsonse/has_no_exception.yml +57 -0
  33. data/spec/cassettes/ElasticAdapter_Index/_delete_index/index_present/repsonse/is_a_Response.yml +57 -0
  34. data/spec/cassettes/ElasticAdapter_Index/_get/document_exists/response/contains_the_document.yml +30 -0
  35. data/spec/cassettes/ElasticAdapter_Index/_index/existing_document/doesn_t_change_the_document_count.yml +84 -0
  36. data/spec/cassettes/ElasticAdapter_Index/_index/existing_document/invokes_to_hash_on_the_document.yml +30 -0
  37. data/spec/cassettes/ElasticAdapter_Index/_index/existing_document/updates_the_document.yml +30 -0
  38. data/spec/cassettes/ElasticAdapter_Index/_index/new_document/indexes_a_document.yml +57 -0
  39. data/spec/cassettes/ElasticAdapter_Index/_index/new_document/invokes_to_hash_on_the_document.yml +30 -0
  40. data/spec/cassettes/ElasticAdapter_Index/_search/match_all/returns_all_documents.yml +30 -0
  41. data/spec/cassettes/ElasticAdapter_Index/_search/zoo/returns_one_document.yml +30 -0
  42. data/spec/cassettes/ElasticAdapter_Index/_search/zoo/returns_the_wanted_document.yml +30 -0
  43. data/spec/cassettes/ElasticAdapter_Index/_suggest/query_ba_/returns_bar.yml +30 -0
  44. data/spec/cassettes/ElasticAdapter_Index/_suggest/query_ba_/returns_one_result.yml +30 -0
  45. data/spec/cassettes/ElasticAdapter_Index/_validate/invalid_query/is_a_response.yml +30 -0
  46. data/spec/cassettes/ElasticAdapter_Index/_validate/invalid_query/is_false.yml +31 -0
  47. data/spec/cassettes/ElasticAdapter_Index/_validate/valid_query/is_a_response.yml +30 -0
  48. data/spec/cassettes/ElasticAdapter_Index/_validate/valid_query/is_true.yml +30 -0
  49. data/spec/decoration/response_decorator_factory_spec.rb +75 -0
  50. data/spec/document_type_spec.rb +42 -0
  51. data/spec/elastic_adapter_spec.rb +4 -0
  52. data/spec/index_spec.rb +458 -0
  53. data/spec/response_spec.rb +80 -0
  54. data/spec/spec_helper.rb +102 -0
  55. metadata +243 -0
@@ -0,0 +1,458 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.shared_examples "response without exception" do
4
+ it "is a Response" do
5
+ expect(response).to be_a ElasticAdapter::Response
6
+ end
7
+
8
+ it "has no exception" do
9
+ expect(response).not_to have_key :exception
10
+ end
11
+ end
12
+
13
+ RSpec.shared_examples "response with exception" do
14
+ it "is a Response" do
15
+ expect(response).to be_a ElasticAdapter::Response
16
+ end
17
+
18
+ it "has an exception" do
19
+ expect(response).to have_key :exception
20
+ end
21
+ end
22
+
23
+ module ElasticAdapter
24
+ describe Index, :vcr do
25
+ def test_index(name = "test_index", options = {})
26
+ params = {
27
+ name: name,
28
+ url: "http://localhost:9200",
29
+ log: true,
30
+ settings: {},
31
+ document_type: OpenStruct.new(
32
+ name: "test_doc",
33
+ mappings: {
34
+ test_doc: {
35
+ properties: {
36
+ foo: { type: "string" }
37
+ }
38
+ }
39
+ }
40
+ )
41
+ }.merge(options)
42
+
43
+ Index.new(params)
44
+ end
45
+
46
+ def create_test_index(name = "test_index", options = {})
47
+ test_index(name, options).create_index
48
+ end
49
+
50
+ def delete_test_index(name = "test_index", options = {})
51
+ test_index(name, options).delete_index
52
+ end
53
+
54
+ def index_document(document, name = "test_index", options = {})
55
+ test_index(name, options).index(document)
56
+ end
57
+
58
+ def wait_for_elasticsearch
59
+ if ENV["RECORDING"]
60
+ sleep 1
61
+ end
62
+ end
63
+
64
+ let(:name) { "test_index" }
65
+ let(:mappings) do
66
+ {
67
+ test_index: {
68
+ properties: {
69
+ foo: {
70
+ type: "string"
71
+ }
72
+ }
73
+ }
74
+ }
75
+ end
76
+ let(:document_type) do
77
+ OpenStruct.new(name: "test_doc", mappings: mappings)
78
+ end
79
+ let(:settings) { { number_of_shards: 1 } }
80
+ let(:log) { true }
81
+ let(:url) { "http://localhost:9200"}
82
+
83
+ let(:subject) do
84
+ Index.new(
85
+ name: name,
86
+ settings: settings,
87
+ document_type: document_type,
88
+ url: url,
89
+ log: log
90
+ )
91
+ end
92
+
93
+ describe "#initialize" do
94
+ it "assigns the name" do
95
+ expect(subject.instance_variable_get('@name')).to be name
96
+ end
97
+
98
+ it "assigns the settings" do
99
+ expect(subject.instance_variable_get('@settings')).to be settings
100
+ end
101
+
102
+ it "assigns the document_type" do
103
+ expect(subject.instance_variable_get('@document_type')).to be document_type
104
+ end
105
+
106
+ it "assigns the url" do
107
+ expect(subject.instance_variable_get('@url')).to be url
108
+ end
109
+
110
+ it "assigns the log" do
111
+ expect(subject.instance_variable_get('@log')).to be log
112
+ end
113
+ end
114
+
115
+ describe "getter" do
116
+ describe "name" do
117
+ it "returns the name" do
118
+ expect(subject.name).to eq name
119
+ end
120
+ end
121
+
122
+ describe "settings" do
123
+ it "returns the settings" do
124
+ expect(subject.settings).to eq settings
125
+ end
126
+ end
127
+
128
+ describe "document_type" do
129
+ it "returns the document_type" do
130
+ expect(subject.document_type).to eq document_type
131
+ end
132
+ end
133
+
134
+ describe "url" do
135
+ it "returns the url" do
136
+ expect(subject.url).to eq url
137
+ end
138
+ end
139
+
140
+ describe "log" do
141
+ it "returns the log" do
142
+ expect(subject.log).to eq log
143
+ end
144
+ end
145
+
146
+ describe "client" do
147
+ it "returns the client" do
148
+ expect(subject.client).to be_a ::Elasticsearch::Transport::Client
149
+ end
150
+ end
151
+ end
152
+
153
+ describe "#validate" do
154
+ before :all do
155
+ create_test_index
156
+ wait_for_elasticsearch
157
+ end
158
+
159
+ after :all do
160
+ delete_test_index
161
+ end
162
+
163
+ context "invalid query" do
164
+ let(:query) do
165
+ {
166
+ asd: "[[[ BOOM! ]]]"
167
+ }
168
+ end
169
+
170
+ let(:response) { subject.validate(query) }
171
+
172
+ it "is false" do
173
+ expect(response).to eq false
174
+ end
175
+
176
+ it "is a response" do
177
+ expect(response).to be_a Decoration::ValidationResponse
178
+ end
179
+ end
180
+
181
+ context "valid query" do
182
+ let(:query) do
183
+ {
184
+ query: {
185
+ match_all: {}
186
+ }
187
+ }
188
+ end
189
+
190
+ let(:response) { subject.validate(query) }
191
+
192
+ it "is true" do
193
+ expect(response).to eq true
194
+ end
195
+
196
+ it "is a response" do
197
+ expect(response).to be_a Decoration::ValidationResponse
198
+ end
199
+ end
200
+ end
201
+
202
+ describe "#suggest" do
203
+ before :all do
204
+ create_test_index "test_index", document_type: OpenStruct.new(
205
+ name: "test_doc",
206
+ mappings: {
207
+ test_doc: {
208
+ properties: {
209
+ foo: { type: "completion" }
210
+ }
211
+ }
212
+ }
213
+ )
214
+
215
+ index_document(foo: {input: "bar"})
216
+ index_document(foo: {input: "zoo"})
217
+ sleep 1
218
+ end
219
+
220
+ after :all do
221
+ delete_test_index
222
+ end
223
+
224
+ context "query 'ba'" do
225
+ let(:query) do
226
+ {
227
+ foo_suggest: {
228
+ text: "ba",
229
+ completion: {
230
+ field: "foo"
231
+ }
232
+ }
233
+ }
234
+ end
235
+
236
+ let(:response) { subject.suggest(query)}
237
+
238
+ it "returns one result" do
239
+ expect(response.count).to eq 1
240
+ end
241
+
242
+ it "returns bar" do
243
+ expect(response[:options].first).to include text: "bar"
244
+ end
245
+
246
+ end
247
+ end
248
+
249
+ describe "#search" do
250
+ before :all do
251
+ create_test_index
252
+ index_document(foo: "bar", id: 1)
253
+ index_document(foo: "zoo", id: 2)
254
+ sleep 1
255
+ end
256
+
257
+ after :all do
258
+ delete_test_index
259
+ end
260
+
261
+ context "match_all" do
262
+ it "returns all documents" do
263
+ expect(subject.search({query: {match_all: {}}}).count).to eq 2
264
+ end
265
+ end
266
+
267
+ context "zoo" do
268
+ let(:response) { subject.search(query: {match: {foo: "zoo"}})}
269
+ it "returns one document" do
270
+ expect(response.count).to eq 1
271
+ end
272
+
273
+ it "returns the wanted document" do
274
+ expect(response[:hits].first[:id]).to eq "2"
275
+ expect(response[:hits].first[:foo]).to eq "zoo"
276
+ end
277
+ end
278
+ end
279
+
280
+ describe "#get" do
281
+ context "document exists" do
282
+ let(:document) { {id: "1", foo: "bar"} }
283
+ before :all do
284
+ create_test_index
285
+ index_document(foo: "bar", id: 1)
286
+ end
287
+
288
+ after :all do
289
+ delete_test_index
290
+ end
291
+
292
+ let(:response) { subject.get(1) }
293
+
294
+ describe "response" do
295
+ it "contains the document" do
296
+ expect(response).to eq document
297
+ end
298
+ end
299
+ end
300
+ end
301
+
302
+ describe "#index" do
303
+ context "new document" do
304
+ let(:document) { { foo: "bar" } }
305
+
306
+ before :all do
307
+ create_test_index
308
+ end
309
+
310
+ after :all do
311
+ delete_test_index
312
+ end
313
+
314
+ it "indexes a document" do
315
+ subject.index(document)
316
+ # wait_for_elasticsearch
317
+ sleep 1
318
+ expect(subject.count).to eq 1
319
+ end
320
+
321
+ it "invokes to_hash on the document" do
322
+ expect(document).to receive(:to_hash).and_return(document.to_hash)
323
+ subject.index(document)
324
+ end
325
+ end
326
+
327
+ context "existing document" do
328
+ let(:document) { {foo: "baz", id: 1} }
329
+
330
+ before :all do
331
+ create_test_index
332
+ # wait_for_elasticsearch
333
+ sleep 1
334
+ index_document foo: "bar", id: 1
335
+ # wait_for_elasticsearch
336
+ sleep 1
337
+ end
338
+
339
+ after :all do
340
+ delete_test_index
341
+ end
342
+
343
+ it "doesn't change the document count" do
344
+ expect(subject.count).to eq 1
345
+ subject.index(document)
346
+ sleep 1
347
+ # wait_for_elasticsearch
348
+ expect(subject.count).to eq 1
349
+ end
350
+
351
+ it "invokes to_hash on the document" do
352
+ expect(document).to receive(:to_hash).and_return(document.to_hash)
353
+ subject.index(document)
354
+ end
355
+
356
+ it "updates the document" do
357
+ expect(subject.get(1)[:foo]).to eq "baz"
358
+ end
359
+ end
360
+ end
361
+
362
+ describe "#count" do
363
+ context "empty index" do
364
+ before :all do
365
+ create_test_index
366
+ wait_for_elasticsearch
367
+ end
368
+
369
+ after :all do
370
+ delete_test_index
371
+ end
372
+
373
+ it "returs the amount of all documents" do
374
+ expect(subject.count).to eq 0
375
+ end
376
+
377
+ it "is a response" do
378
+ expect(subject.count).to be_a Decoration::CountResponse
379
+ end
380
+ end
381
+
382
+ context "not empty index" do
383
+ before :all do
384
+ create_test_index
385
+ index_document foo: "bar"
386
+ sleep 1
387
+ # wait_for_elasticsearch
388
+ end
389
+
390
+ after :all do
391
+ delete_test_index
392
+ end
393
+
394
+ it "returns 1" do
395
+ expect(subject.count).to eq 1
396
+ end
397
+
398
+ it "is a response" do
399
+ expect(subject.count).to be_a Decoration::CountResponse
400
+ end
401
+ end
402
+ end
403
+
404
+ describe "#delete_index" do
405
+ context "index present" do
406
+ before :each do
407
+ create_test_index
408
+ end
409
+
410
+ let(:response) { subject.delete_index }
411
+
412
+ describe "repsonse" do
413
+ include_examples "response without exception"
414
+ end
415
+ end
416
+
417
+ context "index not present" do
418
+ let(:response) { subject.delete_index }
419
+
420
+ describe "repsonse" do
421
+ include_examples "response with exception"
422
+ end
423
+ end
424
+ end
425
+
426
+ describe "#create_index" do
427
+ context "index is present" do
428
+ before :all do
429
+ create_test_index
430
+ end
431
+
432
+ after :all do
433
+ delete_test_index
434
+ end
435
+
436
+ let(:response) { subject.create_index }
437
+
438
+ describe "response" do
439
+ # TODO fix this
440
+ # Somehow VCR doesn't record the requests for the current context
441
+ include_examples "response with exception"
442
+ end
443
+ end
444
+
445
+ context "index not present" do
446
+ after :each do
447
+ delete_test_index
448
+ end
449
+
450
+ let(:response) { subject.create_index }
451
+
452
+ describe "response" do
453
+ include_examples "response without exception"
454
+ end
455
+ end
456
+ end
457
+ end
458
+ end
@@ -0,0 +1,80 @@
1
+ require "spec_helper"
2
+
3
+ module ElasticAdapter
4
+ describe Response do
5
+ describe "delegation" do
6
+ let(:hash) { { foo: "bar" } }
7
+ let(:response) { Response.new(hash) }
8
+
9
+ describe "#original_object" do
10
+ it "returns the original hash" do
11
+ expect(response.original_object).to be hash
12
+ end
13
+ end
14
+
15
+ describe "object" do
16
+ it "returns the sanitized hash" do
17
+ expect(response.object).to eq({ foo: "bar" })
18
+ end
19
+ end
20
+ end
21
+
22
+ describe "sanitization" do
23
+ it "turns all strings in Hash keys to symbols" do
24
+ hash = {"foo" => "bar"}
25
+ response = Response.new(hash)
26
+ expect(response.keys.first).to be_a Symbol
27
+ end
28
+
29
+ it "removes all leading underscores from keys" do
30
+ hash = {"_foo" => {"_bar" => "baz" }}
31
+ expected = {foo: {bar: "baz" }}
32
+ response = Response.new(hash)
33
+ expect(response.object).to eq expected
34
+ end
35
+ end
36
+
37
+ describe "#failure?" do
38
+ context "no exception" do
39
+ let(:hash) { { foo: "bar" } }
40
+ let(:response) { Response.new(hash) }
41
+
42
+ it "returns false" do
43
+ expect(response.failure?).to be false
44
+ end
45
+ end
46
+
47
+ context "with exception" do
48
+ let(:hash) { { foo: "bar", exception: ArgumentError.new("foo") } }
49
+ let(:response) { Response.new(hash) }
50
+
51
+ it "returns true" do
52
+ expect(response.failure?).to be true
53
+ end
54
+ end
55
+ end
56
+
57
+ describe "#decorate" do
58
+ context "find request" do
59
+ let(:document) { {foo: "bar", id: 1} }
60
+ let(:response_hash) do
61
+ {
62
+ "found" => true,
63
+ "_id" => 1,
64
+ "_source" => {
65
+ "foo" => "bar"
66
+ }
67
+ }
68
+ end
69
+
70
+ let(:response) do
71
+ response = Response.new(response_hash)
72
+ end
73
+
74
+ it "is the document" do
75
+ expect(response.decorate.to_hash).to eq document
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,102 @@
1
+ require "elastic_adapter"
2
+ require "rake"
3
+ require "webmock/rspec"
4
+ require "vcr"
5
+
6
+ VCR.configure do |config|
7
+ config.cassette_library_dir = 'spec/cassettes'
8
+ config.hook_into :webmock
9
+ config.default_cassette_options = { record: :new_episodes }
10
+ config.configure_rspec_metadata!
11
+ config.allow_http_connections_when_no_cassette = true
12
+ end
13
+
14
+ # This file was generated by the `rspec --init` command. Conventionally, all
15
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
16
+ # The generated `.rspec` file contains `--require spec_helper` which will cause this
17
+ # file to always be loaded, without a need to explicitly require it in any files.
18
+ #
19
+ # Given that it is always loaded, you are encouraged to keep this file as
20
+ # light-weight as possible. Requiring heavyweight dependencies from this file
21
+ # will add to the boot time of your test suite on EVERY test run, even for an
22
+ # individual file that may not need all of that loaded. Instead, consider making
23
+ # a separate helper file that requires the additional dependencies and performs
24
+ # the additional setup, and require it from the spec files that actually need it.
25
+ #
26
+ # The `.rspec` file also contains a few flags that are not defaults but that
27
+ # users commonly want.
28
+ #
29
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
30
+ RSpec.configure do |config|
31
+ # rspec-expectations config goes here. You can use an alternate
32
+ # assertion/expectation library such as wrong or the stdlib/minitest
33
+ # assertions if you prefer.
34
+ config.expect_with :rspec do |expectations|
35
+ # This option will default to `true` in RSpec 4. It makes the `description`
36
+ # and `failure_message` of custom matchers include text for helper methods
37
+ # defined using `chain`, e.g.:
38
+ # be_bigger_than(2).and_smaller_than(4).description
39
+ # # => "be bigger than 2 and smaller than 4"
40
+ # ...rather than:
41
+ # # => "be bigger than 2"
42
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
43
+ end
44
+
45
+ # rspec-mocks config goes here. You can use an alternate test double
46
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
47
+ config.mock_with :rspec do |mocks|
48
+ # Prevents you from mocking or stubbing a method that does not exist on
49
+ # a real object. This is generally recommended, and will default to
50
+ # `true` in RSpec 4.
51
+ mocks.verify_partial_doubles = true
52
+ end
53
+
54
+ # The settings below are suggested to provide a good initial experience
55
+ # with RSpec, but feel free to customize to your heart's content.
56
+ =begin
57
+ # These two settings work together to allow you to limit a spec run
58
+ # to individual examples or groups you care about by tagging them with
59
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
60
+ # get run.
61
+ config.filter_run :focus
62
+ config.run_all_when_everything_filtered = true
63
+
64
+ # Limits the available syntax to the non-monkey patched syntax that is recommended.
65
+ # For more details, see:
66
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
67
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
68
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
69
+ config.disable_monkey_patching!
70
+
71
+ # This setting enables warnings. It's recommended, but in some cases may
72
+ # be too noisy due to issues in dependencies.
73
+ config.warnings = true
74
+
75
+ # Many RSpec users commonly either run the entire suite or an individual
76
+ # file, and it's useful to allow more verbose output when running an
77
+ # individual spec file.
78
+ if config.files_to_run.one?
79
+ # Use the documentation formatter for detailed output,
80
+ # unless a formatter has already been configured
81
+ # (e.g. via a command-line flag).
82
+ config.default_formatter = 'doc'
83
+ end
84
+
85
+ # Print the 10 slowest examples and example groups at the
86
+ # end of the spec run, to help surface which specs are running
87
+ # particularly slow.
88
+ config.profile_examples = 10
89
+
90
+ # Run specs in random order to surface order dependencies. If you find an
91
+ # order dependency and want to debug it, you can fix the order by providing
92
+ # the seed, which is printed after each run.
93
+ # --seed 1234
94
+ config.order = :random
95
+
96
+ # Seed global randomization in this process using the `--seed` CLI option.
97
+ # Setting this allows you to use `--seed` to deterministically reproduce
98
+ # test failures related to randomization by passing the same `--seed` value
99
+ # as the one that triggered the failure.
100
+ Kernel.srand config.seed
101
+ =end
102
+ end