gom-elasticsearch-adapter 0.1.0
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.
- data/LICENSE +20 -0
- data/README.rdoc +4 -0
- data/Rakefile +48 -0
- data/lib/gom/elasticsearch-adapter.rb +5 -0
- data/lib/gom/storage.rb +6 -0
- data/lib/gom/storage/elastic_search.rb +9 -0
- data/lib/gom/storage/elastic_search/adapter.rb +94 -0
- data/lib/gom/storage/elastic_search/collection.rb +6 -0
- data/lib/gom/storage/elastic_search/collection/fetcher.rb +16 -0
- data/lib/gom/storage/elastic_search/couchdb.rb +6 -0
- data/lib/gom/storage/elastic_search/couchdb/river.rb +56 -0
- data/lib/gom/storage/elastic_search/draft.rb +6 -0
- data/lib/gom/storage/elastic_search/draft/builder.rb +56 -0
- data/spec/acceptance/adapter_spec.rb +7 -0
- data/spec/helper.rb +9 -0
- data/spec/storage_configuration.rb +27 -0
- metadata +113 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Philipp Brüll
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
gem 'rspec'
|
3
|
+
gem 'reek'
|
4
|
+
require 'rspec'
|
5
|
+
require 'rake/rdoctask'
|
6
|
+
require 'rspec/core/rake_task'
|
7
|
+
require 'reek/rake/task'
|
8
|
+
|
9
|
+
task :default => :spec
|
10
|
+
|
11
|
+
namespace :gem do
|
12
|
+
|
13
|
+
desc "Builds the gem"
|
14
|
+
task :build do
|
15
|
+
system "gem build *.gemspec && mkdir -p pkg/ && mv *.gem pkg/"
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Builds and installs the gem"
|
19
|
+
task :install => :build do
|
20
|
+
system "gem install pkg/"
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
Reek::Rake::Task.new do |task|
|
26
|
+
task.fail_on_error = true
|
27
|
+
end
|
28
|
+
|
29
|
+
desc "Generate the rdoc"
|
30
|
+
Rake::RDocTask.new do |rdoc|
|
31
|
+
rdoc.rdoc_files.add [ "README.rdoc", "lib/**/*.rb" ]
|
32
|
+
rdoc.main = "README.rdoc"
|
33
|
+
rdoc.title = ""
|
34
|
+
end
|
35
|
+
|
36
|
+
desc "Run all specs in spec directory"
|
37
|
+
RSpec::Core::RakeTask.new do |task|
|
38
|
+
task.pattern = "spec/lib/**/*_spec.rb"
|
39
|
+
end
|
40
|
+
|
41
|
+
namespace :spec do
|
42
|
+
|
43
|
+
desc "Run all integration specs in spec/acceptance directory"
|
44
|
+
RSpec::Core::RakeTask.new(:acceptance) do |task|
|
45
|
+
task.pattern = "spec/acceptance/**/*_spec.rb"
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
data/lib/gom/storage.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
|
2
|
+
module GOM::Storage::ElasticSearch
|
3
|
+
|
4
|
+
autoload :Adapter, File.join(File.dirname(__FILE__), "elastic_search", "adapter")
|
5
|
+
autoload :Collection, File.join(File.dirname(__FILE__), "elastic_search", "collection")
|
6
|
+
autoload :CouchDB, File.join(File.dirname(__FILE__), "elastic_search", "couchdb")
|
7
|
+
autoload :Draft, File.join(File.dirname(__FILE__), "elastic_search", "draft")
|
8
|
+
|
9
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'tire'
|
2
|
+
|
3
|
+
# The ElasticSearch storage adapter.
|
4
|
+
class GOM::Storage::ElasticSearch::Adapter < GOM::Storage::Adapter
|
5
|
+
|
6
|
+
attr_reader :storage_configuration
|
7
|
+
|
8
|
+
def setup
|
9
|
+
setup_connection
|
10
|
+
setup_index
|
11
|
+
assign_storage
|
12
|
+
setup_river
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
def fetch(id)
|
20
|
+
storage_adapter.fetch id
|
21
|
+
end
|
22
|
+
|
23
|
+
def store(draft)
|
24
|
+
storage_adapter.store draft
|
25
|
+
end
|
26
|
+
|
27
|
+
def remove(id)
|
28
|
+
storage_adapter.remove id
|
29
|
+
end
|
30
|
+
|
31
|
+
def collection(name, options = { })
|
32
|
+
view = configuration.views[name.to_sym]
|
33
|
+
raise ArgumentError, "the given view #{name} isn't defined!'" unless view
|
34
|
+
|
35
|
+
query_string = build_query view.class_name, options[:query]
|
36
|
+
search = Tire.search @index_name do
|
37
|
+
query { string query_string }
|
38
|
+
end
|
39
|
+
|
40
|
+
GOM::Object::Collection.new GOM::Storage::ElasticSearch::Collection::Fetcher.new(search.results), configuration.name
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def storage_adapter
|
46
|
+
storage_configuration.adapter
|
47
|
+
end
|
48
|
+
|
49
|
+
def setup_connection
|
50
|
+
@host, @port = *configuration.values_at(:host, :port)
|
51
|
+
@host ||= "localhost"
|
52
|
+
@port ||= 9200
|
53
|
+
|
54
|
+
# Tire.configure { url "http://#{@host}:#{@port}" }
|
55
|
+
end
|
56
|
+
|
57
|
+
def setup_index
|
58
|
+
@index_name, delete_index_if_exists, create_index_if_missing =
|
59
|
+
*configuration.values_at(:index_name, :delete_index_if_exists, :create_index_if_missing)
|
60
|
+
|
61
|
+
Tire.index @index_name do
|
62
|
+
delete if delete_index_if_exists && exists?
|
63
|
+
create if create_index_if_missing && !exists?
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def assign_storage
|
68
|
+
assign_to_storage = configuration[:assign_to_storage]
|
69
|
+
|
70
|
+
@storage_configuration = GOM::Storage::Configuration[assign_to_storage]
|
71
|
+
raise ArgumentError, "the specified storage #{assign_to_storage} doesn't exists" unless @storage_configuration
|
72
|
+
end
|
73
|
+
|
74
|
+
def setup_river
|
75
|
+
delete_river_if_exists, create_river_if_missing =
|
76
|
+
*configuration.values_at(:delete_river_if_exists, :create_river_if_missing)
|
77
|
+
|
78
|
+
river = GOM::Storage::ElasticSearch::CouchDB::River.new :couch_db => storage_configuration,
|
79
|
+
:elastic_search => {
|
80
|
+
:host => @host,
|
81
|
+
:port => @port,
|
82
|
+
:index_name => @index_name
|
83
|
+
}
|
84
|
+
|
85
|
+
river.delete_if_exists if delete_river_if_exists
|
86
|
+
river.create_if_missing if create_river_if_missing
|
87
|
+
end
|
88
|
+
|
89
|
+
def build_query(model_class, query)
|
90
|
+
terms = [ model_class ].flatten.compact.map{ |klass| "model_class:\"#{klass}\"" }
|
91
|
+
"(#{terms.join(" OR ")})" + (query && query != "" ? " AND #{query}" : "")
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
class GOM::Storage::ElasticSearch::Collection::Fetcher
|
3
|
+
|
4
|
+
def initialize(results)
|
5
|
+
@results = results
|
6
|
+
end
|
7
|
+
|
8
|
+
def drafts
|
9
|
+
drafts = [ ]
|
10
|
+
@results.each do |item|
|
11
|
+
drafts << GOM::Storage::ElasticSearch::Draft::Builder.new(item).draft
|
12
|
+
end
|
13
|
+
drafts
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'transport'
|
2
|
+
|
3
|
+
class GOM::Storage::ElasticSearch::CouchDB::River
|
4
|
+
|
5
|
+
def initialize(options)
|
6
|
+
@couch_db = options[:couch_db]
|
7
|
+
@elastic_search = options[:elastic_search]
|
8
|
+
end
|
9
|
+
|
10
|
+
def create
|
11
|
+
Transport::JSON.request :put, "#{elastic_search_base_url}/_river/#{@elastic_search[:index_name]}/_meta",
|
12
|
+
:body => {
|
13
|
+
:type => "couchdb",
|
14
|
+
:couchdb => {
|
15
|
+
:host => @couch_db[:host],
|
16
|
+
:port => @couch_db[:port],
|
17
|
+
:db => @couch_db[:database],
|
18
|
+
:user => @couch_db[:username],
|
19
|
+
:password => @couch_db[:password]
|
20
|
+
},
|
21
|
+
:index => {
|
22
|
+
:index => @elastic_search[:index_name],
|
23
|
+
:type => @elastic_search[:index_name],
|
24
|
+
:bulk_size => "100",
|
25
|
+
:bulk_timeout => "10ms"
|
26
|
+
}
|
27
|
+
},
|
28
|
+
:expected_status_code => [ 200, 201 ]
|
29
|
+
end
|
30
|
+
|
31
|
+
def create_if_missing
|
32
|
+
create unless exists?
|
33
|
+
end
|
34
|
+
|
35
|
+
def delete
|
36
|
+
Transport::JSON.request :delete, "#{elastic_search_base_url}/_river/#{@elastic_search[:index_name]}", :expected_status_code => 200
|
37
|
+
end
|
38
|
+
|
39
|
+
def delete_if_exists
|
40
|
+
delete if exists?
|
41
|
+
end
|
42
|
+
|
43
|
+
def exists?
|
44
|
+
Transport::JSON.request :get, "#{elastic_search_base_url}/_river/#{@elastic_search[:index_name]}/_meta", :expected_status_code => 200
|
45
|
+
true
|
46
|
+
rescue Transport::UnexpectedStatusCodeError
|
47
|
+
false
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def elastic_search_base_url
|
53
|
+
"http://#{@elastic_search[:host]}:#{@elastic_search[:port]}"
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
|
2
|
+
# Builds a draft out of a search result item document.
|
3
|
+
class GOM::Storage::ElasticSearch::Draft::Builder
|
4
|
+
|
5
|
+
def initialize(item)
|
6
|
+
@item = item.to_hash
|
7
|
+
end
|
8
|
+
|
9
|
+
def draft
|
10
|
+
initialize_draft
|
11
|
+
set_object_id
|
12
|
+
set_class
|
13
|
+
set_properties_and_relations
|
14
|
+
@draft
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def initialize_draft
|
20
|
+
@draft = GOM::Object::Draft.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def set_object_id
|
24
|
+
@draft.object_id = @item[:_id]
|
25
|
+
end
|
26
|
+
|
27
|
+
def set_class
|
28
|
+
@draft.class_name = @item[:model_class]
|
29
|
+
end
|
30
|
+
|
31
|
+
def set_properties_and_relations
|
32
|
+
@item.each do |key, value|
|
33
|
+
set_property key.to_s, value if property_key?(key)
|
34
|
+
set_relation key.to_s, value if relation_key?(key)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def set_property(key, value)
|
39
|
+
@draft.properties[key.to_sym] = value
|
40
|
+
end
|
41
|
+
|
42
|
+
def set_relation(key, value)
|
43
|
+
name = key.sub /_id$/, ""
|
44
|
+
id = GOM::Object::Id.new value
|
45
|
+
@draft.relations[name.to_sym] = GOM::Object::Proxy.new id
|
46
|
+
end
|
47
|
+
|
48
|
+
def property_key?(key)
|
49
|
+
!relation_key?(key) && ![ "_id", "_rev", "model_class" ].include?(key)
|
50
|
+
end
|
51
|
+
|
52
|
+
def relation_key?(key)
|
53
|
+
!!(key =~ /.+_id$/)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
data/spec/helper.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
gem 'rspec', '>= 2'
|
3
|
+
require 'rspec'
|
4
|
+
|
5
|
+
require 'gom/spec'
|
6
|
+
require 'gom/couchdb-adapter'
|
7
|
+
|
8
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "lib", "gom", "elasticsearch-adapter"))
|
9
|
+
require File.join(File.dirname(__FILE__), "storage_configuration")
|
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
GOM::Storage.configure {
|
3
|
+
storage {
|
4
|
+
name :test_couchdb_storage
|
5
|
+
adapter :couchdb
|
6
|
+
username "test"
|
7
|
+
password "test"
|
8
|
+
database "test"
|
9
|
+
delete_database_if_exists false
|
10
|
+
create_database_if_missing true
|
11
|
+
}
|
12
|
+
storage {
|
13
|
+
name :test_storage
|
14
|
+
adapter :elasticsearch
|
15
|
+
index_name "test"
|
16
|
+
delete_index_if_exists false
|
17
|
+
create_index_if_missing true
|
18
|
+
delete_river_if_exists false
|
19
|
+
create_river_if_missing true
|
20
|
+
assign_to_storage :test_couchdb_storage
|
21
|
+
view {
|
22
|
+
name :test_search_view
|
23
|
+
kind :search
|
24
|
+
model_class GOM::Spec::Object
|
25
|
+
}
|
26
|
+
}
|
27
|
+
}
|
metadata
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gom-elasticsearch-adapter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Philipp Brüll
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-10-19 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: gom
|
16
|
+
requirement: &18084220 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.5.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *18084220
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: gom-couchdb-adapter
|
27
|
+
requirement: &18083500 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.5.0
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *18083500
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rspec
|
38
|
+
requirement: &18082780 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '2'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *18082780
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: reek
|
49
|
+
requirement: &18082120 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.2'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *18082120
|
58
|
+
description: ElasticSearch adapter for the General Object Mapper. Current versions
|
59
|
+
of ElasticSearch are supported.
|
60
|
+
email: b.phifty@gmail.com
|
61
|
+
executables: []
|
62
|
+
extensions: []
|
63
|
+
extra_rdoc_files:
|
64
|
+
- README.rdoc
|
65
|
+
files:
|
66
|
+
- README.rdoc
|
67
|
+
- LICENSE
|
68
|
+
- Rakefile
|
69
|
+
- lib/gom/elasticsearch-adapter.rb
|
70
|
+
- lib/gom/storage/elastic_search.rb
|
71
|
+
- lib/gom/storage/elastic_search/collection/fetcher.rb
|
72
|
+
- lib/gom/storage/elastic_search/couchdb/river.rb
|
73
|
+
- lib/gom/storage/elastic_search/adapter.rb
|
74
|
+
- lib/gom/storage/elastic_search/draft/builder.rb
|
75
|
+
- lib/gom/storage/elastic_search/draft.rb
|
76
|
+
- lib/gom/storage/elastic_search/couchdb.rb
|
77
|
+
- lib/gom/storage/elastic_search/collection.rb
|
78
|
+
- lib/gom/storage.rb
|
79
|
+
- spec/helper.rb
|
80
|
+
- spec/storage_configuration.rb
|
81
|
+
- spec/acceptance/adapter_spec.rb
|
82
|
+
homepage: http://github.com/phifty/gom-elasticsearch-adapter
|
83
|
+
licenses: []
|
84
|
+
post_install_message:
|
85
|
+
rdoc_options: []
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
segments:
|
95
|
+
- 0
|
96
|
+
hash: 41961588728074855
|
97
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ! '>='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
segments:
|
104
|
+
- 0
|
105
|
+
hash: 41961588728074855
|
106
|
+
requirements: []
|
107
|
+
rubyforge_project: gom-elasticsearch-adapter
|
108
|
+
rubygems_version: 1.8.10
|
109
|
+
signing_key:
|
110
|
+
specification_version: 3
|
111
|
+
summary: ElasticSearch adapter for the General Object Mapper.
|
112
|
+
test_files:
|
113
|
+
- spec/acceptance/adapter_spec.rb
|