elasticsearch-persistence 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
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