elasticsearch-persistence-queryable 0.1.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/CHANGELOG.md +16 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +13 -0
- data/README.md +678 -0
- data/Rakefile +57 -0
- data/elasticsearch-persistence.gemspec +57 -0
- data/examples/music/album.rb +34 -0
- data/examples/music/artist.rb +50 -0
- data/examples/music/artists/_form.html.erb +8 -0
- data/examples/music/artists/artists_controller.rb +67 -0
- data/examples/music/artists/artists_controller_test.rb +53 -0
- data/examples/music/artists/index.html.erb +57 -0
- data/examples/music/artists/show.html.erb +51 -0
- data/examples/music/assets/application.css +226 -0
- data/examples/music/assets/autocomplete.css +48 -0
- data/examples/music/assets/blank_cover.png +0 -0
- data/examples/music/assets/form.css +113 -0
- data/examples/music/index_manager.rb +60 -0
- data/examples/music/search/index.html.erb +93 -0
- data/examples/music/search/search_controller.rb +41 -0
- data/examples/music/search/search_controller_test.rb +9 -0
- data/examples/music/search/search_helper.rb +15 -0
- data/examples/music/suggester.rb +45 -0
- data/examples/music/template.rb +392 -0
- data/examples/music/vendor/assets/jquery-ui-1.10.4.custom.min.css +7 -0
- data/examples/music/vendor/assets/jquery-ui-1.10.4.custom.min.js +6 -0
- data/examples/notes/.gitignore +7 -0
- data/examples/notes/Gemfile +28 -0
- data/examples/notes/README.markdown +36 -0
- data/examples/notes/application.rb +238 -0
- data/examples/notes/config.ru +7 -0
- data/examples/notes/test.rb +118 -0
- data/lib/elasticsearch/per_thread_registry.rb +53 -0
- data/lib/elasticsearch/persistence/client.rb +51 -0
- data/lib/elasticsearch/persistence/inheritence.rb +9 -0
- data/lib/elasticsearch/persistence/model/base.rb +95 -0
- data/lib/elasticsearch/persistence/model/callbacks.rb +37 -0
- data/lib/elasticsearch/persistence/model/errors.rb +9 -0
- data/lib/elasticsearch/persistence/model/find.rb +155 -0
- data/lib/elasticsearch/persistence/model/gateway_delegation.rb +23 -0
- data/lib/elasticsearch/persistence/model/hash_wrapper.rb +17 -0
- data/lib/elasticsearch/persistence/model/rails.rb +39 -0
- data/lib/elasticsearch/persistence/model/store.rb +271 -0
- data/lib/elasticsearch/persistence/model.rb +148 -0
- data/lib/elasticsearch/persistence/null_relation.rb +56 -0
- data/lib/elasticsearch/persistence/query_cache.rb +68 -0
- data/lib/elasticsearch/persistence/querying.rb +21 -0
- data/lib/elasticsearch/persistence/relation/delegation.rb +130 -0
- data/lib/elasticsearch/persistence/relation/finder_methods.rb +39 -0
- data/lib/elasticsearch/persistence/relation/merger.rb +179 -0
- data/lib/elasticsearch/persistence/relation/query_builder.rb +279 -0
- data/lib/elasticsearch/persistence/relation/query_methods.rb +362 -0
- data/lib/elasticsearch/persistence/relation/search_option_methods.rb +44 -0
- data/lib/elasticsearch/persistence/relation/spawn_methods.rb +61 -0
- data/lib/elasticsearch/persistence/relation.rb +110 -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 +105 -0
- data/lib/elasticsearch/persistence/repository/search.rb +156 -0
- data/lib/elasticsearch/persistence/repository/serialize.rb +31 -0
- data/lib/elasticsearch/persistence/repository/store.rb +94 -0
- data/lib/elasticsearch/persistence/repository.rb +77 -0
- data/lib/elasticsearch/persistence/scoping/default.rb +137 -0
- data/lib/elasticsearch/persistence/scoping/named.rb +70 -0
- data/lib/elasticsearch/persistence/scoping.rb +52 -0
- data/lib/elasticsearch/persistence/version.rb +5 -0
- data/lib/elasticsearch/persistence.rb +157 -0
- data/lib/elasticsearch/rails_compatibility.rb +17 -0
- data/lib/rails/generators/elasticsearch/model/model_generator.rb +21 -0
- data/lib/rails/generators/elasticsearch/model/templates/model.rb.tt +9 -0
- data/lib/rails/generators/elasticsearch_generator.rb +2 -0
- data/lib/rails/instrumentation/railtie.rb +31 -0
- data/lib/rails/instrumentation.rb +10 -0
- data/test/integration/model/model_basic_test.rb +157 -0
- 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 +114 -0
- data/test/integration/repository/virtus_model_test.rb +114 -0
- data/test/test_helper.rb +53 -0
- data/test/unit/model_base_test.rb +48 -0
- data/test/unit/model_find_test.rb +148 -0
- data/test/unit/model_gateway_test.rb +99 -0
- data/test/unit/model_rails_test.rb +88 -0
- data/test/unit/model_store_test.rb +514 -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 +388 -0
- data/test/unit/repository_indexing_test.rb +37 -0
- data/test/unit/repository_module_test.rb +146 -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 +117 -0
- data/test/unit/repository_serialize_test.rb +57 -0
- data/test/unit/repository_store_test.rb +303 -0
- metadata +487 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
module Elasticsearch
|
2
|
+
module Persistence
|
3
|
+
module Instrumentation
|
4
|
+
|
5
|
+
class Railtie < ::Rails::Railtie
|
6
|
+
include ActionView::Helpers::NumberHelper
|
7
|
+
def time_diff(start, finish)
|
8
|
+
begin
|
9
|
+
((finish.to_time - start.to_time) * 1000).to_s(:rounded, precision: 5, strip_insignificant_zeros: true)
|
10
|
+
rescue
|
11
|
+
number_with_precision((finish.to_time - start.to_time) * 1000, precision: 5, strip_insignificant_zeros: true)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
ActiveSupport::Notifications.subscribe 'query.elasticsearch' do |name, start, finish, id, payload|
|
16
|
+
::Rails.logger.debug([" #{payload[:name]}".bright, "(#{time_diff(start,finish)}ms)",payload[:query]].join(" ").color(:yellow))
|
17
|
+
end
|
18
|
+
|
19
|
+
ActiveSupport::Notifications.subscribe 'cache.query.elasticsearch' do |name, start, finish, id, payload|
|
20
|
+
::Rails.logger.debug([" #{payload[:name]}".bright, "CACHE".color(:mediumpurple).bright ,"(#{time_diff(start,finish)}ms)", payload[:query]].join(" ").color(:yellow))
|
21
|
+
end
|
22
|
+
|
23
|
+
initializer 'elasticsearch_persistence.set_defaults' do
|
24
|
+
config.elasticsearch_cache_store = :redis_store
|
25
|
+
config.elasticsearch_expire_cache_in = 15.minutes
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'elasticsearch/persistence/model'
|
4
|
+
|
5
|
+
module Elasticsearch
|
6
|
+
module Persistence
|
7
|
+
class PersistenceModelBasicIntegrationTest < Elasticsearch::Test::IntegrationTestCase
|
8
|
+
|
9
|
+
class ::Person
|
10
|
+
include Elasticsearch::Persistence::Model
|
11
|
+
|
12
|
+
settings index: { number_of_shards: 1 }
|
13
|
+
|
14
|
+
attribute :name, String,
|
15
|
+
mapping: { fields: {
|
16
|
+
name: { type: 'string', analyzer: 'snowball' },
|
17
|
+
raw: { type: 'string', analyzer: 'keyword' }
|
18
|
+
} }
|
19
|
+
|
20
|
+
attribute :birthday, Date
|
21
|
+
attribute :department, String
|
22
|
+
attribute :salary, Integer
|
23
|
+
attribute :admin, Boolean, default: false
|
24
|
+
|
25
|
+
validates :name, presence: true
|
26
|
+
end
|
27
|
+
|
28
|
+
context "A basic persistence model" do
|
29
|
+
setup do
|
30
|
+
Person.create_index! force: true
|
31
|
+
end
|
32
|
+
|
33
|
+
should "save the object with custom ID" do
|
34
|
+
person = Person.new id: 1, name: 'Number One'
|
35
|
+
person.save
|
36
|
+
|
37
|
+
document = Person.find(1)
|
38
|
+
assert_not_nil document
|
39
|
+
assert_equal 'Number One', document.name
|
40
|
+
end
|
41
|
+
|
42
|
+
should "create the object with custom ID" do
|
43
|
+
person = Person.create id: 1, name: 'Number One'
|
44
|
+
|
45
|
+
document = Person.find(1)
|
46
|
+
assert_not_nil document
|
47
|
+
assert_equal 'Number One', document.name
|
48
|
+
end
|
49
|
+
|
50
|
+
should "save and find the object" do
|
51
|
+
person = Person.new name: 'John Smith', birthday: Date.parse('1970-01-01')
|
52
|
+
person.save
|
53
|
+
|
54
|
+
assert_not_nil person.id
|
55
|
+
document = Person.find(person.id)
|
56
|
+
|
57
|
+
assert_instance_of Person, document
|
58
|
+
assert_equal 'John Smith', document.name
|
59
|
+
assert_equal 'John Smith', Person.find(person.id).name
|
60
|
+
|
61
|
+
assert_not_nil Elasticsearch::Persistence.client.get index: 'people', type: 'person', id: person.id
|
62
|
+
end
|
63
|
+
|
64
|
+
should "delete the object" do
|
65
|
+
person = Person.create name: 'John Smith', birthday: Date.parse('1970-01-01')
|
66
|
+
|
67
|
+
person.destroy
|
68
|
+
assert person.frozen?
|
69
|
+
|
70
|
+
assert_raise Elasticsearch::Transport::Transport::Errors::NotFound do
|
71
|
+
Elasticsearch::Persistence.client.get index: 'people', type: 'person', id: person.id
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
should "update an object attribute" do
|
76
|
+
person = Person.create name: 'John Smith'
|
77
|
+
|
78
|
+
person.update name: 'UPDATED'
|
79
|
+
|
80
|
+
assert_equal 'UPDATED', person.name
|
81
|
+
assert_equal 'UPDATED', Person.find(person.id).name
|
82
|
+
end
|
83
|
+
|
84
|
+
should "increment an object attribute" do
|
85
|
+
person = Person.create name: 'John Smith', salary: 1_000
|
86
|
+
|
87
|
+
person.increment :salary
|
88
|
+
|
89
|
+
assert_equal 1_001, person.salary
|
90
|
+
assert_equal 1_001, Person.find(person.id).salary
|
91
|
+
end
|
92
|
+
|
93
|
+
should "update the object timestamp" do
|
94
|
+
person = Person.create name: 'John Smith'
|
95
|
+
updated_at = person.updated_at
|
96
|
+
|
97
|
+
sleep 1
|
98
|
+
person.touch
|
99
|
+
|
100
|
+
assert person.updated_at > updated_at, [person.updated_at, updated_at].inspect
|
101
|
+
|
102
|
+
found = Person.find(person.id)
|
103
|
+
assert found.updated_at > updated_at, [found.updated_at, updated_at].inspect
|
104
|
+
end
|
105
|
+
|
106
|
+
should "find instances by search" do
|
107
|
+
Person.create name: 'John Smith'
|
108
|
+
Person.create name: 'Mary Smith'
|
109
|
+
Person.gateway.refresh_index!
|
110
|
+
|
111
|
+
people = Person.search query: { match: { name: 'smith' } },
|
112
|
+
highlight: { fields: { name: {} } }
|
113
|
+
|
114
|
+
assert_equal 2, people.total
|
115
|
+
assert_equal 2, people.size
|
116
|
+
|
117
|
+
assert people.map_with_hit { |o,h| h._score }.all? { |s| s > 0 }
|
118
|
+
|
119
|
+
assert_not_nil people.first.hit
|
120
|
+
assert_match /smith/i, people.first.hit.highlight['name'].first
|
121
|
+
end
|
122
|
+
|
123
|
+
should "find instances in batches" do
|
124
|
+
50.times { |i| Person.create name: "John #{i+1}" }
|
125
|
+
Person.gateway.refresh_index!
|
126
|
+
|
127
|
+
@batches = 0
|
128
|
+
@results = []
|
129
|
+
|
130
|
+
Person.find_in_batches(_source_include: 'name') do |batch|
|
131
|
+
@batches += 1
|
132
|
+
@results += batch.map(&:name)
|
133
|
+
end
|
134
|
+
|
135
|
+
assert_equal 3, @batches
|
136
|
+
assert_equal 50, @results.size
|
137
|
+
assert_contains @results, 'John 1'
|
138
|
+
end
|
139
|
+
|
140
|
+
should "find each instance" do
|
141
|
+
50.times { |i| Person.create name: "John #{i+1}" }
|
142
|
+
Person.gateway.refresh_index!
|
143
|
+
|
144
|
+
@results = []
|
145
|
+
|
146
|
+
Person.find_each(_source_include: 'name') do |person|
|
147
|
+
@results << person.name
|
148
|
+
end
|
149
|
+
|
150
|
+
assert_equal 50, @results.size
|
151
|
+
assert_contains @results, 'John 1'
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Elasticsearch
|
4
|
+
module Persistence
|
5
|
+
class RepositoryCustomClassIntegrationTest < Elasticsearch::Test::IntegrationTestCase
|
6
|
+
|
7
|
+
class ::MyNote
|
8
|
+
attr_reader :attributes
|
9
|
+
|
10
|
+
def initialize(attributes={})
|
11
|
+
@attributes = Hashie::Mash.new(attributes)
|
12
|
+
end
|
13
|
+
|
14
|
+
def method_missing(method_name, *arguments, &block)
|
15
|
+
attributes.respond_to?(method_name) ? attributes.__send__(method_name, *arguments, &block) : super
|
16
|
+
end
|
17
|
+
|
18
|
+
def respond_to?(method_name, include_private=false)
|
19
|
+
attributes.respond_to?(method_name) || super
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_hash
|
23
|
+
@attributes
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "A custom repository class" do
|
28
|
+
setup do
|
29
|
+
class ::MyNotesRepository
|
30
|
+
include Elasticsearch::Persistence::Repository
|
31
|
+
|
32
|
+
klass MyNote
|
33
|
+
|
34
|
+
settings number_of_shards: 1 do
|
35
|
+
mapping do
|
36
|
+
indexes :title, analyzer: 'snowball'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
create_index!
|
41
|
+
|
42
|
+
def deserialize(document)
|
43
|
+
klass.new document.merge(document['_source'])
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
@repository = MyNotesRepository.new
|
48
|
+
|
49
|
+
@repository.client.cluster.health wait_for_status: 'yellow'
|
50
|
+
end
|
51
|
+
|
52
|
+
should "save the object under a correct index and type" do
|
53
|
+
@repository.save MyNote.new(id: '1', title: 'Test')
|
54
|
+
result = @repository.find(1)
|
55
|
+
|
56
|
+
assert_instance_of MyNote, result
|
57
|
+
assert_equal 'Test', result.title
|
58
|
+
|
59
|
+
assert_not_nil Elasticsearch::Persistence.client.get index: 'my_notes_repository',
|
60
|
+
type: 'my_note',
|
61
|
+
id: '1'
|
62
|
+
end
|
63
|
+
|
64
|
+
should "delete the object" do
|
65
|
+
note = MyNote.new id: 1, title: 'Test'
|
66
|
+
@repository.save note
|
67
|
+
|
68
|
+
assert_not_nil @repository.find(1)
|
69
|
+
|
70
|
+
@repository.delete(note)
|
71
|
+
assert_raise(Elasticsearch::Persistence::Repository::DocumentNotFound) { @repository.find(1) }
|
72
|
+
end
|
73
|
+
|
74
|
+
should "retrieve the object via a search query" do
|
75
|
+
note = MyNote.new title: 'Testing'
|
76
|
+
@repository.save note, refresh: true
|
77
|
+
|
78
|
+
results = @repository.search query: { match: { title: 'Test' } }
|
79
|
+
assert_equal 'Testing', results.first.title
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -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,114 @@
|
|
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 "count notes" do
|
100
|
+
@repository.save Note.new(title: 'Test')
|
101
|
+
@repository.client.indices.refresh index: @repository.index_name
|
102
|
+
assert_equal 1, @repository.count
|
103
|
+
end
|
104
|
+
|
105
|
+
should "save and find a plain hash" do
|
106
|
+
@repository.save id: 1, title: 'Hash'
|
107
|
+
result = @repository.find(1)
|
108
|
+
assert_equal 'Hash', result['_source']['title']
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
114
|
+
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,53 @@
|
|
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
|
+
if defined?(RUBY_VERSION) && RUBY_VERSION > '2.2'
|
12
|
+
require 'test-unit'
|
13
|
+
require 'mocha/test_unit'
|
14
|
+
else
|
15
|
+
require 'minitest/autorun'
|
16
|
+
require 'mocha/mini_test'
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'shoulda-context'
|
20
|
+
|
21
|
+
require 'turn' unless ENV["TM_FILEPATH"] || ENV["NOTURN"] || defined?(RUBY_VERSION) && RUBY_VERSION > '2.2'
|
22
|
+
|
23
|
+
require 'ansi'
|
24
|
+
require 'oj'
|
25
|
+
|
26
|
+
require 'elasticsearch/extensions/test/cluster'
|
27
|
+
require 'elasticsearch/extensions/test/startup_shutdown'
|
28
|
+
|
29
|
+
require 'elasticsearch/persistence'
|
30
|
+
|
31
|
+
module Elasticsearch
|
32
|
+
module Test
|
33
|
+
class IntegrationTestCase < ::Test::Unit::TestCase
|
34
|
+
extend Elasticsearch::Extensions::Test::StartupShutdown
|
35
|
+
|
36
|
+
startup { Elasticsearch::Extensions::Test::Cluster.start(nodes: 1) if ENV['SERVER'] and not Elasticsearch::Extensions::Test::Cluster.running? }
|
37
|
+
shutdown { Elasticsearch::Extensions::Test::Cluster.stop if ENV['SERVER'] && started? }
|
38
|
+
context "IntegrationTest" do; should "noop on Ruby 1.8" do; end; end if RUBY_1_8
|
39
|
+
|
40
|
+
def setup
|
41
|
+
tracer = ::Logger.new(STDERR)
|
42
|
+
tracer.formatter = lambda { |s, d, p, m| "#{m.gsub(/^.*$/) { |n| ' ' + n }.ansi(:faint)}\n" }
|
43
|
+
Elasticsearch::Persistence.client = Elasticsearch::Client.new \
|
44
|
+
host: "localhost:#{(ENV['TEST_CLUSTER_PORT'] || 9250)}",
|
45
|
+
tracer: (ENV['QUIET'] ? nil : tracer)
|
46
|
+
end
|
47
|
+
|
48
|
+
def teardown
|
49
|
+
Elasticsearch::Persistence.client.indices.delete index: '_all'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'elasticsearch/persistence/model'
|
4
|
+
require 'elasticsearch/persistence/model/rails'
|
5
|
+
|
6
|
+
class Elasticsearch::Persistence::ModelBaseTest < Test::Unit::TestCase
|
7
|
+
context "The model" do
|
8
|
+
setup do
|
9
|
+
class DummyBaseModel
|
10
|
+
include Elasticsearch::Persistence::Model
|
11
|
+
|
12
|
+
attribute :name, String
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
should "respond to id, _id, _index, _type and _version" do
|
17
|
+
model = DummyBaseModel.new
|
18
|
+
|
19
|
+
[:id, :_id, :_index, :_type, :_version].each { |method| assert_respond_to model, method }
|
20
|
+
end
|
21
|
+
|
22
|
+
should "set the ID from attributes during initialization" do
|
23
|
+
m = DummyBaseModel.new id: 1
|
24
|
+
assert_equal 1, m.id
|
25
|
+
|
26
|
+
m = DummyBaseModel.new 'id' => 2
|
27
|
+
assert_equal 2, m.id
|
28
|
+
end
|
29
|
+
|
30
|
+
should "set the ID using setter method" do
|
31
|
+
m = DummyBaseModel.new id: 1
|
32
|
+
assert_equal 1, m.id
|
33
|
+
|
34
|
+
m.id = 2
|
35
|
+
assert_equal 2, m.id
|
36
|
+
end
|
37
|
+
|
38
|
+
should "have ID in attributes" do
|
39
|
+
m = DummyBaseModel.new id: 1, name: 'Test'
|
40
|
+
assert_equal 1, m.attributes[:id]
|
41
|
+
end
|
42
|
+
|
43
|
+
should "have the customized inspect method" do
|
44
|
+
m = DummyBaseModel.new name: 'Test'
|
45
|
+
assert_match /name\: "Test"/, m.inspect
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|