1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
|
# frozen_string_literal: true
require 'rubocop/cop/mixin/active_record_helper'
require_relative '../../code_reuse_helpers'
module RuboCop
module Cop
module Database
# Checks the use of .pluck(:attribute) without setting a limit.
#
# @example
#
# # bad
# def all
# Project.where(user_id: User.pluck(:id))
# end
#
# # good
# def all(limit)
# Project.where(user_id: User.limit(limit).pluck(:id))
# end
class AvoidUsingPluckWithoutLimit < RuboCop::Cop::Base
include RuboCop::Cop::ActiveRecordHelper
include RuboCop::CodeReuseHelpers
MSG = 'Avoid using `pluck` without defining a proper `limit`. ' \
'Querying with too much values inside an `IN` clause can result in database performance degradation. ' \
'See https://gitlab.com/gitlab-com/gl-infra/production/-/issues/17168'
RESTRICT_ON_SEND = %i[pluck].freeze
def_node_matcher :pluck_with_limit?, <<~PATTERN
(send (send _ :limit _) ...)
PATTERN
def on_send(node)
return unless should_scan?(node)
return if pluck_with_limit?(node)
add_offense(node.loc.selector)
end
private
# It limits the check to ActiveRecord, Models, Finders and Service classes
def should_scan?(node)
inherit_active_record_base?(node) || in_model?(node) || in_finder?(node) || in_service_class?(node)
end
end
end
end
end
|