Skip to content

Commit 610de43

Browse files
committed
Allow customization of the inclusion level in the serializer
1 parent daed4e0 commit 610de43

2 files changed

Lines changed: 171 additions & 13 deletions

File tree

lib/userlist/push/serializer.rb

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ def self.serialize(resource, **options)
99

1010
attr_reader :context
1111

12-
def initialize(context:)
12+
def initialize(context:, include: nil)
1313
@context = context
14+
@include = normalize_include_options(include)
1415
end
1516

1617
def serialize(resource)
@@ -28,7 +29,7 @@ def serialize?(resource)
2829
private
2930

3031
def serialize_resource(resource)
31-
return resource.identifier if serialized_resources.include?(resource)
32+
return serialize_identifier(resource) if serialized?(resource)
3233

3334
serialized_resources << resource
3435

@@ -37,34 +38,48 @@ def serialize_resource(resource)
3738
serialized = {}
3839

3940
resource.attribute_names.each do |name|
40-
serialized[name] = resource.send(name)
41+
serialized[name] = serialize_attribute(resource, name)
4142
end
4243

4344
resource.association_names.each do |name|
44-
next unless result = serialize_association(resource.send(name))
45+
next unless result = serialize_association(resource, name)
4546

4647
serialized[name] = result
4748
end
4849

4950
serialized
5051
end
5152

52-
def serialize_association(association)
53-
return unless association
53+
def serialize_attribute(resource, name)
54+
resource.send(name)
55+
end
56+
57+
def serialize_association(resource, name)
58+
return unless association = resource.send(name)
59+
return serialize_identifier(association) unless include?(name)
60+
61+
with_include_for(name) do
62+
case association
63+
when Userlist::Push::ResourceCollection
64+
serialize_collection(association)
65+
when Userlist::Push::Resource
66+
serialize_resource(association)
67+
else
68+
raise "Cannot serialize association type: #{association.class}"
69+
end
70+
end
71+
end
5472

55-
case association
56-
when Userlist::Push::ResourceCollection
57-
serialize_collection(association)
73+
def serialize_identifier(resource)
74+
case resource
5875
when Userlist::Push::Resource
59-
serialize_resource(association)
60-
else
61-
raise "Cannot serialize association type: #{association.class}"
76+
resource.identifier
6277
end
6378
end
6479

6580
def serialize_collection(collection)
6681
serialized = collection
67-
.map(&method(:serialize_association))
82+
.map(&method(:serialize_resource))
6883
.compact
6984
.reject(&:empty?)
7085

@@ -74,6 +89,36 @@ def serialize_collection(collection)
7489
def serialized_resources
7590
@serialized_resources ||= Set.new
7691
end
92+
93+
def serialized?(resource)
94+
serialized_resources.include?(resource)
95+
end
96+
97+
def include?(name)
98+
@include.nil? || @include.fetch(name.to_sym, false)
99+
end
100+
101+
def with_include_for(name)
102+
original_include = @include
103+
@include = @include&.fetch(name.to_sym, false)
104+
105+
yield
106+
ensure
107+
@include = original_include
108+
end
109+
110+
def normalize_include_options(value)
111+
case value
112+
when Array
113+
value.inject({}) { |acc, v| acc.merge(normalize_include_options(v)) }
114+
when Hash
115+
value.to_h { |k, v| [k.to_sym, normalize_include_options(v)] }
116+
when Symbol, String
117+
{ value.to_sym => {} }
118+
when false
119+
{}
120+
end
121+
end
77122
end
78123
end
79124
end

spec/userlist/push/serializer_spec.rb

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,119 @@
192192
)
193193
end
194194
end
195+
196+
describe 'include option' do
197+
let(:other_user) do
198+
Userlist::Push::User.new(
199+
identifier: 'other-user-identifier',
200+
201+
)
202+
end
203+
204+
let(:other_relationship) do
205+
Userlist::Push::Relationship.new(
206+
user: other_user,
207+
company: company,
208+
properties: {
209+
role: 'member'
210+
}
211+
)
212+
end
213+
214+
before do
215+
company.relationships = [relationship, other_relationship]
216+
end
217+
218+
context 'when the include option is set to false' do
219+
subject { described_class.new(context: :push, include: false) }
220+
221+
it 'should not include relationships' do
222+
expect(payload).to eq(
223+
identifier: 'user-identifier',
224+
225+
signed_up_at: nil
226+
)
227+
end
228+
end
229+
230+
context 'when the include option is set to :relationships' do
231+
subject { described_class.new(context: :push, include: :relationships) }
232+
233+
it 'should include relationships' do
234+
expect(payload).to eq(
235+
identifier: 'user-identifier',
236+
237+
signed_up_at: nil,
238+
relationships: [
239+
{
240+
user: 'user-identifier',
241+
company: 'company-identifier',
242+
properties: {
243+
role: 'admin'
244+
}
245+
}
246+
]
247+
)
248+
end
249+
end
250+
251+
context 'when the include option is set to { relationships: [:company] }' do
252+
subject { described_class.new(context: :push, include: [{ relationships: [{ company: [] }] }]) }
253+
254+
it 'should include relationships' do
255+
expect(payload).to eq(
256+
identifier: 'user-identifier',
257+
258+
signed_up_at: nil,
259+
relationships: [
260+
{
261+
user: 'user-identifier',
262+
company: {
263+
identifier: 'company-identifier',
264+
name: 'Example, Inc.',
265+
signed_up_at: nil
266+
},
267+
properties: {
268+
role: 'admin'
269+
}
270+
}
271+
]
272+
)
273+
end
274+
end
275+
276+
context 'when the include option is set to { relationships: { company: :relationships } }' do
277+
subject { described_class.new(context: :push, include: { relationships: { company: :relationships } }) }
278+
279+
it 'should include relationships' do
280+
expect(payload).to eq(
281+
identifier: 'user-identifier',
282+
283+
signed_up_at: nil,
284+
relationships: [
285+
{
286+
user: 'user-identifier',
287+
company: {
288+
identifier: 'company-identifier',
289+
name: 'Example, Inc.',
290+
signed_up_at: nil,
291+
relationships: [
292+
{
293+
company: 'company-identifier',
294+
user: 'other-user-identifier',
295+
properties: { role: 'member' }
296+
}
297+
]
298+
},
299+
properties: {
300+
role: 'admin'
301+
}
302+
}
303+
]
304+
)
305+
end
306+
end
307+
end
195308
end
196309

197310
context 'when serializing the company' do

0 commit comments

Comments
 (0)