class RuboCop::Cop::Rails::WhereNot


User.where.not(users: { name: ‘Gabe’ })
User.where.not(name: [‘john’, ‘jane’])
User.where.not(name: nil)
User.where.not(name: ‘Gabe’)
# good
User.where(‘users.name != :name’, name: ‘Gabe’)
User.where(‘name NOT IN (:names)’, names: [‘john’, ‘jane’])
User.where(‘name NOT IN (?)’, [‘john’, ‘jane’])
User.where(‘name IS NOT NULL’)
User.where(‘name <> :name’, name: ‘Gabe’)
User.where(‘name <> ?’, ‘Gabe’)
User.where(‘name != :name’, name: ‘Gabe’)
User.where(‘name != ?’, ‘Gabe’)
# bad
@example
in ‘where` can be replaced with `where.not(…)`.
Identifies places where manually constructed SQL

def build_good_method(dot, column, value)

def build_good_method(dot, column, value)
  dot ||= '.'
  if column.include?('.')
    table, column = column.split('.')
    "where#{dot}not(#{table}: { #{column}: #{value} })"
  else
    "where#{dot}not(#{column}: #{value})"
  end
end

def extract_column_and_value(template_node, value_node)

rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
def extract_column_and_value(template_node, value_node)
  value =
    case template_node.value
    when NOT_EQ_ANONYMOUS_RE, NOT_IN_ANONYMOUS_RE
      value_node&.source
    when NOT_EQ_NAMED_RE, NOT_IN_NAMED_RE
      return unless value_node&.hash_type?
      pair = value_node.pairs.find { |p| p.key.value.to_sym == Regexp.last_match(2).to_sym }
      pair.value.source
    when IS_NOT_NULL_RE
      'nil'
    else
      return
    end
  column_qualifier = Regexp.last_match(1)
  return if column_qualifier.count('.') > 1
  [column_qualifier, value]
end

def offense_range(node)

def offense_range(node)
  range_between(node.loc.selector.begin_pos, node.source_range.end_pos)
end

def on_send(node)

def on_send(node)
  where_method_call?(node) do |template_node, value_node|
    value_node = value_node.first
    range = offense_range(node)
    column, value = extract_column_and_value(template_node, value_node)
    return unless value
    good_method = build_good_method(node.loc.dot&.source, column, value)
    message = format(MSG, good_method: good_method)
    add_offense(range, message: message) do |corrector|
      corrector.replace(range, good_method)
    end
  end
end