active_record_doctor 1.8.0 → 1.10.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 +316 -54
- data/lib/active_record_doctor/config/default.rb +76 -0
- data/lib/active_record_doctor/config/loader.rb +137 -0
- data/lib/active_record_doctor/config.rb +14 -0
- data/lib/active_record_doctor/detectors/base.rb +142 -21
- data/lib/active_record_doctor/detectors/extraneous_indexes.rb +59 -48
- data/lib/active_record_doctor/detectors/incorrect_boolean_presence_validation.rb +31 -23
- data/lib/active_record_doctor/detectors/incorrect_dependent_option.rb +102 -35
- data/lib/active_record_doctor/detectors/incorrect_length_validation.rb +63 -0
- data/lib/active_record_doctor/detectors/mismatched_foreign_key_type.rb +45 -0
- data/lib/active_record_doctor/detectors/missing_foreign_keys.rb +32 -23
- data/lib/active_record_doctor/detectors/missing_non_null_constraint.rb +41 -28
- data/lib/active_record_doctor/detectors/missing_presence_validation.rb +29 -23
- data/lib/active_record_doctor/detectors/missing_unique_indexes.rb +92 -32
- data/lib/active_record_doctor/detectors/short_primary_key_type.rb +45 -0
- data/lib/active_record_doctor/detectors/undefined_table_references.rb +17 -20
- data/lib/active_record_doctor/detectors/unindexed_deleted_at.rb +43 -18
- data/lib/active_record_doctor/detectors/unindexed_foreign_keys.rb +31 -20
- data/lib/active_record_doctor/detectors.rb +12 -4
- data/lib/active_record_doctor/errors.rb +226 -0
- data/lib/active_record_doctor/help.rb +39 -0
- data/lib/active_record_doctor/rake/task.rb +78 -0
- data/lib/active_record_doctor/runner.rb +41 -0
- data/lib/active_record_doctor/version.rb +1 -1
- data/lib/active_record_doctor.rb +8 -3
- data/lib/generators/active_record_doctor/add_indexes/add_indexes_generator.rb +34 -21
- data/lib/tasks/active_record_doctor.rake +9 -18
- data/test/active_record_doctor/config/loader_test.rb +120 -0
- data/test/active_record_doctor/config_test.rb +116 -0
- data/test/active_record_doctor/detectors/disable_test.rb +30 -0
- data/test/active_record_doctor/detectors/extraneous_indexes_test.rb +165 -8
- data/test/active_record_doctor/detectors/incorrect_boolean_presence_validation_test.rb +48 -5
- data/test/active_record_doctor/detectors/incorrect_dependent_option_test.rb +288 -12
- data/test/active_record_doctor/detectors/incorrect_length_validation_test.rb +105 -0
- data/test/active_record_doctor/detectors/mismatched_foreign_key_type_test.rb +82 -0
- data/test/active_record_doctor/detectors/missing_foreign_keys_test.rb +50 -4
- data/test/active_record_doctor/detectors/missing_non_null_constraint_test.rb +172 -24
- data/test/active_record_doctor/detectors/missing_presence_validation_test.rb +111 -14
- data/test/active_record_doctor/detectors/missing_unique_indexes_test.rb +223 -10
- data/test/active_record_doctor/detectors/short_primary_key_type_test.rb +72 -0
- data/test/active_record_doctor/detectors/undefined_table_references_test.rb +34 -21
- data/test/active_record_doctor/detectors/unindexed_deleted_at_test.rb +118 -8
- data/test/active_record_doctor/detectors/unindexed_foreign_keys_test.rb +56 -4
- data/test/active_record_doctor/runner_test.rb +42 -0
- data/test/generators/active_record_doctor/add_indexes/add_indexes_generator_test.rb +131 -0
- data/test/model_factory.rb +73 -23
- data/test/setup.rb +65 -71
- metadata +43 -7
- data/lib/active_record_doctor/printers/io_printer.rb +0 -133
- data/lib/active_record_doctor/task.rb +0 -28
- data/test/active_record_doctor/printers/io_printer_test.rb +0 -33
data/test/setup.rb
CHANGED
@@ -7,45 +7,25 @@
|
|
7
7
|
require "uri"
|
8
8
|
|
9
9
|
require "active_record"
|
10
|
+
require "pg"
|
11
|
+
require "mysql2"
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
The DATABASE environment variable is not set. It must be set before running the
|
23
|
-
test suite. Valid values are "mysql" and "postgresql".
|
24
|
-
ERROR
|
25
|
-
# rubocop:enable Style/StderrPuts
|
26
|
-
exit(1)
|
27
|
-
else raise("unrecognized database #{ENV['DATABASE']}")
|
28
|
-
end
|
29
|
-
ActiveRecord::Base.establish_connection(ENV.fetch("DATABASE_URL", DEFAULT_DATABASE_URL))
|
13
|
+
adapter = ENV.fetch("DATABASE_ADAPTER")
|
14
|
+
ActiveRecord::Base.establish_connection(
|
15
|
+
adapter: adapter,
|
16
|
+
host: ENV["DATABASE_HOST"],
|
17
|
+
port: ENV["DATABASE_PORT"],
|
18
|
+
username: ENV["DATABASE_USERNAME"],
|
19
|
+
password: ENV["DATABASE_PASSWORD"],
|
20
|
+
database: "active_record_doctor_test"
|
21
|
+
)
|
22
|
+
|
23
|
+
puts "Using #{adapter}"
|
30
24
|
|
31
25
|
# We need to call #connection to enfore Active Record to actually establish
|
32
26
|
# the connection.
|
33
27
|
ActiveRecord::Base.connection
|
34
28
|
|
35
|
-
# We need to mock Rails because some detectors depend on .eager_load! This must
|
36
|
-
# happen AFTER loading active_record_doctor as otherwise it'd attempt to
|
37
|
-
# install a Railtie.
|
38
|
-
module Rails
|
39
|
-
class TestApplication
|
40
|
-
def eager_load!
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def self.application
|
45
|
-
@application ||= TestApplication.new
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
29
|
# Load Active Record Doctor.
|
50
30
|
require "active_record_doctor"
|
51
31
|
|
@@ -53,23 +33,52 @@ require "active_record_doctor"
|
|
53
33
|
require "minitest"
|
54
34
|
require "minitest/autorun"
|
55
35
|
require "minitest/fork_executor"
|
56
|
-
|
57
36
|
require_relative "model_factory"
|
58
37
|
|
38
|
+
# Filter out Minitest backtrace while allowing backtrace from other libraries
|
39
|
+
# to be shown.
|
40
|
+
Minitest.backtrace_filter = Minitest::BacktraceFilter.new
|
41
|
+
|
42
|
+
# Uncomment in case there's test case interference.
|
43
|
+
Minitest.parallel_executor = Minitest::ForkExecutor.new
|
44
|
+
|
59
45
|
# Prepare the test class.
|
60
46
|
class Minitest::Test
|
47
|
+
include ModelFactory
|
48
|
+
|
61
49
|
def setup
|
62
|
-
#
|
63
|
-
|
64
|
-
ModelFactory.cleanup
|
50
|
+
# Delete remnants (models and tables) of previous test case runs.
|
51
|
+
cleanup_models
|
65
52
|
end
|
66
53
|
|
67
54
|
def teardown
|
68
|
-
|
55
|
+
@config_path = nil
|
56
|
+
|
57
|
+
if @previous_dir
|
58
|
+
Dir.chdir(@previous_dir)
|
59
|
+
@previous_dir = nil
|
60
|
+
end
|
61
|
+
|
62
|
+
# Ensure all remnants of previous test runs, most likely in form of tables,
|
63
|
+
# are removed.
|
64
|
+
cleanup_models
|
69
65
|
end
|
70
66
|
|
71
67
|
private
|
72
68
|
|
69
|
+
attr_reader :config_path
|
70
|
+
|
71
|
+
def config_file(content)
|
72
|
+
@previous_dir = Dir.pwd
|
73
|
+
|
74
|
+
directory = Dir.mktmpdir("active_record_doctor")
|
75
|
+
@config_path = File.join(directory, ".active_record_doctor")
|
76
|
+
File.write(@config_path, content)
|
77
|
+
Dir.chdir(directory)
|
78
|
+
|
79
|
+
@config_path
|
80
|
+
end
|
81
|
+
|
73
82
|
def postgresql?
|
74
83
|
ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
|
75
84
|
end
|
@@ -78,49 +87,34 @@ class Minitest::Test
|
|
78
87
|
ActiveRecord::Base.connection.adapter_name == "Mysql2"
|
79
88
|
end
|
80
89
|
|
81
|
-
def
|
82
|
-
|
90
|
+
def detector_name
|
91
|
+
self.class.name.sub(/Test$/, "").demodulize.underscore.to_sym
|
83
92
|
end
|
84
93
|
|
85
|
-
def create_model(*args, &block)
|
86
|
-
ModelFactory.create_model(*args, &block)
|
87
|
-
end
|
88
|
-
|
89
|
-
# Return the detector class under test.
|
90
|
-
def detector_class
|
91
|
-
self.class.name.sub(/Test$/, "").constantize
|
92
|
-
end
|
93
|
-
|
94
|
-
# Run the appropriate detector. The detector name is inferred from the test class.
|
95
94
|
def run_detector
|
96
|
-
|
95
|
+
io = StringIO.new
|
96
|
+
runner = ActiveRecordDoctor::Runner.new(load_config, io)
|
97
|
+
success = runner.run_one(detector_name)
|
98
|
+
[success, io.string]
|
97
99
|
end
|
98
100
|
|
99
|
-
def
|
100
|
-
|
101
|
-
printer = ActiveRecordDoctor::Printers::IOPrinter.new(output)
|
102
|
-
success = ActiveRecordDoctor::Task.new(detector_class, printer).run
|
103
|
-
[success, output.string]
|
101
|
+
def load_config
|
102
|
+
ActiveRecordDoctor.load_config_with_defaults(@config_path)
|
104
103
|
end
|
105
104
|
|
106
105
|
def assert_problems(expected_output)
|
107
|
-
success,
|
108
|
-
|
109
|
-
|
110
|
-
refute(success)
|
106
|
+
success, output = run_detector
|
107
|
+
assert_equal(sort_lines(expected_output), sort_lines(output))
|
108
|
+
refute(success, "Expected the detector to return failure.")
|
111
109
|
end
|
112
110
|
|
113
|
-
def refute_problems
|
114
|
-
success,
|
111
|
+
def refute_problems(expected_output = "")
|
112
|
+
success, output = run_detector
|
113
|
+
assert_equal(sort_lines(expected_output), sort_lines(output))
|
114
|
+
assert(success, "Expected the detector to return success.")
|
115
|
+
end
|
115
116
|
|
116
|
-
|
117
|
-
|
117
|
+
def sort_lines(string)
|
118
|
+
string.split("\n").sort.join("\n")
|
118
119
|
end
|
119
120
|
end
|
120
|
-
|
121
|
-
# Filter out Minitest backtrace while allowing backtrace from other libraries
|
122
|
-
# to be shown.
|
123
|
-
Minitest.backtrace_filter = Minitest::BacktraceFilter.new
|
124
|
-
|
125
|
-
# Uncomment in case there's test case interference.
|
126
|
-
Minitest.parallel_executor = Minitest::ForkExecutor.new
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_record_doctor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Greg Navis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-07-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: 1.1.4
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: railties
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 4.2.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 4.2.0
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: rake
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -104,37 +118,52 @@ files:
|
|
104
118
|
- MIT-LICENSE.txt
|
105
119
|
- README.md
|
106
120
|
- lib/active_record_doctor.rb
|
121
|
+
- lib/active_record_doctor/config.rb
|
122
|
+
- lib/active_record_doctor/config/default.rb
|
123
|
+
- lib/active_record_doctor/config/loader.rb
|
107
124
|
- lib/active_record_doctor/detectors.rb
|
108
125
|
- lib/active_record_doctor/detectors/base.rb
|
109
126
|
- lib/active_record_doctor/detectors/extraneous_indexes.rb
|
110
127
|
- lib/active_record_doctor/detectors/incorrect_boolean_presence_validation.rb
|
111
128
|
- lib/active_record_doctor/detectors/incorrect_dependent_option.rb
|
129
|
+
- lib/active_record_doctor/detectors/incorrect_length_validation.rb
|
130
|
+
- lib/active_record_doctor/detectors/mismatched_foreign_key_type.rb
|
112
131
|
- lib/active_record_doctor/detectors/missing_foreign_keys.rb
|
113
132
|
- lib/active_record_doctor/detectors/missing_non_null_constraint.rb
|
114
133
|
- lib/active_record_doctor/detectors/missing_presence_validation.rb
|
115
134
|
- lib/active_record_doctor/detectors/missing_unique_indexes.rb
|
135
|
+
- lib/active_record_doctor/detectors/short_primary_key_type.rb
|
116
136
|
- lib/active_record_doctor/detectors/undefined_table_references.rb
|
117
137
|
- lib/active_record_doctor/detectors/unindexed_deleted_at.rb
|
118
138
|
- lib/active_record_doctor/detectors/unindexed_foreign_keys.rb
|
139
|
+
- lib/active_record_doctor/errors.rb
|
140
|
+
- lib/active_record_doctor/help.rb
|
119
141
|
- lib/active_record_doctor/printers.rb
|
120
|
-
- lib/active_record_doctor/printers/io_printer.rb
|
121
142
|
- lib/active_record_doctor/railtie.rb
|
122
|
-
- lib/active_record_doctor/task.rb
|
143
|
+
- lib/active_record_doctor/rake/task.rb
|
144
|
+
- lib/active_record_doctor/runner.rb
|
123
145
|
- lib/active_record_doctor/version.rb
|
124
146
|
- lib/generators/active_record_doctor/add_indexes/USAGE
|
125
147
|
- lib/generators/active_record_doctor/add_indexes/add_indexes_generator.rb
|
126
148
|
- lib/tasks/active_record_doctor.rake
|
149
|
+
- test/active_record_doctor/config/loader_test.rb
|
150
|
+
- test/active_record_doctor/config_test.rb
|
151
|
+
- test/active_record_doctor/detectors/disable_test.rb
|
127
152
|
- test/active_record_doctor/detectors/extraneous_indexes_test.rb
|
128
153
|
- test/active_record_doctor/detectors/incorrect_boolean_presence_validation_test.rb
|
129
154
|
- test/active_record_doctor/detectors/incorrect_dependent_option_test.rb
|
155
|
+
- test/active_record_doctor/detectors/incorrect_length_validation_test.rb
|
156
|
+
- test/active_record_doctor/detectors/mismatched_foreign_key_type_test.rb
|
130
157
|
- test/active_record_doctor/detectors/missing_foreign_keys_test.rb
|
131
158
|
- test/active_record_doctor/detectors/missing_non_null_constraint_test.rb
|
132
159
|
- test/active_record_doctor/detectors/missing_presence_validation_test.rb
|
133
160
|
- test/active_record_doctor/detectors/missing_unique_indexes_test.rb
|
161
|
+
- test/active_record_doctor/detectors/short_primary_key_type_test.rb
|
134
162
|
- test/active_record_doctor/detectors/undefined_table_references_test.rb
|
135
163
|
- test/active_record_doctor/detectors/unindexed_deleted_at_test.rb
|
136
164
|
- test/active_record_doctor/detectors/unindexed_foreign_keys_test.rb
|
137
|
-
- test/active_record_doctor/
|
165
|
+
- test/active_record_doctor/runner_test.rb
|
166
|
+
- test/generators/active_record_doctor/add_indexes/add_indexes_generator_test.rb
|
138
167
|
- test/model_factory.rb
|
139
168
|
- test/setup.rb
|
140
169
|
homepage: https://github.com/gregnavis/active_record_doctor
|
@@ -156,21 +185,28 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
156
185
|
- !ruby/object:Gem::Version
|
157
186
|
version: '0'
|
158
187
|
requirements: []
|
159
|
-
rubygems_version: 3.2.
|
188
|
+
rubygems_version: 3.2.33
|
160
189
|
signing_key:
|
161
190
|
specification_version: 4
|
162
191
|
summary: Identify database issues before they hit production.
|
163
192
|
test_files:
|
193
|
+
- test/active_record_doctor/config/loader_test.rb
|
194
|
+
- test/active_record_doctor/config_test.rb
|
195
|
+
- test/active_record_doctor/detectors/disable_test.rb
|
164
196
|
- test/active_record_doctor/detectors/extraneous_indexes_test.rb
|
165
197
|
- test/active_record_doctor/detectors/incorrect_boolean_presence_validation_test.rb
|
166
198
|
- test/active_record_doctor/detectors/incorrect_dependent_option_test.rb
|
199
|
+
- test/active_record_doctor/detectors/incorrect_length_validation_test.rb
|
200
|
+
- test/active_record_doctor/detectors/mismatched_foreign_key_type_test.rb
|
167
201
|
- test/active_record_doctor/detectors/missing_foreign_keys_test.rb
|
168
202
|
- test/active_record_doctor/detectors/missing_non_null_constraint_test.rb
|
169
203
|
- test/active_record_doctor/detectors/missing_presence_validation_test.rb
|
170
204
|
- test/active_record_doctor/detectors/missing_unique_indexes_test.rb
|
205
|
+
- test/active_record_doctor/detectors/short_primary_key_type_test.rb
|
171
206
|
- test/active_record_doctor/detectors/undefined_table_references_test.rb
|
172
207
|
- test/active_record_doctor/detectors/unindexed_deleted_at_test.rb
|
173
208
|
- test/active_record_doctor/detectors/unindexed_foreign_keys_test.rb
|
174
|
-
- test/active_record_doctor/
|
209
|
+
- test/active_record_doctor/runner_test.rb
|
210
|
+
- test/generators/active_record_doctor/add_indexes/add_indexes_generator_test.rb
|
175
211
|
- test/model_factory.rb
|
176
212
|
- test/setup.rb
|
@@ -1,133 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ActiveRecordDoctor
|
4
|
-
module Printers
|
5
|
-
# Default printer for displaying messages produced by active_record_doctor.
|
6
|
-
class IOPrinter
|
7
|
-
def initialize(io = $stdout)
|
8
|
-
@io = io
|
9
|
-
end
|
10
|
-
|
11
|
-
def unindexed_foreign_keys(unindexed_foreign_keys, _options)
|
12
|
-
return if unindexed_foreign_keys.empty?
|
13
|
-
|
14
|
-
@io.puts("The following foreign keys should be indexed for performance reasons:")
|
15
|
-
@io.puts(unindexed_foreign_keys.sort.map do |table, columns|
|
16
|
-
" #{table} #{columns.sort.join(' ')}"
|
17
|
-
end.join("\n"))
|
18
|
-
end
|
19
|
-
|
20
|
-
def extraneous_indexes(extraneous_indexes, _options)
|
21
|
-
return if extraneous_indexes.empty?
|
22
|
-
|
23
|
-
@io.puts("The following indexes are extraneous and can be removed:")
|
24
|
-
extraneous_indexes.each do |index, details|
|
25
|
-
reason, *params = details
|
26
|
-
case reason
|
27
|
-
when :multi_column
|
28
|
-
@io.puts(" #{index} (can be handled by #{params.join(', ')})")
|
29
|
-
when :primary_key
|
30
|
-
@io.puts(" #{index} (is a primary key of #{params[0]})")
|
31
|
-
else
|
32
|
-
raise("unknown reason #{reason.inspect}")
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def missing_foreign_keys(missing_foreign_keys, _options)
|
38
|
-
return if missing_foreign_keys.empty?
|
39
|
-
|
40
|
-
@io.puts("The following columns lack a foreign key constraint:")
|
41
|
-
@io.puts(missing_foreign_keys.sort.map do |table, columns|
|
42
|
-
" #{table} #{columns.sort.join(' ')}"
|
43
|
-
end.join("\n"))
|
44
|
-
end
|
45
|
-
|
46
|
-
def undefined_table_references(models, options)
|
47
|
-
return if models.empty?
|
48
|
-
|
49
|
-
unless options.fetch(:views_checked)
|
50
|
-
@io.puts(<<WARNING)
|
51
|
-
WARNING: Models backed by database views are supported only in Rails 5+ OR
|
52
|
-
Rails 4.2 + PostgreSQL. It seems this is NOT your setup. Therefore, such models
|
53
|
-
will be erroneously reported below as not having their underlying tables/views.
|
54
|
-
Consider upgrading Rails or disabling this task temporarily.
|
55
|
-
WARNING
|
56
|
-
end
|
57
|
-
|
58
|
-
@io.puts("The following models reference undefined tables:")
|
59
|
-
models.each do |model_name, table_name|
|
60
|
-
@io.puts(" #{model_name} (the table #{table_name} is undefined)")
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def unindexed_deleted_at(indexes, _options)
|
65
|
-
return if indexes.empty?
|
66
|
-
|
67
|
-
@io.puts("The following indexes should include `deleted_at IS NULL`:")
|
68
|
-
indexes.each do |index|
|
69
|
-
@io.puts(" #{index}")
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def missing_unique_indexes(indexes, _options)
|
74
|
-
return if indexes.empty?
|
75
|
-
|
76
|
-
@io.puts("The following indexes should be created to back model-level uniqueness validations:")
|
77
|
-
indexes.each do |table, arrays_of_columns|
|
78
|
-
arrays_of_columns.each do |columns|
|
79
|
-
@io.puts(" #{table}: #{columns.join(', ')}")
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def missing_presence_validation(missing_presence_validators, _options)
|
85
|
-
return if missing_presence_validators.empty?
|
86
|
-
|
87
|
-
@io.puts("The following models and columns should have presence validations:")
|
88
|
-
missing_presence_validators.each do |model_name, array_of_columns|
|
89
|
-
@io.puts(" #{model_name}: #{array_of_columns.join(', ')}")
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
def missing_non_null_constraint(missing_non_null_constraints, _options)
|
94
|
-
return if missing_non_null_constraints.empty?
|
95
|
-
|
96
|
-
@io.puts("The following columns should be marked as `null: false`:")
|
97
|
-
missing_non_null_constraints.each do |table, columns|
|
98
|
-
@io.puts(" #{table}: #{columns.join(', ')}")
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def incorrect_boolean_presence_validation(incorrect_boolean_presence_validations, _options)
|
103
|
-
return if incorrect_boolean_presence_validations.empty?
|
104
|
-
|
105
|
-
@io.puts("The presence of the following boolean columns is validated incorrectly:")
|
106
|
-
incorrect_boolean_presence_validations.each do |table, columns|
|
107
|
-
@io.puts(" #{table}: #{columns.join(', ')}")
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
def incorrect_dependent_option(problems, _options)
|
112
|
-
return if problems.empty?
|
113
|
-
|
114
|
-
@io.puts("The following associations might be using invalid dependent settings:")
|
115
|
-
problems.each do |model, associations|
|
116
|
-
associations.each do |(name, problem)|
|
117
|
-
# rubocop:disable Layout/LineLength
|
118
|
-
message =
|
119
|
-
case problem
|
120
|
-
when :suggest_destroy then "skips callbacks that are defined on the associated model - consider changing to `dependent: :destroy` or similar"
|
121
|
-
when :suggest_delete then "loads the associated model before deleting it - consider using `dependent: :delete`"
|
122
|
-
when :suggest_delete_all then "loads models one-by-one to invoke callbacks even though the related model defines none - consider using `dependent: :delete_all`"
|
123
|
-
else next
|
124
|
-
end
|
125
|
-
# rubocop:enable Layout/LineLength
|
126
|
-
|
127
|
-
@io.puts(" #{model}: #{name} #{message}")
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ActiveRecordDoctor
|
4
|
-
# Rake task for running a detector and reporting its results.
|
5
|
-
class Task
|
6
|
-
DEFAULT_PRINTER = ActiveRecordDoctor::Printers::IOPrinter.new
|
7
|
-
|
8
|
-
def initialize(detector_class, printer = DEFAULT_PRINTER)
|
9
|
-
@detector_class = detector_class
|
10
|
-
@printer = printer
|
11
|
-
end
|
12
|
-
|
13
|
-
def name
|
14
|
-
@detector_class.name.demodulize.underscore.to_sym
|
15
|
-
end
|
16
|
-
|
17
|
-
def description
|
18
|
-
@detector_class.description
|
19
|
-
end
|
20
|
-
|
21
|
-
def run
|
22
|
-
problems, options = @detector_class.run
|
23
|
-
@printer.public_send(name, problems, options)
|
24
|
-
|
25
|
-
problems.empty?
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Load all detectors
|
4
|
-
class ActiveRecordDoctor::Printers::IOPrinterTest < Minitest::Test
|
5
|
-
def test_all_detectors_have_printers
|
6
|
-
ActiveRecordDoctor::Detectors::Base.subclasses.each do |detector_class|
|
7
|
-
name = detector_class.name.demodulize.underscore.to_sym
|
8
|
-
|
9
|
-
assert(
|
10
|
-
ActiveRecordDoctor::Printers::IOPrinter.method_defined?(name),
|
11
|
-
"IOPrinter should define #{name}"
|
12
|
-
)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def test_unindexed_foreign_keys
|
17
|
-
# rubocop:disable Layout/LineLength
|
18
|
-
assert_equal(<<OUTPUT, unindexed_foreign_keys({ "users" => ["profile_id", "account_id"], "account" => ["group_id"] }))
|
19
|
-
The following foreign keys should be indexed for performance reasons:
|
20
|
-
account group_id
|
21
|
-
users account_id profile_id
|
22
|
-
OUTPUT
|
23
|
-
# rubocop:enable Layout/LineLength
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
def unindexed_foreign_keys(argument)
|
29
|
-
io = StringIO.new
|
30
|
-
ActiveRecordDoctor::Printers::IOPrinter.new(io).unindexed_foreign_keys(argument, {})
|
31
|
-
io.string
|
32
|
-
end
|
33
|
-
end
|