-
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathadd_index_columns_count.rb
114 lines (102 loc) · 3.02 KB
/
add_index_columns_count.rb
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# frozen_string_literal: true
module RuboCop
module Cop
module Migration
# Keep non-unique index columns count less than a specified number.
#
# Adding a non-unique index with more than three columns rarely improves performance.
# Instead, start an index with columns that narrow down the results the most.
#
# @example
# # bad
# add_index :users, %i[a b c d]
#
# # good (`MaxColumnsCount: 3` by default)
# add_index :users, %i[a b c]
class AddIndexColumnsCount < RuboCop::Cop::Base
RESTRICT_ON_SEND = %i[
add_index
index
].freeze
# @param node [RuboCop::AST::SendNode]
# @return [void]
def on_send(node)
return if with_unique_option?(node)
column_names_node = column_names_node_from(node)
return unless column_names_node
column_names_count = columns_count_from(column_names_node)
return if column_names_count <= max_columns_count
add_offense(
column_names_node,
message: "Keep unique index columns count less than #{max_columns_count}."
)
end
private
# @!method column_names_node_from_add_index(node)
# @param node [RuboCop::AST::SendNode]
# @return [RuboCop::AST::Node, nil]
def_node_matcher :column_names_node_from_add_index, <<~PATTERN
(send
nil?
:add_index
_
$({array | str | sym} ...)
...
)
PATTERN
# @!method column_names_node_from_index(node)
# @param node [RuboCop::AST::SendNode]
# @return [RuboCop::AST::Node, nil]
def_node_matcher :column_names_node_from_index, <<~PATTERN
(send
lvar
:index
$({array | str | sym} ...)
...
)
PATTERN
# @!method with_unique_option?(node)
# @param node [RuboCop::AST::SendNode]
# @return [Boolean]
def_node_matcher :with_unique_option?, <<~PATTERN
(send
...
(hash
<
(pair
(sym :unique)
true
)
...
>
)
)
PATTERN
# @param node [RuboCop::AST::SendNode]
# @return [RuboCop::AST::Node, nil]
def column_names_node_from(node)
case node.method_name
when :add_index
column_names_node_from_add_index(node)
when :index
column_names_node_from_index(node)
end
end
# @param node [RuboCop::AST::Node]
# @return [Integer, nil]
def columns_count_from(node)
case node.type
when :array
node.values.count
when :sym
1
end
end
# @return [Integer]
def max_columns_count
cop_config['MaxColumnsCount']
end
end
end
end
end