active_record_doctor 1.11.0 → 1.13.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.
- checksums.yaml +4 -4
- data/README.md +41 -14
- data/lib/active_record_doctor/config/loader.rb +1 -1
- data/lib/active_record_doctor/detectors/base.rb +30 -15
- data/lib/active_record_doctor/detectors/extraneous_indexes.rb +14 -9
- data/lib/active_record_doctor/detectors/incorrect_boolean_presence_validation.rb +1 -1
- data/lib/active_record_doctor/detectors/incorrect_dependent_option.rb +44 -31
- data/lib/active_record_doctor/detectors/mismatched_foreign_key_type.rb +1 -1
- data/lib/active_record_doctor/detectors/missing_non_null_constraint.rb +2 -2
- data/lib/active_record_doctor/detectors/missing_unique_indexes.rb +73 -23
- data/lib/active_record_doctor/detectors/short_primary_key_type.rb +3 -3
- data/lib/active_record_doctor/detectors/unindexed_foreign_keys.rb +34 -7
- data/lib/active_record_doctor/logger/hierarchical.rb +1 -1
- data/lib/active_record_doctor/railtie.rb +1 -1
- data/lib/active_record_doctor/runner.rb +1 -1
- data/lib/active_record_doctor/utils.rb +21 -0
- data/lib/active_record_doctor/version.rb +1 -1
- data/lib/active_record_doctor.rb +2 -0
- data/lib/generators/active_record_doctor/add_indexes/add_indexes_generator.rb +14 -14
- data/lib/tasks/active_record_doctor.rake +2 -2
- metadata +11 -47
- data/test/active_record_doctor/config/loader_test.rb +0 -120
- data/test/active_record_doctor/config_test.rb +0 -116
- data/test/active_record_doctor/detectors/disable_test.rb +0 -30
- data/test/active_record_doctor/detectors/extraneous_indexes_test.rb +0 -224
- data/test/active_record_doctor/detectors/incorrect_boolean_presence_validation_test.rb +0 -79
- data/test/active_record_doctor/detectors/incorrect_dependent_option_test.rb +0 -472
- data/test/active_record_doctor/detectors/incorrect_length_validation_test.rb +0 -107
- data/test/active_record_doctor/detectors/mismatched_foreign_key_type_test.rb +0 -116
- data/test/active_record_doctor/detectors/missing_foreign_keys_test.rb +0 -70
- data/test/active_record_doctor/detectors/missing_non_null_constraint_test.rb +0 -273
- data/test/active_record_doctor/detectors/missing_presence_validation_test.rb +0 -232
- data/test/active_record_doctor/detectors/missing_unique_indexes_test.rb +0 -327
- data/test/active_record_doctor/detectors/short_primary_key_type_test.rb +0 -72
- data/test/active_record_doctor/detectors/undefined_table_references_test.rb +0 -55
- data/test/active_record_doctor/detectors/unindexed_deleted_at_test.rb +0 -177
- data/test/active_record_doctor/detectors/unindexed_foreign_keys_test.rb +0 -78
- data/test/active_record_doctor/runner_test.rb +0 -41
- data/test/generators/active_record_doctor/add_indexes/add_indexes_generator_test.rb +0 -131
- data/test/setup.rb +0 -124
@@ -1,224 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class ActiveRecordDoctor::Detectors::ExtraneousIndexesTest < Minitest::Test
|
4
|
-
def test_index_on_primary_key_is_duplicate
|
5
|
-
create_table(:users) do |t|
|
6
|
-
t.index :id
|
7
|
-
end
|
8
|
-
|
9
|
-
assert_problems(<<OUTPUT)
|
10
|
-
remove index_users_on_id - coincides with the primary key on the table
|
11
|
-
OUTPUT
|
12
|
-
end
|
13
|
-
|
14
|
-
def test_partial_index_on_primary_key
|
15
|
-
skip("MySQL doesn't support partial indexes") if mysql?
|
16
|
-
|
17
|
-
create_table(:users) do |t|
|
18
|
-
t.boolean :admin
|
19
|
-
t.index :id, where: "admin"
|
20
|
-
end
|
21
|
-
|
22
|
-
refute_problems
|
23
|
-
end
|
24
|
-
|
25
|
-
def test_index_on_non_standard_primary_key
|
26
|
-
create_table(:profiles, primary_key: :user_id) do |t|
|
27
|
-
t.index :user_id
|
28
|
-
end
|
29
|
-
|
30
|
-
assert_problems(<<OUTPUT)
|
31
|
-
remove index_profiles_on_user_id - coincides with the primary key on the table
|
32
|
-
OUTPUT
|
33
|
-
end
|
34
|
-
|
35
|
-
def test_non_unique_version_of_index_is_duplicate
|
36
|
-
create_table(:users) do |t|
|
37
|
-
t.string :email
|
38
|
-
t.index :email, unique: true, name: "unique_index_on_users_email"
|
39
|
-
end
|
40
|
-
|
41
|
-
# Rails 4.2 compatibility - can't be pulled into the block above.
|
42
|
-
ActiveRecord::Base.connection.add_index :users, :email, name: "index_users_on_email"
|
43
|
-
|
44
|
-
assert_problems(<<OUTPUT)
|
45
|
-
remove index_users_on_email - can be replaced by unique_index_on_users_email
|
46
|
-
OUTPUT
|
47
|
-
end
|
48
|
-
|
49
|
-
def test_single_column_covered_by_unique_and_non_unique_multi_column_is_duplicate
|
50
|
-
create_table(:users) do |t|
|
51
|
-
t.string :first_name
|
52
|
-
t.string :last_name
|
53
|
-
t.string :email
|
54
|
-
t.index [:last_name, :first_name, :email]
|
55
|
-
t.index [:last_name, :first_name],
|
56
|
-
unique: true,
|
57
|
-
name: "unique_index_on_users_last_name_and_first_name"
|
58
|
-
t.index :last_name
|
59
|
-
end
|
60
|
-
|
61
|
-
assert_problems(<<OUTPUT)
|
62
|
-
remove index_users_on_last_name - can be replaced by index_users_on_last_name_and_first_name_and_email or unique_index_on_users_last_name_and_first_name
|
63
|
-
OUTPUT
|
64
|
-
end
|
65
|
-
|
66
|
-
def test_multi_column_covered_by_unique_and_non_unique_multi_column_is_duplicate
|
67
|
-
create_table(:users) do |t|
|
68
|
-
t.string :first_name
|
69
|
-
t.string :last_name
|
70
|
-
t.string :email
|
71
|
-
t.index [:last_name, :first_name, :email]
|
72
|
-
t.index [:last_name, :first_name],
|
73
|
-
unique: true,
|
74
|
-
name: "unique_index_on_users_last_name_and_first_name"
|
75
|
-
end
|
76
|
-
|
77
|
-
# Rails 4.2 compatibility - can't be pulled into the block above.
|
78
|
-
ActiveRecord::Base.connection.add_index :users, [:last_name, :first_name]
|
79
|
-
|
80
|
-
assert_problems(<<OUTPUT)
|
81
|
-
remove index_users_on_last_name_and_first_name - can be replaced by index_users_on_last_name_and_first_name_and_email or unique_index_on_users_last_name_and_first_name
|
82
|
-
OUTPUT
|
83
|
-
end
|
84
|
-
|
85
|
-
def test_unique_index_with_fewer_columns
|
86
|
-
create_table(:users) do |t|
|
87
|
-
t.string :first_name
|
88
|
-
t.string :last_name
|
89
|
-
t.index :first_name, unique: true
|
90
|
-
t.index [:last_name, :first_name], unique: true
|
91
|
-
end
|
92
|
-
|
93
|
-
assert_problems(<<OUTPUT)
|
94
|
-
remove index_users_on_last_name_and_first_name - can be replaced by index_users_on_first_name
|
95
|
-
OUTPUT
|
96
|
-
end
|
97
|
-
|
98
|
-
def test_not_covered_by_different_index_type
|
99
|
-
create_table(:users) do |t|
|
100
|
-
t.string :first_name
|
101
|
-
t.string :last_name
|
102
|
-
t.index [:last_name, :first_name], using: :btree
|
103
|
-
|
104
|
-
if mysql?
|
105
|
-
t.index :last_name, type: :fulltext
|
106
|
-
else
|
107
|
-
t.index :last_name, using: :hash
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
refute_problems
|
112
|
-
end
|
113
|
-
|
114
|
-
def test_not_covered_by_partial_index
|
115
|
-
skip("MySQL doesn't support partial indexes") if mysql?
|
116
|
-
|
117
|
-
create_table(:users) do |t|
|
118
|
-
t.string :first_name
|
119
|
-
t.string :last_name
|
120
|
-
t.boolean :active
|
121
|
-
t.index [:last_name, :first_name], where: "active"
|
122
|
-
t.index :last_name
|
123
|
-
end
|
124
|
-
|
125
|
-
refute_problems
|
126
|
-
end
|
127
|
-
|
128
|
-
def test_not_covered_with_different_opclasses
|
129
|
-
skip("ActiveRecord < 5.2 doesn't support operator classes") if ActiveRecord::VERSION::STRING < "5.2"
|
130
|
-
skip("MySQL doesn't support operator classes") if mysql?
|
131
|
-
|
132
|
-
create_table(:users) do |t|
|
133
|
-
t.string :first_name
|
134
|
-
t.string :last_name
|
135
|
-
t.index [:last_name, :first_name], opclass: :varchar_pattern_ops
|
136
|
-
t.index :last_name
|
137
|
-
end
|
138
|
-
|
139
|
-
refute_problems
|
140
|
-
end
|
141
|
-
|
142
|
-
def test_config_ignore_tables
|
143
|
-
# The detector recognizes two kinds of errors and both must take
|
144
|
-
# ignore_tables into account. We trigger those errors by indexing the
|
145
|
-
# primary key (the first extraneous index) and then indexing email twice
|
146
|
-
# (index2... is the other extraneous index).
|
147
|
-
create_table(:users) do |t|
|
148
|
-
t.index :id
|
149
|
-
t.string :email
|
150
|
-
|
151
|
-
t.index :email, name: "index1_on_users_email"
|
152
|
-
t.index :email, name: "index2_on_users_email"
|
153
|
-
end
|
154
|
-
|
155
|
-
config_file(<<-CONFIG)
|
156
|
-
ActiveRecordDoctor.configure do |config|
|
157
|
-
config.detector :extraneous_indexes,
|
158
|
-
ignore_tables: ["users"]
|
159
|
-
end
|
160
|
-
CONFIG
|
161
|
-
|
162
|
-
refute_problems
|
163
|
-
end
|
164
|
-
|
165
|
-
def test_config_global_ignore_tables
|
166
|
-
create_table(:users) do |t|
|
167
|
-
t.index :id
|
168
|
-
t.string :email
|
169
|
-
|
170
|
-
t.index :email, name: "index1_on_users_email"
|
171
|
-
t.index :email, name: "index2_on_users_email"
|
172
|
-
end
|
173
|
-
|
174
|
-
config_file(<<-CONFIG)
|
175
|
-
ActiveRecordDoctor.configure do |config|
|
176
|
-
config.global :ignore_tables, ["users"]
|
177
|
-
end
|
178
|
-
CONFIG
|
179
|
-
|
180
|
-
refute_problems
|
181
|
-
end
|
182
|
-
|
183
|
-
def test_config_global_ignore_indexes
|
184
|
-
create_table(:users) do |t|
|
185
|
-
t.index :id
|
186
|
-
t.string :email
|
187
|
-
|
188
|
-
t.index :email, name: "index1_on_users_email"
|
189
|
-
t.index :email, name: "index2_on_users_email"
|
190
|
-
end
|
191
|
-
|
192
|
-
config_file(<<-CONFIG)
|
193
|
-
ActiveRecordDoctor.configure do |config|
|
194
|
-
config.global :ignore_indexes, [
|
195
|
-
"index1_on_users_email",
|
196
|
-
"index2_on_users_email",
|
197
|
-
"index_users_on_id",
|
198
|
-
]
|
199
|
-
end
|
200
|
-
CONFIG
|
201
|
-
|
202
|
-
refute_problems
|
203
|
-
end
|
204
|
-
|
205
|
-
def test_config_detector_ignore_indexes
|
206
|
-
create_table(:users) do |t|
|
207
|
-
t.index :id
|
208
|
-
t.string :email
|
209
|
-
t.string :api_key
|
210
|
-
|
211
|
-
t.index :email, name: "index_on_users_email"
|
212
|
-
t.index [:email, :api_key], name: "index_on_users_email_and_api_key"
|
213
|
-
end
|
214
|
-
|
215
|
-
config_file(<<-CONFIG)
|
216
|
-
ActiveRecordDoctor.configure do |config|
|
217
|
-
config.detector :extraneous_indexes,
|
218
|
-
ignore_indexes: ["index_users_on_id", "index_on_users_email"]
|
219
|
-
end
|
220
|
-
CONFIG
|
221
|
-
|
222
|
-
refute_problems
|
223
|
-
end
|
224
|
-
end
|
@@ -1,79 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class ActiveRecordDoctor::Detectors::IncorrectBooleanPresenceValidationTest < Minitest::Test
|
4
|
-
def test_presence_true_is_reported_on_boolean_only
|
5
|
-
create_table(:users) do |t|
|
6
|
-
t.string :email, null: false
|
7
|
-
t.boolean :active, null: false
|
8
|
-
end.define_model do
|
9
|
-
# email is a non-boolean column whose presence CAN be validated in the
|
10
|
-
# usual way. We include it in the test model to ensure the detector reports
|
11
|
-
# only boolean columns.
|
12
|
-
validates :email, :active, presence: true
|
13
|
-
end
|
14
|
-
|
15
|
-
assert_problems(<<~OUTPUT)
|
16
|
-
replace the `presence` validator on TransientRecord::Models::User.active with `inclusion` - `presence` can't be used on booleans
|
17
|
-
OUTPUT
|
18
|
-
end
|
19
|
-
|
20
|
-
def test_inclusion_is_not_reported
|
21
|
-
create_table(:users) do |t|
|
22
|
-
t.boolean :active, null: false
|
23
|
-
end.define_model do
|
24
|
-
validates :active, inclusion: { in: [true, false] }
|
25
|
-
end
|
26
|
-
|
27
|
-
refute_problems
|
28
|
-
end
|
29
|
-
|
30
|
-
def test_models_with_non_existent_tables_are_skipped
|
31
|
-
define_model(:User)
|
32
|
-
|
33
|
-
refute_problems
|
34
|
-
end
|
35
|
-
|
36
|
-
def test_config_ignore_models
|
37
|
-
create_table(:users) do |t|
|
38
|
-
t.string :email, null: false
|
39
|
-
end.define_model
|
40
|
-
|
41
|
-
config_file(<<-CONFIG)
|
42
|
-
ActiveRecordDoctor.configure do |config|
|
43
|
-
config.detector :incorrect_boolean_presence_validation,
|
44
|
-
ignore_models: ["ModelFactory.User"]
|
45
|
-
end
|
46
|
-
CONFIG
|
47
|
-
|
48
|
-
refute_problems
|
49
|
-
end
|
50
|
-
|
51
|
-
def test_global_ignore_models
|
52
|
-
create_table(:users) do |t|
|
53
|
-
t.string :email, null: false
|
54
|
-
end.define_model
|
55
|
-
|
56
|
-
config_file(<<-CONFIG)
|
57
|
-
ActiveRecordDoctor.configure do |config|
|
58
|
-
config.global :ignore_models, ["ModelFactory.User"]
|
59
|
-
end
|
60
|
-
CONFIG
|
61
|
-
|
62
|
-
refute_problems
|
63
|
-
end
|
64
|
-
|
65
|
-
def test_config_ignore_attributes
|
66
|
-
create_table(:users) do |t|
|
67
|
-
t.string :email, null: false
|
68
|
-
end.define_model
|
69
|
-
|
70
|
-
config_file(<<-CONFIG)
|
71
|
-
ActiveRecordDoctor.configure do |config|
|
72
|
-
config.detector :incorrect_boolean_presence_validation,
|
73
|
-
ignore_attributes: ["ModelFactory.User.email"]
|
74
|
-
end
|
75
|
-
CONFIG
|
76
|
-
|
77
|
-
refute_problems
|
78
|
-
end
|
79
|
-
end
|