class ConvertNotificationsEventPayloadToJson < ActiveRecord::Migration[5.1]
  def self.up
    Notification20170831143534.transaction do
      Notification20170831143534.find_each do |notification|
        json = yaml_to_json(notification.event_payload)
        notification.update!(event_payload: json)
      end
    end
  end

  def self.down
    raise ActiveRecord::IrreversibleMigration
  end
end

def yaml_to_json(yaml)
  YAML.safe_load(yaml)
      .traverse do |value|
        if value.is_a?(String)
          value.force_encoding('UTF-8')
        else
          value
        end
      end
      .to_json
end

# Notification model only for migration in order to avoid errors coming from the serialization in the actual Notification model
class Notification20170831143534 < ApplicationRecord
  self.table_name = 'notifications'
  self.inheritance_column = :_type_disabled
end

# Hash extension is used to run force_encoding against each string value in the hash
# in data migration to convert yaml to json serialisation for event payloads
class Hash
  def traverse(&)
    traverse_value(self, &)
  end

  private

  def traverse_value(value, &)
    case value
    when Hash
      value.each { |key, sub_value| value[key] = traverse_value(sub_value, &) }

    when Array
      value.map { |element| traverse_value(element, &) }

    else
      yield(value)

    end
  end
end
