materialist 0.1.0 → 1.0.0

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: ddfdebe864838d6fdb912aee5d3002417aca969b
4
- data.tar.gz: 13ebd4c0bad48a307820aaa28c81d674335da88c
3
+ metadata.gz: 2369c3f2842a7dc8cc9ff3efe2339328b7cf14aa
4
+ data.tar.gz: d043d9df4eda5667d6a09b040a485c39e7c16449
5
5
  SHA512:
6
- metadata.gz: c082a2dfffdae443aaafb41d20f4a12da3203a90bbae0e4bd8075f77364fdc67d2386de3373572d1a0b6b46bbb93d0e7a1adca2df59777f15de7c9eb9fbf0d02
7
- data.tar.gz: 80d88005986ec167b4d599085e9fcd424c37b4cab98baacc44a38deed1731e035c8acc8da118e0be286b17f5c2de1adf95ddd4a45253b43ba9648169b4f79113
6
+ metadata.gz: 78c9b1b5683feadc832ac2184b0b79b1a52f421697b4d921af7e776da7607218093e6a7f9aa12cb5fc2ddf8147c4752c0b4649fc3ea748e408ccc01aec98d9ff
7
+ data.tar.gz: 7f9b3b1a197b8c793a040b3d1cb894282bc58446055910c3727d08fea83678de23c7823bcdb613b57b5ec8161c360a00518e96dfc1dd8444641fe6a683399bd9
data/README.md CHANGED
@@ -143,7 +143,10 @@ If missing, materialist skips materialising the resource itself, but will contin
143
143
  with any other functionality -- such as `materialize_link`.
144
144
 
145
145
  #### `capture <key>, as: <column> (default: key)`
146
- describes mapping a resource key to database column.
146
+ describes mapping a resource key to a database column.
147
+
148
+ #### `capture_link_href <key>, as: <column>`
149
+ describes mapping a link href (as it appears on the hateous response) to a database column.
147
150
 
148
151
  #### `link <key>`
149
152
  describes materializing from a relation of the resource. This can be nested to any depth as shown above.
@@ -155,17 +158,20 @@ describes materializing the linked entity.
155
158
  This simulates a `:noop` event on the given topic and the `url` of the
156
159
  liked resource `<key>` as it appears on the response (`_links`) -- meaning the materializer for the given topic will be invoked.
157
160
 
158
- #### `after_upsert <method>` -- also `after_destroy`
159
- describes the name of the instance method to be invoked after a record was materialized.
161
+ #### `after_upsert <method> (, <method>(, ...))` -- also `after_destroy`
162
+ describes the name of the instance method(s) to be invoked after a record was materialized.
160
163
 
161
164
  ```ruby
162
165
  class ZoneMaterializer
163
166
  include Materialist::Materializer
164
167
 
165
- after_upsert :my_method
168
+ after_upsert :my_method, :my_second_method
166
169
 
167
170
  def my_method(record)
168
171
  end
172
+
173
+ def my_second_method(record)
174
+ end
169
175
  end
170
176
  ```
171
177
 
data/lib/materialist.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Materialist
2
- VERSION = '0.1.0'
2
+ VERSION = '1.0.0'
3
3
  end
@@ -36,6 +36,15 @@ module Materialist
36
36
  attr_reader :key, :mapping
37
37
  end
38
38
 
39
+ class LinkHrefMapping
40
+ def initialize(key:, as:)
41
+ @key = key
42
+ @as = as
43
+ end
44
+
45
+ attr_reader :key, :as
46
+ end
47
+
39
48
  module ClassMethods
40
49
  attr_reader :__materialist_options, :__materialist_dsl_mapping_stack
41
50
 
@@ -55,6 +64,10 @@ module Materialist
55
64
  __materialist_dsl_mapping_stack.last << FieldMapping.new(key: key, as: as)
56
65
  end
57
66
 
67
+ def capture_link_href(key, as:)
68
+ __materialist_dsl_mapping_stack.last << LinkHrefMapping.new(key: key, as: as)
69
+ end
70
+
58
71
  def link(key)
59
72
  link_mapping = LinkMapping.new(key: key)
60
73
  __materialist_dsl_mapping_stack.last << link_mapping
@@ -67,12 +80,12 @@ module Materialist
67
80
  __materialist_options[:model_class] = klass
68
81
  end
69
82
 
70
- def after_upsert(method_name)
71
- __materialist_options[:after_upsert] = method_name
83
+ def after_upsert(*method_array)
84
+ __materialist_options[:after_upsert] = method_array
72
85
  end
73
86
 
74
- def after_destroy(method_name)
75
- __materialist_options[:after_destroy] = method_name
87
+ def after_destroy(*method_array)
88
+ __materialist_options[:after_destroy] = method_array
76
89
  end
77
90
  end
78
91
 
@@ -89,7 +102,7 @@ module Materialist
89
102
 
90
103
  if materialize_self?
91
104
  upsert_record.tap do |entity|
92
- instance.send(after_upsert, entity) if after_upsert
105
+ send_messages(after_upsert, entity) unless after_upsert.nil?
93
106
  end
94
107
  end
95
108
 
@@ -109,7 +122,7 @@ module Materialist
109
122
  return unless materialize_self?
110
123
  model_class.find_by(source_url: url).tap do |entity|
111
124
  entity.destroy!.tap do |entity|
112
- instance.send(after_destroy, entity) if after_destroy
125
+ send_messages(after_destroy, entity) unless after_destroy.nil?
113
126
  end if entity
114
127
  end
115
128
  end
@@ -177,7 +190,13 @@ module Materialist
177
190
  mapping.inject({}) do |result, m|
178
191
  case m
179
192
  when FieldMapping
180
- result.tap { |r| r[m.as] = resource.body[m.key] }
193
+ result.tap { |r| r[m.as] = serializable_value(resource.body[m.key]) }
194
+ when LinkHrefMapping
195
+ result.tap do |r|
196
+ if resource.body._links.include?(m.key)
197
+ r[m.as] = resource.body._links[m.key].href
198
+ end
199
+ end
181
200
  when LinkMapping
182
201
  resource.body._links.include?(m.key) ?
183
202
  result.merge(build_attributes(resource_at(resource.send(m.key).url), m.mapping || [])) :
@@ -188,6 +207,11 @@ module Materialist
188
207
  end
189
208
  end
190
209
 
210
+ def serializable_value(value)
211
+ value_is_complex_object = value.is_a?(Hash) || value.is_a?(Array)
212
+ value_is_complex_object ? value.to_json : value
213
+ end
214
+
191
215
  def resource_at(url)
192
216
  api_client.get(url, options: { enable_caching: false })
193
217
  rescue Routemaster::Errors::ResourceNotFound
@@ -202,6 +226,10 @@ module Materialist
202
226
  response_class: Routemaster::Responses::HateoasResponse
203
227
  )
204
228
  end
229
+
230
+ def send_messages(messages, arguments)
231
+ messages.each { |message| instance.send(message, arguments) }
232
+ end
205
233
  end
206
234
  end
207
235
  end
@@ -13,6 +13,8 @@ RSpec.describe Materialist::Materializer do
13
13
  persist_to :foobar
14
14
  capture :name
15
15
  capture :age, as: :how_old
16
+ capture_link_href :city, as: :city_url
17
+ capture_link_href :account, as: :account_url
16
18
 
17
19
  materialize_link :city
18
20
 
@@ -99,7 +101,8 @@ RSpec.describe Materialist::Materializer do
99
101
  end
100
102
 
101
103
  class Foobar < BaseModel
102
- attr_accessor :source_url, :name, :how_old, :age, :timezone, :country_tld
104
+ attr_accessor :source_url, :name, :how_old, :age, :timezone,
105
+ :country_tld, :city_url, :account_url
103
106
  end
104
107
 
105
108
  class City < BaseModel
@@ -117,6 +120,8 @@ RSpec.describe Materialist::Materializer do
117
120
  let(:city_body) {{ _links: { country: { href: country_url }}, name: 'paris', timezone: 'Europe/Paris' }}
118
121
  let(:source_url) { 'https://service.dev/foobars/1' }
119
122
  let(:source_body) {{ _links: { city: { href: city_url }}, name: 'jack', age: 30 }}
123
+ let(:complex_url) { 'https://service.dev/hashes/1' }
124
+ let(:complex_body) {{ _links: { city: { href: city_url }}, name: { first_name: 'Mo', last_name: 'Town' }, age: [30,31,44] }}
120
125
 
121
126
  def stub_resource(url, body)
122
127
  stub_request(:get, url).to_return(
@@ -133,6 +138,7 @@ RSpec.describe Materialist::Materializer do
133
138
  stub_resource source_url, source_body
134
139
  stub_resource country_url, country_body
135
140
  stub_resource city_url, city_body
141
+ stub_resource complex_url, complex_body
136
142
  end
137
143
 
138
144
  let(:action) { :create }
@@ -145,6 +151,7 @@ RSpec.describe Materialist::Materializer do
145
151
  expect(inserted.how_old).to eq source_body[:age]
146
152
  expect(inserted.timezone).to eq city_body[:timezone]
147
153
  expect(inserted.country_tld).to eq country_body[:tld]
154
+ expect(inserted.account_url).to be_nil
148
155
  end
149
156
 
150
157
  it "materializes linked record separately in db" do
@@ -154,6 +161,17 @@ RSpec.describe Materialist::Materializer do
154
161
  expect(inserted.name).to eq city_body[:name]
155
162
  end
156
163
 
164
+ context "when there are complex value types" do
165
+ let(:perform) { FoobarMaterializer.perform(complex_url, action) }
166
+
167
+ it "serialises the complex value into json" do
168
+ expect{perform}.to change{Foobar.count}.by 1
169
+ inserted = Foobar.find_by(source_url: complex_url)
170
+ expect(inserted.name).to eq complex_body[:name].to_json
171
+ expect(inserted.how_old).to eq complex_body[:age].to_json
172
+ end
173
+ end
174
+
157
175
  context "when record already exists" do
158
176
  let!(:record) { Foobar.create!(source_url: source_url, name: 'mo') }
159
177
 
@@ -255,6 +273,18 @@ RSpec.describe Materialist::Materializer do
255
273
  it "calls after_upsert method" do
256
274
  expect{ perform }.to change { record.actions_called[:after_upsert] }
257
275
  end
276
+
277
+ it "calls more than one after_upsert method" do
278
+ class FoobarMaterializer
279
+ after_upsert :my_method, :my_method2
280
+
281
+ def my_method2(entity)
282
+ entity.actions_called[:after_upsert2] = true
283
+ end
284
+ end
285
+ expect{ perform }.to change { record.actions_called[:after_upsert] }
286
+ .and change { record.actions_called[:after_upsert2] }
287
+ end
258
288
  end
259
289
  end
260
290
 
@@ -299,6 +329,18 @@ RSpec.describe Materialist::Materializer do
299
329
  expect{ perform }.to change { record.actions_called[:after_destroy] }
300
330
  end
301
331
 
332
+ it "calls more than one after_destroy method" do
333
+ class FoobarMaterializer
334
+ after_destroy :my_method, :my_method2
335
+
336
+ def my_method2(entity)
337
+ entity.actions_called[:after_destroy2] = true
338
+ end
339
+ end
340
+ expect{ perform }.to change { record.actions_called[:after_destroy] }
341
+ .and change { record.actions_called[:after_destroy2] }
342
+ end
343
+
302
344
  context "when resource doesn't exist locally" do
303
345
  it "does not raise error" do
304
346
  Foobar.destroy_all
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: 0.1.0
4
+ version: 1.0.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-09-12 00:00:00.000000000 Z
11
+ date: 2017-10-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sidekiq