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.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +41 -0
- data/Rakefile +24 -0
- data/elastic_adapter.gemspec +30 -0
- data/example.env +4 -0
- data/lib/elastic_adapter/decoration/count_response.rb +18 -0
- data/lib/elastic_adapter/decoration/decorator.rb +39 -0
- data/lib/elastic_adapter/decoration/hit_decorator.rb +25 -0
- data/lib/elastic_adapter/decoration/response_decorator_factory.rb +51 -0
- data/lib/elastic_adapter/decoration/search_response.rb +29 -0
- data/lib/elastic_adapter/decoration/suggestion_response.rb +25 -0
- data/lib/elastic_adapter/decoration/validation_response.rb +16 -0
- data/lib/elastic_adapter/document_type.rb +21 -0
- data/lib/elastic_adapter/index.rb +108 -0
- data/lib/elastic_adapter/response.rb +57 -0
- data/lib/elastic_adapter/version.rb +3 -0
- data/lib/elastic_adapter.rb +21 -0
- data/spec/cassettes/ElasticAdapter_Index/_count/empty_index/is_a_response.yml +30 -0
- data/spec/cassettes/ElasticAdapter_Index/_count/empty_index/returs_the_amount_of_all_documents.yml +30 -0
- data/spec/cassettes/ElasticAdapter_Index/_count/not_empty_index/is_a_response.yml +30 -0
- data/spec/cassettes/ElasticAdapter_Index/_count/not_empty_index/returns_1.yml +30 -0
- data/spec/cassettes/ElasticAdapter_Index/_create_index/index_is_present/response/has_an_exception.yml +30 -0
- data/spec/cassettes/ElasticAdapter_Index/_create_index/index_is_present/response/is_a_Response.yml +30 -0
- data/spec/cassettes/ElasticAdapter_Index/_create_index/index_not_present/response/has_no_exception.yml +57 -0
- data/spec/cassettes/ElasticAdapter_Index/_create_index/index_not_present/response/is_a_Response.yml +57 -0
- data/spec/cassettes/ElasticAdapter_Index/_delete_index/index_not_present/repsonse/has_an_exception.yml +30 -0
- data/spec/cassettes/ElasticAdapter_Index/_delete_index/index_not_present/repsonse/is_a_Response.yml +30 -0
- data/spec/cassettes/ElasticAdapter_Index/_delete_index/index_present/repsonse/has_no_exception.yml +57 -0
- data/spec/cassettes/ElasticAdapter_Index/_delete_index/index_present/repsonse/is_a_Response.yml +57 -0
- data/spec/cassettes/ElasticAdapter_Index/_get/document_exists/response/contains_the_document.yml +30 -0
- data/spec/cassettes/ElasticAdapter_Index/_index/existing_document/doesn_t_change_the_document_count.yml +84 -0
- data/spec/cassettes/ElasticAdapter_Index/_index/existing_document/invokes_to_hash_on_the_document.yml +30 -0
- data/spec/cassettes/ElasticAdapter_Index/_index/existing_document/updates_the_document.yml +30 -0
- data/spec/cassettes/ElasticAdapter_Index/_index/new_document/indexes_a_document.yml +57 -0
- data/spec/cassettes/ElasticAdapter_Index/_index/new_document/invokes_to_hash_on_the_document.yml +30 -0
- data/spec/cassettes/ElasticAdapter_Index/_search/match_all/returns_all_documents.yml +30 -0
- data/spec/cassettes/ElasticAdapter_Index/_search/zoo/returns_one_document.yml +30 -0
- data/spec/cassettes/ElasticAdapter_Index/_search/zoo/returns_the_wanted_document.yml +30 -0
- data/spec/cassettes/ElasticAdapter_Index/_suggest/query_ba_/returns_bar.yml +30 -0
- data/spec/cassettes/ElasticAdapter_Index/_suggest/query_ba_/returns_one_result.yml +30 -0
- data/spec/cassettes/ElasticAdapter_Index/_validate/invalid_query/is_a_response.yml +30 -0
- data/spec/cassettes/ElasticAdapter_Index/_validate/invalid_query/is_false.yml +31 -0
- data/spec/cassettes/ElasticAdapter_Index/_validate/valid_query/is_a_response.yml +30 -0
- data/spec/cassettes/ElasticAdapter_Index/_validate/valid_query/is_true.yml +30 -0
- data/spec/decoration/response_decorator_factory_spec.rb +75 -0
- data/spec/document_type_spec.rb +42 -0
- data/spec/elastic_adapter_spec.rb +4 -0
- data/spec/index_spec.rb +458 -0
- data/spec/response_spec.rb +80 -0
- data/spec/spec_helper.rb +102 -0
- metadata +243 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b7d2b6efb6221dc7ad620073a1d963ce0f92415f
|
4
|
+
data.tar.gz: c881d1dbbfd1c00d4864224ff8296758709258bd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b8d5f3a1b40dc170c471f14e4a1cc5552cca27c6fa96542f4fb7bee5e17386a34abe7e3247f8e4ebb9afb125d84242636bfb3a238ec1d5d3d3b0ab4eb1aef974
|
7
|
+
data.tar.gz: 744cf2cdf6619e92f49aea07ded6d0e6e4640e769b262b6d3e566fdb52e823109b54a7dbe908d054d1a83adfd6ce7e6c08c163f6250f3dd186b4f58aff35f12c
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Kristopher Bredemeier
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# ElasticAdapter
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'elastic_adapter'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install elastic_adapter
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
TODO: Write usage instructions here
|
24
|
+
|
25
|
+
|
26
|
+
## Testing and Development
|
27
|
+
|
28
|
+
For a few specs I needed to place some sleep statements to make them work. To not slow down the specs with the sleep statements and for other reasons
|
29
|
+
I decided to use VCR to capture the requests. I added a rake taks which sets an environment variable which is used in a helper function to decide either to
|
30
|
+
`sleep 1` or not. This way the specs are not slowed down. To execute the rake task run `rake record`.
|
31
|
+
|
32
|
+
Unfortunatly VCR skips recording some context blocks for unknown reason. I didn't had the time to look into that yet. That means that it is required
|
33
|
+
to have a running elasticsearch at `localhost:9200` to run the specs.
|
34
|
+
|
35
|
+
## Contributing
|
36
|
+
|
37
|
+
1. Fork it ( https://github.com/kbredemeier/elastic_adapter/fork )
|
38
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
39
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
40
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
41
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
require "fileutils"
|
4
|
+
require "yard"
|
5
|
+
|
6
|
+
RSpec::Core::RakeTask.new(:spec)
|
7
|
+
|
8
|
+
task default: :spec
|
9
|
+
|
10
|
+
task :console do
|
11
|
+
exec "irb -r elastic_adapter -I ./lib"
|
12
|
+
end
|
13
|
+
|
14
|
+
RSpec::Core::RakeTask.new(:record) do |t|
|
15
|
+
ENV['RECORDING'] = "1"
|
16
|
+
FileUtils.rm_rf "spec/cassettes"
|
17
|
+
t.rspec_opts = "--tag vcr"
|
18
|
+
end
|
19
|
+
|
20
|
+
YARD::Rake::YardocTask.new(:doc) do |t|
|
21
|
+
t.files = ['lib/**/*.rb']
|
22
|
+
# t.options = ['--any', '--extra', '--opts'] # optional
|
23
|
+
# t.stats_options = ['--list-undoc'] # optional
|
24
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'elastic_adapter/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "elastic_adapter"
|
8
|
+
spec.version = ElasticAdapter::VERSION
|
9
|
+
spec.authors = ["Kristopher Bredemeier"]
|
10
|
+
spec.email = ["k.bredemeier@gmail.com"]
|
11
|
+
spec.summary = %q{Repository like access to elasticseach indices}
|
12
|
+
spec.description = %q{Repository like access to elasticseach indices}
|
13
|
+
spec.homepage = "https://github.com/kbredemeier/elastic_adatper"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "elasticsearch", "~> 1.0.6"
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
25
|
+
spec.add_development_dependency "rspec", "~> 3.1.0"
|
26
|
+
spec.add_development_dependency "vcr", "~> 2.9.3"
|
27
|
+
spec.add_development_dependency "webmock", "~> 1.20.4"
|
28
|
+
spec.add_development_dependency "pry-byebug", "~> 3.0.1"
|
29
|
+
spec.add_development_dependency "yard", "~> 0.8.7.6"
|
30
|
+
end
|
data/example.env
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
module ElasticAdapter
|
2
|
+
module Decoration
|
3
|
+
# Used to wrap responses from the elasticsearch count api
|
4
|
+
# After decoration the decorator will point to the actual
|
5
|
+
# count returned by elasticsearch
|
6
|
+
class CountResponse < Decorator
|
7
|
+
|
8
|
+
# Reduced the hash to the count returned by elasticsearch
|
9
|
+
#
|
10
|
+
# @param [Object] object
|
11
|
+
# @return [Integer] the count returned by elasticsearch
|
12
|
+
def alter_object(object)
|
13
|
+
object[:count]
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require "delegate"
|
2
|
+
|
3
|
+
module ElasticAdapter
|
4
|
+
module Decoration
|
5
|
+
# Abstract base class for response decorators
|
6
|
+
# @abstract
|
7
|
+
#
|
8
|
+
# @attr [Object] original_object the original unmodified object
|
9
|
+
class Decorator < SimpleDelegator
|
10
|
+
|
11
|
+
attr_reader :original_object
|
12
|
+
|
13
|
+
# Takes an object and stores it in `@original_object` and saves a
|
14
|
+
# altered version as the decorated object
|
15
|
+
#
|
16
|
+
# @param [Object] object
|
17
|
+
def initialize(object)
|
18
|
+
@original_object = object
|
19
|
+
__setobj__(alter_object(object))
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns the underlaying altered object
|
23
|
+
#
|
24
|
+
# @return [Object] the altered object
|
25
|
+
def object
|
26
|
+
__getobj__
|
27
|
+
end
|
28
|
+
|
29
|
+
# Is intended to alter the passed object to change it's interface
|
30
|
+
#
|
31
|
+
# @param [Object] object
|
32
|
+
# @return [Object]
|
33
|
+
def alter_object(object)
|
34
|
+
fail NotImplementedError, "alter_object must be overriden in subclasses!"
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module ElasticAdapter
|
2
|
+
module Decoration
|
3
|
+
# Used to decorate responses from the elasticsearch get api or
|
4
|
+
# to decorate single hits returned from the elasticsearch
|
5
|
+
# search api
|
6
|
+
#
|
7
|
+
# @see ResponseDecoratorFactory
|
8
|
+
# @see SearchResponse#alter_object
|
9
|
+
class HitDecorator < Decorator
|
10
|
+
# Reduces the interface of a single hit
|
11
|
+
#
|
12
|
+
# @param [Hash] hash
|
13
|
+
# @return [Hash]
|
14
|
+
def alter_object(hash)
|
15
|
+
new_hash = {}
|
16
|
+
new_hash[:id] = hash[:id]
|
17
|
+
hash[:source].each do |key, value|
|
18
|
+
new_hash[key] = value
|
19
|
+
end
|
20
|
+
|
21
|
+
new_hash
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module ElasticAdapter
|
2
|
+
module Decoration
|
3
|
+
# This class is used inside the Response and is used to determin
|
4
|
+
# the decorator for responses returned by elasticsearch
|
5
|
+
#
|
6
|
+
# @see Response#decorate
|
7
|
+
class ResponseDecoratorFactory
|
8
|
+
class << self
|
9
|
+
# Takes a response and returns it with the right decorator
|
10
|
+
# applied
|
11
|
+
#
|
12
|
+
# @param [Hash] response a response returned by elasticsearch
|
13
|
+
# @return [Docorator] a decorated response
|
14
|
+
def decorate(response)
|
15
|
+
if response.key? :acknowledged
|
16
|
+
elsif response.key? :created
|
17
|
+
elsif response.key? :exception
|
18
|
+
elsif response.key? :count
|
19
|
+
return CountResponse.new(response)
|
20
|
+
elsif response.key? :source
|
21
|
+
return HitDecorator.new(response)
|
22
|
+
elsif response.key? :hits
|
23
|
+
return SearchResponse.new(response)
|
24
|
+
elsif response.key? :valid
|
25
|
+
return ValidationResponse.new(response)
|
26
|
+
elsif suggestion?(response)
|
27
|
+
return SuggestionResponse.new(response)
|
28
|
+
end
|
29
|
+
|
30
|
+
response
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
# Checks if the passed response is a response
|
36
|
+
# from the elasticsearch suggest api
|
37
|
+
#
|
38
|
+
# @param [Hash] response
|
39
|
+
# @return [Boolean]
|
40
|
+
def suggestion?(response)
|
41
|
+
second_key = response[response.keys[1]]
|
42
|
+
return false unless second_key.is_a? Array
|
43
|
+
return false if second_key.empty?
|
44
|
+
return false unless second_key.first.is_a? Hash
|
45
|
+
return false unless second_key.first.key? :options
|
46
|
+
return true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module ElasticAdapter
|
2
|
+
module Decoration
|
3
|
+
# Used to decorate responses from the elasticsearch search api
|
4
|
+
#
|
5
|
+
# @attr_reader [Integer] count the total amount of search results
|
6
|
+
class SearchResponse < Decorator
|
7
|
+
|
8
|
+
attr_reader :count
|
9
|
+
|
10
|
+
# Reduces the interface and assigns the @count variable
|
11
|
+
#
|
12
|
+
# @param [Hash] hash
|
13
|
+
# @return [Hash]
|
14
|
+
def alter_object(hash)
|
15
|
+
new_hash = {}
|
16
|
+
new_hash[:count] = hash[:hits][:total]
|
17
|
+
@count = new_hash[:count]
|
18
|
+
new_hash[:hits] = []
|
19
|
+
|
20
|
+
hash[:hits][:hits].each do |hit|
|
21
|
+
new_hash[:hits] << HitDecorator.new(hit)
|
22
|
+
end
|
23
|
+
|
24
|
+
new_hash
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module ElasticAdapter
|
2
|
+
module Decoration
|
3
|
+
# Used to decorate responses from the elasticsearch suggestion api
|
4
|
+
# @attr_reader [Integer] count the amount of suggestions
|
5
|
+
class SuggestionResponse < Decorator
|
6
|
+
|
7
|
+
attr_reader :count
|
8
|
+
|
9
|
+
# Builds a Hash with a smaller interface from the
|
10
|
+
# decorated response
|
11
|
+
#
|
12
|
+
# @param [Hash] hash
|
13
|
+
# @return [Hash]
|
14
|
+
def alter_object(hash)
|
15
|
+
new_hash = {}
|
16
|
+
new_hash[:options] = hash[hash.keys[1]].first[:options]
|
17
|
+
new_hash
|
18
|
+
end
|
19
|
+
|
20
|
+
def count
|
21
|
+
@count ||= self[:options].length
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ElasticAdapter
|
2
|
+
module Decoration
|
3
|
+
# Used to decorate responses from the elasticseach suggest api.
|
4
|
+
# Delegates to a Boolean
|
5
|
+
class ValidationResponse < Decorator
|
6
|
+
|
7
|
+
# Returns the validation status from the original hash
|
8
|
+
#
|
9
|
+
# @param [Hash] hash
|
10
|
+
# @return [Hash]
|
11
|
+
def alter_object(hash)
|
12
|
+
hash[:valid]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ElasticAdapter
|
2
|
+
# This class is intended to hold information about
|
3
|
+
# a document in an elasticsearch index
|
4
|
+
#
|
5
|
+
# @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping.html Elasticsearch Mappings
|
6
|
+
#
|
7
|
+
# @attr_reader [String] name the name of the document
|
8
|
+
# @attr_reader [Hash] mappings the mappings for the document
|
9
|
+
class DocumentType
|
10
|
+
|
11
|
+
attr_reader :name, :mappings
|
12
|
+
|
13
|
+
# @param [String] name
|
14
|
+
# @param [Hash] mappings
|
15
|
+
def initialize(name, mappings)
|
16
|
+
@name = name
|
17
|
+
@mappings = mappings
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module ElasticAdapter
|
2
|
+
# This class encapsulates the access to an elasticsearch index
|
3
|
+
class Index
|
4
|
+
attr_reader :name, :settings, :document_type, :url, :log, :client
|
5
|
+
|
6
|
+
def initialize(params)
|
7
|
+
@name = params.fetch(:name)
|
8
|
+
@settings = params.fetch(:settings)
|
9
|
+
@document_type = params.fetch(:document_type)
|
10
|
+
@url = params.fetch(:url)
|
11
|
+
@log = params.fetch(:log)
|
12
|
+
@client = params.fetch(:client, Elasticsearch::Client.new(url: url, log: log))
|
13
|
+
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def create_index
|
18
|
+
handle_api_call do
|
19
|
+
client.indices.create(
|
20
|
+
index: name,
|
21
|
+
body: {
|
22
|
+
mappings: document_type.mappings,
|
23
|
+
settings: settings
|
24
|
+
}
|
25
|
+
)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def delete_index
|
30
|
+
handle_api_call do
|
31
|
+
client.indices.delete index: name
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def count(query = {query:{match_all: {}}})
|
36
|
+
handle_api_call do
|
37
|
+
client.count index: name, body: query
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def index(document)
|
42
|
+
doc = document.to_hash.merge({})
|
43
|
+
|
44
|
+
params = {
|
45
|
+
index: name,
|
46
|
+
id: doc.delete(:id),
|
47
|
+
type: document_type.name,
|
48
|
+
body: doc
|
49
|
+
}
|
50
|
+
|
51
|
+
response = handle_api_call do
|
52
|
+
client.index(params)
|
53
|
+
end
|
54
|
+
|
55
|
+
response
|
56
|
+
end
|
57
|
+
|
58
|
+
def get(id)
|
59
|
+
handle_api_call do
|
60
|
+
client.get(
|
61
|
+
index: name,
|
62
|
+
type: document_type.name,
|
63
|
+
id: id
|
64
|
+
)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def search(query)
|
69
|
+
handle_api_call do
|
70
|
+
client.search(
|
71
|
+
index: name,
|
72
|
+
body: query
|
73
|
+
)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def suggest(query)
|
78
|
+
handle_api_call do
|
79
|
+
client.suggest(
|
80
|
+
index: name,
|
81
|
+
body: query
|
82
|
+
)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def validate(query)
|
87
|
+
handle_api_call do
|
88
|
+
client.indices.validate_query(
|
89
|
+
index: name,
|
90
|
+
explain: true,
|
91
|
+
body: query
|
92
|
+
)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def handle_api_call
|
99
|
+
begin
|
100
|
+
Response.new(yield).decorate
|
101
|
+
rescue Elasticsearch::Transport::Transport::Error => e
|
102
|
+
Response.new(
|
103
|
+
exception: e
|
104
|
+
)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module ElasticAdapter
|
2
|
+
# Serves to wrap the responses from elasticsearch
|
3
|
+
class Response < ::ElasticAdapter::Decoration::Decorator
|
4
|
+
|
5
|
+
# Checks if the operation was successfull
|
6
|
+
#
|
7
|
+
# @return [Boolean]
|
8
|
+
def success?
|
9
|
+
!failure?
|
10
|
+
end
|
11
|
+
|
12
|
+
# Checks if the operation failed
|
13
|
+
#
|
14
|
+
# @return [Boolean]
|
15
|
+
def failure?
|
16
|
+
key?(:exception)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Decorates the response with the right decorator
|
20
|
+
#
|
21
|
+
# @return [Decorator] returns the decorated response
|
22
|
+
def decorate
|
23
|
+
Decoration::ResponseDecoratorFactory.decorate(self)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# Sanitizes a nested hash. It removes leading underscores
|
29
|
+
# from keys and turns them into symbols. This methods gets
|
30
|
+
# overridden by other response decorators.
|
31
|
+
#
|
32
|
+
# @param [Hash] hash
|
33
|
+
# @return [Hash]
|
34
|
+
def alter_object(object)
|
35
|
+
object.inject({}) do |result, (key, value)|
|
36
|
+
new_value = nil
|
37
|
+
|
38
|
+
case value
|
39
|
+
when Hash
|
40
|
+
new_value = alter_object(value)
|
41
|
+
when Array
|
42
|
+
new_value = value.map { |i| alter_object(i) }
|
43
|
+
else
|
44
|
+
new_value = value
|
45
|
+
end
|
46
|
+
|
47
|
+
result[remove_leading_underscore(key).to_sym] = new_value
|
48
|
+
|
49
|
+
result
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def remove_leading_underscore(string)
|
54
|
+
/^_?(.*)$/.match(string)[1]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "elasticsearch"
|
2
|
+
|
3
|
+
require "elastic_adapter/version"
|
4
|
+
require "elastic_adapter/document_type"
|
5
|
+
require "elastic_adapter/decoration/decorator"
|
6
|
+
require "elastic_adapter/decoration/hit_decorator"
|
7
|
+
require "elastic_adapter/decoration/count_response"
|
8
|
+
require "elastic_adapter/decoration/validation_response"
|
9
|
+
require "elastic_adapter/decoration/suggestion_response"
|
10
|
+
require "elastic_adapter/decoration/search_response"
|
11
|
+
require "elastic_adapter/decoration/response_decorator_factory"
|
12
|
+
require "elastic_adapter/response"
|
13
|
+
require "elastic_adapter/index"
|
14
|
+
|
15
|
+
begin
|
16
|
+
require "pry"
|
17
|
+
rescue LoadError
|
18
|
+
end
|
19
|
+
|
20
|
+
module ElasticAdapter
|
21
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: http://localhost:9200/test_index/_count
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: '{"query":{"match_all":{}}}'
|
9
|
+
headers:
|
10
|
+
User-Agent:
|
11
|
+
- Faraday v0.9.1
|
12
|
+
Accept-Encoding:
|
13
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
14
|
+
Accept:
|
15
|
+
- "*/*"
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 200
|
19
|
+
message: OK
|
20
|
+
headers:
|
21
|
+
Content-Type:
|
22
|
+
- application/json; charset=UTF-8
|
23
|
+
Content-Length:
|
24
|
+
- '59'
|
25
|
+
body:
|
26
|
+
encoding: UTF-8
|
27
|
+
string: '{"count":0,"_shards":{"total":5,"successful":5,"failed":0}}'
|
28
|
+
http_version:
|
29
|
+
recorded_at: Thu, 05 Feb 2015 21:07:02 GMT
|
30
|
+
recorded_with: VCR 2.9.3
|
data/spec/cassettes/ElasticAdapter_Index/_count/empty_index/returs_the_amount_of_all_documents.yml
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: http://localhost:9200/test_index/_count
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: '{"query":{"match_all":{}}}'
|
9
|
+
headers:
|
10
|
+
User-Agent:
|
11
|
+
- Faraday v0.9.1
|
12
|
+
Accept-Encoding:
|
13
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
14
|
+
Accept:
|
15
|
+
- "*/*"
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 200
|
19
|
+
message: OK
|
20
|
+
headers:
|
21
|
+
Content-Type:
|
22
|
+
- application/json; charset=UTF-8
|
23
|
+
Content-Length:
|
24
|
+
- '59'
|
25
|
+
body:
|
26
|
+
encoding: UTF-8
|
27
|
+
string: '{"count":0,"_shards":{"total":5,"successful":5,"failed":0}}'
|
28
|
+
http_version:
|
29
|
+
recorded_at: Thu, 05 Feb 2015 19:30:14 GMT
|
30
|
+
recorded_with: VCR 2.9.3
|
@@ -0,0 +1,30 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: http://localhost:9200/test_index/_count
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: '{"query":{"match_all":{}}}'
|
9
|
+
headers:
|
10
|
+
User-Agent:
|
11
|
+
- Faraday v0.9.1
|
12
|
+
Accept-Encoding:
|
13
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
14
|
+
Accept:
|
15
|
+
- "*/*"
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 200
|
19
|
+
message: OK
|
20
|
+
headers:
|
21
|
+
Content-Type:
|
22
|
+
- application/json; charset=UTF-8
|
23
|
+
Content-Length:
|
24
|
+
- '59'
|
25
|
+
body:
|
26
|
+
encoding: UTF-8
|
27
|
+
string: '{"count":1,"_shards":{"total":5,"successful":5,"failed":0}}'
|
28
|
+
http_version:
|
29
|
+
recorded_at: Thu, 05 Feb 2015 21:05:04 GMT
|
30
|
+
recorded_with: VCR 2.9.3
|