materialist 0.1.0 → 1.0.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 +4 -4
- data/README.md +10 -4
- data/lib/materialist.rb +1 -1
- data/lib/materialist/materializer.rb +35 -7
- data/spec/materialist/materializer_spec.rb +43 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2369c3f2842a7dc8cc9ff3efe2339328b7cf14aa
|
4
|
+
data.tar.gz: d043d9df4eda5667d6a09b040a485c39e7c16449
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
@@ -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(
|
71
|
-
__materialist_options[:after_upsert] =
|
83
|
+
def after_upsert(*method_array)
|
84
|
+
__materialist_options[:after_upsert] = method_array
|
72
85
|
end
|
73
86
|
|
74
|
-
def after_destroy(
|
75
|
-
__materialist_options[:after_destroy] =
|
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
|
-
|
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
|
-
|
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,
|
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:
|
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-
|
11
|
+
date: 2017-10-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sidekiq
|