Sha256: b5bbfc929183b13c0cb8c1664667be9e3810eca799a590145e61011305abb15c

Contents?: true

Size: 1.61 KB

Versions: 1

Compression:

Stored size: 1.61 KB

Contents

require 'active_support/log_subscriber'

module ActiveRecord
  module Explainer
    class Subscriber < ActiveSupport::LogSubscriber # :nodoc:
      def sql(event)
        payload = event.payload
        return if ignore_payload?(payload) || !ActiveRecord::Base.connection.supports_explain?

        # Save `affected_rows` and restore after issuing EXPLAIN query because
        # the query will resets `affected_rows` to 0.
        original_affectet_rows = affected_rows
        debug exec_explain(sql: payload[:sql], binds: payload[:binds])
      ensure
        affectet_rows = original_affectet_rows
      end

      private

      IGNORED_PAYLOADS = %w[SCHEMA EXPLAIN].freeze
      EXPLAINED_SQLS = /\A\s*(with|select|update|delete|insert)\b/i.freeze

      def ignore_payload?(payload)
        payload[:cached] ||
          IGNORED_PAYLOADS.include?(payload[:name]) ||
          payload[:sql] !~ EXPLAINED_SQLS
      end

      def exec_explain(sql:, binds:)
        msg = +"EXPLAIN for: #{sql}"
        unless binds.empty?
          msg << ' '
          msg << binds.map { |attr| render_bind(attr) }.inspect
        end
        msg << "\n"
        msg << ActiveRecord::Base.connection.explain(sql, binds)
        color(msg, :yellow)
      end

      def render_bind(attr)
        value =
          if attr.type.binary? && attr.value
            "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
          else
            ActiveRecord::Base.connection.type_cast(attr.value_for_database)
          end

        [attr.name, value]
      end

      def logger
        ActiveRecord::Explainer.config.logger
      end
    end
  end
end

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
activerecord-explainer-0.2.4 lib/activerecord/explainer/subscriber.rb