materialist 2.0.0 → 2.1.0

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: 52edad7b633726d80df5bf86cb2190a0f68b6094
4
- data.tar.gz: 2db6abb9165052f9a564751c49ea3c9c6f7c7a34
3
+ metadata.gz: d2acc5e6e25f3d5fb77c44a7c6dc465442b307b4
4
+ data.tar.gz: 155b6c787990989d49e59eb83190ad9adeb592f0
5
5
  SHA512:
6
- metadata.gz: 8ae7bb5132903ff79355624196fdb2e0e087534b29ab7c76734ce014b65959701b414539ce937f0cbe787c4335119778a622a76cf5f0f15599279675e97aefb1
7
- data.tar.gz: 404ed0434c32eaf7c7353771f05cdf3c907214d7fec93503227eb359beb37ca4bd6ad1e29d140c427e797d186df04f6e798c58a665f50c9743e57ae06877b722
6
+ metadata.gz: c65249eadde28bed09a39c7114569a5d420f6f356b139b135913db8b84e732751d65aa3e27e12e8706f44d25c8af67fef0c3afc344e03a0f941911873f46ae2f
7
+ data.tar.gz: '0296ac0b29e449b14259be7f175898172f5fb8e65785f8e6cb082a95365d24dd969d26a2e4747df77a9e253db0c3a7149e9fd95a7c747a0b3cf60ee50d137cd8'
data/README.md CHANGED
@@ -118,6 +118,10 @@ class ZoneMaterializer
118
118
 
119
119
  persist_to :zone
120
120
 
121
+ source_key :source_id do |url|
122
+ /(\d+)\/?$/.match(url)[1]
123
+ end
124
+
121
125
  capture :id, as: :orderweb_id
122
126
  capture :code
123
127
  capture :name
@@ -142,6 +146,12 @@ describes the name of the active record model to be used.
142
146
  If missing, materialist skips materialising the resource itself, but will continue
143
147
  with any other functionality -- such as `materialize_link`.
144
148
 
149
+
150
+ #### `source_key <column> <url_parser_block> (default: url)`
151
+ describes the column used to persist the unique identifier parsed from the url_parser_block.
152
+ By default the column used is `:source_url` and the original `url` is used as the identifier.
153
+ Passing an optional block allows you to extract an identifier from the URL.
154
+
145
155
  #### `capture <key>, as: <column> (default: key)`
146
156
  describes mapping a resource key to a database column.
147
157
 
@@ -169,7 +179,7 @@ class ZoneMaterializer
169
179
 
170
180
  def my_method(record)
171
181
  end
172
-
182
+
173
183
  def my_second_method(record)
174
184
  end
175
185
  end
@@ -80,6 +80,11 @@ module Materialist
80
80
  __materialist_options[:model_class] = klass
81
81
  end
82
82
 
83
+ def source_key(key, &url_parser_block)
84
+ __materialist_options[:source_key] = key
85
+ __materialist_options[:url_parser] = url_parser_block
86
+ end
87
+
83
88
  def after_upsert(*method_array)
84
89
  __materialist_options[:after_upsert] = method_array
85
90
  end
@@ -120,7 +125,7 @@ module Materialist
120
125
 
121
126
  def destroy
122
127
  return unless materialize_self?
123
- model_class.find_by(source_url: url).tap do |entity|
128
+ model_class.find_by(source_lookup(url)).tap do |entity|
124
129
  entity.destroy!.tap do |entity|
125
130
  send_messages(after_destroy, entity) unless after_destroy.nil?
126
131
  end if entity
@@ -136,7 +141,7 @@ module Materialist
136
141
  end
137
142
 
138
143
  def upsert_record
139
- model_class.find_or_initialize_by(source_url: url).tap do |entity|
144
+ model_class.find_or_initialize_by(source_lookup(url)).tap do |entity|
140
145
  entity.update_attributes attributes
141
146
  entity.save!
142
147
  end
@@ -176,6 +181,18 @@ module Materialist
176
181
  options.fetch(:model_class).to_s.camelize.constantize
177
182
  end
178
183
 
184
+ def source_key
185
+ options.fetch(:source_key, :source_url)
186
+ end
187
+
188
+ def url_parser
189
+ options[:url_parser] || ->url { url }
190
+ end
191
+
192
+ def source_lookup(url)
193
+ @_source_lookup ||= { source_key => url_parser.call(url) }
194
+ end
195
+
179
196
  def attributes
180
197
  build_attributes root_resource, mapping
181
198
  end
data/lib/materialist.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Materialist
2
- VERSION = '2.0.0'
2
+ VERSION = '2.1.0'
3
3
  end
@@ -11,6 +11,7 @@ RSpec.describe Materialist::Materializer do
11
11
  include Materialist::Materializer
12
12
 
13
13
  persist_to :foobar
14
+
14
15
  capture :name
15
16
  capture :age, as: :how_old
16
17
  capture_link_href :city, as: :city_url
@@ -31,6 +32,19 @@ RSpec.describe Materialist::Materializer do
31
32
  include Materialist::Materializer
32
33
 
33
34
  persist_to :city
35
+ source_key :source_url
36
+ capture :name
37
+ end
38
+
39
+ class DefinedSourceMaterializer
40
+ include Materialist::Materializer
41
+
42
+ persist_to :defined_source
43
+
44
+ source_key :source_id do |url|
45
+ url.split('/').last.to_i
46
+ end
47
+
34
48
  capture :name
35
49
  end
36
50
  end
@@ -42,37 +56,49 @@ RSpec.describe Materialist::Materializer do
42
56
  end
43
57
 
44
58
  def save!
45
- self.class.all[source_url] = self
59
+ self.class.all[source_key_value] = self
46
60
  end
47
61
 
48
62
  def destroy!
49
- self.class.all.delete source_url
63
+ self.class.all.delete source_key_value
50
64
  end
51
65
 
52
66
  def reload
53
- self.class.all[source_url]
67
+ self.class.all[source_key_value]
54
68
  end
55
69
 
56
70
  def actions_called
57
71
  @_actions_called ||= {}
58
72
  end
59
73
 
74
+ private def source_key_value
75
+ send(self.class.source_key_column)
76
+ end
77
+
60
78
  class << self
61
- attr_accessor :error_to_throw_once_in_find_or_initialize_by
79
+ attr_accessor :error_to_throw_once_in_find_or_initialize_by,
80
+ :source_key_column
62
81
 
63
- def find_or_initialize_by(source_url:)
82
+ def find_or_initialize_by(kv_hash)
64
83
  if(err = error_to_throw_once_in_find_or_initialize_by)
65
84
  self.error_to_throw_once_in_find_or_initialize_by = nil
66
85
  raise err
67
86
  end
68
87
 
69
- (all[source_url] || self.new).tap do |record|
70
- record.source_url = source_url
88
+ key_value = kv_hash[source_key_column]
89
+
90
+ (all[key_value] || self.new).tap do |record|
91
+ record.send("#{source_key_column}=", key_value)
71
92
  end
72
93
  end
73
94
 
74
- def find_by(source_url:)
75
- all[source_url]
95
+ def source_key_column
96
+ @source_key_column || :source_url
97
+ end
98
+
99
+ def find_by(kv_hash)
100
+ key_value = kv_hash[source_key_column]
101
+ all[key_value]
76
102
  end
77
103
 
78
104
  def create!(attrs)
@@ -109,6 +135,11 @@ RSpec.describe Materialist::Materializer do
109
135
  attr_accessor :source_url, :name
110
136
  end
111
137
 
138
+ class DefinedSource < BaseModel
139
+ attr_accessor :source_id, :name
140
+ self.source_key_column = :source_id
141
+ end
142
+
112
143
  module ActiveRecord
113
144
  class RecordNotUnique < StandardError; end
114
145
  class RecordInvalid < StandardError; end
@@ -120,6 +151,9 @@ RSpec.describe Materialist::Materializer do
120
151
  let(:city_body) {{ _links: { country: { href: country_url }}, name: 'paris', timezone: 'Europe/Paris' }}
121
152
  let(:source_url) { 'https://service.dev/foobars/1' }
122
153
  let(:source_body) {{ _links: { city: { href: city_url }}, name: 'jack', age: 30 }}
154
+ let(:defined_source_id) { 65 }
155
+ let(:defined_source_url) { "https://service.dev/defined_sources/#{defined_source_id}" }
156
+ let(:defined_source_body) {{ name: 'ben' }}
123
157
 
124
158
  def stub_resource(url, body)
125
159
  stub_request(:get, url).to_return(
@@ -132,10 +166,12 @@ RSpec.describe Materialist::Materializer do
132
166
  before do
133
167
  Foobar.destroy_all
134
168
  City.destroy_all
169
+ DefinedSource.destroy_all
135
170
 
136
171
  stub_resource source_url, source_body
137
172
  stub_resource country_url, country_body
138
173
  stub_resource city_url, city_body
174
+ stub_resource defined_source_url, defined_source_body
139
175
  end
140
176
 
141
177
  let(:action) { :create }
@@ -362,5 +398,49 @@ RSpec.describe Materialist::Materializer do
362
398
  end
363
399
  end
364
400
  end
401
+
402
+ context "when creating a new entity based on the source_key column" do
403
+ let(:perform) { DefinedSourceMaterializer.perform(defined_source_url, action) }
404
+
405
+ it "creates based on source_key" do
406
+ expect{perform}.to change{DefinedSource.count}.by 1
407
+ end
408
+
409
+ it "sets the correct source key" 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
415
+ end
416
+
417
+ context "when updating a new entity based on the source_key column" do
418
+ let(:action) { :update }
419
+ let!(:record) { DefinedSource.create!(source_id: defined_source_id, name: 'mo') }
420
+ let(:perform) { DefinedSourceMaterializer.perform(defined_source_url, action) }
421
+
422
+ it "updates based on source_key" do
423
+ perform
424
+ expect(DefinedSource.count).to eq 1
425
+ end
426
+
427
+ it "updates the existing record" do
428
+ perform
429
+ inserted = DefinedSource.find_by(source_id: defined_source_id)
430
+ expect(inserted.source_id).to eq defined_source_id
431
+ expect(inserted.name).to eq defined_source_body[:name]
432
+ end
433
+ end
434
+
435
+ context "when deleting an entity based on the source_key column" do
436
+ let(:action) { :delete }
437
+ let!(:record) { DefinedSource.create!(source_id: defined_source_id, name: 'mo') }
438
+ let(:perform) { DefinedSourceMaterializer.perform(defined_source_url, action) }
439
+
440
+ it "deletes based on source_key" do
441
+ perform
442
+ expect(DefinedSource.count).to eq 0
443
+ end
444
+ end
365
445
  end
366
446
  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: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mo Valipour
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-06 00:00:00.000000000 Z
11
+ date: 2017-11-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sidekiq