elasticsearch-persistence 0.0.0 → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/LICENSE.txt +10 -19
- data/README.md +432 -14
- data/Rakefile +56 -0
- data/elasticsearch-persistence.gemspec +45 -17
- data/examples/sinatra/.gitignore +7 -0
- data/examples/sinatra/Gemfile +28 -0
- data/examples/sinatra/README.markdown +36 -0
- data/examples/sinatra/application.rb +238 -0
- data/examples/sinatra/config.ru +7 -0
- data/examples/sinatra/test.rb +118 -0
- data/lib/elasticsearch/persistence.rb +88 -2
- data/lib/elasticsearch/persistence/client.rb +51 -0
- data/lib/elasticsearch/persistence/repository.rb +75 -0
- data/lib/elasticsearch/persistence/repository/class.rb +71 -0
- data/lib/elasticsearch/persistence/repository/find.rb +73 -0
- data/lib/elasticsearch/persistence/repository/naming.rb +115 -0
- data/lib/elasticsearch/persistence/repository/response/results.rb +90 -0
- data/lib/elasticsearch/persistence/repository/search.rb +60 -0
- data/lib/elasticsearch/persistence/repository/serialize.rb +31 -0
- data/lib/elasticsearch/persistence/repository/store.rb +95 -0
- data/lib/elasticsearch/persistence/version.rb +1 -1
- data/test/integration/repository/custom_class_test.rb +85 -0
- data/test/integration/repository/customized_class_test.rb +82 -0
- data/test/integration/repository/default_class_test.rb +108 -0
- data/test/integration/repository/virtus_model_test.rb +114 -0
- data/test/test_helper.rb +46 -0
- data/test/unit/persistence_test.rb +32 -0
- data/test/unit/repository_class_test.rb +51 -0
- data/test/unit/repository_client_test.rb +32 -0
- data/test/unit/repository_find_test.rb +375 -0
- data/test/unit/repository_indexing_test.rb +37 -0
- data/test/unit/repository_module_test.rb +144 -0
- data/test/unit/repository_naming_test.rb +146 -0
- data/test/unit/repository_response_results_test.rb +98 -0
- data/test/unit/repository_search_test.rb +97 -0
- data/test/unit/repository_serialize_test.rb +57 -0
- data/test/unit/repository_store_test.rb +287 -0
- metadata +288 -20
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Elasticsearch
|
4
|
+
module Persistence
|
5
|
+
class RepositoryCustomizedClassIntegrationTest < Elasticsearch::Test::IntegrationTestCase
|
6
|
+
|
7
|
+
module ::My
|
8
|
+
class Note
|
9
|
+
attr_reader :attributes
|
10
|
+
|
11
|
+
def initialize(attributes={})
|
12
|
+
@attributes = attributes
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_hash
|
16
|
+
@attributes
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "A custom repository class" do
|
22
|
+
setup do
|
23
|
+
@repository = Elasticsearch::Persistence::Repository.new do
|
24
|
+
index 'my_notes'
|
25
|
+
type 'my_note'
|
26
|
+
klass My::Note
|
27
|
+
|
28
|
+
settings number_of_shards: 1 do
|
29
|
+
mapping do
|
30
|
+
indexes :title, analyzer: 'snowball'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
create_index!
|
35
|
+
end
|
36
|
+
|
37
|
+
@repository.client.cluster.health wait_for_status: 'yellow'
|
38
|
+
end
|
39
|
+
|
40
|
+
should "save the object under a correct index and type" do
|
41
|
+
@repository.save My::Note.new(id: '1', title: 'Test')
|
42
|
+
|
43
|
+
assert_instance_of My::Note, @repository.find(1)
|
44
|
+
assert_not_nil Elasticsearch::Persistence.client.get index: 'my_notes', type: 'my_note', id: '1'
|
45
|
+
end
|
46
|
+
|
47
|
+
should "update the document" do
|
48
|
+
@repository.save Note.new(id: 1, title: 'Test')
|
49
|
+
|
50
|
+
@repository.update 1, doc: { title: 'UPDATED' }
|
51
|
+
assert_equal 'UPDATED', @repository.find(1).attributes['title']
|
52
|
+
end
|
53
|
+
|
54
|
+
should "update the document with a script" do
|
55
|
+
@repository.save Note.new(id: 1, title: 'Test')
|
56
|
+
|
57
|
+
@repository.update 1, script: 'ctx._source.title = "UPDATED"'
|
58
|
+
assert_equal 'UPDATED', @repository.find(1).attributes['title']
|
59
|
+
end
|
60
|
+
|
61
|
+
should "delete the object" do
|
62
|
+
note = My::Note.new id: 1, title: 'Test'
|
63
|
+
@repository.save note
|
64
|
+
|
65
|
+
assert_not_nil @repository.find(1)
|
66
|
+
|
67
|
+
@repository.delete(note)
|
68
|
+
assert_raise(Elasticsearch::Persistence::Repository::DocumentNotFound) { @repository.find(1) }
|
69
|
+
end
|
70
|
+
|
71
|
+
should "create the index with correct mapping" do
|
72
|
+
note = My::Note.new title: 'Testing'
|
73
|
+
@repository.save note, refresh: true
|
74
|
+
|
75
|
+
results = @repository.search query: { match: { title: 'Test' } }
|
76
|
+
assert_equal 'Testing', results.first.attributes['title']
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Elasticsearch
|
4
|
+
module Persistence
|
5
|
+
class RepositoryDefaultClassIntegrationTest < Elasticsearch::Test::IntegrationTestCase
|
6
|
+
|
7
|
+
class ::Note
|
8
|
+
attr_reader :attributes
|
9
|
+
|
10
|
+
def initialize(attributes={})
|
11
|
+
@attributes = attributes
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_hash
|
15
|
+
@attributes
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context "The default repository class" do
|
20
|
+
setup do
|
21
|
+
@repository = Elasticsearch::Persistence::Repository.new
|
22
|
+
@repository.client.cluster.health wait_for_status: 'yellow'
|
23
|
+
end
|
24
|
+
|
25
|
+
should "save the object with a custom ID and find it" do
|
26
|
+
@repository.save Note.new(id: '1', title: 'Test')
|
27
|
+
|
28
|
+
assert_equal 'Test', @repository.find(1).attributes['title']
|
29
|
+
end
|
30
|
+
|
31
|
+
should "save the object with an auto-generated ID and find it" do
|
32
|
+
response = @repository.save Note.new(title: 'Test')
|
33
|
+
|
34
|
+
assert_equal 'Test', @repository.find(response['_id']).attributes['title']
|
35
|
+
end
|
36
|
+
|
37
|
+
should "update the document" do
|
38
|
+
@repository.save Note.new(id: 1, title: 'Test')
|
39
|
+
|
40
|
+
@repository.update 1, type: 'note', doc: { title: 'UPDATED' }
|
41
|
+
assert_equal 'UPDATED', @repository.find(1).attributes['title']
|
42
|
+
end
|
43
|
+
|
44
|
+
should "update the document with a script" do
|
45
|
+
@repository.save Note.new(id: 1, title: 'Test')
|
46
|
+
|
47
|
+
@repository.update 1, type: 'note', script: 'ctx._source.title = "UPDATED"'
|
48
|
+
assert_equal 'UPDATED', @repository.find(1).attributes['title']
|
49
|
+
end
|
50
|
+
|
51
|
+
should "save the document with an upsert" do
|
52
|
+
@repository.update 1, type: 'note', script: 'ctx._source.clicks += 1', upsert: { clicks: 1 }
|
53
|
+
assert_equal 1, @repository.find(1).attributes['clicks']
|
54
|
+
end
|
55
|
+
|
56
|
+
should "delete an object" do
|
57
|
+
note = Note.new(id: '1', title: 'Test')
|
58
|
+
|
59
|
+
@repository.save(note)
|
60
|
+
assert_not_nil @repository.find(1)
|
61
|
+
@repository.delete(note)
|
62
|
+
assert_raise(Elasticsearch::Persistence::Repository::DocumentNotFound) { @repository.find(1) }
|
63
|
+
end
|
64
|
+
|
65
|
+
should "find multiple objects" do
|
66
|
+
(1..5).each { |i| @repository.save Note.new(id: i, title: "Test #{i}") }
|
67
|
+
|
68
|
+
assert_equal 5, @repository.find(1, 2, 3, 4, 5).size
|
69
|
+
assert_equal 5, @repository.find([1, 2, 3, 4, 5]).size
|
70
|
+
end
|
71
|
+
|
72
|
+
should "pass options to save and find" do
|
73
|
+
note = Note.new(id: '1', title: 'Test')
|
74
|
+
@repository.save note, routing: 'ABC'
|
75
|
+
|
76
|
+
assert_raise Elasticsearch::Persistence::Repository::DocumentNotFound do
|
77
|
+
@repository.find(1, routing: 'DEF')
|
78
|
+
end
|
79
|
+
|
80
|
+
assert_nothing_raised do
|
81
|
+
note = @repository.find(1, routing: 'ABC')
|
82
|
+
assert_instance_of Note, note
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
should "find notes with full text search" do
|
87
|
+
@repository.save Note.new(title: 'Test')
|
88
|
+
@repository.save Note.new(title: 'Test Test')
|
89
|
+
@repository.save Note.new(title: 'Crust')
|
90
|
+
@repository.client.indices.refresh index: @repository.index_name
|
91
|
+
|
92
|
+
results = @repository.search 'test'
|
93
|
+
assert_equal 2, results.size
|
94
|
+
|
95
|
+
results = @repository.search query: { match: { title: 'Test' } }
|
96
|
+
assert_equal 2, results.size
|
97
|
+
end
|
98
|
+
|
99
|
+
should "save and find a plain hash" do
|
100
|
+
@repository.save id: 1, title: 'Hash'
|
101
|
+
result = @repository.find(1)
|
102
|
+
assert_equal 'Hash', result['_source']['title']
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'virtus'
|
4
|
+
|
5
|
+
module Elasticsearch
|
6
|
+
module Persistence
|
7
|
+
class RepositoryWithVirtusIntegrationTest < Elasticsearch::Test::IntegrationTestCase
|
8
|
+
|
9
|
+
class ::Page
|
10
|
+
include Virtus.model
|
11
|
+
|
12
|
+
attribute :id, String, writer: :private
|
13
|
+
attribute :title, String
|
14
|
+
attribute :views, Integer, default: 0
|
15
|
+
attribute :published, Boolean, default: false
|
16
|
+
attribute :slug, String, default: lambda { |page, attr| page.title.downcase.gsub(' ', '-') }
|
17
|
+
|
18
|
+
def set_id(id)
|
19
|
+
self.id = id
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "The repository with a Virtus model" do
|
24
|
+
setup do
|
25
|
+
@repository = Elasticsearch::Persistence::Repository.new do
|
26
|
+
index :pages
|
27
|
+
klass Page
|
28
|
+
|
29
|
+
def deserialize(document)
|
30
|
+
page = klass.new document['_source']
|
31
|
+
page.set_id document['_id']
|
32
|
+
page
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
should "save and find the object" do
|
38
|
+
page = Page.new title: 'Test Page'
|
39
|
+
|
40
|
+
response = @repository.save page
|
41
|
+
id = response['_id']
|
42
|
+
|
43
|
+
result = @repository.find(id)
|
44
|
+
|
45
|
+
assert_instance_of Page, result
|
46
|
+
assert_equal 'Test Page', result.title
|
47
|
+
assert_equal 0, result.views
|
48
|
+
|
49
|
+
assert_not_nil Elasticsearch::Persistence.client.get index: 'pages',
|
50
|
+
type: 'page',
|
51
|
+
id: id
|
52
|
+
end
|
53
|
+
|
54
|
+
should "update the object with a partial document" do
|
55
|
+
response = @repository.save Page.new(title: 'Test')
|
56
|
+
id = response['_id']
|
57
|
+
|
58
|
+
page = @repository.find(id)
|
59
|
+
|
60
|
+
assert_equal 'Test', page.title
|
61
|
+
|
62
|
+
@repository.update page.id, doc: { title: 'UPDATE' }
|
63
|
+
|
64
|
+
page = @repository.find(id)
|
65
|
+
assert_equal 'UPDATE', page.title
|
66
|
+
end
|
67
|
+
|
68
|
+
should "update the object with a Hash" do
|
69
|
+
response = @repository.save Page.new(title: 'Test')
|
70
|
+
id = response['_id']
|
71
|
+
|
72
|
+
page = @repository.find(id)
|
73
|
+
|
74
|
+
assert_equal 'Test', page.title
|
75
|
+
|
76
|
+
@repository.update id: page.id, title: 'UPDATE'
|
77
|
+
|
78
|
+
page = @repository.find(id)
|
79
|
+
assert_equal 'UPDATE', page.title
|
80
|
+
end
|
81
|
+
|
82
|
+
should "update the object with a script" do
|
83
|
+
response = @repository.save Page.new(title: 'Test Page')
|
84
|
+
id = response['_id']
|
85
|
+
|
86
|
+
page = @repository.find(id)
|
87
|
+
|
88
|
+
assert_not_nil page.id
|
89
|
+
assert_equal 0, page.views
|
90
|
+
|
91
|
+
@repository.update page.id, script: 'ctx._source.views += 1'
|
92
|
+
|
93
|
+
page = @repository.find(id)
|
94
|
+
assert_equal 1, page.views
|
95
|
+
|
96
|
+
@repository.update id: page.id, script: 'ctx._source.views += 1'
|
97
|
+
|
98
|
+
page = @repository.find(id)
|
99
|
+
assert_equal 2, page.views
|
100
|
+
end
|
101
|
+
|
102
|
+
should "update the object with a script and params" do
|
103
|
+
response = @repository.save Page.new(title: 'Test Page')
|
104
|
+
|
105
|
+
@repository.update id: response['_id'], script: 'ctx._source.views += count', params: { count: 3 }
|
106
|
+
|
107
|
+
page = @repository.find(response['_id'])
|
108
|
+
assert_equal 3, page.views
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
RUBY_1_8 = defined?(RUBY_VERSION) && RUBY_VERSION < '1.9'
|
2
|
+
|
3
|
+
exit(0) if RUBY_1_8
|
4
|
+
|
5
|
+
require 'simplecov' and SimpleCov.start { add_filter "/test|test_/" } if ENV["COVERAGE"]
|
6
|
+
|
7
|
+
# Register `at_exit` handler for integration tests shutdown.
|
8
|
+
# MUST be called before requiring `test/unit`.
|
9
|
+
at_exit { Elasticsearch::Test::IntegrationTestCase.__run_at_exit_hooks } if ENV['SERVER']
|
10
|
+
|
11
|
+
require 'test/unit'
|
12
|
+
require 'shoulda-context'
|
13
|
+
require 'mocha/setup'
|
14
|
+
require 'turn' unless ENV["TM_FILEPATH"] || ENV["NOTURN"] || RUBY_1_8
|
15
|
+
|
16
|
+
require 'ansi'
|
17
|
+
require 'oj'
|
18
|
+
|
19
|
+
require 'elasticsearch/extensions/test/cluster'
|
20
|
+
require 'elasticsearch/extensions/test/startup_shutdown'
|
21
|
+
|
22
|
+
require 'elasticsearch/persistence'
|
23
|
+
|
24
|
+
module Elasticsearch
|
25
|
+
module Test
|
26
|
+
class IntegrationTestCase < ::Test::Unit::TestCase
|
27
|
+
extend Elasticsearch::Extensions::Test::StartupShutdown
|
28
|
+
|
29
|
+
startup { Elasticsearch::Extensions::Test::Cluster.start(nodes: 1) if ENV['SERVER'] and not Elasticsearch::Extensions::Test::Cluster.running? }
|
30
|
+
shutdown { Elasticsearch::Extensions::Test::Cluster.stop if ENV['SERVER'] && started? }
|
31
|
+
context "IntegrationTest" do; should "noop on Ruby 1.8" do; end; end if RUBY_1_8
|
32
|
+
|
33
|
+
def setup
|
34
|
+
tracer = ::Logger.new(STDERR)
|
35
|
+
tracer.formatter = lambda { |s, d, p, m| "#{m.gsub(/^.*$/) { |n| ' ' + n }.ansi(:faint)}\n" }
|
36
|
+
Elasticsearch::Persistence.client = Elasticsearch::Client.new \
|
37
|
+
host: "localhost:#{(ENV['TEST_CLUSTER_PORT'] || 9250)}",
|
38
|
+
tracer: (ENV['QUIET'] ? nil : tracer)
|
39
|
+
end
|
40
|
+
|
41
|
+
def teardown
|
42
|
+
Elasticsearch::Persistence.client.indices.delete index: '_all'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Elasticsearch::Persistence::ModuleTest < Test::Unit::TestCase
|
4
|
+
context "The Persistence module" do
|
5
|
+
|
6
|
+
context "client" do
|
7
|
+
should "have a default client" do
|
8
|
+
client = Elasticsearch::Persistence.client
|
9
|
+
assert_not_nil client
|
10
|
+
assert_instance_of Elasticsearch::Transport::Client, client
|
11
|
+
end
|
12
|
+
|
13
|
+
should "allow to set a client" do
|
14
|
+
begin
|
15
|
+
Elasticsearch::Persistence.client = "Foobar"
|
16
|
+
assert_equal "Foobar", Elasticsearch::Persistence.client
|
17
|
+
ensure
|
18
|
+
Elasticsearch::Persistence.client = nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
should "allow to set a client with DSL" do
|
23
|
+
begin
|
24
|
+
Elasticsearch::Persistence.client "Foobar"
|
25
|
+
assert_equal "Foobar", Elasticsearch::Persistence.client
|
26
|
+
ensure
|
27
|
+
Elasticsearch::Persistence.client = nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Elasticsearch::Persistence::RepositoryClassTest < Test::Unit::TestCase
|
4
|
+
context "The default repository class" do
|
5
|
+
|
6
|
+
context "when initialized" do
|
7
|
+
should "be created from the module" do
|
8
|
+
repository = Elasticsearch::Persistence::Repository.new
|
9
|
+
assert_instance_of Elasticsearch::Persistence::Repository::Class, repository
|
10
|
+
end
|
11
|
+
|
12
|
+
should "store and access the options" do
|
13
|
+
repository = Elasticsearch::Persistence::Repository::Class.new foo: 'bar'
|
14
|
+
assert_equal 'bar', repository.options[:foo]
|
15
|
+
end
|
16
|
+
|
17
|
+
should "instance eval a passed block" do
|
18
|
+
$foo = 100
|
19
|
+
repository = Elasticsearch::Persistence::Repository::Class.new() { $foo += 1 }
|
20
|
+
assert_equal 101, $foo
|
21
|
+
end
|
22
|
+
|
23
|
+
should "call a passed block with self" do
|
24
|
+
foo = 100
|
25
|
+
repository = Elasticsearch::Persistence::Repository::Class.new do |r|
|
26
|
+
assert_instance_of Elasticsearch::Persistence::Repository::Class, r
|
27
|
+
foo += 1
|
28
|
+
end
|
29
|
+
assert_equal 101, foo
|
30
|
+
end
|
31
|
+
|
32
|
+
should "configure the index name based on options" do
|
33
|
+
repository = Elasticsearch::Persistence::Repository::Class.new index: 'foobar'
|
34
|
+
assert_equal 'foobar', repository.index_name
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
should "include the repository methods" do
|
39
|
+
repository = Elasticsearch::Persistence::Repository::Class.new
|
40
|
+
|
41
|
+
%w( index_name document_type klass
|
42
|
+
mappings settings client client=
|
43
|
+
create_index! delete_index! refresh_index!
|
44
|
+
save delete serialize deserialize
|
45
|
+
exists? find search ).each do |method|
|
46
|
+
assert_respond_to repository, method
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Elasticsearch::Persistence::RepositoryClientTest < Test::Unit::TestCase
|
4
|
+
context "The repository client" do
|
5
|
+
setup do
|
6
|
+
@shoulda_subject = Class.new() { include Elasticsearch::Persistence::Repository::Client }.new
|
7
|
+
end
|
8
|
+
|
9
|
+
should "have a default client" do
|
10
|
+
assert_not_nil subject.client
|
11
|
+
assert_instance_of Elasticsearch::Transport::Client, subject.client
|
12
|
+
end
|
13
|
+
|
14
|
+
should "allow to set a client" do
|
15
|
+
begin
|
16
|
+
subject.client = "Foobar"
|
17
|
+
assert_equal "Foobar", subject.client
|
18
|
+
ensure
|
19
|
+
subject.client = nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
should "allow to set the client with DSL" do
|
24
|
+
begin
|
25
|
+
subject.client "Foobar"
|
26
|
+
assert_equal "Foobar", subject.client
|
27
|
+
ensure
|
28
|
+
subject.client = nil
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|