lib/wolf_core/infrastructure/application_serializer.rb



# frozen_string_literal: true

module WolfCore
  class ApplicationSerializer
    attr_reader :object, :options

    def initialize(object, options = {})
      @object = object
      @options = options
    end

    def self.serialize_all(collection, options = {})
      collection.map { |item| serialize(item, options) }
    end

    def self.serialize(entity, options = {})
      new(entity, options).as_json.with_indifferent_access
    end

    def self.attributes(*attrs)
      _attributes.concat(attrs.map(&:to_sym))
    end

    def self.has_many(relationship, serializer:) # rubocop:disable Naming/PredicateName
      _relationships[relationship.to_sym] = serializer
    end

    def self.has_one(relationship, serializer:) # rubocop:disable Naming/PredicateName
      _relationships[relationship.to_sym] = serializer
    end

    def self._attributes
      @_attributes ||= []
    end

    def self._relationships
      @_relationships ||= {}
    end

    def as_json(*)
      attributes = serialized_attributes
      relationships = serialized_relationships
      attributes.merge(relationships)
    end

    private

    def serialized_attributes
      self.class._attributes.each_with_object({}) do |attribute, hash|
        hash[attribute] = if respond_to?(attribute, true)
                            send(attribute)
                          elsif object.respond_to?(attribute)
                            object.public_send(attribute)
                          end
      end
    end

    def serialized_relationships
      self.class._relationships.each_with_object({}) do |(key, serializer_class), hash|
        related_object = object.public_send(key)
        hash[key] = if related_object.is_a?(Enumerable)
                      serializer_class.serialize_all(related_object, options)
                    else
                      serializer_class.serialize(related_object, options).as_json
                    end
      end
    end
  end
end