materialist 3.6.0 → 3.8.2

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
- SHA1:
3
- metadata.gz: dc140c911742867585c275c7b87a08cce340b165
4
- data.tar.gz: dd08e90c55127a4b8375f859613ec73cda95970d
2
+ SHA256:
3
+ metadata.gz: ce1a473a4a182ebbf80364ac65046c146796067e5901d2bec1fac4f24fe9d39f
4
+ data.tar.gz: 61a6d7e77e9d044490b5a2fc92a9c69ce4ece93237344a6b0332fb0d376c9dd8
5
5
  SHA512:
6
- metadata.gz: 4bcb195f30deff05ab9c83de55475473f8efee6a599cb694f47fdb55438b5374988a6f12872d5078af57c76c978d45208f0829a962b1d41d79f9ef1c824740eb
7
- data.tar.gz: 0d15e15c152b85765a3dca6c96dbe28787e780a15b68c505cf4dfd6d0c4e1b732c17c64275794733a096790999e3a0d59be32ba9e48a8c7d374c5fd1b4c6e33b
6
+ metadata.gz: b46b98674ee9d5482a505bb6aea3d8683b31b74e25a72fb1b25515d13a8d8c8de4afd7389d20b89ea8bbe0480fcab5a1699347f50bd9f38d807465a88c6816b9
7
+ data.tar.gz: 72eae6ef4cbe277c1c45a9ad5dff11ada17c8392b3ec709048e6baf1f85e7b195e184d41341b9634513d0520a8c0cd67ddda8f7ba33287f20b3bd918f3f20595
data/README.md CHANGED
@@ -91,7 +91,7 @@ Materialist.configure do |config|
91
91
  end
92
92
  ```
93
93
 
94
- - `topics` (only when using in `.subscribe`): A string array of topics to be used.
94
+ - `topics` (only when using in `.subscribe`): A string array of topics to be used.
95
95
  If not provided nothing would be materialized.
96
96
  - `sidekiq_options` (optional, default: `{ retry: 10 }`) -- See [Sidekiq docs](https://github.com/mperham/sidekiq/wiki/Advanced-Options#workers) for list of options
97
97
  - `api_client` (optional) -- You can pass your `Routemaster::APIClient` instance
@@ -155,8 +155,8 @@ class ZoneMaterializer
155
155
 
156
156
  persist_to :zone
157
157
 
158
- source_key :source_id do |url|
159
- /(\d+)\/?$/.match(url)[1]
158
+ source_key :source_id do |url, response|
159
+ /(\d+)\/?$/.match(url)[1] # or response.dig(:some_attr)
160
160
  end
161
161
 
162
162
  capture :id, as: :orderweb_id
@@ -189,10 +189,10 @@ describes the name of the active record model to be used.
189
189
  If missing, materialist skips materialising the resource itself, but will continue
190
190
  with any other functionality -- such as `materialize_link`.
191
191
 
192
- #### `source_key <column> <url_parser_block> (default: url)`
192
+ #### `source_key <column> <parser_block> (default: url, resource response body[create, update action only])`
193
193
  describes the column used to persist the unique identifier parsed from the url_parser_block.
194
194
  By default the column used is `:source_url` and the original `url` is used as the identifier.
195
- Passing an optional block allows you to extract an identifier from the URL.
195
+ Passing an optional block allows you to extract an identifier from the URL and captured attributes.
196
196
 
197
197
  #### `capture <key>, as: <column> (default: key)`
198
198
  describes mapping a resource key to a database column.
@@ -243,6 +243,24 @@ class ZoneMaterializer
243
243
  end
244
244
  ```
245
245
 
246
+ #### `before_upsert_with_payload <method> (, <method>(, ...))`
247
+ describes the name of the instance method(s) to be invoked before a record is
248
+ materialized, with the record as it exists in the database, or nil if it has
249
+ not been created yet. The function will get as a second argument the `payload`
250
+ of the HTTP response, this can be used to add additional information/persist
251
+ other objects.
252
+
253
+
254
+ ```ruby
255
+ class ZoneMaterializer
256
+ include Materialist::Materializer
257
+
258
+ before_upsert_with_payload :my_method
259
+
260
+ def my_method(record, payload); end
261
+ end
262
+ ```
263
+
246
264
 
247
265
  #### `after_upsert <method> (, <method>(, ...))` -- also `after_destroy`
248
266
  describes the name of the instance method(s) to be invoked after a record was materialized, with the updated record as a parameter. See above for a similar example implementation.
data/RELEASE_NOTES.md CHANGED
@@ -1,6 +1,13 @@
1
1
  ## Next
2
2
 
3
3
  _list pending release notes here..._
4
+ ## 3.8.2
5
+
6
+ - Fix Rails 6 deprecation warning for `update_attributes!`
7
+
8
+ ## 3.8.1
9
+
10
+ - ActiveSupport >= 6
4
11
 
5
12
  ## 3.6.0
6
13
 
@@ -38,9 +38,18 @@ module Materialist
38
38
  __materialist_options[:sidekiq_options] = options
39
39
  end
40
40
 
41
- def source_key(key, &url_parser_block)
41
+ def source_key(key, &source_key_parser)
42
42
  __materialist_options[:source_key] = key
43
- __materialist_options[:url_parser] = url_parser_block
43
+ __materialist_options[:source_key_parser] = source_key_parser
44
+ end
45
+
46
+ # This method is meant to be used for cases when the application needs
47
+ # to have access to the `payload` that is returned on the HTTP call.
48
+ # Such an example would be if the application logic requires all
49
+ # relationships to be present before the `resource` is saved in the
50
+ # database. Introduced in https://github.com/deliveroo/materialist/pull/47
51
+ def before_upsert_with_payload(*method_array)
52
+ __materialist_options[:before_upsert_with_payload] = method_array
44
53
  end
45
54
 
46
55
  def before_upsert(*method_array)
@@ -59,9 +59,10 @@ module Materialist
59
59
  end
60
60
 
61
61
  def upsert_record
62
- model_class.find_or_initialize_by(source_lookup(url)).tap do |entity|
62
+ model_class.find_or_initialize_by(source_lookup(url, resource)).tap do |entity|
63
63
  send_messages(before_upsert, entity) unless before_upsert.nil?
64
- entity.update_attributes!(attributes)
64
+ before_upsert_with_payload&.each { |m| instance.send(m, entity, resource) }
65
+ entity.update!(attributes)
65
66
  end
66
67
  end
67
68
 
@@ -74,7 +75,6 @@ module Materialist
74
75
  return unless link = resource.dig(:_links, key)
75
76
  return unless materializer_class = MaterializerFactory.class_from_topic(opts.fetch(:topic))
76
77
 
77
- # TODO: perhaps consider doing this asynchronously some how?
78
78
  materializer_class.perform(link[:href], :noop)
79
79
  end
80
80
 
@@ -86,6 +86,10 @@ module Materialist
86
86
  options[:before_upsert]
87
87
  end
88
88
 
89
+ def before_upsert_with_payload
90
+ options[:before_upsert_with_payload]
91
+ end
92
+
89
93
  def after_upsert
90
94
  options[:after_upsert]
91
95
  end
@@ -106,12 +110,12 @@ module Materialist
106
110
  options.fetch(:source_key, :source_url)
107
111
  end
108
112
 
109
- def url_parser
110
- options[:url_parser] || ->url { url }
113
+ def source_key_parser
114
+ options[:source_key_parser] || ->(url, data) { url }
111
115
  end
112
116
 
113
- def source_lookup(url)
114
- @_source_lookup ||= { source_key => url_parser.call(url) }
117
+ def source_lookup(url, resource={})
118
+ @_source_lookup ||= { source_key => source_key_parser.call(url, resource) }
115
119
  end
116
120
 
117
121
  def attributes
@@ -1,3 +1,3 @@
1
1
  module Materialist
2
- VERSION = '3.6.0'
2
+ VERSION = '3.8.2'
3
3
  end
@@ -50,7 +50,7 @@ RSpec.describe Materialist::Materializer::Internals::Materializer do
50
50
  let(:source_body) {{ _links: { city: { href: city_url }}, name: 'jack', age: 30 }}
51
51
  let(:defined_source_id) { 65 }
52
52
  let(:defined_source_url) { "https://service.dev/defined_sources/#{defined_source_id}" }
53
- let(:defined_source_body) {{ name: 'ben' }}
53
+ let(:defined_source_body) {{ name: 'ben', id: defined_source_id }}
54
54
 
55
55
  def stub_resource(url, body)
56
56
  stub_request(:get, url).to_return(
@@ -199,8 +199,13 @@ RSpec.describe Materialist::Materializer::Internals::Materializer do
199
199
 
200
200
  persist_to :foobar
201
201
  before_upsert :before_hook
202
+ before_upsert_with_payload :before_hook_with_payload
202
203
  after_upsert :after_hook
203
204
 
205
+ def before_hook_with_payload(entity, payload)
206
+ self.actions_called[:before_hook_with_payload] = true
207
+ end
208
+
204
209
  def before_hook(entity); self.actions_called[:before_hook] = true; end
205
210
  def after_hook(entity); self.actions_called[:after_hook] = true; end
206
211
  end
@@ -209,6 +214,11 @@ RSpec.describe Materialist::Materializer::Internals::Materializer do
209
214
  %i(create update noop).each do |action_name|
210
215
  context "when action is :#{action_name}" do
211
216
  let(:action) { action_name }
217
+
218
+ it "calls before_upsert_with_payload method" do
219
+ expect{ perform }.to change { actions_called[:before_hook_with_payload] }
220
+ end
221
+
212
222
  it "calls before_upsert method" do
213
223
  expect{ perform }.to change { actions_called[:before_hook] }
214
224
  end
@@ -225,8 +235,16 @@ RSpec.describe Materialist::Materializer::Internals::Materializer do
225
235
 
226
236
  persist_to :foobar
227
237
  before_upsert :before_hook, :before_hook2
238
+ before_upsert_with_payload :before_hook_with_payload, :before_hook_with_payload2
228
239
  after_upsert :after_hook, :after_hook2
229
240
 
241
+ def before_hook_with_payload(entity, payload)
242
+ self.actions_called[:before_hook_with_payload] = true
243
+ end
244
+ def before_hook_with_payload2(entity, payload)
245
+ self.actions_called[:before_hook_with_payload2] = true
246
+ end
247
+
230
248
  def before_hook(entity); self.actions_called[:before_hook] = true; end
231
249
  def before_hook2(entity); self.actions_called[:before_hook2] = true; end
232
250
  def after_hook(entity); self.actions_called[:after_hook] = true; end
@@ -239,6 +257,8 @@ RSpec.describe Materialist::Materializer::Internals::Materializer do
239
257
  .and change { actions_called[:before_hook2] }
240
258
  .and change { actions_called[:after_hook] }
241
259
  .and change { actions_called[:after_hook2] }
260
+ .and change { actions_called[:before_hook_with_payload] }
261
+ .and change { actions_called[:before_hook_with_payload2] }
242
262
  end
243
263
  end
244
264
  end
@@ -360,62 +380,87 @@ RSpec.describe Materialist::Materializer::Internals::Materializer do
360
380
  end
361
381
 
362
382
  context "entity based on the source_key column" do
363
- subject do
364
- Class.new do
365
- include Materialist::Materializer
383
+ shared_examples 'an upsert materialization event' do
384
+ context "when creating" do
385
+ let(:perform) { subject.perform(defined_source_url, action) }
366
386
 
367
- persist_to :defined_source
368
-
369
- source_key :source_id do |url|
370
- url.split('/').last.to_i
387
+ it "creates based on source_key" do
388
+ expect{perform}.to change{DefinedSource.count}.by 1
371
389
  end
372
390
 
373
- capture :name
391
+ it "sets the correct source key" do
392
+ perform
393
+ inserted = DefinedSource.find_by(source_id: defined_source_id)
394
+ expect(inserted.source_id).to eq defined_source_id
395
+ expect(inserted.name).to eq defined_source_body[:name]
396
+ end
374
397
  end
375
- end
376
398
 
377
- context "when creating" do
378
- let(:perform) { subject.perform(defined_source_url, action) }
399
+ context "when updating" do
400
+ let(:action) { :update }
401
+ let!(:record) { DefinedSource.create!(source_id: defined_source_id, name: 'mo') }
402
+ let(:perform) { subject.perform(defined_source_url, action) }
379
403
 
380
- it "creates based on source_key" do
381
- expect{perform}.to change{DefinedSource.count}.by 1
382
- end
404
+ it "updates based on source_key" do
405
+ perform
406
+ expect(DefinedSource.count).to eq 1
407
+ end
383
408
 
384
- it "sets the correct source key" do
385
- perform
386
- inserted = DefinedSource.find_by(source_id: defined_source_id)
387
- expect(inserted.source_id).to eq defined_source_id
388
- expect(inserted.name).to eq defined_source_body[:name]
409
+ it "updates the existing record" do
410
+ perform
411
+ inserted = DefinedSource.find_by(source_id: defined_source_id)
412
+ expect(inserted.source_id).to eq defined_source_id
413
+ expect(inserted.name).to eq defined_source_body[:name]
414
+ end
389
415
  end
390
416
  end
391
417
 
392
- context "when updating" do
393
- let(:action) { :update }
394
- let!(:record) { DefinedSource.create!(source_id: defined_source_id, name: 'mo') }
395
- let(:perform) { subject.perform(defined_source_url, action) }
418
+ context 'with url source key parser' do
419
+ subject do
420
+ Class.new do
421
+ include Materialist::Materializer
422
+
423
+ persist_to :defined_source
424
+
425
+ source_key :source_id do |url|
426
+ url.split('/').last.to_i
427
+ end
396
428
 
397
- it "updates based on source_key" do
398
- perform
399
- expect(DefinedSource.count).to eq 1
429
+ capture :name
430
+ end
400
431
  end
401
432
 
402
- it "updates the existing record" do
403
- perform
404
- inserted = DefinedSource.find_by(source_id: defined_source_id)
405
- expect(inserted.source_id).to eq defined_source_id
406
- expect(inserted.name).to eq defined_source_body[:name]
433
+ context "when deleting" do
434
+ let(:action) { :delete }
435
+ let!(:record) { DefinedSource.create!(source_id: defined_source_id, name: 'mo') }
436
+ let(:perform) { subject.perform(defined_source_url, action) }
437
+
438
+ it "deletes based on source_key" do
439
+ perform
440
+ expect(DefinedSource.count).to eq 0
441
+ end
407
442
  end
443
+
444
+ it_behaves_like 'an upsert materialization event'
408
445
  end
409
446
 
410
- context "when deleting" do
411
- let(:action) { :delete }
412
- let!(:record) { DefinedSource.create!(source_id: defined_source_id, name: 'mo') }
413
- let(:perform) { subject.perform(defined_source_url, action) }
447
+ context 'with resource source key parser' do
448
+ subject do
449
+ Class.new do
450
+ include Materialist::Materializer
414
451
 
415
- it "deletes based on source_key" do
416
- perform
417
- expect(DefinedSource.count).to eq 0
452
+ persist_to :defined_source
453
+
454
+ source_key :source_id do |_, resource|
455
+ resource.dig(:id)
456
+ end
457
+
458
+ capture :name
459
+ capture :id
460
+ end
418
461
  end
462
+
463
+ it_behaves_like 'an upsert materialization event'
419
464
  end
420
465
  end
421
466
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: materialist
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.6.0
4
+ version: 3.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mo Valipour
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-06-12 00:00:00.000000000 Z
11
+ date: 2021-11-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sidekiq
@@ -178,7 +178,7 @@ dependencies:
178
178
  - - ">="
179
179
  - !ruby/object:Gem::Version
180
180
  version: '0'
181
- description:
181
+ description:
182
182
  email:
183
183
  - valipour@gmail.com
184
184
  executables: []
@@ -232,7 +232,7 @@ homepage: http://github.com/deliveroo/materialist
232
232
  licenses:
233
233
  - MIT
234
234
  metadata: {}
235
- post_install_message:
235
+ post_install_message:
236
236
  rdoc_options: []
237
237
  require_paths:
238
238
  - lib
@@ -247,9 +247,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
247
247
  - !ruby/object:Gem::Version
248
248
  version: '0'
249
249
  requirements: []
250
- rubyforge_project:
251
- rubygems_version: 2.6.14.1
252
- signing_key:
250
+ rubygems_version: 3.0.9
251
+ signing_key:
253
252
  specification_version: 4
254
253
  summary: Utilities to materialize routemaster topics
255
254
  test_files: