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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 55426b2295af55ae3c3c5e22b5db473b208b74a0
4
- data.tar.gz: 86391c93cbec7a02acc48ddd1f42f01b48dff606
3
+ metadata.gz: 0e68271351dc49665d55b42ef03261773e0e0487
4
+ data.tar.gz: 0062f28b76d0d5e73484b10ba4480e74b576efe4
5
5
  SHA512:
6
- metadata.gz: 6a628a20d7500464ad4e810ef22269152a301a31508a6b0df11b22e0fdd7a67ce0607f58a675ccafaa9bdb04748d2aae829e9aeba2bae626c643a1cccf23f76d
7
- data.tar.gz: 632053ca6192adbbaac8b2e6565043d658bf66a659db9fbf4341dbc89907a2526cc477493f1d324b33c9857ddd02e7e646ab566b07e1cbc5345ee00d1eda42c3
6
+ metadata.gz: 1610448416e545c6dc7ed1ce18760833fd0f48e3452ea9887762b303896c3dd7cd8ca28e71cff25ed9a9a6062d063944ecc06f8f7cd7483819a05665f7c06553
7
+ data.tar.gz: 02df7217562efa1277489e1e8878fff983f509f5351d0533d2231154bc556829063a4e8369afddc0c3b722f505e46d59108f3220c1c49c83eb058ef89ab0d291
@@ -1,4 +1,16 @@
1
- # 0.1.7
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 behaviour:
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 inicialize when deserializing documents
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 "Successfuly saved: #{self}" }
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
- # Successfuly saved: #<Article {...}>
576
+ # Successfully saved: #<Article {...}>
571
577
  ```
572
578
 
573
579
  The model also supports familiar `find_in_batches` and `find_each` methods to efficiently
@@ -22,7 +22,6 @@ class Album
22
22
  attribute :label, Hash, mapping: { type: 'object' }
23
23
 
24
24
  attribute :title
25
- attribute :suggest_title, String, default: {}, mapping: { type: 'completion', payloads: true }
26
25
  attribute :released, Date
27
26
  attribute :notes
28
27
  attribute :uri
@@ -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, DateTime, default: lambda { |o,a| Time.now.utc }
119
- attribute :updated_at, DateTime, default: lambda { |o,a| Time.now.utc }
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
@@ -13,7 +13,7 @@ module Elasticsearch
13
13
  end
14
14
 
15
15
  def update(attributes={}, options={})
16
- super(__convert_rails_dates(attributes))
16
+ super(__convert_rails_dates(attributes), options)
17
17
  end
18
18
  end
19
19
  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)
@@ -1,5 +1,5 @@
1
1
  module Elasticsearch
2
2
  module Persistence
3
- VERSION = "0.1.7"
3
+ VERSION = "0.1.8"
4
4
  end
5
5
  end
@@ -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: 'person', id: person.id
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
- m = DummyBaseModel.new id: 1
24
- assert_equal 1, m.id
23
+ model = DummyBaseModel.new id: 1
24
+ assert_equal 1, model.id
25
25
 
26
- m = DummyBaseModel.new 'id' => 2
27
- assert_equal 2, m.id
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
- m = DummyBaseModel.new id: 1
32
- assert_equal 1, m.id
31
+ model = DummyBaseModel.new id: 1
32
+ assert_equal 1, model.id
33
33
 
34
- m.id = 2
35
- assert_equal 2, m.id
34
+ model.id = 2
35
+ assert_equal 2, model.id
36
36
  end
37
37
 
38
38
  should "have ID in attributes" do
39
- m = DummyBaseModel.new id: 1, name: 'Test'
40
- assert_equal 1, m.attributes[:id]
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
- m = DummyBaseModel.new name: 'Test'
45
- assert_match /name\: "Test"/, m.inspect
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.7
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-04-08 00:00:00.000000000 Z
11
+ date: 2015-10-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: elasticsearch