module FastJsonapi::SerializationCore

Attributes

attributes_to_serialize[RW]
cachable_relationships_to_serialize[RW]
cache_store_instance[RW]
cache_store_options[RW]
meta_to_serialize[RW]
record_id[RW]
record_type[RW]
record_type_block[RW]
relationships_to_serialize[RW]
transform_method[RW]
uncachable_relationships_to_serialize[RW]

Public Instance Methods

attributes_hash(record, fieldset = nil, params = {}) click to toggle source
# File lib/fast_jsonapi/serialization_core.rb, line 44
def attributes_hash(record, fieldset = nil, params = {})
  attributes = attributes_to_serialize
  attributes = attributes.slice(*fieldset) if fieldset.present?
  attributes = {} if fieldset == []

  attributes.each_with_object({}) do |(_k, attribute), hash|
    attribute.serialize(record, params, hash)
  end
end
get_included_records(record, includes_list, known_included_objects, fieldsets, params = {}) click to toggle source

includes handler

# File lib/fast_jsonapi/serialization_core.rb, line 171
def get_included_records(record, includes_list, known_included_objects, fieldsets, params = {})
  return unless includes_list.present?
  return [] unless relationships_to_serialize

  includes_list = parse_includes_list(includes_list)

  includes_list.each_with_object([]) do |include_item, included_records|
    relationship_item = relationships_to_serialize[include_item.first]

    next unless relationship_item&.include_relationship?(record, params)

    included_objects = Array(relationship_item.fetch_associated_object(record, params))
    next if included_objects.empty?

    static_serializer = relationship_item.static_serializer
    static_record_type = relationship_item.static_record_type

    included_objects.each do |inc_obj|
      serializer = static_serializer || relationship_item.serializer_for(inc_obj, params)
      record_type = static_record_type || serializer.record_type

      if include_item.last.any?
        serializer_records = serializer.get_included_records(inc_obj, include_item.last, known_included_objects, fieldsets, params)
        included_records.concat(serializer_records) unless serializer_records.empty?
      end

      code = "#{record_type}_#{serializer.id_from_record(inc_obj, params)}"
      next if known_included_objects.include?(code)

      known_included_objects << code

      included_records << serializer.record_hash(inc_obj, fieldsets[record_type], includes_list, params)
    end
  end
end
id_from_record(record, params) click to toggle source

rubocop:enable Lint/UnusedMethodArgument

# File lib/fast_jsonapi/serialization_core.rb, line 122
def id_from_record(record, params)
  return FastJsonapi.call_proc(record_id, record, params) if record_id.is_a?(Proc)
  return record.send(record_id) if record_id
  raise MandatoryField, 'id is a mandatory field in the jsonapi spec' unless record.respond_to?(:id)

  record.id
end
id_hash(id, record_type, default_return = false) click to toggle source
# File lib/fast_jsonapi/serialization_core.rb, line 30
def id_hash(id, record_type, default_return = false)
  if id.present?
    { id: id.to_s, type: record_type }
  else
    default_return ? { id: nil, type: record_type } : nil
  end
end
meta_hash(record, params = {}) click to toggle source
# File lib/fast_jsonapi/serialization_core.rb, line 65
def meta_hash(record, params = {})
  FastJsonapi.call_proc(meta_to_serialize, record, params)
end
parse_includes_list(includes_list) click to toggle source

It chops out the root association (first part) from each include.

It keeps an unique list and collects all of the rest of the include value to hand it off to the next related to include serializer.

This method will turn that include array into a Hash that looks like:

{
    authors: Set.new([
      'books',
      'books.genre',
      'books.genre.books',
      'books.genre.books.authors',
      'books.genre.books.genre'
    ]),
    genre: Set.new(['books'])
}

Because the serializer only cares about the root associations included, it only needs the first segment of each include (for books, it’s the “authors” and “genre”) and it doesn’t need to waste cycles parsing the rest of the include value. That will be done by the next serializer in line.

@param includes_list [List] to be parsed @return [Hash]

# File lib/fast_jsonapi/serialization_core.rb, line 162
def parse_includes_list(includes_list)
  includes_list.each_with_object({}) do |include_item, include_sets|
    include_base, include_remainder = include_item.to_s.split('.', 2)
    include_sets[include_base.to_sym] ||= Set.new
    include_sets[include_base.to_sym] << include_remainder if include_remainder
  end
end
record_cache_options(options, fieldset, includes_list, params) click to toggle source

Cache options helper. Use it to adapt cache keys/rules.

If a fieldset is specified, it modifies the namespace to include the fields from the fieldset.

@param options [Hash] default cache options @param fieldset [Array, nil] passed fieldset values @param includes_list [Array, nil] passed included values @param params [Hash] the serializer params

@return [Hash] processed options hash rubocop:disable Lint/UnusedMethodArgument

# File lib/fast_jsonapi/serialization_core.rb, line 103
def record_cache_options(options, fieldset, includes_list, params)
  return options unless fieldset

  options = options ? options.dup : {}
  options[:namespace] ||= 'jsonapi-serializer'

  fieldset_key = fieldset.join('_')

  # Use a fixed-length fieldset key if the current length is more than
  # the length of a SHA1 digest
  if fieldset_key.length > 40
    fieldset_key = Digest::SHA1.hexdigest(fieldset_key)
  end

  options[:namespace] = "#{options[:namespace]}-fieldset:#{fieldset_key}"
  options
end
record_hash(record, fieldset, includes_list, params = {}) click to toggle source
# File lib/fast_jsonapi/serialization_core.rb, line 69
def record_hash(record, fieldset, includes_list, params = {})
  if cache_store_instance
    cache_opts = record_cache_options(cache_store_options, fieldset, includes_list, params)
    record_hash = cache_store_instance.fetch(record, **cache_opts) do
      temp_hash = id_hash(id_from_record(record, params), type_from_record(record, record_type), true)
      temp_hash[:attributes] = attributes_hash(record, fieldset, params) if attributes_to_serialize.present?
      temp_hash[:relationships] = relationships_hash(record, cachable_relationships_to_serialize, fieldset, includes_list, params) if cachable_relationships_to_serialize.present?
      temp_hash[:links] = links_hash(record, params) if data_links.present?
      temp_hash
    end
    record_hash[:relationships] = (record_hash[:relationships] || {}).merge(relationships_hash(record, uncachable_relationships_to_serialize, fieldset, includes_list, params)) if uncachable_relationships_to_serialize.present?
  else
    record_hash = id_hash(id_from_record(record, params), type_from_record(record, record_type), true)
    record_hash[:attributes] = attributes_hash(record, fieldset, params) if attributes_to_serialize.present?
    record_hash[:relationships] = relationships_hash(record, nil, fieldset, includes_list, params) if relationships_to_serialize.present?
    record_hash[:links] = links_hash(record, params) if data_links.present?
  end

  record_hash[:meta] = meta_hash(record, params) if meta_to_serialize.present?
  record_hash
end
relationships_hash(record, relationships = nil, fieldset = nil, includes_list = nil, params = {}) click to toggle source
# File lib/fast_jsonapi/serialization_core.rb, line 54
def relationships_hash(record, relationships = nil, fieldset = nil, includes_list = nil, params = {})
  relationships = relationships_to_serialize if relationships.nil?
  relationships = relationships.slice(*fieldset) if fieldset.present?
  relationships = {} if fieldset == []

  relationships.each_with_object({}) do |(key, relationship), hash|
    included = includes_list.present? && includes_list.include?(key)
    relationship.serialize(record, included, params, hash)
  end
end
type_from_record(record, record_type) click to toggle source
# File lib/fast_jsonapi/serialization_core.rb, line 130
def type_from_record(record, record_type)
  return FastJsonapi.call_proc(record_type_block, record) if record_type_block.is_a?(Proc)

  record_type
end