lol_dba 2.1.5 → 2.1.6
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/.codeclimate.yml +179 -0
- data/.gitignore +1 -1
- data/.rspec +2 -0
- data/.rubocop.yml +7 -0
- data/.travis.yml +16 -9
- data/Appraisals +19 -12
- data/Gemfile +1 -8
- data/Gemfile.lock +60 -59
- data/README.md +5 -2
- data/Rakefile +4 -4
- data/bin/lol_dba +2 -2
- data/gemfiles/rails_3_2.gemfile +0 -3
- data/gemfiles/rails_3_2.gemfile.lock +33 -31
- data/gemfiles/rails_4_0.gemfile +0 -3
- data/gemfiles/rails_4_0.gemfile.lock +31 -27
- data/gemfiles/rails_4_1.gemfile +0 -3
- data/gemfiles/rails_4_1.gemfile.lock +29 -26
- data/gemfiles/rails_4_2.gemfile +0 -3
- data/gemfiles/rails_4_2.gemfile.lock +52 -48
- data/gemfiles/rails_5_0.gemfile +0 -3
- data/gemfiles/rails_5_0.gemfile.lock +55 -51
- data/gemfiles/rails_5_1.gemfile +0 -3
- data/gemfiles/rails_5_1.gemfile.lock +57 -53
- data/gemfiles/rails_5_2.gemfile +9 -0
- data/gemfiles/rails_5_2.gemfile.lock +115 -0
- data/lib/lol_dba/cli.rb +26 -15
- data/lib/lol_dba/index_finding/belongs_to.rb +32 -0
- data/lib/lol_dba/index_finding/error_logging.rb +15 -0
- data/lib/lol_dba/index_finding/has_and_belongs_to_many.rb +20 -0
- data/lib/lol_dba/index_finding/has_many.rb +47 -0
- data/lib/lol_dba/index_finding/index_finder.rb +81 -0
- data/lib/lol_dba/index_finding/migration_formatter.rb +50 -0
- data/lib/lol_dba/index_finding/relation_inspector.rb +30 -0
- data/lib/lol_dba/index_finding/relation_inspector_factory.rb +13 -0
- data/lib/lol_dba/rails_compatibility.rb +47 -0
- data/lib/lol_dba/railtie.rb +2 -2
- data/lib/lol_dba/sql_migrations/migration.rb +51 -0
- data/lib/lol_dba/sql_migrations/migration_mocker.rb +70 -0
- data/lib/lol_dba/sql_migrations/sql_generator.rb +49 -0
- data/lib/lol_dba/sql_migrations/writer.rb +29 -0
- data/lib/lol_dba/version.rb +1 -1
- data/lib/lol_dba.rb +14 -188
- data/lib/tasks/lol_dba.rake +7 -8
- data/lol_dba.gemspec +19 -16
- data/spec/associations_index_spec.rb +43 -56
- data/spec/fixtures/app/models/address.rb +0 -1
- data/spec/fixtures/app/models/billable_week.rb +1 -3
- data/spec/fixtures/app/models/company.rb +0 -1
- data/spec/fixtures/app/models/complex_billable_week.rb +0 -1
- data/spec/fixtures/app/models/complex_timesheet.rb +0 -1
- data/spec/fixtures/app/models/country.rb +1 -1
- data/spec/fixtures/app/models/favourite.rb +0 -2
- data/spec/fixtures/app/models/freelancer.rb +1 -3
- data/spec/fixtures/app/models/gift.rb +0 -2
- data/spec/fixtures/app/models/god.rb +1 -1
- data/spec/fixtures/app/models/project.rb +0 -2
- data/spec/fixtures/app/models/timesheet.rb +1 -3
- data/spec/fixtures/app/models/user.rb +0 -2
- data/spec/fixtures/app/models/worker.rb +0 -1
- data/spec/fixtures/app/models/worker_user.rb +2 -3
- data/spec/fixtures/schema.rb +53 -53
- data/spec/migration_formatter_spec.rb +66 -0
- data/spec/spec_helper.rb +17 -9
- data/spec/sql_generator_spec.rb +9 -0
- metadata +88 -19
- data/lib/lol_dba/migration.rb +0 -40
- data/lib/lol_dba/sql_generator.rb +0 -96
- data/lib/lol_dba/writer.rb +0 -25
- data/spec/common_function_spec.rb +0 -96
|
@@ -1,36 +1,36 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
lol_dba (2.1.
|
|
5
|
-
actionpack (>= 3.0)
|
|
6
|
-
activerecord (>= 3.0)
|
|
7
|
-
railties (>= 3.0)
|
|
4
|
+
lol_dba (2.1.5)
|
|
5
|
+
actionpack (>= 3.0, < 6.0)
|
|
6
|
+
activerecord (>= 3.0, < 6.0)
|
|
7
|
+
railties (>= 3.0, < 6.0)
|
|
8
8
|
|
|
9
9
|
GEM
|
|
10
10
|
remote: https://rubygems.org/
|
|
11
11
|
specs:
|
|
12
|
-
actionpack (5.1.
|
|
13
|
-
actionview (= 5.1.
|
|
14
|
-
activesupport (= 5.1.
|
|
12
|
+
actionpack (5.1.7)
|
|
13
|
+
actionview (= 5.1.7)
|
|
14
|
+
activesupport (= 5.1.7)
|
|
15
15
|
rack (~> 2.0)
|
|
16
16
|
rack-test (>= 0.6.3)
|
|
17
17
|
rails-dom-testing (~> 2.0)
|
|
18
18
|
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
|
19
|
-
actionview (5.1.
|
|
20
|
-
activesupport (= 5.1.
|
|
19
|
+
actionview (5.1.7)
|
|
20
|
+
activesupport (= 5.1.7)
|
|
21
21
|
builder (~> 3.1)
|
|
22
22
|
erubi (~> 1.4)
|
|
23
23
|
rails-dom-testing (~> 2.0)
|
|
24
24
|
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
|
25
|
-
activemodel (5.1.
|
|
26
|
-
activesupport (= 5.1.
|
|
27
|
-
activerecord (5.1.
|
|
28
|
-
activemodel (= 5.1.
|
|
29
|
-
activesupport (= 5.1.
|
|
25
|
+
activemodel (5.1.7)
|
|
26
|
+
activesupport (= 5.1.7)
|
|
27
|
+
activerecord (5.1.7)
|
|
28
|
+
activemodel (= 5.1.7)
|
|
29
|
+
activesupport (= 5.1.7)
|
|
30
30
|
arel (~> 8.0)
|
|
31
|
-
activesupport (5.1.
|
|
31
|
+
activesupport (5.1.7)
|
|
32
32
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
33
|
-
i18n (
|
|
33
|
+
i18n (>= 0.7, < 2)
|
|
34
34
|
minitest (~> 5.1)
|
|
35
35
|
tzinfo (~> 1.1)
|
|
36
36
|
appraisal (2.2.0)
|
|
@@ -39,57 +39,61 @@ GEM
|
|
|
39
39
|
thor (>= 0.14.0)
|
|
40
40
|
arel (8.0.0)
|
|
41
41
|
builder (3.2.3)
|
|
42
|
-
concurrent-ruby (1.
|
|
43
|
-
crass (1.0.
|
|
42
|
+
concurrent-ruby (1.1.5)
|
|
43
|
+
crass (1.0.4)
|
|
44
44
|
diff-lcs (1.3)
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
docile (1.3.1)
|
|
46
|
+
erubi (1.8.0)
|
|
47
|
+
i18n (1.6.0)
|
|
47
48
|
concurrent-ruby (~> 1.0)
|
|
48
|
-
|
|
49
|
+
json (2.2.0)
|
|
50
|
+
loofah (2.2.3)
|
|
49
51
|
crass (~> 1.0.2)
|
|
50
52
|
nokogiri (>= 1.5.9)
|
|
51
|
-
method_source (0.9.
|
|
52
|
-
mini_portile2 (2.
|
|
53
|
+
method_source (0.9.2)
|
|
54
|
+
mini_portile2 (2.4.0)
|
|
53
55
|
minitest (5.11.3)
|
|
54
|
-
nokogiri (1.
|
|
55
|
-
mini_portile2 (~> 2.
|
|
56
|
-
|
|
57
|
-
rack (
|
|
58
|
-
rack-test (0.8.3)
|
|
56
|
+
nokogiri (1.10.2)
|
|
57
|
+
mini_portile2 (~> 2.4.0)
|
|
58
|
+
rack (2.0.7)
|
|
59
|
+
rack-test (1.1.0)
|
|
59
60
|
rack (>= 1.0, < 3)
|
|
60
61
|
rails-dom-testing (2.0.3)
|
|
61
62
|
activesupport (>= 4.2.0)
|
|
62
63
|
nokogiri (>= 1.6)
|
|
63
|
-
rails-html-sanitizer (1.0.
|
|
64
|
-
loofah (~> 2.
|
|
65
|
-
railties (5.1.
|
|
66
|
-
actionpack (= 5.1.
|
|
67
|
-
activesupport (= 5.1.
|
|
64
|
+
rails-html-sanitizer (1.0.4)
|
|
65
|
+
loofah (~> 2.2, >= 2.2.2)
|
|
66
|
+
railties (5.1.7)
|
|
67
|
+
actionpack (= 5.1.7)
|
|
68
|
+
activesupport (= 5.1.7)
|
|
68
69
|
method_source
|
|
69
70
|
rake (>= 0.8.7)
|
|
70
71
|
thor (>= 0.18.1, < 2.0)
|
|
71
|
-
rake (12.3.
|
|
72
|
-
rspec-core (3.
|
|
73
|
-
rspec-support (~> 3.
|
|
74
|
-
rspec-expectations (3.
|
|
72
|
+
rake (12.3.2)
|
|
73
|
+
rspec-core (3.8.0)
|
|
74
|
+
rspec-support (~> 3.8.0)
|
|
75
|
+
rspec-expectations (3.8.2)
|
|
75
76
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
76
|
-
rspec-support (~> 3.
|
|
77
|
-
rspec-mocks (3.
|
|
77
|
+
rspec-support (~> 3.8.0)
|
|
78
|
+
rspec-mocks (3.8.0)
|
|
78
79
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
79
|
-
rspec-support (~> 3.
|
|
80
|
-
rspec-rails (3.
|
|
80
|
+
rspec-support (~> 3.8.0)
|
|
81
|
+
rspec-rails (3.8.2)
|
|
81
82
|
actionpack (>= 3.0)
|
|
82
83
|
activesupport (>= 3.0)
|
|
83
84
|
railties (>= 3.0)
|
|
84
|
-
rspec-core (~> 3.
|
|
85
|
-
rspec-expectations (~> 3.
|
|
86
|
-
rspec-mocks (~> 3.
|
|
87
|
-
rspec-support (~> 3.
|
|
88
|
-
rspec-support (3.
|
|
85
|
+
rspec-core (~> 3.8.0)
|
|
86
|
+
rspec-expectations (~> 3.8.0)
|
|
87
|
+
rspec-mocks (~> 3.8.0)
|
|
88
|
+
rspec-support (~> 3.8.0)
|
|
89
|
+
rspec-support (3.8.0)
|
|
90
|
+
simplecov (0.16.1)
|
|
91
|
+
docile (~> 1.1)
|
|
92
|
+
json (>= 1.8, < 3)
|
|
93
|
+
simplecov-html (~> 0.10.0)
|
|
94
|
+
simplecov-html (0.10.2)
|
|
89
95
|
sqlite3 (1.3.13)
|
|
90
|
-
|
|
91
|
-
power_assert
|
|
92
|
-
thor (0.20.0)
|
|
96
|
+
thor (0.20.3)
|
|
93
97
|
thread_safe (0.3.6)
|
|
94
98
|
tzinfo (1.2.5)
|
|
95
99
|
thread_safe (~> 0.1)
|
|
@@ -100,12 +104,12 @@ PLATFORMS
|
|
|
100
104
|
DEPENDENCIES
|
|
101
105
|
actionpack (~> 5.1.0)
|
|
102
106
|
activerecord (~> 5.1.0)
|
|
103
|
-
appraisal
|
|
107
|
+
appraisal (~> 2.2)
|
|
104
108
|
lol_dba!
|
|
105
109
|
railties (~> 5.1.0)
|
|
106
110
|
rspec-rails
|
|
107
|
-
|
|
108
|
-
|
|
111
|
+
simplecov (~> 0.1)
|
|
112
|
+
sqlite3 (~> 1.3.5)
|
|
109
113
|
|
|
110
114
|
BUNDLED WITH
|
|
111
|
-
1.
|
|
115
|
+
1.17.3
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: ..
|
|
3
|
+
specs:
|
|
4
|
+
lol_dba (2.1.5)
|
|
5
|
+
actionpack (>= 3.0, < 6.0)
|
|
6
|
+
activerecord (>= 3.0, < 6.0)
|
|
7
|
+
railties (>= 3.0, < 6.0)
|
|
8
|
+
|
|
9
|
+
GEM
|
|
10
|
+
remote: https://rubygems.org/
|
|
11
|
+
specs:
|
|
12
|
+
actionpack (5.2.3)
|
|
13
|
+
actionview (= 5.2.3)
|
|
14
|
+
activesupport (= 5.2.3)
|
|
15
|
+
rack (~> 2.0)
|
|
16
|
+
rack-test (>= 0.6.3)
|
|
17
|
+
rails-dom-testing (~> 2.0)
|
|
18
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
|
19
|
+
actionview (5.2.3)
|
|
20
|
+
activesupport (= 5.2.3)
|
|
21
|
+
builder (~> 3.1)
|
|
22
|
+
erubi (~> 1.4)
|
|
23
|
+
rails-dom-testing (~> 2.0)
|
|
24
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
|
25
|
+
activemodel (5.2.3)
|
|
26
|
+
activesupport (= 5.2.3)
|
|
27
|
+
activerecord (5.2.3)
|
|
28
|
+
activemodel (= 5.2.3)
|
|
29
|
+
activesupport (= 5.2.3)
|
|
30
|
+
arel (>= 9.0)
|
|
31
|
+
activesupport (5.2.3)
|
|
32
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
33
|
+
i18n (>= 0.7, < 2)
|
|
34
|
+
minitest (~> 5.1)
|
|
35
|
+
tzinfo (~> 1.1)
|
|
36
|
+
appraisal (2.2.0)
|
|
37
|
+
bundler
|
|
38
|
+
rake
|
|
39
|
+
thor (>= 0.14.0)
|
|
40
|
+
arel (9.0.0)
|
|
41
|
+
builder (3.2.3)
|
|
42
|
+
concurrent-ruby (1.1.5)
|
|
43
|
+
crass (1.0.4)
|
|
44
|
+
diff-lcs (1.3)
|
|
45
|
+
docile (1.3.1)
|
|
46
|
+
erubi (1.8.0)
|
|
47
|
+
i18n (1.6.0)
|
|
48
|
+
concurrent-ruby (~> 1.0)
|
|
49
|
+
json (2.2.0)
|
|
50
|
+
loofah (2.2.3)
|
|
51
|
+
crass (~> 1.0.2)
|
|
52
|
+
nokogiri (>= 1.5.9)
|
|
53
|
+
method_source (0.9.2)
|
|
54
|
+
mini_portile2 (2.4.0)
|
|
55
|
+
minitest (5.11.3)
|
|
56
|
+
nokogiri (1.10.2)
|
|
57
|
+
mini_portile2 (~> 2.4.0)
|
|
58
|
+
rack (2.0.7)
|
|
59
|
+
rack-test (1.1.0)
|
|
60
|
+
rack (>= 1.0, < 3)
|
|
61
|
+
rails-dom-testing (2.0.3)
|
|
62
|
+
activesupport (>= 4.2.0)
|
|
63
|
+
nokogiri (>= 1.6)
|
|
64
|
+
rails-html-sanitizer (1.0.4)
|
|
65
|
+
loofah (~> 2.2, >= 2.2.2)
|
|
66
|
+
railties (5.2.3)
|
|
67
|
+
actionpack (= 5.2.3)
|
|
68
|
+
activesupport (= 5.2.3)
|
|
69
|
+
method_source
|
|
70
|
+
rake (>= 0.8.7)
|
|
71
|
+
thor (>= 0.19.0, < 2.0)
|
|
72
|
+
rake (12.3.2)
|
|
73
|
+
rspec-core (3.8.0)
|
|
74
|
+
rspec-support (~> 3.8.0)
|
|
75
|
+
rspec-expectations (3.8.2)
|
|
76
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
77
|
+
rspec-support (~> 3.8.0)
|
|
78
|
+
rspec-mocks (3.8.0)
|
|
79
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
80
|
+
rspec-support (~> 3.8.0)
|
|
81
|
+
rspec-rails (3.8.2)
|
|
82
|
+
actionpack (>= 3.0)
|
|
83
|
+
activesupport (>= 3.0)
|
|
84
|
+
railties (>= 3.0)
|
|
85
|
+
rspec-core (~> 3.8.0)
|
|
86
|
+
rspec-expectations (~> 3.8.0)
|
|
87
|
+
rspec-mocks (~> 3.8.0)
|
|
88
|
+
rspec-support (~> 3.8.0)
|
|
89
|
+
rspec-support (3.8.0)
|
|
90
|
+
simplecov (0.16.1)
|
|
91
|
+
docile (~> 1.1)
|
|
92
|
+
json (>= 1.8, < 3)
|
|
93
|
+
simplecov-html (~> 0.10.0)
|
|
94
|
+
simplecov-html (0.10.2)
|
|
95
|
+
sqlite3 (1.3.13)
|
|
96
|
+
thor (0.20.3)
|
|
97
|
+
thread_safe (0.3.6)
|
|
98
|
+
tzinfo (1.2.5)
|
|
99
|
+
thread_safe (~> 0.1)
|
|
100
|
+
|
|
101
|
+
PLATFORMS
|
|
102
|
+
ruby
|
|
103
|
+
|
|
104
|
+
DEPENDENCIES
|
|
105
|
+
actionpack (~> 5.2.0)
|
|
106
|
+
activerecord (~> 5.2.0)
|
|
107
|
+
appraisal (~> 2.2)
|
|
108
|
+
lol_dba!
|
|
109
|
+
railties (~> 5.2.0)
|
|
110
|
+
rspec-rails
|
|
111
|
+
simplecov (~> 0.1)
|
|
112
|
+
sqlite3 (~> 1.3.5)
|
|
113
|
+
|
|
114
|
+
BUNDLED WITH
|
|
115
|
+
1.17.3
|
data/lib/lol_dba/cli.rb
CHANGED
|
@@ -4,43 +4,54 @@ require 'lol_dba/version'
|
|
|
4
4
|
|
|
5
5
|
module LolDba
|
|
6
6
|
class CLI
|
|
7
|
-
|
|
8
7
|
class << self
|
|
9
8
|
def start
|
|
9
|
+
new(Dir.pwd, parse_options).start(ARGV.first)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def parse_options
|
|
10
13
|
options = {}
|
|
11
14
|
OptionParser.new do |opts|
|
|
12
|
-
opts.on('-d', '--debug',
|
|
13
|
-
|
|
15
|
+
opts.on('-d', '--debug',
|
|
16
|
+
'Show stack traces when an error occurs.') do |opt|
|
|
17
|
+
options[:debug] = opt
|
|
18
|
+
end
|
|
19
|
+
opts.on_tail('-v', '--version', 'Show version') do
|
|
14
20
|
puts LolDba::VERSION
|
|
15
21
|
exit
|
|
16
22
|
end
|
|
17
23
|
end.parse!
|
|
18
|
-
new(Dir.pwd, options).start
|
|
19
24
|
end
|
|
20
25
|
end
|
|
21
26
|
|
|
22
27
|
def initialize(path, options)
|
|
23
|
-
@path
|
|
28
|
+
@path = path
|
|
29
|
+
@options = options
|
|
24
30
|
end
|
|
25
31
|
|
|
26
|
-
def start
|
|
32
|
+
def start(arg)
|
|
27
33
|
load_application
|
|
28
|
-
arg
|
|
34
|
+
select_action(arg)
|
|
35
|
+
rescue Exception => exception
|
|
36
|
+
if @options[:debug]
|
|
37
|
+
warn "Failed: #{exception.class}: #{exception.message}"
|
|
38
|
+
warn exception.backtrace.map { |trace| " from #{trace}" }
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
protected
|
|
43
|
+
|
|
44
|
+
def select_action(arg)
|
|
29
45
|
if arg =~ /db:find_indexes/
|
|
30
|
-
LolDba.
|
|
46
|
+
LolDba::IndexFinder.run
|
|
31
47
|
elsif arg !~ /\[/
|
|
32
|
-
LolDba::SqlGenerator.
|
|
48
|
+
LolDba::SqlGenerator.run('all')
|
|
33
49
|
else
|
|
34
50
|
which = arg.match(/.*\[(.*)\].*/).captures[0]
|
|
35
|
-
LolDba::SqlGenerator.
|
|
51
|
+
LolDba::SqlGenerator.run(which)
|
|
36
52
|
end
|
|
37
|
-
rescue Exception => e
|
|
38
|
-
$stderr.puts "Failed: #{e.class}: #{e.message}" if @options[:debug]
|
|
39
|
-
$stderr.puts e.backtrace.map { |t| " from #{t}" } if @options[:debug]
|
|
40
53
|
end
|
|
41
54
|
|
|
42
|
-
protected
|
|
43
|
-
|
|
44
55
|
# Tks to https://github.com/voormedia/rails-erd/blob/master/lib/rails_erd/cli.rb
|
|
45
56
|
def load_application
|
|
46
57
|
require "#{@path}/config/environment"
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module LolDba
|
|
2
|
+
class BelongsTo < RelationInspector
|
|
3
|
+
def relation_columns
|
|
4
|
+
if reflection_options.options[:polymorphic]
|
|
5
|
+
name = reflection_options.name
|
|
6
|
+
poly_type = "#{name}_type"
|
|
7
|
+
poly_id = "#{name}_id"
|
|
8
|
+
[poly_type, poly_id].sort
|
|
9
|
+
else
|
|
10
|
+
foreign_key = non_polymorphic_fk
|
|
11
|
+
|
|
12
|
+
# not a clue why rails 4.1+ creates this left_side_id thing
|
|
13
|
+
foreign_key == 'left_side_id' ? nil : foreign_key.to_s
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def table_name
|
|
18
|
+
model_class.table_name
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def non_polymorphic_fk
|
|
24
|
+
foreign_key = reflection_options.options[:foreign_key]
|
|
25
|
+
foreign_key ||= if reflection_options.respond_to?(:primary_key_name)
|
|
26
|
+
reflection_options.primary_key_name
|
|
27
|
+
else
|
|
28
|
+
reflection_options.foreign_key
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module LolDba
|
|
2
|
+
class ErrorLogging
|
|
3
|
+
def self.log(model_class, reflection_options, exception)
|
|
4
|
+
puts 'some errors here...'
|
|
5
|
+
puts 'please, create an issue with the following information here:'
|
|
6
|
+
puts 'https://github.com/plentz/lol_dba/issues'
|
|
7
|
+
puts '***************************'
|
|
8
|
+
puts "class: #{model_class}"
|
|
9
|
+
puts "association type: #{reflection_options.macro}"
|
|
10
|
+
puts "association options: #{reflection_options.options}"
|
|
11
|
+
puts "exception: #{exception.message}"
|
|
12
|
+
exception.backtrace.each { |trace| puts trace }
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module LolDba
|
|
2
|
+
class HasAndBelongsToMany < RelationInspector
|
|
3
|
+
def relation_columns
|
|
4
|
+
foreign_key = get_through_foreign_key(model_class, reflection_options)
|
|
5
|
+
index_name = [association_fk, foreign_key].map(&:to_s).sort
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def table_name
|
|
9
|
+
table_name = reflection_options.options[:join_table]
|
|
10
|
+
table_name || [model_class.table_name, reflection_name.to_s].sort.join('_')
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def association_fk
|
|
16
|
+
association_fk = reflection_options.options[:association_foreign_key]
|
|
17
|
+
association_fk || "#{reflection_name.to_s.singularize}_id"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module LolDba
|
|
2
|
+
class HasMany < RelationInspector
|
|
3
|
+
def relation_columns
|
|
4
|
+
# has_many tables are threaten by the other side of the relation
|
|
5
|
+
return nil unless through && reflections[through.to_s]
|
|
6
|
+
|
|
7
|
+
# FIXME: currently we don't support :through =>
|
|
8
|
+
# :another_regular_has_many_and_non_through_relation
|
|
9
|
+
if (association_foreign_key = find_association_fk).present?
|
|
10
|
+
[association_foreign_key, foreign_key].map(&:to_s).sort
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def table_name
|
|
15
|
+
through_class.table_name
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def find_association_fk
|
|
21
|
+
if (source = reflection_options.options[:source])
|
|
22
|
+
association_reflection = through_reflections[source.to_s]
|
|
23
|
+
return nil if association_reflection.options[:polymorphic]
|
|
24
|
+
get_through_foreign_key(association_reflection.klass, reflection_options)
|
|
25
|
+
elsif belongs_to_reflections = through_reflections[reflection_name.singularize]
|
|
26
|
+
# go to joining model through has_many and find belongs_to
|
|
27
|
+
belongs_to_reflections.options[:foreign_key]
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def through_class
|
|
32
|
+
reflections[through.to_s].klass
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def through
|
|
36
|
+
reflection_options.options[:through]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def foreign_key
|
|
40
|
+
get_through_foreign_key(model_class, reflection_options)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def through_reflections
|
|
44
|
+
through_class.reflections.stringify_keys
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
module LolDba
|
|
2
|
+
class IndexFinder
|
|
3
|
+
def self.run
|
|
4
|
+
MigrationFormatter.new(check_for_indexes).puts_migration_content
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def self.check_for_indexes
|
|
8
|
+
eager_load_if_needed
|
|
9
|
+
|
|
10
|
+
required_indexes = Hash.new([])
|
|
11
|
+
|
|
12
|
+
model_classes.each do |model_class|
|
|
13
|
+
unless model_class.descends_from_active_record?
|
|
14
|
+
index_name = [model_class.inheritance_column, model_class.base_class.primary_key].sort
|
|
15
|
+
required_indexes[model_class.base_class.table_name] += [index_name]
|
|
16
|
+
end
|
|
17
|
+
reflections = model_class.reflections.stringify_keys
|
|
18
|
+
reflections.each_pair do |reflection_name, reflection_options|
|
|
19
|
+
begin
|
|
20
|
+
clazz = RelationInspectorFactory.for(reflection_options.macro)
|
|
21
|
+
next unless clazz.present?
|
|
22
|
+
inspector = clazz.new(model_class, reflection_options,
|
|
23
|
+
reflection_name)
|
|
24
|
+
columns = inspector.relation_columns
|
|
25
|
+
|
|
26
|
+
unless columns.nil? || reflection_options.options.include?(:class)
|
|
27
|
+
required_indexes[inspector.table_name.to_s] += [columns]
|
|
28
|
+
end
|
|
29
|
+
rescue StandardError => exception
|
|
30
|
+
LolDba::ErrorLogging.log(model_class, reflection_options, exception)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
missing_indexes(required_indexes)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.missing_indexes(indexes_required)
|
|
39
|
+
missing_indexes = {}
|
|
40
|
+
indexes_required.each do |table_name, foreign_keys|
|
|
41
|
+
next if foreign_keys.blank? || !tables.include?(table_name.to_s)
|
|
42
|
+
keys_to_add = foreign_keys.uniq - existing_indexes(table_name)
|
|
43
|
+
missing_indexes[table_name] = keys_to_add unless keys_to_add.empty?
|
|
44
|
+
end
|
|
45
|
+
missing_indexes
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.tables
|
|
49
|
+
LolDba::RailsCompatibility.tables
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def self.existing_indexes(table_name)
|
|
53
|
+
table_indexes(table_name) + primary_key(table_name)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def self.table_indexes(table_name)
|
|
57
|
+
indexes = ActiveRecord::Base.connection.indexes(table_name.to_sym)
|
|
58
|
+
indexes.collect do |index|
|
|
59
|
+
index.columns.size > 1 ? index.columns : index.columns.first
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def self.primary_key(table_name)
|
|
64
|
+
Array(ActiveRecord::Base.connection.primary_key(table_name.to_s))
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def self.model_classes
|
|
68
|
+
ActiveRecord::Base.descendants.select do |obj|
|
|
69
|
+
Class == obj.class && session_store?(obj)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def self.session_store?(obj)
|
|
74
|
+
!defined?(ActiveRecord::SessionStore::Session) || obj != ActiveRecord::SessionStore::Session
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def self.eager_load_if_needed
|
|
78
|
+
Rails.application.eager_load! if defined?(Rails) && !Rails.env.test?
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module LolDba
|
|
2
|
+
class MigrationFormatter
|
|
3
|
+
def initialize(indexes)
|
|
4
|
+
@indexes = indexes
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def puts_migration_content
|
|
8
|
+
formated_indexes = format_for_migration(@indexes)
|
|
9
|
+
if formated_indexes.blank?
|
|
10
|
+
puts 'Yey, no missing indexes found!'
|
|
11
|
+
else
|
|
12
|
+
puts migration_instructions(formated_indexes)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def format_for_migration(missing_indexes)
|
|
17
|
+
add = []
|
|
18
|
+
missing_indexes.each do |table_name, keys_to_add|
|
|
19
|
+
keys_to_add.each do |key|
|
|
20
|
+
next if key.blank?
|
|
21
|
+
add << format_index(table_name, key)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
add
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def format_index(table_name, key)
|
|
28
|
+
if key.is_a?(Array)
|
|
29
|
+
keys = key.collect { |col| ":#{col}" }
|
|
30
|
+
"add_index :#{table_name}, [#{keys.join(', ')}]"
|
|
31
|
+
else
|
|
32
|
+
"add_index :#{table_name}, :#{key}"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def migration_instructions(formated_indexes)
|
|
37
|
+
<<-MIGRATION
|
|
38
|
+
* TIP: if you have a problem with the index name('index name too long'), you can
|
|
39
|
+
solve with the :name option. Something like :name => 'my_index'.
|
|
40
|
+
* run `rails g migration AddMissingIndexes` and add the following content:
|
|
41
|
+
|
|
42
|
+
class AddMissingIndexes < ActiveRecord::Migration
|
|
43
|
+
def change
|
|
44
|
+
#{formated_indexes.sort.uniq.join("\n ")}
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
MIGRATION
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module LolDba
|
|
2
|
+
class RelationInspector
|
|
3
|
+
attr_reader :model_class, :reflection_options, :reflection_name
|
|
4
|
+
|
|
5
|
+
def initialize(model_class, reflection_options, reflection_name)
|
|
6
|
+
@model_class = model_class
|
|
7
|
+
@reflection_options = reflection_options
|
|
8
|
+
@reflection_name = reflection_name
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def get_through_foreign_key(target_class, reflection_options)
|
|
12
|
+
# has_many :through
|
|
13
|
+
reflection = target_class.reflections[reflection_options.options[:through].to_s]
|
|
14
|
+
|
|
15
|
+
# has_and_belongs_to_many
|
|
16
|
+
reflection ||= reflection_options
|
|
17
|
+
|
|
18
|
+
# Guess foreign key?
|
|
19
|
+
if reflection.options[:foreign_key]
|
|
20
|
+
reflection.options[:foreign_key]
|
|
21
|
+
else
|
|
22
|
+
"#{target_class.name.tableize.singularize}_id"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def reflections
|
|
27
|
+
model_class.reflections.stringify_keys
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|