elasticsearch-persistence-queryable 0.1.8
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 +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
|