elastic_adapter 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|