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