Skip to content

Commit 7b23add

Browse files
kyreevesshishirmk
authored andcommitted
working on new relationship class
1 parent f864099 commit 7b23add

4 files changed

Lines changed: 125 additions & 76 deletions

File tree

lib/fast_jsonapi/object_serializer.rb

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
require 'active_support/concern'
55
require 'active_support/inflector'
66
require 'fast_jsonapi/attribute'
7+
require 'fast_jsonapi/relationship'
78
require 'fast_jsonapi/serialization_core'
89

910
module FastJsonapi
@@ -169,38 +170,32 @@ def attributes(*attributes_list, &block)
169170

170171
alias_method :attribute, :attributes
171172

172-
def add_relationship(name, relationship)
173+
def add_relationship(relationship)
173174
self.relationships_to_serialize = {} if relationships_to_serialize.nil?
174175
self.cachable_relationships_to_serialize = {} if cachable_relationships_to_serialize.nil?
175176
self.uncachable_relationships_to_serialize = {} if uncachable_relationships_to_serialize.nil?
176-
177-
if !relationship[:cached]
178-
self.uncachable_relationships_to_serialize[name] = relationship
177+
178+
if !relationship.cached
179+
self.uncachable_relationships_to_serialize[relationship.name] = relationship
179180
else
180-
self.cachable_relationships_to_serialize[name] = relationship
181+
self.cachable_relationships_to_serialize[relationship.name] = relationship
181182
end
182-
self.relationships_to_serialize[name] = relationship
183+
self.relationships_to_serialize[relationship.name] = relationship
183184
end
184185

185186
def has_many(relationship_name, options = {}, &block)
186-
name = relationship_name.to_sym
187-
hash = create_relationship_hash(relationship_name, :has_many, options, block)
188-
add_relationship(name, hash)
187+
create_relationship(relationship_name, :has_many, options, block)
189188
end
190189

191190
def has_one(relationship_name, options = {}, &block)
192-
name = relationship_name.to_sym
193-
hash = create_relationship_hash(relationship_name, :has_one, options, block)
194-
add_relationship(name, hash)
191+
create_relationship(relationship_name, :has_one, options, block)
195192
end
196193

197194
def belongs_to(relationship_name, options = {}, &block)
198-
name = relationship_name.to_sym
199-
hash = create_relationship_hash(relationship_name, :belongs_to, options, block)
200-
add_relationship(name, hash)
195+
create_relationship(relationship_name, :belongs_to, options, block)
201196
end
202197

203-
def create_relationship_hash(base_key, relationship_type, options, block)
198+
def create_relationship(base_key, relationship_type, options, block)
204199
name = base_key.to_sym
205200
if relationship_type == :has_many
206201
base_serialization_key = base_key.to_s.singularize
@@ -211,7 +206,7 @@ def create_relationship_hash(base_key, relationship_type, options, block)
211206
base_key_sym = name
212207
id_postfix = '_id'
213208
end
214-
{
209+
relationship = Relationship.new(
215210
key: options[:key] || run_key_transform(base_key),
216211
name: name,
217212
id_method_name: options[:id_method_name] || "#{base_serialization_key}#{id_postfix}".to_sym,
@@ -220,10 +215,11 @@ def create_relationship_hash(base_key, relationship_type, options, block)
220215
object_block: block,
221216
serializer: compute_serializer_name(options[:serializer] || base_key_sym),
222217
relationship_type: relationship_type,
223-
cached: options[:cached] || false,
218+
cached: options[:cached],
224219
polymorphic: fetch_polymorphic_option(options),
225220
conditional_proc: options[:if]
226-
}
221+
)
222+
add_relationship(relationship)
227223
end
228224

229225
def compute_serializer_name(serializer_key)
@@ -255,8 +251,8 @@ def validate_includes!(includes)
255251
parse_include_item(include_item).each do |parsed_include|
256252
relationship_to_include = klass.relationships_to_serialize[parsed_include]
257253
raise ArgumentError, "#{parsed_include} is not specified as a relationship on #{klass.name}" unless relationship_to_include
258-
raise NotImplementedError if relationship_to_include[:polymorphic].is_a?(Hash)
259-
klass = relationship_to_include[:serializer].to_s.constantize
254+
raise NotImplementedError if relationship_to_include.polymorphic.is_a?(Hash)
255+
klass = relationship_to_include.serializer.to_s.constantize
260256
end
261257
end
262258
end

lib/fast_jsonapi/relationship.rb

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
module FastJsonapi
2+
class Relationship
3+
attr_reader :key, :name, :id_method_name, :record_type, :object_method_name, :object_block, :serializer, :relationship_type, :cached, :polymorphic, :conditional_proc
4+
5+
def initialize(
6+
key:,
7+
name:,
8+
id_method_name:,
9+
record_type:,
10+
object_method_name:,
11+
object_block:,
12+
serializer:,
13+
relationship_type:,
14+
cached: false,
15+
polymorphic:,
16+
conditional_proc:
17+
)
18+
@key = key
19+
@name = name
20+
@id_method_name = id_method_name
21+
@record_type = record_type
22+
@object_method_name = object_method_name
23+
@object_block = object_block
24+
@serializer = serializer
25+
@relationship_type = relationship_type
26+
@cached = cached
27+
@polymorphic = polymorphic
28+
@conditional_proc = conditional_proc
29+
end
30+
31+
def serialize(record, serialization_params, output_hash)
32+
if include_relationship?(record, serialization_params)
33+
empty_case = relationship_type == :has_many ? [] : nil
34+
output_hash[key] = {
35+
data: ids_hash_from_record_and_relationship(record, serialization_params) || empty_case
36+
}
37+
end
38+
end
39+
40+
private
41+
42+
def include_relationship?(record, serialization_params)
43+
if conditional_proc.present?
44+
conditional_proc.call(record, serialization_params)
45+
else
46+
true
47+
end
48+
end
49+
50+
def ids_hash_from_record_and_relationship(record, params = {})
51+
return ids_hash(
52+
fetch_id(record, params)
53+
) unless polymorphic
54+
55+
return unless associated_object = fetch_associated_object(record, params)
56+
57+
return associated_object.map do |object|
58+
id_hash_from_record object, polymorphic
59+
end if associated_object.respond_to? :map
60+
61+
id_hash_from_record associated_object, polymorphic
62+
end
63+
64+
def id_hash_from_record(record, record_types)
65+
# memoize the record type within the record_types dictionary, then assigning to record_type:
66+
associated_record_type = record_types[record.class] ||= record.class.name.underscore.to_sym
67+
id_hash(record.id, associated_record_type)
68+
end
69+
70+
def ids_hash(ids)
71+
return ids.map { |id| id_hash(id, record_type) } if ids.respond_to? :map
72+
id_hash(ids, record_type) # ids variable is just a single id here
73+
end
74+
75+
def id_hash(id, associated_record_type, default_return=false)
76+
if id.present?
77+
{ id: id.to_s, type: record_type }
78+
else
79+
default_return ? { id: nil, type: associated_record_type } : nil
80+
end
81+
end
82+
83+
def fetch_associated_object(record, params)
84+
return object_block.call(record, params) unless object_block.nil?
85+
record.send(object_method_name)
86+
end
87+
88+
def fetch_id(record, params)
89+
unless object_block.nil?
90+
object = object_block.call(record, params)
91+
92+
return object.map(&:id) if object.respond_to? :map
93+
return object.try(:id)
94+
end
95+
96+
record.public_send(id_method_name)
97+
end
98+
end
99+
end

lib/fast_jsonapi/serialization_core.rb

Lines changed: 8 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -34,34 +34,6 @@ def id_hash(id, record_type, default_return=false)
3434
end
3535
end
3636

37-
def ids_hash(ids, record_type)
38-
return ids.map { |id| id_hash(id, record_type) } if ids.respond_to? :map
39-
id_hash(ids, record_type) # ids variable is just a single id here
40-
end
41-
42-
def id_hash_from_record(record, record_types)
43-
# memoize the record type within the record_types dictionary, then assigning to record_type:
44-
record_type = record_types[record.class] ||= record.class.name.underscore.to_sym
45-
id_hash(record.id, record_type)
46-
end
47-
48-
def ids_hash_from_record_and_relationship(record, relationship, params = {})
49-
polymorphic = relationship[:polymorphic]
50-
51-
return ids_hash(
52-
fetch_id(record, relationship, params),
53-
relationship[:record_type]
54-
) unless polymorphic
55-
56-
return unless associated_object = fetch_associated_object(record, relationship, params)
57-
58-
return associated_object.map do |object|
59-
id_hash_from_record object, polymorphic
60-
end if associated_object.respond_to? :map
61-
62-
id_hash_from_record associated_object, polymorphic
63-
end
64-
6537
def links_hash(record, params = {})
6638
data_links.each_with_object({}) do |(key, method), link_hash|
6739
link_hash[key] = if method.is_a?(Proc)
@@ -82,14 +54,7 @@ def relationships_hash(record, relationships = nil, params = {})
8254
relationships = relationships_to_serialize if relationships.nil?
8355

8456
relationships.each_with_object({}) do |(_k, relationship), hash|
85-
conditional_proc = relationship[:conditional_proc]
86-
if conditional_proc.blank? || conditional_proc.call(record, params)
87-
name = relationship[:key]
88-
empty_case = relationship[:relationship_type] == :has_many ? [] : nil
89-
hash[name] = {
90-
data: ids_hash_from_record_and_relationship(record, relationship, params) || empty_case
91-
}
92-
end
57+
relationship.serialize(record, params, hash)
9358
end
9459
end
9560

@@ -146,12 +111,12 @@ def get_included_records(record, includes_list, known_included_objects, params =
146111
items = parse_include_item(include_item)
147112
items.each do |item|
148113
next unless relationships_to_serialize && relationships_to_serialize[item]
149-
conditional_proc = relationships_to_serialize[item][:conditional_proc]
114+
conditional_proc = relationships_to_serialize[item].conditional_proc
150115
next if conditional_proc && !conditional_proc.call(record, params)
151-
raise NotImplementedError if @relationships_to_serialize[item][:polymorphic].is_a?(Hash)
152-
record_type = @relationships_to_serialize[item][:record_type]
153-
serializer = @relationships_to_serialize[item][:serializer].to_s.constantize
154-
relationship_type = @relationships_to_serialize[item][:relationship_type]
116+
raise NotImplementedError if @relationships_to_serialize[item].polymorphic.is_a?(Hash)
117+
record_type = @relationships_to_serialize[item].record_type
118+
serializer = @relationships_to_serialize[item].serializer.to_s.constantize
119+
relationship_type = @relationships_to_serialize[item].relationship_type
155120

156121
included_objects = fetch_associated_object(record, @relationships_to_serialize[item], params)
157122
next if included_objects.blank?
@@ -174,19 +139,8 @@ def get_included_records(record, includes_list, known_included_objects, params =
174139
end
175140

176141
def fetch_associated_object(record, relationship, params)
177-
return relationship[:object_block].call(record, params) unless relationship[:object_block].nil?
178-
record.send(relationship[:object_method_name])
179-
end
180-
181-
def fetch_id(record, relationship, params)
182-
unless relationship[:object_block].nil?
183-
object = relationship[:object_block].call(record, params)
184-
185-
return object.map(&:id) if object.respond_to? :map
186-
return object.try(:id)
187-
end
188-
189-
record.public_send(relationship[:id_method_name])
142+
return relationship.object_block.call(record, params) unless relationship.object_block.nil?
143+
record.send(relationship.object_method_name)
190144
end
191145
end
192146
end

spec/shared/examples/object_serializer_class_methods_examples.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
RSpec.shared_examples 'returning correct relationship hash' do |serializer, id_method_name, record_type|
22
it 'returns correct relationship hash' do
3-
expect(relationship).to be_instance_of(Hash)
3+
expect(relationship).to be_instance_of(FastJsonapi::Relationship)
44
expect(relationship.keys).to all(be_instance_of(Symbol))
55
expect(relationship[:serializer]).to be serializer
66
expect(relationship[:id_method_name]).to be id_method_name

0 commit comments

Comments
 (0)