gitlab-org--gitlab-foss/rubocop/cop/usage_data/large_table.rb

88 lines
2.6 KiB
Ruby

# frozen_string_literal: true
module RuboCop
module Cop
module UsageData
class LargeTable < RuboCop::Cop::Cop
# This cop checks that batch count and distinct_count are used in usage_data.rb files in metrics based on ActiveRecord models.
#
# @example
#
# # bad
# Issue.count
# List.assignee.count
# ::Ci::Pipeline.auto_devops_source.count
# ZoomMeeting.distinct.count(:issue_id)
#
# # Good
# count(Issue)
# count(List.assignee)
# count(::Ci::Pipeline.auto_devops_source)
# distinct_count(ZoomMeeting, :issue_id)
MSG = 'Use one of the %{count_methods} methods for counting on %{class_name}'
# Match one level const as Issue, Gitlab
def_node_matcher :one_level_node, <<~PATTERN
(send
(const {nil? cbase} $...)
$...)
PATTERN
# Match two level const as ::Clusters::Cluster, ::Ci::Pipeline
def_node_matcher :two_level_node, <<~PATTERN
(send
(const
(const {nil? cbase} $...)
$...)
$...)
PATTERN
def on_send(node)
one_level_matches = one_level_node(node)
two_level_matches = two_level_node(node)
return unless Array(one_level_matches).any? || Array(two_level_matches).any?
if one_level_matches
class_name = one_level_matches[0].first
method_used = one_level_matches[1]&.first
else
class_name = "#{two_level_matches[0].first}::#{two_level_matches[1].first}".to_sym
method_used = two_level_matches[2]&.first
end
return if non_related?(class_name) || allowed_methods.include?(method_used)
counters_used = node.ancestors.any? { |ancestor| allowed_method?(ancestor) }
unless counters_used
add_offense(node, location: :expression, message: format(MSG, count_methods: count_methods.join(', '), class_name: class_name))
end
end
private
def count_methods
cop_config['CountMethods'] || []
end
def allowed_methods
cop_config['AllowedMethods'] || []
end
def non_related_classes
cop_config['NonRelatedClasses'] || []
end
def non_related?(class_name)
non_related_classes.include?(class_name)
end
def allowed_method?(ancestor)
ancestor.send_type? && !ancestor.dot? && count_methods.include?(ancestor.method_name)
end
end
end
end
end