elasticsearch-persistence 0.1.7 → 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 +4 -4
- data/CHANGELOG.md +13 -1
- data/README.md +11 -5
- data/examples/music/album.rb +0 -1
- data/lib/elasticsearch/persistence/model.rb +9 -3
- data/lib/elasticsearch/persistence/model/rails.rb +1 -1
- data/lib/elasticsearch/persistence/model/store.rb +15 -3
- data/lib/elasticsearch/persistence/version.rb +1 -1
- data/test/integration/model/model_basic_test.rb +26 -1
- data/test/integration/repository/default_class_test.rb +2 -0
- data/test/unit/model_base_test.rb +36 -12
- data/test/unit/model_rails_test.rb +17 -0
- data/test/unit/model_store_test.rb +34 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0e68271351dc49665d55b42ef03261773e0e0487
|
4
|
+
data.tar.gz: 0062f28b76d0d5e73484b10ba4480e74b576efe4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1610448416e545c6dc7ed1ce18760833fd0f48e3452ea9887762b303896c3dd7cd8ca28e71cff25ed9a9a6062d063944ecc06f8f7cd7483819a05665f7c06553
|
7
|
+
data.tar.gz: 02df7217562efa1277489e1e8878fff983f509f5351d0533d2231154bc556829063a4e8369afddc0c3b722f505e46d59108f3220c1c49c83eb058ef89ab0d291
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,16 @@
|
|
1
|
-
|
1
|
+
## 0.1.8
|
2
|
+
|
3
|
+
* Added `cluster.health wait_for_status: 'yellow'` to Repository integration test
|
4
|
+
* Fixed tests for the updates to the `update` method for Persistence::Model
|
5
|
+
* Fixed timestamp tests
|
6
|
+
* Fixed typos and broken links in documentation, fixed examples
|
7
|
+
* Fixed, that `MyModel#save` does in fact persist `updated_at` attribute
|
8
|
+
* Fixed, that `options` have not been passed to gateway in MyModel#update
|
9
|
+
* Short-circuit the operation and return `false` when the model is not valid
|
10
|
+
* Fixed the problem where `document_type` configuration was not propagated to mapping
|
11
|
+
|
12
|
+
|
13
|
+
## 0.1.7
|
2
14
|
|
3
15
|
* Added an integration test for the `MyModel.all` method
|
4
16
|
* Improved the "music" example application
|
data/README.md
CHANGED
@@ -23,12 +23,18 @@ or install it from a source code checkout:
|
|
23
23
|
|
24
24
|
## Usage
|
25
25
|
|
26
|
+
The library provides two different patterns for adding persistence to your Ruby objects:
|
27
|
+
|
28
|
+
* [Repository Pattern](#the-repository-pattern)
|
29
|
+
* [ActiveRecord Pattern](#the-activerecord-pattern)
|
30
|
+
|
26
31
|
### The Repository Pattern
|
27
32
|
|
28
33
|
The `Elasticsearch::Persistence::Repository` module provides an implementation of the
|
29
34
|
[repository pattern](http://martinfowler.com/eaaCatalog/repository.html) and allows
|
30
35
|
to save, delete, find and search objects stored in Elasticsearch, as well as configure
|
31
|
-
mappings and settings for the index.
|
36
|
+
mappings and settings for the index. It's an unobtrusive and decoupled way of adding
|
37
|
+
persistence to your Ruby objects.
|
32
38
|
|
33
39
|
Let's have a simple plain old Ruby object (PORO):
|
34
40
|
|
@@ -92,7 +98,7 @@ repository.delete(note)
|
|
92
98
|
=> {"found"=>true, "_index"=>"repository", "_type"=>"note", "_id"=>"1", "_version"=>2}
|
93
99
|
```
|
94
100
|
|
95
|
-
The repository module provides a number of features and facilities to configure and customize the
|
101
|
+
The repository module provides a number of features and facilities to configure and customize the behavior:
|
96
102
|
|
97
103
|
* Configuring the Elasticsearch [client](https://github.com/elasticsearch/elasticsearch-ruby#usage) being used
|
98
104
|
* Setting the index name, document type, and object class for deserialization
|
@@ -120,7 +126,7 @@ repository = Elasticsearch::Persistence::Repository.new do
|
|
120
126
|
# Set a custom document type
|
121
127
|
type :my_note
|
122
128
|
|
123
|
-
# Specify the class to
|
129
|
+
# Specify the class to initialize when deserializing documents
|
124
130
|
klass Note
|
125
131
|
|
126
132
|
# Configure the settings and mappings for the Elasticsearch index
|
@@ -488,7 +494,7 @@ class Article
|
|
488
494
|
|
489
495
|
# Execute code after saving the model.
|
490
496
|
#
|
491
|
-
after_save { puts "
|
497
|
+
after_save { puts "Successfully saved: #{self}" }
|
492
498
|
end
|
493
499
|
```
|
494
500
|
|
@@ -567,7 +573,7 @@ Any callbacks defined in the model will be triggered during the persistence oper
|
|
567
573
|
|
568
574
|
```ruby
|
569
575
|
article.save
|
570
|
-
#
|
576
|
+
# Successfully saved: #<Article {...}>
|
571
577
|
```
|
572
578
|
|
573
579
|
The model also supports familiar `find_in_batches` and `find_each` methods to efficiently
|
data/examples/music/album.rb
CHANGED
@@ -71,7 +71,6 @@ module Elasticsearch
|
|
71
71
|
delegate :settings,
|
72
72
|
:mappings,
|
73
73
|
:mapping,
|
74
|
-
:document_type,
|
75
74
|
:document_type=,
|
76
75
|
:index_name,
|
77
76
|
:index_name=,
|
@@ -80,6 +79,13 @@ module Elasticsearch
|
|
80
79
|
:create_index!,
|
81
80
|
:refresh_index!,
|
82
81
|
to: :gateway
|
82
|
+
|
83
|
+
# forward document type to mappings when set
|
84
|
+
def document_type(type = nil)
|
85
|
+
return gateway.document_type unless type
|
86
|
+
gateway.document_type type
|
87
|
+
mapping.type = type
|
88
|
+
end
|
83
89
|
end
|
84
90
|
|
85
91
|
# Configure the repository based on the model (set up index_name, etc)
|
@@ -115,8 +121,8 @@ module Elasticsearch
|
|
115
121
|
|
116
122
|
# Set up common attributes
|
117
123
|
#
|
118
|
-
attribute :created_at,
|
119
|
-
attribute :updated_at,
|
124
|
+
attribute :created_at, Time, default: lambda { |o,a| Time.now.utc }
|
125
|
+
attribute :updated_at, Time, default: lambda { |o,a| Time.now.utc }
|
120
126
|
|
121
127
|
attr_reader :hit
|
122
128
|
end
|
@@ -53,10 +53,10 @@ module Elasticsearch
|
|
53
53
|
options.update index: self._index if self._index
|
54
54
|
options.update type: self._type if self._type
|
55
55
|
|
56
|
-
response = self.class.gateway.save(self, options)
|
57
|
-
|
58
56
|
self[:updated_at] = Time.now.utc
|
59
57
|
|
58
|
+
response = self.class.gateway.save(self, options)
|
59
|
+
|
60
60
|
@_id = response['_id']
|
61
61
|
@_index = response['_index']
|
62
62
|
@_type = response['_type']
|
@@ -99,9 +99,22 @@ module Elasticsearch
|
|
99
99
|
# p.update name: 'UPDATED'
|
100
100
|
# => {"_index"=>"people", ... "_version"=>2}
|
101
101
|
#
|
102
|
+
# @example Pass a version for concurrency control
|
103
|
+
#
|
104
|
+
# p.update( { name: 'UPDATED' }, { version: 2 } )
|
105
|
+
# => {"_index"=>"people", ... "_version"=>3}
|
106
|
+
#
|
107
|
+
# @example An exception is raised when the version doesn't match
|
108
|
+
#
|
109
|
+
# p.update( { name: 'UPDATED' }, { version: 2 } )
|
110
|
+
# => Elasticsearch::Transport::Transport::Errors::Conflict: [409] {"error" ... }
|
111
|
+
#
|
102
112
|
# @return [Hash] The Elasticsearch response as a Hash
|
103
113
|
#
|
104
114
|
def update(attributes={}, options={})
|
115
|
+
unless options.delete(:validate) == false
|
116
|
+
return false unless valid?
|
117
|
+
end
|
105
118
|
raise DocumentNotPersisted, "Object not persisted: #{self.inspect}" unless persisted?
|
106
119
|
|
107
120
|
run_callbacks :update do
|
@@ -109,7 +122,6 @@ module Elasticsearch
|
|
109
122
|
options.update type: self._type if self._type
|
110
123
|
|
111
124
|
attributes.update( { updated_at: Time.now.utc } )
|
112
|
-
|
113
125
|
response = self.class.gateway.update(self.id, { doc: attributes}.merge(options))
|
114
126
|
|
115
127
|
self.attributes = self.attributes.merge(attributes)
|
@@ -12,6 +12,7 @@ module Elasticsearch
|
|
12
12
|
include Elasticsearch::Persistence::Model::Rails
|
13
13
|
|
14
14
|
settings index: { number_of_shards: 1 }
|
15
|
+
document_type 'human_being'
|
15
16
|
|
16
17
|
attribute :name, String,
|
17
18
|
mapping: { fields: {
|
@@ -60,7 +61,7 @@ module Elasticsearch
|
|
60
61
|
assert_equal 'John Smith', document.name
|
61
62
|
assert_equal 'John Smith', Person.find(person.id).name
|
62
63
|
|
63
|
-
assert_not_nil Elasticsearch::Persistence.client.get index: 'people', type: '
|
64
|
+
assert_not_nil Elasticsearch::Persistence.client.get index: 'people', type: 'human_being', id: person.id
|
64
65
|
end
|
65
66
|
|
66
67
|
should "not save an invalid object" do
|
@@ -143,6 +144,30 @@ module Elasticsearch
|
|
143
144
|
assert found.updated_at > updated_at, [found.updated_at, updated_at].inspect
|
144
145
|
end
|
145
146
|
|
147
|
+
should 'update the object timestamp on save' do
|
148
|
+
person = Person.create name: 'John Smith'
|
149
|
+
person.admin = true
|
150
|
+
sleep 1
|
151
|
+
person.save
|
152
|
+
|
153
|
+
Person.gateway.refresh_index!
|
154
|
+
|
155
|
+
found = Person.find(person.id)
|
156
|
+
|
157
|
+
# Compare without milliseconds
|
158
|
+
assert_equal person.updated_at.to_i, found.updated_at.to_i
|
159
|
+
end
|
160
|
+
|
161
|
+
should "respect the version" do
|
162
|
+
person = Person.create name: 'John Smith'
|
163
|
+
|
164
|
+
person.update( { name: 'UPDATE 1' })
|
165
|
+
|
166
|
+
assert_raise Elasticsearch::Transport::Transport::Errors::Conflict do
|
167
|
+
person.update( { name: 'UPDATE 2' }, { version: 1 } )
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
146
171
|
should "find all instances" do
|
147
172
|
Person.create name: 'John Smith'
|
148
173
|
Person.create name: 'Mary Smith'
|
@@ -73,6 +73,8 @@ module Elasticsearch
|
|
73
73
|
note = Note.new(id: '1', title: 'Test')
|
74
74
|
@repository.save note, routing: 'ABC'
|
75
75
|
|
76
|
+
@repository.client.cluster.health level: 'indices', wait_for_status: 'yellow'
|
77
|
+
|
76
78
|
assert_raise Elasticsearch::Persistence::Repository::DocumentNotFound do
|
77
79
|
@repository.find(1, routing: 'DEF')
|
78
80
|
end
|
@@ -20,29 +20,53 @@ class Elasticsearch::Persistence::ModelBaseTest < Test::Unit::TestCase
|
|
20
20
|
end
|
21
21
|
|
22
22
|
should "set the ID from attributes during initialization" do
|
23
|
-
|
24
|
-
assert_equal 1,
|
23
|
+
model = DummyBaseModel.new id: 1
|
24
|
+
assert_equal 1, model.id
|
25
25
|
|
26
|
-
|
27
|
-
assert_equal 2,
|
26
|
+
model = DummyBaseModel.new 'id' => 2
|
27
|
+
assert_equal 2, model.id
|
28
28
|
end
|
29
29
|
|
30
30
|
should "set the ID using setter method" do
|
31
|
-
|
32
|
-
assert_equal 1,
|
31
|
+
model = DummyBaseModel.new id: 1
|
32
|
+
assert_equal 1, model.id
|
33
33
|
|
34
|
-
|
35
|
-
assert_equal 2,
|
34
|
+
model.id = 2
|
35
|
+
assert_equal 2, model.id
|
36
36
|
end
|
37
37
|
|
38
38
|
should "have ID in attributes" do
|
39
|
-
|
40
|
-
assert_equal 1,
|
39
|
+
model = DummyBaseModel.new id: 1, name: 'Test'
|
40
|
+
assert_equal 1, model.attributes[:id]
|
41
41
|
end
|
42
42
|
|
43
43
|
should "have the customized inspect method" do
|
44
|
-
|
45
|
-
assert_match /name\: "Test"/,
|
44
|
+
model = DummyBaseModel.new name: 'Test'
|
45
|
+
assert_match /name\: "Test"/, model.inspect
|
46
|
+
end
|
47
|
+
|
48
|
+
context "with custom document_type" do
|
49
|
+
setup do
|
50
|
+
@model = DummyBaseModel
|
51
|
+
@gateway = mock()
|
52
|
+
@mapping = mock()
|
53
|
+
@model.stubs(:gateway).returns(@gateway)
|
54
|
+
@gateway.stubs(:mapping).returns(@mapping)
|
55
|
+
@document_type = 'dummybase'
|
56
|
+
end
|
57
|
+
|
58
|
+
should "forward the argument to mapping" do
|
59
|
+
@gateway.expects(:document_type).with(@document_type).once
|
60
|
+
@mapping.expects(:type=).with(@document_type).once
|
61
|
+
@model.document_type @document_type
|
62
|
+
end
|
63
|
+
|
64
|
+
should "return the value from the gateway" do
|
65
|
+
@gateway.expects(:document_type).once.returns(@document_type)
|
66
|
+
@mapping.expects(:type=).never
|
67
|
+
returned_type = @model.document_type
|
68
|
+
assert_equal @document_type, returned_type
|
69
|
+
end
|
46
70
|
end
|
47
71
|
end
|
48
72
|
end
|
@@ -91,5 +91,22 @@ class Elasticsearch::Persistence::ModelRailsTest < Test::Unit::TestCase
|
|
91
91
|
assert_equal "2014-01-01", m.published_on.iso8601
|
92
92
|
end
|
93
93
|
|
94
|
+
context "when updating," do
|
95
|
+
should "pass the options to gateway" do
|
96
|
+
model = MyRailsModel.new name: 'Test'
|
97
|
+
model.stubs(:persisted?).returns(true)
|
98
|
+
|
99
|
+
model.class.gateway
|
100
|
+
.expects(:update)
|
101
|
+
.with do |object, options|
|
102
|
+
assert_equal 'ABC', options[:routing]
|
103
|
+
true
|
104
|
+
end
|
105
|
+
.returns({'_id' => 'abc123'})
|
106
|
+
|
107
|
+
assert model.update( { title: 'UPDATED' }, { routing: 'ABC' } )
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
94
111
|
end
|
95
112
|
end
|
@@ -311,6 +311,40 @@ class Elasticsearch::Persistence::ModelStoreTest < Test::Unit::TestCase
|
|
311
311
|
assert subject.update( {}, { script: 'EXEC' } )
|
312
312
|
end
|
313
313
|
|
314
|
+
should "not update an invalid model" do
|
315
|
+
@gateway
|
316
|
+
.expects(:update)
|
317
|
+
.never
|
318
|
+
|
319
|
+
subject.instance_eval do
|
320
|
+
def valid?; false; end;
|
321
|
+
end
|
322
|
+
|
323
|
+
assert ! subject.update(title: 'INVALID')
|
324
|
+
end
|
325
|
+
|
326
|
+
should "skip the validation with the :validate option" do
|
327
|
+
subject.expects(:persisted?).returns(true).at_least_once
|
328
|
+
subject.expects(:id).returns('abc123').at_least_once
|
329
|
+
|
330
|
+
@gateway
|
331
|
+
.expects(:update)
|
332
|
+
.with do |object, options|
|
333
|
+
assert_equal 'abc123', object
|
334
|
+
assert_equal nil, options[:id]
|
335
|
+
assert_equal 'INVALID', options[:doc][:title]
|
336
|
+
true
|
337
|
+
end
|
338
|
+
.returns({'_id' => 'abc123'})
|
339
|
+
|
340
|
+
subject.instance_eval do
|
341
|
+
def valid?; false; end;
|
342
|
+
end
|
343
|
+
|
344
|
+
assert subject.update( { title: 'INVALID' }, { validate: false } )
|
345
|
+
assert subject.persisted?
|
346
|
+
end
|
347
|
+
|
314
348
|
should "pass the options to gateway" do
|
315
349
|
subject.expects(:persisted?).returns(true)
|
316
350
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: elasticsearch-persistence
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Karel Minarik
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-10-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: elasticsearch
|