* add hash benchmarking to performance tests * Add missing attribute in README example * Disable GC before doing performance test * Enable oj to AM for fair benchmark test * ability to customize rendering of attributes via a block * fixed attribute render spec * minimized specs to specifially test this feature * Update README to include attribute definitions * Fixed syntax error * Fixed merge issues
120 lines
4.8 KiB
Ruby
120 lines
4.8 KiB
Ruby
require 'active_support/concern'
|
|
require 'fast_jsonapi/multi_to_json'
|
|
|
|
module FastJsonapi
|
|
module SerializationCore
|
|
extend ActiveSupport::Concern
|
|
|
|
included do
|
|
class << self
|
|
attr_accessor :attributes_to_serialize,
|
|
:relationships_to_serialize,
|
|
:cachable_relationships_to_serialize,
|
|
:uncachable_relationships_to_serialize,
|
|
:record_type,
|
|
:cache_length,
|
|
:cached
|
|
end
|
|
end
|
|
|
|
class_methods do
|
|
def id_hash(id, record_type)
|
|
return { id: id.to_s, type: record_type } if id.present?
|
|
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: record.id.to_s, type: record_type }
|
|
end
|
|
|
|
def ids_hash_from_record_and_relationship(record, relationship)
|
|
polymorphic = relationship[:polymorphic]
|
|
|
|
return ids_hash(
|
|
record.public_send(relationship[:id_method_name]),
|
|
relationship[:record_type]
|
|
) unless polymorphic
|
|
|
|
object_method_name = relationship.fetch(:object_method_name, relationship[:name])
|
|
return unless associated_object = record.send(object_method_name)
|
|
|
|
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 attributes_hash(record)
|
|
attributes_to_serialize.each_with_object({}) do |(key, method), attr_hash|
|
|
attr_hash[key] = method.is_a?(Proc) ? method.call(record) : record.public_send(method)
|
|
end
|
|
end
|
|
|
|
def relationships_hash(record, relationships = nil)
|
|
relationships = relationships_to_serialize if relationships.nil?
|
|
|
|
relationships.each_with_object({}) do |(_k, relationship), hash|
|
|
name = relationship[:key]
|
|
id_method_name = relationship[:id_method_name]
|
|
record_type = relationship[:record_type]
|
|
empty_case = relationship[:relationship_type] == :has_many ? [] : nil
|
|
hash[name] = {
|
|
data: ids_hash_from_record_and_relationship(record, relationship) || empty_case
|
|
}
|
|
end
|
|
end
|
|
|
|
def record_hash(record)
|
|
if cached
|
|
record_hash = Rails.cache.fetch(record.cache_key, expires_in: cache_length) do
|
|
temp_hash = id_hash(record.id, record_type) || { id: nil, type: record_type }
|
|
temp_hash[:attributes] = attributes_hash(record) if attributes_to_serialize.present?
|
|
temp_hash[:relationships] = {}
|
|
temp_hash[:relationships] = relationships_hash(record, cachable_relationships_to_serialize) if cachable_relationships_to_serialize.present?
|
|
temp_hash
|
|
end
|
|
record_hash[:relationships] = record_hash[:relationships].merge(relationships_hash(record, uncachable_relationships_to_serialize)) if uncachable_relationships_to_serialize.present?
|
|
record_hash
|
|
else
|
|
record_hash = id_hash(record.id, record_type) || { id: nil, type: record_type }
|
|
record_hash[:attributes] = attributes_hash(record) if attributes_to_serialize.present?
|
|
record_hash[:relationships] = relationships_hash(record) if relationships_to_serialize.present?
|
|
record_hash
|
|
end
|
|
end
|
|
|
|
# Override #to_json for alternative implementation
|
|
def to_json(payload)
|
|
FastJsonapi::MultiToJson.to_json(payload) if payload.present?
|
|
end
|
|
|
|
# includes handler
|
|
|
|
def get_included_records(record, includes_list, known_included_objects)
|
|
includes_list.each_with_object([]) do |item, included_records|
|
|
object_method_name = @relationships_to_serialize[item][:object_method_name]
|
|
record_type = @relationships_to_serialize[item][:record_type]
|
|
serializer = @relationships_to_serialize[item][:serializer].to_s.constantize
|
|
relationship_type = @relationships_to_serialize[item][:relationship_type]
|
|
included_objects = record.send(object_method_name)
|
|
next if included_objects.blank?
|
|
included_objects = [included_objects] unless relationship_type == :has_many
|
|
included_objects.each do |inc_obj|
|
|
code = "#{record_type}_#{inc_obj.id}"
|
|
next if known_included_objects.key?(code)
|
|
known_included_objects[code] = inc_obj
|
|
included_records << serializer.record_hash(inc_obj)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|