materialist 3.6.0 → 3.8.2

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
- 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: