rubocop-isucon 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -1
  3. data/README.md +17 -6
  4. data/config/default.yml +36 -0
  5. data/lib/rubocop/cop/isucon/correctors/{mysql2_n_plus_one_query_corrector → n_plus_one_query_corrector}/correctable_methods.rb +1 -1
  6. data/lib/rubocop/cop/isucon/correctors/{mysql2_n_plus_one_query_corrector → n_plus_one_query_corrector}/replace_methods.rb +1 -1
  7. data/lib/rubocop/cop/isucon/correctors/{mysql2_n_plus_one_query_corrector.rb → n_plus_one_query_corrector.rb} +15 -4
  8. data/lib/rubocop/cop/isucon/mixin/join_without_index_methods.rb +87 -0
  9. data/lib/rubocop/cop/isucon/mixin/many_join_table_methods.rb +39 -0
  10. data/lib/rubocop/cop/isucon/mixin/mysql2_xquery_methods.rb +7 -116
  11. data/lib/rubocop/cop/isucon/mixin/n_plus_one_query_methods.rb +153 -0
  12. data/lib/rubocop/cop/isucon/mixin/offense_location_methods.rb +130 -0
  13. data/lib/rubocop/cop/isucon/mixin/select_asterisk_methods.rb +148 -0
  14. data/lib/rubocop/cop/isucon/mixin/sqlite3_execute_methods.rb +67 -0
  15. data/lib/rubocop/cop/isucon/mixin/where_without_index_methods.rb +96 -0
  16. data/lib/rubocop/cop/isucon/mysql2/join_without_index.rb +4 -67
  17. data/lib/rubocop/cop/isucon/mysql2/many_join_table.rb +1 -26
  18. data/lib/rubocop/cop/isucon/mysql2/n_plus_one_query.rb +4 -114
  19. data/lib/rubocop/cop/isucon/mysql2/select_asterisk.rb +1 -135
  20. data/lib/rubocop/cop/isucon/mysql2/where_without_index.rb +5 -70
  21. data/lib/rubocop/cop/isucon/sqlite3/join_without_index.rb +37 -0
  22. data/lib/rubocop/cop/isucon/sqlite3/many_join_table.rb +61 -0
  23. data/lib/rubocop/cop/isucon/sqlite3/n_plus_one_query.rb +70 -0
  24. data/lib/rubocop/cop/isucon/sqlite3/select_asterisk.rb +37 -0
  25. data/lib/rubocop/cop/isucon/sqlite3/where_without_index.rb +40 -0
  26. data/lib/rubocop/cop/isucon_cops.rb +13 -1
  27. data/lib/rubocop/isucon/version.rb +1 -1
  28. metadata +17 -5
@@ -26,144 +26,10 @@ module RuboCop
26
26
  # db.xquery('SELECT users.id, users.name FROM users')
27
27
  #
28
28
  class SelectAsterisk < Base
29
- include Mixin::DatabaseMethods
30
29
  include Mixin::Mysql2XqueryMethods
30
+ include Mixin::SelectAsteriskMethods
31
31
 
32
32
  extend AutoCorrector
33
-
34
- MSG = "Use SELECT with column names. (e.g. `SELECT id, name FROM table_name`)"
35
-
36
- TODO = "# TODO: Remove needless columns if necessary\n"
37
-
38
- # @param node [RuboCop::AST::Node]
39
- def on_send(node)
40
- with_error_handling(node) do
41
- with_xquery(node) do |type, root_gda|
42
- next unless root_gda
43
-
44
- check_and_register_offence(type: type, root_gda: root_gda, node: node)
45
- end
46
- end
47
- end
48
-
49
- private
50
-
51
- # @param type [Symbol] Node type. one of `:str`, `:dstr`
52
- # @param root_gda [RuboCop::Isucon::GDA::Client]
53
- # @param node [RuboCop::AST::Node]
54
- def check_and_register_offence(type:, root_gda:, node:)
55
- root_gda.visit_all do |gda|
56
- next unless gda.ast.respond_to?(:expr_list)
57
-
58
- gda.ast.expr_list.each do |select_field_node|
59
- check_and_register_offence_for_select_field_node(
60
- type: type, node: node, gda: gda,
61
- select_field_node: select_field_node
62
- )
63
- end
64
- end
65
- end
66
-
67
- # @param type [Symbol] Node type. one of `:str`, `:dstr`
68
- # @param node [RuboCop::AST::Node]
69
- # @param gda [RuboCop::Isucon::GDA::Client]
70
- # @param select_field_node [GDA::Nodes::SelectField]
71
- def check_and_register_offence_for_select_field_node(type:, node:, gda:, select_field_node:)
72
- return unless select_field_node.respond_to?(:expr)
73
-
74
- select_field = parse_select_field_node(select_field_node)
75
-
76
- return unless select_field[:column_name] == "*"
77
-
78
- loc = offense_location(type: type, node: node, gda_location: select_field_node.expr.location)
79
- return unless loc
80
-
81
- add_offense(loc) do |corrector|
82
- perform_autocorrect(corrector: corrector, loc: loc, gda: gda, node: node,
83
- select_table_name: select_field[:table_name])
84
- end
85
- end
86
-
87
- # @param select_field_node [GDA::Nodes::SelectField]
88
- # @return [Hash<Symbol, String>] table_name, column_name
89
- def parse_select_field_node(select_field_node)
90
- column_elements = select_field_node.expr.value.split(".", 2)
91
-
92
- case column_elements.count
93
- when 1
94
- return { column_name: column_elements[0] }
95
- when 2
96
- return { table_name: column_elements[0], column_name: column_elements[1] }
97
- end
98
-
99
- {}
100
- end
101
-
102
- # @param corrector [RuboCop::Cop::Corrector]
103
- # @param loc [Parser::Source::Range]
104
- # @param gda [RuboCop::Isucon::GDA::Client]
105
- # @param node [RuboCop::AST::Node]
106
- # @param select_table_name [String,nil] table names included in the SELECT clause
107
- def perform_autocorrect(corrector:, loc:, gda:, node:, select_table_name:)
108
- return unless enabled_database?
109
- return if gda.table_names.empty?
110
-
111
- if select_table_name
112
- return unless gda.table_names.include?(select_table_name)
113
-
114
- replace_asterisk(corrector: corrector, loc: loc, table_name: select_table_name, table_prefix: true)
115
- else
116
- return unless gda.table_names.length == 1
117
-
118
- replace_asterisk(corrector: corrector, loc: loc, table_name: gda.table_names[0], table_prefix: false)
119
- end
120
-
121
- insert_todo_comment(corrector: corrector, node: node)
122
- end
123
-
124
- # @param corrector [RuboCop::Cop::Corrector]
125
- # @param loc [Parser::Source::Range]
126
- # @param table_name [String]
127
- # @param table_prefix [Boolean] Whether add table name to prefix (e.g. `users`.`name`)
128
- def replace_asterisk(corrector:, loc:, table_name:, table_prefix:)
129
- select_columns = columns_in_select_clause(table_name: table_name, table_prefix: table_prefix)
130
- corrector.replace(loc, select_columns)
131
- end
132
-
133
- # @param table_name [String]
134
- # @param table_prefix [Boolean] Whether add table name to prefix (e.g. `users`.`name`)
135
- # @return [String]
136
- def columns_in_select_clause(table_name:, table_prefix:)
137
- column_names = connection.column_names(table_name)
138
-
139
- column_names.map do |column|
140
- if table_prefix
141
- "`#{table_name}`.`#{column}`"
142
- else
143
- "`#{column}`"
144
- end
145
- end.join(", ")
146
- end
147
-
148
- # @param corrector [RuboCop::Cop::Corrector]
149
- # @param node [RuboCop::AST::Node]
150
- def insert_todo_comment(corrector:, node:)
151
- current_line = node.loc.expression.line
152
- current_line_range = node.loc.expression.source_buffer.line_range(current_line)
153
-
154
- indent = node_indent_level(node)
155
- comment_line = (" " * indent) + TODO
156
- corrector.insert_before(current_line_range, comment_line)
157
- end
158
-
159
- # @param node [RuboCop::AST::Node]
160
- # @return [Integer]
161
- def node_indent_level(node)
162
- node.loc.expression.source_line =~ /^(\s+)/
163
- return 0 unless Regexp.last_match(1)
164
-
165
- Regexp.last_match(1).length
166
- end
167
33
  end
168
34
  end
169
35
  end
@@ -19,84 +19,19 @@ module RuboCop
19
19
  # db.xquery('SELECT id, title FROM articles WHERE id = ?', id)
20
20
  #
21
21
  class WhereWithoutIndex < Base
22
- include Mixin::DatabaseMethods
23
22
  include Mixin::Mysql2XqueryMethods
23
+ include Mixin::WhereWithoutIndexMethods
24
24
 
25
25
  MSG = "This where clause doesn't seem to have an index. " \
26
26
  "(e.g. `ALTER TABLE %<table_name>s ADD INDEX index_%<column_name>s (%<column_name>s)`)"
27
27
 
28
- # @param node [RuboCop::AST::Node]
29
- def on_send(node)
30
- with_error_handling(node) do
31
- return unless enabled_database?
32
-
33
- with_xquery(node) do |type, root_gda|
34
- next unless root_gda
35
- next if exists_index_in_where_clause_columns?(root_gda)
36
-
37
- register_offense(type: type, node: node, root_gda: root_gda)
38
- end
39
- end
40
- end
41
-
42
28
  private
43
29
 
44
- # @param type [Symbol] Node type. one of `:str`, `:dstr`
45
- # @param node [RuboCop::AST::Node]
46
- # @param root_gda [RuboCop::Isucon::GDA::Client]
47
- def register_offense(type:, node:, root_gda:)
48
- root_gda.visit_all do |gda|
49
- next if gda.where_nodes.empty?
50
-
51
- loc = offense_location(type: type, node: node, gda_location: gda.where_nodes.first.location)
52
- next unless loc
53
-
54
- message = offense_message(gda)
55
- add_offense(loc, message: message)
56
- end
57
- end
58
-
59
- # @param gda [RuboCop::Isucon::GDA::Client]
60
- def offense_message(gda)
61
- column_name = gda.where_conditions[0].column_operand
62
- table_name = find_table_name_from_column_name(table_names: gda.table_names, column_name: column_name)
63
- format(MSG, table_name: table_name, column_name: column_name)
64
- end
65
-
66
- # @param root_gda [RuboCop::Isucon::GDA::Client]
67
- # @return [Boolean]
68
- def exists_index_in_where_clause_columns?(root_gda)
69
- root_gda.visit_all do |gda|
70
- gda.table_names.each do |table_name|
71
- return true if covered_where_column_in_index?(gda: gda, table_name: table_name)
72
- return true if covered_where_column_in_primary_key?(gda: gda, table_name: table_name)
73
- end
74
- end
75
-
76
- false
77
- end
78
-
79
- # @param gda [RuboCop::Isucon::GDA::Client]
80
- # @param table_name [String]
81
- # @return [Boolean]
82
- def covered_where_column_in_index?(gda:, table_name:)
83
- indexes = connection.indexes(table_name)
84
- index_first_columns = indexes.map { |index| index.columns[0] }
85
-
86
- gda.where_conditions.any? do |condition|
87
- index_first_columns.include?(condition.column_operand)
88
- end
89
- end
90
-
91
- # @param gda [RuboCop::Isucon::GDA::Client]
92
30
  # @param table_name [String]
93
- # @return [Boolean]
94
- def covered_where_column_in_primary_key?(gda:, table_name:)
95
- primary_keys = connection.primary_keys(table_name)
96
- return false if primary_keys.empty?
97
-
98
- where_columns = gda.where_conditions.map(&:column_operand)
99
- primary_keys.all? { |primary_key| where_columns.include?(primary_key) }
31
+ # @param column_name [String]
32
+ # @return [String]
33
+ def generate_offense_message(table_name:, column_name:)
34
+ format(MSG, table_name: table_name, column_name: column_name)
100
35
  end
101
36
  end
102
37
  end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Isucon
6
+ module Sqlite3
7
+ # Check for `JOIN` without index
8
+ #
9
+ # @note If `Database` isn't configured, this cop's feature (offense detection and auto-correct) will not be available.
10
+ #
11
+ # @example
12
+ # # bad (user_id is not indexed)
13
+ # db.execute('SELECT id, title FROM articles JOIN users ON users.id = articles.user_id')
14
+ #
15
+ # # good (user_id is indexed)
16
+ # db.execute('SELECT id, title FROM articles JOIN users ON users.id = articles.user_id')
17
+ #
18
+ class JoinWithoutIndex < Base
19
+ include Mixin::Sqlite3ExecuteMethods
20
+ include Mixin::JoinWithoutIndexMethods
21
+
22
+ MSG = "This join clause doesn't seem to have an index. " \
23
+ "(e.g. `CREATE INDEX index_%<table_name>s_%<column_name>s ON %<table_name>s (%<column_name>s)`)"
24
+
25
+ private
26
+
27
+ # @param table_name [String]
28
+ # @param column_name [String]
29
+ # @return [String]
30
+ def generate_offense_message(table_name:, column_name:)
31
+ format(MSG, table_name: table_name, column_name: column_name)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Isucon
6
+ module Sqlite3
7
+ # Check if SQL contains many JOINs
8
+ #
9
+ # @example CountTables: 3 (default)
10
+ # # bad
11
+ # totals = db.execute(
12
+ # "SELECT IFNULL(SUM(`submissions`.`score`), 0) AS `total_score`" \
13
+ # " FROM `users`" \
14
+ # " JOIN `registrations` ON `users`.`id` = `registrations`.`user_id`" \
15
+ # " JOIN `courses` ON `registrations`.`course_id` = `courses`.`id`" \
16
+ # " LEFT JOIN `classes` ON `courses`.`id` = `classes`.`course_id`" \
17
+ # " LEFT JOIN `submissions` ON `users`.`id` = `submissions`.`user_id` AND `submissions`.`class_id` = `classes`.`id`" \
18
+ # " WHERE `courses`.`id` = ?" \
19
+ # " GROUP BY `users`.`id`",
20
+ # [course[:id]]
21
+ # ).map { |_| _[:total_score] }
22
+ #
23
+ # # good
24
+ # registration_users_count =
25
+ # db.execute("SELECT COUNT(`user_id`) AS cnt FROM `registrations` WHERE `course_id` = ?", [course[:id]]).first[:cnt]
26
+ #
27
+ # totals = db.execute(<<~SQL, course[:id]).map { |_| _[:total_score] }
28
+ # SELECT IFNULL(SUM(`submissions`.`score`), 0) AS `total_score`
29
+ # FROM `submissions`
30
+ # JOIN `classes` ON `classes`.`id` = `submissions`.`class_id`
31
+ # WHERE `classes`.`course_id` = ?
32
+ # GROUP BY `submissions`.`user_id`
33
+ # SQL
34
+ #
35
+ # if totals.count < registration_users_count
36
+ # no_submissions_count = registration_users_count - totals.count
37
+ # totals += [0] * no_submissions_count
38
+ # end
39
+ #
40
+ # @example CountTables: 5
41
+ # # good
42
+ # totals = db.execute(
43
+ # "SELECT IFNULL(SUM(`submissions`.`score`), 0) AS `total_score`" \
44
+ # " FROM `users`" \
45
+ # " JOIN `registrations` ON `users`.`id` = `registrations`.`user_id`" \
46
+ # " JOIN `courses` ON `registrations`.`course_id` = `courses`.`id`" \
47
+ # " LEFT JOIN `classes` ON `courses`.`id` = `classes`.`course_id`" \
48
+ # " LEFT JOIN `submissions` ON `users`.`id` = `submissions`.`user_id` AND `submissions`.`class_id` = `classes`.`id`" \
49
+ # " WHERE `courses`.`id` = ?" \
50
+ # " GROUP BY `users`.`id`",
51
+ # [course[:id]]
52
+ # ).map { |_| _[:total_score] }
53
+ #
54
+ class ManyJoinTable < Base
55
+ include Mixin::Sqlite3ExecuteMethods
56
+ include Mixin::ManyJoinTableMethods
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Isucon
6
+ module Sqlite3
7
+ # rubocop:disable Layout/LineLength
8
+
9
+ # Checks that N+1 query is not used
10
+ #
11
+ # @note If `Database` isn't configured, auto-correct will not be available. (Only offense detection can be used)
12
+ #
13
+ # @note For the number of N+1 queries that can be detected by this cop, there are too few that can be corrected automatically
14
+ #
15
+ # @example
16
+ # # bad
17
+ # reservations = db.execute('SELECT * FROM `reservations` WHERE `schedule_id` = ?', [schedule_id]).map do |reservation|
18
+ # reservation[:user] = db.execute('SELECT * FROM `users` WHERE `id` = ? LIMIT 1', [id]).first
19
+ # reservation
20
+ # end
21
+ #
22
+ # # good
23
+ # rows = db.xquery(<<~SQL, [schedule_id])
24
+ # SELECT
25
+ # r.id AS reservation_id,
26
+ # r.schedule_id AS reservation_schedule_id,
27
+ # r.user_id AS reservation_user_id,
28
+ # r.created_at AS reservation_created_at,
29
+ # u.id AS user_id,
30
+ # u.email AS user_email,
31
+ # u.nickname AS user_nickname,
32
+ # u.staff AS user_staff,
33
+ # u.created_at AS user_created_at
34
+ # FROM `reservations` AS r
35
+ # INNER JOIN users u ON u.id = r.user_id
36
+ # WHERE r.schedule_id = ?
37
+ # SQL
38
+ #
39
+ # # bad
40
+ # courses.map do |course|
41
+ # teacher = db.execute('SELECT * FROM `users` WHERE `id` = ?', [course[:teacher_id]]).first
42
+ # end
43
+ #
44
+ # # good
45
+ # # This is similar to ActiveRecord's preload
46
+ # # c.f. https://guides.rubyonrails.org/active_record_querying.html#preload
47
+ # courses.map do |course|
48
+ # @users_by_id ||= db.execute('SELECT * FROM `users` WHERE `id` IN (?)', [courses.map { |course| course[:teacher_id] }]).each_with_object({}) { |v, hash| hash[v[:id]] = v }
49
+ # teacher = @users_by_id[course[:teacher_id]]
50
+ # end
51
+ #
52
+ class NPlusOneQuery < Base
53
+ # rubocop:enable Layout/LineLength
54
+
55
+ include Mixin::Sqlite3ExecuteMethods
56
+ include Mixin::NPlusOneQueryMethods
57
+
58
+ extend AutoCorrector
59
+
60
+ private
61
+
62
+ # [Boolean]
63
+ def array_arg?
64
+ true
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Isucon
6
+ module Sqlite3
7
+ # Avoid `SELECT *` in `db.execute`
8
+ #
9
+ # @note If `Database` isn't configured, auto-correct will not be available. (Only offense detection can be used)
10
+ #
11
+ # @note This cop replaces `SELECT *` with a `SELECT` by the columns present in the table (e.g. `SELECT id, name`),
12
+ # but does not check whether the columns are actually used.
13
+ # Please manually delete unused columns after auto corrected
14
+ #
15
+ # @example
16
+ # # bad
17
+ # db.execute('SELECT * FROM users')
18
+ #
19
+ # # bad
20
+ # db.execute('SELECT users.* FROM users')
21
+ #
22
+ # # good
23
+ # db.execute('SELECT id, name FROM users')
24
+ #
25
+ # # good
26
+ # db.execute('SELECT users.id, users.name FROM users')
27
+ #
28
+ class SelectAsterisk < Base
29
+ include Mixin::Sqlite3ExecuteMethods
30
+ include Mixin::SelectAsteriskMethods
31
+
32
+ extend AutoCorrector
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Isucon
6
+ module Sqlite3
7
+ # Check for `WHERE` without index
8
+ #
9
+ # @note If `Database` isn't configured, this cop's feature (offense detection and auto-correct) will not be available.
10
+ #
11
+ # @example
12
+ # # bad (user_id is not indexed)
13
+ # db.execute('SELECT id, title FROM articles WHERE used_id = ?', [user_id])
14
+ #
15
+ # # good (user_id is indexed)
16
+ # db.execute('SELECT id, title FROM articles WHERE used_id = ?', [user_id])
17
+ #
18
+ # # good (id is primary key)
19
+ # db.execute('SELECT id, title FROM articles WHERE id = ?', [id])
20
+ #
21
+ class WhereWithoutIndex < Base
22
+ include Mixin::Sqlite3ExecuteMethods
23
+ include Mixin::WhereWithoutIndexMethods
24
+
25
+ MSG = "This where clause doesn't seem to have an index. " \
26
+ "(e.g. `CREATE INDEX index_%<table_name>s_%<column_name>s ON %<table_name>s (%<column_name>s)`)"
27
+
28
+ private
29
+
30
+ # @param table_name [String]
31
+ # @param column_name [String]
32
+ # @return [String]
33
+ def generate_offense_message(table_name:, column_name:)
34
+ format(MSG, table_name: table_name, column_name: column_name)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,10 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "isucon/mixin/database_methods"
4
+ require_relative "isucon/mixin/join_without_index_methods"
5
+ require_relative "isucon/mixin/offense_location_methods"
6
+ require_relative "isucon/mixin/many_join_table_methods"
4
7
  require_relative "isucon/mixin/mysql2_xquery_methods"
8
+ require_relative "isucon/mixin/n_plus_one_query_methods"
9
+ require_relative "isucon/mixin/select_asterisk_methods"
5
10
  require_relative "isucon/mixin/sinatra_methods"
11
+ require_relative "isucon/mixin/sqlite3_execute_methods"
12
+ require_relative "isucon/mixin/where_without_index_methods"
6
13
 
7
- require_relative "isucon/correctors/mysql2_n_plus_one_query_corrector"
14
+ require_relative "isucon/correctors/n_plus_one_query_corrector"
8
15
 
9
16
  require_relative "isucon/mysql2/join_without_index"
10
17
  require_relative "isucon/mysql2/many_join_table"
@@ -18,3 +25,8 @@ require_relative "isucon/sinatra/rack_logger"
18
25
  require_relative "isucon/sinatra/serve_static_file"
19
26
  require_relative "isucon/shell/backtick"
20
27
  require_relative "isucon/shell/system"
28
+ require_relative "isucon/sqlite3/join_without_index"
29
+ require_relative "isucon/sqlite3/many_join_table"
30
+ require_relative "isucon/sqlite3/n_plus_one_query"
31
+ require_relative "isucon/sqlite3/select_asterisk"
32
+ require_relative "isucon/sqlite3/where_without_index"
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RuboCop
4
4
  module Isucon
5
- VERSION = "0.1.0"
5
+ VERSION = "0.2.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-isucon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - sue445
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-07-23 00:00:00.000000000 Z
11
+ date: 2022-07-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -221,12 +221,19 @@ files:
221
221
  - gemfiles/activerecord_6_1.gemfile
222
222
  - gemfiles/activerecord_7_0.gemfile
223
223
  - lib/rubocop-isucon.rb
224
- - lib/rubocop/cop/isucon/correctors/mysql2_n_plus_one_query_corrector.rb
225
- - lib/rubocop/cop/isucon/correctors/mysql2_n_plus_one_query_corrector/correctable_methods.rb
226
- - lib/rubocop/cop/isucon/correctors/mysql2_n_plus_one_query_corrector/replace_methods.rb
224
+ - lib/rubocop/cop/isucon/correctors/n_plus_one_query_corrector.rb
225
+ - lib/rubocop/cop/isucon/correctors/n_plus_one_query_corrector/correctable_methods.rb
226
+ - lib/rubocop/cop/isucon/correctors/n_plus_one_query_corrector/replace_methods.rb
227
227
  - lib/rubocop/cop/isucon/mixin/database_methods.rb
228
+ - lib/rubocop/cop/isucon/mixin/join_without_index_methods.rb
229
+ - lib/rubocop/cop/isucon/mixin/many_join_table_methods.rb
228
230
  - lib/rubocop/cop/isucon/mixin/mysql2_xquery_methods.rb
231
+ - lib/rubocop/cop/isucon/mixin/n_plus_one_query_methods.rb
232
+ - lib/rubocop/cop/isucon/mixin/offense_location_methods.rb
233
+ - lib/rubocop/cop/isucon/mixin/select_asterisk_methods.rb
229
234
  - lib/rubocop/cop/isucon/mixin/sinatra_methods.rb
235
+ - lib/rubocop/cop/isucon/mixin/sqlite3_execute_methods.rb
236
+ - lib/rubocop/cop/isucon/mixin/where_without_index_methods.rb
230
237
  - lib/rubocop/cop/isucon/mysql2/join_without_index.rb
231
238
  - lib/rubocop/cop/isucon/mysql2/many_join_table.rb
232
239
  - lib/rubocop/cop/isucon/mysql2/n_plus_one_query.rb
@@ -239,6 +246,11 @@ files:
239
246
  - lib/rubocop/cop/isucon/sinatra/logger.rb
240
247
  - lib/rubocop/cop/isucon/sinatra/rack_logger.rb
241
248
  - lib/rubocop/cop/isucon/sinatra/serve_static_file.rb
249
+ - lib/rubocop/cop/isucon/sqlite3/join_without_index.rb
250
+ - lib/rubocop/cop/isucon/sqlite3/many_join_table.rb
251
+ - lib/rubocop/cop/isucon/sqlite3/n_plus_one_query.rb
252
+ - lib/rubocop/cop/isucon/sqlite3/select_asterisk.rb
253
+ - lib/rubocop/cop/isucon/sqlite3/where_without_index.rb
242
254
  - lib/rubocop/cop/isucon_cops.rb
243
255
  - lib/rubocop/isucon.rb
244
256
  - lib/rubocop/isucon/database_connection.rb