working on new relationship class
This commit is contained in:
parent
f864099761
commit
7b23adddc4
@ -4,6 +4,7 @@ require 'active_support/core_ext/object'
|
|||||||
require 'active_support/concern'
|
require 'active_support/concern'
|
||||||
require 'active_support/inflector'
|
require 'active_support/inflector'
|
||||||
require 'fast_jsonapi/attribute'
|
require 'fast_jsonapi/attribute'
|
||||||
|
require 'fast_jsonapi/relationship'
|
||||||
require 'fast_jsonapi/serialization_core'
|
require 'fast_jsonapi/serialization_core'
|
||||||
|
|
||||||
module FastJsonapi
|
module FastJsonapi
|
||||||
@ -169,38 +170,32 @@ module FastJsonapi
|
|||||||
|
|
||||||
alias_method :attribute, :attributes
|
alias_method :attribute, :attributes
|
||||||
|
|
||||||
def add_relationship(name, relationship)
|
def add_relationship(relationship)
|
||||||
self.relationships_to_serialize = {} if relationships_to_serialize.nil?
|
self.relationships_to_serialize = {} if relationships_to_serialize.nil?
|
||||||
self.cachable_relationships_to_serialize = {} if cachable_relationships_to_serialize.nil?
|
self.cachable_relationships_to_serialize = {} if cachable_relationships_to_serialize.nil?
|
||||||
self.uncachable_relationships_to_serialize = {} if uncachable_relationships_to_serialize.nil?
|
self.uncachable_relationships_to_serialize = {} if uncachable_relationships_to_serialize.nil?
|
||||||
|
|
||||||
if !relationship[:cached]
|
if !relationship.cached
|
||||||
self.uncachable_relationships_to_serialize[name] = relationship
|
self.uncachable_relationships_to_serialize[relationship.name] = relationship
|
||||||
else
|
else
|
||||||
self.cachable_relationships_to_serialize[name] = relationship
|
self.cachable_relationships_to_serialize[relationship.name] = relationship
|
||||||
end
|
end
|
||||||
self.relationships_to_serialize[name] = relationship
|
self.relationships_to_serialize[relationship.name] = relationship
|
||||||
end
|
end
|
||||||
|
|
||||||
def has_many(relationship_name, options = {}, &block)
|
def has_many(relationship_name, options = {}, &block)
|
||||||
name = relationship_name.to_sym
|
create_relationship(relationship_name, :has_many, options, block)
|
||||||
hash = create_relationship_hash(relationship_name, :has_many, options, block)
|
|
||||||
add_relationship(name, hash)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def has_one(relationship_name, options = {}, &block)
|
def has_one(relationship_name, options = {}, &block)
|
||||||
name = relationship_name.to_sym
|
create_relationship(relationship_name, :has_one, options, block)
|
||||||
hash = create_relationship_hash(relationship_name, :has_one, options, block)
|
|
||||||
add_relationship(name, hash)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def belongs_to(relationship_name, options = {}, &block)
|
def belongs_to(relationship_name, options = {}, &block)
|
||||||
name = relationship_name.to_sym
|
create_relationship(relationship_name, :belongs_to, options, block)
|
||||||
hash = create_relationship_hash(relationship_name, :belongs_to, options, block)
|
|
||||||
add_relationship(name, hash)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_relationship_hash(base_key, relationship_type, options, block)
|
def create_relationship(base_key, relationship_type, options, block)
|
||||||
name = base_key.to_sym
|
name = base_key.to_sym
|
||||||
if relationship_type == :has_many
|
if relationship_type == :has_many
|
||||||
base_serialization_key = base_key.to_s.singularize
|
base_serialization_key = base_key.to_s.singularize
|
||||||
@ -211,7 +206,7 @@ module FastJsonapi
|
|||||||
base_key_sym = name
|
base_key_sym = name
|
||||||
id_postfix = '_id'
|
id_postfix = '_id'
|
||||||
end
|
end
|
||||||
{
|
relationship = Relationship.new(
|
||||||
key: options[:key] || run_key_transform(base_key),
|
key: options[:key] || run_key_transform(base_key),
|
||||||
name: name,
|
name: name,
|
||||||
id_method_name: options[:id_method_name] || "#{base_serialization_key}#{id_postfix}".to_sym,
|
id_method_name: options[:id_method_name] || "#{base_serialization_key}#{id_postfix}".to_sym,
|
||||||
@ -220,10 +215,11 @@ module FastJsonapi
|
|||||||
object_block: block,
|
object_block: block,
|
||||||
serializer: compute_serializer_name(options[:serializer] || base_key_sym),
|
serializer: compute_serializer_name(options[:serializer] || base_key_sym),
|
||||||
relationship_type: relationship_type,
|
relationship_type: relationship_type,
|
||||||
cached: options[:cached] || false,
|
cached: options[:cached],
|
||||||
polymorphic: fetch_polymorphic_option(options),
|
polymorphic: fetch_polymorphic_option(options),
|
||||||
conditional_proc: options[:if]
|
conditional_proc: options[:if]
|
||||||
}
|
)
|
||||||
|
add_relationship(relationship)
|
||||||
end
|
end
|
||||||
|
|
||||||
def compute_serializer_name(serializer_key)
|
def compute_serializer_name(serializer_key)
|
||||||
@ -255,8 +251,8 @@ module FastJsonapi
|
|||||||
parse_include_item(include_item).each do |parsed_include|
|
parse_include_item(include_item).each do |parsed_include|
|
||||||
relationship_to_include = klass.relationships_to_serialize[parsed_include]
|
relationship_to_include = klass.relationships_to_serialize[parsed_include]
|
||||||
raise ArgumentError, "#{parsed_include} is not specified as a relationship on #{klass.name}" unless relationship_to_include
|
raise ArgumentError, "#{parsed_include} is not specified as a relationship on #{klass.name}" unless relationship_to_include
|
||||||
raise NotImplementedError if relationship_to_include[:polymorphic].is_a?(Hash)
|
raise NotImplementedError if relationship_to_include.polymorphic.is_a?(Hash)
|
||||||
klass = relationship_to_include[:serializer].to_s.constantize
|
klass = relationship_to_include.serializer.to_s.constantize
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
99
lib/fast_jsonapi/relationship.rb
Normal file
99
lib/fast_jsonapi/relationship.rb
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
module FastJsonapi
|
||||||
|
class Relationship
|
||||||
|
attr_reader :key, :name, :id_method_name, :record_type, :object_method_name, :object_block, :serializer, :relationship_type, :cached, :polymorphic, :conditional_proc
|
||||||
|
|
||||||
|
def initialize(
|
||||||
|
key:,
|
||||||
|
name:,
|
||||||
|
id_method_name:,
|
||||||
|
record_type:,
|
||||||
|
object_method_name:,
|
||||||
|
object_block:,
|
||||||
|
serializer:,
|
||||||
|
relationship_type:,
|
||||||
|
cached: false,
|
||||||
|
polymorphic:,
|
||||||
|
conditional_proc:
|
||||||
|
)
|
||||||
|
@key = key
|
||||||
|
@name = name
|
||||||
|
@id_method_name = id_method_name
|
||||||
|
@record_type = record_type
|
||||||
|
@object_method_name = object_method_name
|
||||||
|
@object_block = object_block
|
||||||
|
@serializer = serializer
|
||||||
|
@relationship_type = relationship_type
|
||||||
|
@cached = cached
|
||||||
|
@polymorphic = polymorphic
|
||||||
|
@conditional_proc = conditional_proc
|
||||||
|
end
|
||||||
|
|
||||||
|
def serialize(record, serialization_params, output_hash)
|
||||||
|
if include_relationship?(record, serialization_params)
|
||||||
|
empty_case = relationship_type == :has_many ? [] : nil
|
||||||
|
output_hash[key] = {
|
||||||
|
data: ids_hash_from_record_and_relationship(record, serialization_params) || empty_case
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def include_relationship?(record, serialization_params)
|
||||||
|
if conditional_proc.present?
|
||||||
|
conditional_proc.call(record, serialization_params)
|
||||||
|
else
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def ids_hash_from_record_and_relationship(record, params = {})
|
||||||
|
return ids_hash(
|
||||||
|
fetch_id(record, params)
|
||||||
|
) unless polymorphic
|
||||||
|
|
||||||
|
return unless associated_object = fetch_associated_object(record, params)
|
||||||
|
|
||||||
|
return associated_object.map do |object|
|
||||||
|
id_hash_from_record object, polymorphic
|
||||||
|
end if associated_object.respond_to? :map
|
||||||
|
|
||||||
|
id_hash_from_record associated_object, polymorphic
|
||||||
|
end
|
||||||
|
|
||||||
|
def id_hash_from_record(record, record_types)
|
||||||
|
# memoize the record type within the record_types dictionary, then assigning to record_type:
|
||||||
|
associated_record_type = record_types[record.class] ||= record.class.name.underscore.to_sym
|
||||||
|
id_hash(record.id, associated_record_type)
|
||||||
|
end
|
||||||
|
|
||||||
|
def ids_hash(ids)
|
||||||
|
return ids.map { |id| id_hash(id, record_type) } if ids.respond_to? :map
|
||||||
|
id_hash(ids, record_type) # ids variable is just a single id here
|
||||||
|
end
|
||||||
|
|
||||||
|
def id_hash(id, associated_record_type, default_return=false)
|
||||||
|
if id.present?
|
||||||
|
{ id: id.to_s, type: record_type }
|
||||||
|
else
|
||||||
|
default_return ? { id: nil, type: associated_record_type } : nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch_associated_object(record, params)
|
||||||
|
return object_block.call(record, params) unless object_block.nil?
|
||||||
|
record.send(object_method_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch_id(record, params)
|
||||||
|
unless object_block.nil?
|
||||||
|
object = object_block.call(record, params)
|
||||||
|
|
||||||
|
return object.map(&:id) if object.respond_to? :map
|
||||||
|
return object.try(:id)
|
||||||
|
end
|
||||||
|
|
||||||
|
record.public_send(id_method_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -34,34 +34,6 @@ module FastJsonapi
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def ids_hash(ids, record_type)
|
|
||||||
return ids.map { |id| id_hash(id, record_type) } if ids.respond_to? :map
|
|
||||||
id_hash(ids, record_type) # ids variable is just a single id here
|
|
||||||
end
|
|
||||||
|
|
||||||
def id_hash_from_record(record, record_types)
|
|
||||||
# memoize the record type within the record_types dictionary, then assigning to record_type:
|
|
||||||
record_type = record_types[record.class] ||= record.class.name.underscore.to_sym
|
|
||||||
id_hash(record.id, record_type)
|
|
||||||
end
|
|
||||||
|
|
||||||
def ids_hash_from_record_and_relationship(record, relationship, params = {})
|
|
||||||
polymorphic = relationship[:polymorphic]
|
|
||||||
|
|
||||||
return ids_hash(
|
|
||||||
fetch_id(record, relationship, params),
|
|
||||||
relationship[:record_type]
|
|
||||||
) unless polymorphic
|
|
||||||
|
|
||||||
return unless associated_object = fetch_associated_object(record, relationship, params)
|
|
||||||
|
|
||||||
return associated_object.map do |object|
|
|
||||||
id_hash_from_record object, polymorphic
|
|
||||||
end if associated_object.respond_to? :map
|
|
||||||
|
|
||||||
id_hash_from_record associated_object, polymorphic
|
|
||||||
end
|
|
||||||
|
|
||||||
def links_hash(record, params = {})
|
def links_hash(record, params = {})
|
||||||
data_links.each_with_object({}) do |(key, method), link_hash|
|
data_links.each_with_object({}) do |(key, method), link_hash|
|
||||||
link_hash[key] = if method.is_a?(Proc)
|
link_hash[key] = if method.is_a?(Proc)
|
||||||
@ -82,14 +54,7 @@ module FastJsonapi
|
|||||||
relationships = relationships_to_serialize if relationships.nil?
|
relationships = relationships_to_serialize if relationships.nil?
|
||||||
|
|
||||||
relationships.each_with_object({}) do |(_k, relationship), hash|
|
relationships.each_with_object({}) do |(_k, relationship), hash|
|
||||||
conditional_proc = relationship[:conditional_proc]
|
relationship.serialize(record, params, hash)
|
||||||
if conditional_proc.blank? || conditional_proc.call(record, params)
|
|
||||||
name = relationship[:key]
|
|
||||||
empty_case = relationship[:relationship_type] == :has_many ? [] : nil
|
|
||||||
hash[name] = {
|
|
||||||
data: ids_hash_from_record_and_relationship(record, relationship, params) || empty_case
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -146,12 +111,12 @@ module FastJsonapi
|
|||||||
items = parse_include_item(include_item)
|
items = parse_include_item(include_item)
|
||||||
items.each do |item|
|
items.each do |item|
|
||||||
next unless relationships_to_serialize && relationships_to_serialize[item]
|
next unless relationships_to_serialize && relationships_to_serialize[item]
|
||||||
conditional_proc = relationships_to_serialize[item][:conditional_proc]
|
conditional_proc = relationships_to_serialize[item].conditional_proc
|
||||||
next if conditional_proc && !conditional_proc.call(record, params)
|
next if conditional_proc && !conditional_proc.call(record, params)
|
||||||
raise NotImplementedError if @relationships_to_serialize[item][:polymorphic].is_a?(Hash)
|
raise NotImplementedError if @relationships_to_serialize[item].polymorphic.is_a?(Hash)
|
||||||
record_type = @relationships_to_serialize[item][:record_type]
|
record_type = @relationships_to_serialize[item].record_type
|
||||||
serializer = @relationships_to_serialize[item][:serializer].to_s.constantize
|
serializer = @relationships_to_serialize[item].serializer.to_s.constantize
|
||||||
relationship_type = @relationships_to_serialize[item][:relationship_type]
|
relationship_type = @relationships_to_serialize[item].relationship_type
|
||||||
|
|
||||||
included_objects = fetch_associated_object(record, @relationships_to_serialize[item], params)
|
included_objects = fetch_associated_object(record, @relationships_to_serialize[item], params)
|
||||||
next if included_objects.blank?
|
next if included_objects.blank?
|
||||||
@ -174,19 +139,8 @@ module FastJsonapi
|
|||||||
end
|
end
|
||||||
|
|
||||||
def fetch_associated_object(record, relationship, params)
|
def fetch_associated_object(record, relationship, params)
|
||||||
return relationship[:object_block].call(record, params) unless relationship[:object_block].nil?
|
return relationship.object_block.call(record, params) unless relationship.object_block.nil?
|
||||||
record.send(relationship[:object_method_name])
|
record.send(relationship.object_method_name)
|
||||||
end
|
|
||||||
|
|
||||||
def fetch_id(record, relationship, params)
|
|
||||||
unless relationship[:object_block].nil?
|
|
||||||
object = relationship[:object_block].call(record, params)
|
|
||||||
|
|
||||||
return object.map(&:id) if object.respond_to? :map
|
|
||||||
return object.try(:id)
|
|
||||||
end
|
|
||||||
|
|
||||||
record.public_send(relationship[:id_method_name])
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
RSpec.shared_examples 'returning correct relationship hash' do |serializer, id_method_name, record_type|
|
RSpec.shared_examples 'returning correct relationship hash' do |serializer, id_method_name, record_type|
|
||||||
it 'returns correct relationship hash' do
|
it 'returns correct relationship hash' do
|
||||||
expect(relationship).to be_instance_of(Hash)
|
expect(relationship).to be_instance_of(FastJsonapi::Relationship)
|
||||||
expect(relationship.keys).to all(be_instance_of(Symbol))
|
expect(relationship.keys).to all(be_instance_of(Symbol))
|
||||||
expect(relationship[:serializer]).to be serializer
|
expect(relationship[:serializer]).to be serializer
|
||||||
expect(relationship[:id_method_name]).to be id_method_name
|
expect(relationship[:id_method_name]).to be id_method_name
|
||||||
|
Loading…
x
Reference in New Issue
Block a user