lib/view_model/serialize_context.rb



# frozen_string_literal: true

require 'active_support/core_ext'
require 'view_model/traversal_context'

class ViewModel::SerializeContext < ViewModel::TraversalContext
  class SharedContext < ViewModel::TraversalContext::SharedContext
    attr_reader :references, :flatten_references

    def initialize(flatten_references: false, **rest)
      super(**rest)
      @references         = ViewModel::References.new
      @flatten_references = flatten_references
    end
  end

  def self.shared_context_class
    SharedContext
  end

  delegate :references, :flatten_references, to: :shared_context
  delegate :add_reference, :has_references?, to: :references

  # Return viewmodels referenced during serialization and clear @references.
  def extract_referenced_views!
    refs = references.each.to_h
    references.clear!
    refs
  end

  def serialize_references(json)
    reference_context = self.for_references

    # References should be serialized in a stable order to improve caching via
    # naive response hash.

    serialized_refs = {}

    while references.present?
      extract_referenced_views!.each do |ref, value|
        next if serialized_refs.has_key?(ref)

        serialized_refs[ref] = Jbuilder.new do |j|
          ViewModel.serialize(value, j, serialize_context: reference_context)
        end
      end
    end

    serialized_refs.sort.each do |ref, value|
      json.set!(ref, value)
    end
  end

  def serialize_references_to_hash
    Jbuilder.new { |json| serialize_references(json) }.attributes!
  end
end