schema_comments 0.2.0.alpha5 → 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.
- data/Gemfile +7 -18
- data/Gemfile.lock +64 -83
- data/README.rdoc +1 -1
- data/VERSION +1 -1
- data/lib/schema_comments.rb +8 -8
- data/lib/schema_comments/schema_dumper.rb +101 -40
- data/lib/schema_comments/schema_dumper/mysql.rb +220 -0
- data/spec/annotate_models_spec.rb +9 -2
- data/spec/database.yml +8 -6
- data/spec/fake_app.rb +23 -2
- data/spec/human_readable_schema_comments.yml +14 -14
- data/spec/schema_comments.yml +9 -9
- data/spec/schema_comments/connection_adapters_spec.rb +0 -2
- data/spec/schema_comments/schema_comment_spec.rb +0 -2
- data/spec/schema_comments/schema_comments.yml +10 -10
- data/spec/schema_comments/schema_comments_users_without_column_hash.yml +9 -9
- data/spec/schema_comments/schema_dumper_spec.rb +20 -4
- data/spec/spec_helper.rb +17 -4
- data/spec/yaml_export_spec.rb +8 -8
- metadata +103 -59
- data/Rakefile +0 -44
- data/schema_comments.gemspec +0 -120
- data/spec/.gitignore +0 -3
- data/spec/fixtures/.gitignore +0 -0
- data/spec/rcov.opts +0 -1
- data/spec/schema_comments/.gitignore +0 -2
- data/spec/spec.opts +0 -6
data/Gemfile
CHANGED
@@ -1,23 +1,12 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
|
3
|
-
gem "activesupport", ">= 3.0.0"
|
4
|
-
gem "activerecord", ">= 3.0.0"
|
5
|
-
|
6
3
|
group :test do
|
7
|
-
gem "
|
8
|
-
gem "
|
9
|
-
gem "
|
10
|
-
end
|
4
|
+
gem "sqlite3", :platform => :ruby
|
5
|
+
gem "mysql" , (RUBY_VERSION == '1.9.2' ? "~> 2.8.1" : ">= 0"), :platform => :ruby
|
6
|
+
gem "mysql2" , :platform => :ruby
|
11
7
|
|
12
|
-
#
|
13
|
-
#
|
14
|
-
group :development do
|
15
|
-
gem "rspec", "~> 2.8.0"
|
16
|
-
gem "rspec-rails", "~> 2.8.1"
|
17
|
-
gem "yard", "~> 0.7"
|
18
|
-
gem "rdoc", "~> 3.12"
|
19
|
-
gem "bundler", "~> 1.0.0"
|
20
|
-
gem "jeweler", "~> 1.8.3"
|
21
|
-
gem "simplecov", ">= 0"
|
22
|
-
gem "ZenTest"
|
8
|
+
# gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby
|
9
|
+
# gem "activerecord-jdbcmysql-adapter" , :platform => :jruby
|
23
10
|
end
|
11
|
+
|
12
|
+
gemspec
|
data/Gemfile.lock
CHANGED
@@ -1,125 +1,106 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
schema_comments (0.2.0)
|
5
|
+
activerecord (>= 3.0.0)
|
6
|
+
activesupport (>= 3.0.0)
|
7
|
+
|
1
8
|
GEM
|
2
9
|
remote: http://rubygems.org/
|
3
10
|
specs:
|
4
|
-
ZenTest (4.
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
actionpack (3.2.3)
|
9
|
-
activemodel (= 3.2.3)
|
10
|
-
activesupport (= 3.2.3)
|
11
|
+
ZenTest (4.8.3)
|
12
|
+
actionpack (3.2.11)
|
13
|
+
activemodel (= 3.2.11)
|
14
|
+
activesupport (= 3.2.11)
|
11
15
|
builder (~> 3.0.0)
|
12
16
|
erubis (~> 2.7.0)
|
13
|
-
journey (~> 1.0.
|
17
|
+
journey (~> 1.0.4)
|
14
18
|
rack (~> 1.4.0)
|
15
19
|
rack-cache (~> 1.2)
|
16
20
|
rack-test (~> 0.6.1)
|
17
|
-
sprockets (~> 2.1
|
18
|
-
activemodel (3.2.
|
19
|
-
activesupport (= 3.2.
|
21
|
+
sprockets (~> 2.2.1)
|
22
|
+
activemodel (3.2.11)
|
23
|
+
activesupport (= 3.2.11)
|
20
24
|
builder (~> 3.0.0)
|
21
|
-
activerecord (3.2.
|
22
|
-
activemodel (= 3.2.
|
23
|
-
activesupport (= 3.2.
|
25
|
+
activerecord (3.2.11)
|
26
|
+
activemodel (= 3.2.11)
|
27
|
+
activesupport (= 3.2.11)
|
24
28
|
arel (~> 3.0.2)
|
25
29
|
tzinfo (~> 0.3.29)
|
26
|
-
|
27
|
-
activemodel (= 3.2.3)
|
28
|
-
activesupport (= 3.2.3)
|
29
|
-
activesupport (3.2.3)
|
30
|
+
activesupport (3.2.11)
|
30
31
|
i18n (~> 0.6)
|
31
32
|
multi_json (~> 1.0)
|
32
33
|
arel (3.0.2)
|
33
|
-
|
34
|
+
autotest (4.4.6)
|
35
|
+
ZenTest (>= 4.4.1)
|
36
|
+
builder (3.0.4)
|
34
37
|
diff-lcs (1.1.3)
|
35
38
|
erubis (2.7.0)
|
36
|
-
git (1.2.5)
|
37
39
|
hike (1.2.1)
|
38
|
-
i18n (0.6.
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
json (1.6.6)
|
46
|
-
mail (2.4.4)
|
47
|
-
i18n (>= 0.4.0)
|
48
|
-
mime-types (~> 1.16)
|
49
|
-
treetop (~> 1.4.8)
|
50
|
-
mime-types (1.18)
|
51
|
-
multi_json (1.3.0)
|
52
|
-
polyglot (0.3.3)
|
53
|
-
rack (1.4.1)
|
40
|
+
i18n (0.6.1)
|
41
|
+
journey (1.0.4)
|
42
|
+
json (1.7.6)
|
43
|
+
multi_json (1.5.0)
|
44
|
+
mysql (2.9.0)
|
45
|
+
mysql2 (0.3.11)
|
46
|
+
rack (1.4.4)
|
54
47
|
rack-cache (1.2)
|
55
48
|
rack (>= 0.4)
|
56
49
|
rack-ssl (1.3.2)
|
57
50
|
rack
|
58
|
-
rack-test (0.6.
|
51
|
+
rack-test (0.6.2)
|
59
52
|
rack (>= 1.0)
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
activerecord (= 3.2.3)
|
64
|
-
activeresource (= 3.2.3)
|
65
|
-
activesupport (= 3.2.3)
|
66
|
-
bundler (~> 1.0)
|
67
|
-
railties (= 3.2.3)
|
68
|
-
railties (3.2.3)
|
69
|
-
actionpack (= 3.2.3)
|
70
|
-
activesupport (= 3.2.3)
|
53
|
+
railties (3.2.11)
|
54
|
+
actionpack (= 3.2.11)
|
55
|
+
activesupport (= 3.2.11)
|
71
56
|
rack-ssl (~> 1.3.2)
|
72
57
|
rake (>= 0.8.7)
|
73
58
|
rdoc (~> 3.4)
|
74
|
-
thor (
|
75
|
-
rake (0.
|
59
|
+
thor (>= 0.14.6, < 2.0)
|
60
|
+
rake (10.0.3)
|
76
61
|
rdoc (3.12)
|
77
62
|
json (~> 1.4)
|
78
|
-
rspec (2.
|
79
|
-
rspec-core (~> 2.
|
80
|
-
rspec-expectations (~> 2.
|
81
|
-
rspec-mocks (~> 2.
|
82
|
-
rspec-core (2.
|
83
|
-
rspec-expectations (2.
|
84
|
-
diff-lcs (~> 1.1.
|
85
|
-
rspec-mocks (2.
|
86
|
-
rspec-rails (2.
|
63
|
+
rspec (2.10.0)
|
64
|
+
rspec-core (~> 2.10.0)
|
65
|
+
rspec-expectations (~> 2.10.0)
|
66
|
+
rspec-mocks (~> 2.10.0)
|
67
|
+
rspec-core (2.10.1)
|
68
|
+
rspec-expectations (2.10.0)
|
69
|
+
diff-lcs (~> 1.1.3)
|
70
|
+
rspec-mocks (2.10.1)
|
71
|
+
rspec-rails (2.10.1)
|
87
72
|
actionpack (>= 3.0)
|
88
73
|
activesupport (>= 3.0)
|
89
74
|
railties (>= 3.0)
|
90
|
-
rspec (~> 2.
|
91
|
-
simplecov (0.
|
75
|
+
rspec (~> 2.10.0)
|
76
|
+
simplecov (0.7.1)
|
92
77
|
multi_json (~> 1.0)
|
93
|
-
simplecov-html (~> 0.
|
94
|
-
simplecov-html (0.
|
95
|
-
sprockets (2.
|
78
|
+
simplecov-html (~> 0.7.1)
|
79
|
+
simplecov-html (0.7.1)
|
80
|
+
sprockets (2.2.2)
|
96
81
|
hike (~> 1.2)
|
82
|
+
multi_json (~> 1.0)
|
97
83
|
rack (~> 1.0)
|
98
84
|
tilt (~> 1.1, != 1.3.0)
|
99
|
-
sqlite3 (1.3.
|
100
|
-
thor (0.
|
85
|
+
sqlite3 (1.3.7)
|
86
|
+
thor (0.17.0)
|
101
87
|
tilt (1.3.3)
|
102
|
-
|
103
|
-
|
104
|
-
polyglot (>= 0.3.1)
|
105
|
-
tzinfo (0.3.33)
|
106
|
-
yaml_waml (0.3.0)
|
107
|
-
yard (0.7.5)
|
88
|
+
tzinfo (0.3.35)
|
89
|
+
yard (0.8.3)
|
108
90
|
|
109
91
|
PLATFORMS
|
110
92
|
ruby
|
111
93
|
|
112
94
|
DEPENDENCIES
|
113
|
-
ZenTest
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
rspec (~> 2.
|
121
|
-
|
95
|
+
ZenTest (= 4.8.3)
|
96
|
+
autotest
|
97
|
+
bundler
|
98
|
+
mysql
|
99
|
+
mysql2
|
100
|
+
rake
|
101
|
+
rspec (~> 2.10.0)
|
102
|
+
rspec-rails (~> 2.10.1)
|
103
|
+
schema_comments!
|
122
104
|
simplecov
|
123
105
|
sqlite3
|
124
|
-
|
125
|
-
yard (~> 0.7)
|
106
|
+
yard
|
data/README.rdoc
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.0
|
1
|
+
0.2.0
|
data/lib/schema_comments.rb
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
require 'active_support/core_ext/module'
|
2
2
|
|
3
3
|
module SchemaComments
|
4
|
-
VERSION =
|
4
|
+
VERSION = File.read(File.expand_path("../../VERSION", __FILE__))
|
5
5
|
|
6
|
-
autoload :Base, 'schema_comments/base'
|
6
|
+
autoload :Base , 'schema_comments/base'
|
7
7
|
autoload :ConnectionAdapters, 'schema_comments/connection_adapters'
|
8
|
-
autoload :Migration, 'schema_comments/migration'
|
9
|
-
autoload :Migrator, 'schema_comments/migrator'
|
10
|
-
autoload :Schema, 'schema_comments/schema'
|
11
|
-
autoload :SchemaComment, 'schema_comments/schema_comment'
|
12
|
-
autoload :SchemaDumper, 'schema_comments/schema_dumper'
|
8
|
+
autoload :Migration , 'schema_comments/migration'
|
9
|
+
autoload :Migrator , 'schema_comments/migrator'
|
10
|
+
autoload :Schema , 'schema_comments/schema'
|
11
|
+
autoload :SchemaComment , 'schema_comments/schema_comment'
|
12
|
+
autoload :SchemaDumper , 'schema_comments/schema_dumper'
|
13
13
|
|
14
14
|
mattr_accessor :yaml_path
|
15
|
-
self.yaml_path = Rails.root.join("db/schema_comments.yml").to_s if defined?(Rails)
|
15
|
+
self.yaml_path = Rails.root.join("db/schema_comments.yml").to_s if defined?(Rails) && Rails.root
|
16
16
|
|
17
17
|
mattr_accessor :quiet
|
18
18
|
|
@@ -2,27 +2,31 @@
|
|
2
2
|
module SchemaComments
|
3
3
|
class SchemaDumper < ActiveRecord::SchemaDumper
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
autoload :Mysql, 'schema_comments/schema_dumper/mysql'
|
6
|
+
|
7
|
+
def self.dump(connection=ActiveRecord::Base.connection, stream=STDOUT)
|
8
|
+
dumper =
|
9
|
+
case connection.adapter_name
|
10
|
+
when /mysql/i then
|
11
|
+
SchemaComments::SchemaDumper::Mysql.new(connection)
|
12
|
+
else
|
13
|
+
new(connection)
|
14
|
+
end
|
15
|
+
dumper.dump(stream)
|
16
|
+
stream
|
11
17
|
end
|
12
18
|
|
13
|
-
def
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
match_count.to_i > 0
|
19
|
+
def dump(stream)
|
20
|
+
header(stream)
|
21
|
+
tables(stream)
|
22
|
+
selectable_attrs(stream)
|
23
|
+
trailer(stream)
|
24
|
+
stream
|
20
25
|
end
|
21
26
|
|
22
|
-
|
23
|
-
# MySQLは、ビューもテーブルとして扱うので、一個一個チェックします。
|
24
|
-
return if mysql_view?(table)
|
27
|
+
private
|
25
28
|
|
29
|
+
def table(table, stream)
|
26
30
|
columns = @connection.columns(table)
|
27
31
|
begin
|
28
32
|
tbl = StringIO.new
|
@@ -118,33 +122,90 @@ module SchemaComments
|
|
118
122
|
config ? config['adapter'] : ActiveRecord::Base.connection.adapter_name
|
119
123
|
end
|
120
124
|
|
121
|
-
def
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
125
|
+
def selectable_attrs(stream)
|
126
|
+
return unless defined?(SelectableAttr)
|
127
|
+
enum_defs = []
|
128
|
+
classes = Dir["app/models/*.rb"].map{|f| File.basename(f, ".*").camelize.constantize}.select{|k| k.respond_to?(:single_selectable_attrs)}
|
129
|
+
classes.each do |klass|
|
130
|
+
(klass.single_selectable_attrs + klass.multi_selectable_attrs).each do |enum_name|
|
131
|
+
enum = klass.send(klass.enum_base_name(enum_name) + "_enum")
|
132
|
+
enum_def = enum_defs.detect{|enum_def| enum_def[:enum] === enum && enum_def[:enum_name] == enum_name}
|
133
|
+
unless enum_def
|
134
|
+
enum_def = {:enum => enum, :enum_name => enum_name, :usages => []}
|
135
|
+
enum_defs << enum_def
|
136
|
+
end
|
137
|
+
enum_def[:usages] << {:class => klass, :enum_name => enum_name}
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
stream.puts
|
142
|
+
|
143
|
+
enum_defs.each do |enum_def|
|
144
|
+
selectable_attr(enum_def[:enum], enum_def[:usages], stream)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def selectable_attr(enum, usages, stream)
|
149
|
+
buf = StringIO.new
|
150
|
+
|
151
|
+
specs = []
|
152
|
+
usages.each do |usage|
|
153
|
+
klass = usage[:class]
|
154
|
+
method_caption = nil
|
155
|
+
if col = usage[:class].columns.detect{|c| c.name == usage[:enum_name]}
|
156
|
+
method_caption = col.comment
|
157
|
+
end
|
158
|
+
method_caption ||= usage[:enum_name]
|
159
|
+
spec = {
|
160
|
+
:class_name => klass.name,
|
161
|
+
:methos_name => usage[:enum_name],
|
162
|
+
:class_caption => klass.table_comment,
|
163
|
+
:method_caption => method_caption
|
164
|
+
}
|
165
|
+
specs << spec
|
127
166
|
end
|
167
|
+
keys = [:class_name, :methos_name, :class_caption, :method_caption]
|
168
|
+
lengths = keys.map{ |key| specs.map{ |spec| spec[key] ? spec[key].length + 2 : 0 }.max }
|
169
|
+
format_string = lengths.map{ |len| "%-#{len}s" }
|
170
|
+
format_string *= ''
|
171
|
+
specs.each do |spec|
|
172
|
+
values = keys.zip(lengths).map{ |key, len| spec.key?(key) ? spec[key] + " " : " " * len }
|
173
|
+
buf.print(' # ')
|
174
|
+
buf.print((format_string % values).gsub(/,\s*$/, '').strip)
|
175
|
+
buf.puts
|
176
|
+
end
|
177
|
+
buf.puts " #"
|
178
|
+
|
179
|
+
selectable_attr_with_default(enum, usages, buf)
|
180
|
+
|
181
|
+
buf.puts " #"
|
182
|
+
buf.puts
|
183
|
+
|
184
|
+
buf.rewind
|
185
|
+
stream.print buf.read
|
128
186
|
end
|
129
187
|
|
130
|
-
def
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
188
|
+
def selectable_attr_with_default(enum, usages, buf)
|
189
|
+
entry_specs = enum.entries.map do |e|
|
190
|
+
{:id => "#{e.id.inspect} |", :name => e.name.inspect, :options => e.options ? e.options.inspect : ''}
|
191
|
+
end
|
192
|
+
entry_specs.unshift({
|
193
|
+
:id => "val |", :name => "name and options", :options => ""})
|
194
|
+
keys = [:id, :name, :options] & entry_specs.map{ |k| k.keys }.flatten
|
195
|
+
lengths = keys.map{ |key| entry_specs.map{ |spec| spec[key] ? spec[key].length + 2 : 0 }.max }
|
196
|
+
format_string = ["%#{lengths[0]}s" ] + lengths[1..-1].map{ |len| "%-#{len}s" }
|
197
|
+
format_string *= ''
|
198
|
+
entry_specs.each_with_index do |enum_spec, idx|
|
199
|
+
values = keys.zip(lengths).map{ |key, len| enum_spec.key?(key) ? enum_spec[key] + " " : " " * len }
|
200
|
+
line = (format_string % values).gsub(/\s+\Z/, '')
|
201
|
+
buf.print(' # ')
|
202
|
+
buf.print(line)
|
203
|
+
buf.puts
|
204
|
+
if idx == 0
|
205
|
+
buf.print(' # ')
|
206
|
+
buf.puts("-" * line.length)
|
207
|
+
end
|
208
|
+
end
|
148
209
|
end
|
149
210
|
|
150
211
|
end
|
@@ -0,0 +1,220 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'schema_comments/schema_dumper'
|
3
|
+
|
4
|
+
module SchemaComments
|
5
|
+
|
6
|
+
class SchemaDumper::Mysql < SchemaComments::SchemaDumper
|
7
|
+
|
8
|
+
class << self
|
9
|
+
public :new
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
def tables(stream)
|
14
|
+
result = super(stream)
|
15
|
+
# ビューはtableの後に実行するようにしないと rake db:schema:load で失敗します。
|
16
|
+
mysql_views(stream)
|
17
|
+
result
|
18
|
+
end
|
19
|
+
|
20
|
+
def mysql_view?(table)
|
21
|
+
return false unless adapter_name == 'mysql'
|
22
|
+
match_count = @connection.select_value(
|
23
|
+
"select count(*) from information_schema.TABLES where TABLE_TYPE = 'VIEW' AND TABLE_SCHEMA = '%s' AND TABLE_NAME = '%s'" % [
|
24
|
+
config["database"], table])
|
25
|
+
match_count.to_i > 0
|
26
|
+
end
|
27
|
+
|
28
|
+
def config
|
29
|
+
ActiveRecord::Base.configurations[Rails.env] || ActiveRecord::Base.configurations[ ENV['DB'] ]
|
30
|
+
end
|
31
|
+
|
32
|
+
def adapter_name
|
33
|
+
c = ActiveRecord::Base.configurations[Rails.env]
|
34
|
+
c ? c['adapter'] : ActiveRecord::Base.connection.adapter_name
|
35
|
+
end
|
36
|
+
|
37
|
+
def header(stream)
|
38
|
+
define_params = @version ? ":version => #{@version}" : ""
|
39
|
+
|
40
|
+
if stream.respond_to?(:external_encoding)
|
41
|
+
stream.puts "# encoding: #{stream.external_encoding.name}"
|
42
|
+
end
|
43
|
+
|
44
|
+
stream.puts <<HEADER
|
45
|
+
# This file is auto-generated from the current state of the database. Instead
|
46
|
+
# of editing this file, please use the migrations feature of Active Record to
|
47
|
+
# incrementally modify your database, and then regenerate this schema definition.
|
48
|
+
#
|
49
|
+
# Note that this schema.rb definition is the authoritative source for your
|
50
|
+
# database schema. If you need to create the application database on another
|
51
|
+
# system, you should be using db:schema:load, not running all the migrations
|
52
|
+
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
53
|
+
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
54
|
+
#
|
55
|
+
# It's strongly recommended to check this file into your version control system.
|
56
|
+
|
57
|
+
ActiveRecord::Schema.define(#{define_params}) do
|
58
|
+
|
59
|
+
HEADER
|
60
|
+
end
|
61
|
+
|
62
|
+
def table(table, stream)
|
63
|
+
# MySQLは、ビューもテーブルとして扱うので、一個一個チェックします。
|
64
|
+
return if mysql_view?(table)
|
65
|
+
|
66
|
+
columns = @connection.columns(table)
|
67
|
+
begin
|
68
|
+
tbl = StringIO.new
|
69
|
+
|
70
|
+
# first dump primary key column
|
71
|
+
if @connection.respond_to?(:pk_and_sequence_for)
|
72
|
+
pk, _ = @connection.pk_and_sequence_for(table)
|
73
|
+
elsif @connection.respond_to?(:primary_key)
|
74
|
+
pk = @connection.primary_key(table)
|
75
|
+
end
|
76
|
+
|
77
|
+
tbl.print " create_table #{table.inspect}"
|
78
|
+
pk_exist = columns.detect { |c| c.name == pk } # for print ALTER TABLE ADD PRIMARY KEY
|
79
|
+
if pk_exist
|
80
|
+
if pk != 'id'
|
81
|
+
tbl.print %Q(, :primary_key => "#{pk}")
|
82
|
+
end
|
83
|
+
else
|
84
|
+
tbl.print ", :id => false"
|
85
|
+
end
|
86
|
+
tbl.print ", :force => true"
|
87
|
+
|
88
|
+
table_comment = @connection.table_comment(table)
|
89
|
+
tbl.print ", :comment => '#{table_comment}'" unless table_comment.blank?
|
90
|
+
|
91
|
+
tbl.puts " do |t|"
|
92
|
+
|
93
|
+
# then dump all non-primary key columns
|
94
|
+
column_specs = columns.map do |column|
|
95
|
+
raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" if @types[column.type].nil?
|
96
|
+
# next if column.name == pk
|
97
|
+
spec = {}
|
98
|
+
spec[:name] = column.name.inspect
|
99
|
+
|
100
|
+
# AR has an optimization which handles zero-scale decimals as integers. This
|
101
|
+
# code ensures that the dumper still dumps the column as a decimal.
|
102
|
+
# spec[:type] = if column.type == :integer && [/^numeric/, /^decimal/].any? { |e| e.match(column.sql_type) }
|
103
|
+
# 'decimal'
|
104
|
+
# else
|
105
|
+
# column.type.to_s
|
106
|
+
# end
|
107
|
+
spec[:type] = column.sql_type.inspect
|
108
|
+
# spec[:limit] = column.limit.inspect if column.limit != @types[column.type][:limit] && spec[:type] != 'decimal'
|
109
|
+
spec[:precision] = column.precision.inspect if column.precision
|
110
|
+
spec[:scale] = column.scale.inspect if column.scale
|
111
|
+
spec[:null] = 'false' unless column.null
|
112
|
+
spec[:default] = default_string(column.default) if column.has_default?
|
113
|
+
if column.name == pk
|
114
|
+
spec[:comment] = '"AUTO_INCREMENT PRIMARY KEY by rails"'
|
115
|
+
else
|
116
|
+
spec[:comment] = '"' << (column.comment || '').gsub(/\"/, '\"') << '"' # ここでinspectを使うと最後の文字だけ文字化け(UTF-8のコード)になっちゃう
|
117
|
+
end
|
118
|
+
(spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k.inspect} => ")}
|
119
|
+
spec
|
120
|
+
end.compact
|
121
|
+
|
122
|
+
# find all migration keys used in this table
|
123
|
+
# keys = [:name, :limit, :precision, :scale, :default, :null, :comment] & column_specs.map{ |k| k.keys }.flatten
|
124
|
+
keys = [:name, :type, :default, :null, :comment] & column_specs.map{ |k| k.keys }.flatten
|
125
|
+
|
126
|
+
# figure out the lengths for each column based on above keys
|
127
|
+
lengths = keys.map{ |key| column_specs.map{ |spec| spec[key] ? spec[key].length + 2 : 0 }.max }
|
128
|
+
|
129
|
+
# the string we're going to sprintf our values against, with standardized column widths
|
130
|
+
format_string = lengths.map{ |len| "%-#{len}s" }
|
131
|
+
|
132
|
+
# find the max length for the 'type' column, which is special
|
133
|
+
# type_length = column_specs.map{ |column| column[:type].length }.max
|
134
|
+
|
135
|
+
# add column type definition to our format string
|
136
|
+
# format_string.unshift " t.%-#{type_length}s "
|
137
|
+
|
138
|
+
format_string.unshift " t.column "
|
139
|
+
|
140
|
+
format_string *= ''
|
141
|
+
|
142
|
+
column_specs.each do |colspec|
|
143
|
+
values = keys.zip(lengths).map{ |key, len| colspec.key?(key) ? colspec[key] + ", " : " " * len }
|
144
|
+
# values.unshift colspec[:type]
|
145
|
+
s = (format_string % values).gsub(/,\s*$/, '')
|
146
|
+
|
147
|
+
if colspec[:name] == pk.inspect
|
148
|
+
tbl.print(s.sub(/ t.column /, " #t.column "))
|
149
|
+
else
|
150
|
+
tbl.print(s)
|
151
|
+
end
|
152
|
+
tbl.puts
|
153
|
+
end
|
154
|
+
|
155
|
+
tbl.puts " end"
|
156
|
+
primary_keys(table, tbl) unless pk_exist
|
157
|
+
tbl.puts
|
158
|
+
|
159
|
+
indexes(table, tbl)
|
160
|
+
|
161
|
+
tbl.rewind
|
162
|
+
stream.print tbl.read
|
163
|
+
rescue => e
|
164
|
+
stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
|
165
|
+
stream.puts "# #{e.message}"
|
166
|
+
stream.puts
|
167
|
+
end
|
168
|
+
|
169
|
+
stream
|
170
|
+
end
|
171
|
+
|
172
|
+
def mysql_views(stream)
|
173
|
+
view_names = @connection.select_values(
|
174
|
+
"select TABLE_NAME from information_schema.TABLES where TABLE_TYPE = 'VIEW' AND TABLE_SCHEMA = '%s'" % config["database"])
|
175
|
+
view_names.each do |view_name|
|
176
|
+
mysql_view(view_name, stream)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def mysql_view(view_name, stream)
|
181
|
+
ddl = @connection.select_value("show create view #{view_name}")
|
182
|
+
ddl.gsub!(/^CREATE .+? VIEW /i, "CREATE OR REPLACE VIEW ")
|
183
|
+
ddl.gsub!(/AS select/, "AS \n select\n")
|
184
|
+
ddl.gsub!(/( AS \`.+?\`\,)/){ "#{$1}\n" }
|
185
|
+
ddl.gsub!(/ from /i , "\n from \n")
|
186
|
+
ddl.gsub!(/ where /i , "\n where \n")
|
187
|
+
ddl.gsub!(/ order by /i , "\n order by \n")
|
188
|
+
ddl.gsub!(/ having /i , "\n having \n")
|
189
|
+
ddl.gsub!(/ union /i , "\n union \n")
|
190
|
+
ddl.gsub!(/ and /i , "\n and ")
|
191
|
+
ddl.gsub!(/ or /i , "\n or ")
|
192
|
+
ddl.gsub!(/inner join/i , "\n inner join")
|
193
|
+
ddl.gsub!(/left join/i , "\n left join")
|
194
|
+
ddl.gsub!(/left outer join/i, "\n left outer join")
|
195
|
+
stream.print(" ActiveRecord::Base.connection.execute(<<-EOS)\n")
|
196
|
+
stream.print(ddl.split(/\n/).map{|line| ' ' << line.strip}.join("\n"))
|
197
|
+
stream.print("\n EOS\n")
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
def primary_keys(table, tbl)
|
202
|
+
res = @connection.select("SHOW CREATE TABLE #{table}")
|
203
|
+
create_table = res.first['Create Table']
|
204
|
+
pks = create_table.scan(/\sPRIMARY KEY \((.+)\)\,/).flatten.first.
|
205
|
+
split(/,/).map{|s| s.gsub(/^\`|\`$/, '')}
|
206
|
+
tbl.puts(" execute \"ALTER TABLE #{table} ADD PRIMARY KEY (#{pks.join(',')})\"")
|
207
|
+
|
208
|
+
if create_table =~ /`id` (.+) NOT NULL AUTO_INCREMENT,/
|
209
|
+
tbl.puts(" execute \"ALTER TABLE #{table} CHANGE COLUMN `id` `id` #{$1} NOT NULL AUTO_INCREMENT\"")
|
210
|
+
end
|
211
|
+
|
212
|
+
if create_table =~ %r{/\*\!50100 (PARTITION .+ )\*/}m
|
213
|
+
st = $1.gsub(/\n/, ' ')
|
214
|
+
tbl.puts(" execute \"ALTER TABLE #{table} #{st}\"")
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
end
|
219
|
+
|
220
|
+
end
|