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 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 "rails", ">= 3.0.0"
8
- gem "sqlite3"
9
- gem "yaml_waml"
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
- # Add dependencies to develop your gem here.
13
- # Include everything needed to run rake, tests, features, etc.
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.7.0)
5
- actionmailer (3.2.3)
6
- actionpack (= 3.2.3)
7
- mail (~> 2.4.4)
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.1)
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.2)
18
- activemodel (3.2.3)
19
- activesupport (= 3.2.3)
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.3)
22
- activemodel (= 3.2.3)
23
- activesupport (= 3.2.3)
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
- activeresource (3.2.3)
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
- builder (3.0.0)
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.0)
39
- jeweler (1.8.3)
40
- bundler (~> 1.0)
41
- git (>= 1.2.5)
42
- rake
43
- rdoc
44
- journey (1.0.3)
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.1)
51
+ rack-test (0.6.2)
59
52
  rack (>= 1.0)
60
- rails (3.2.3)
61
- actionmailer (= 3.2.3)
62
- actionpack (= 3.2.3)
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 (~> 0.14.6)
75
- rake (0.9.2.2)
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.8.0)
79
- rspec-core (~> 2.8.0)
80
- rspec-expectations (~> 2.8.0)
81
- rspec-mocks (~> 2.8.0)
82
- rspec-core (2.8.0)
83
- rspec-expectations (2.8.0)
84
- diff-lcs (~> 1.1.2)
85
- rspec-mocks (2.8.0)
86
- rspec-rails (2.8.1)
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.8.0)
91
- simplecov (0.6.1)
75
+ rspec (~> 2.10.0)
76
+ simplecov (0.7.1)
92
77
  multi_json (~> 1.0)
93
- simplecov-html (~> 0.5.3)
94
- simplecov-html (0.5.3)
95
- sprockets (2.1.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.5)
100
- thor (0.14.6)
85
+ sqlite3 (1.3.7)
86
+ thor (0.17.0)
101
87
  tilt (1.3.3)
102
- treetop (1.4.10)
103
- polyglot
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
- activerecord (>= 3.0.0)
115
- activesupport (>= 3.0.0)
116
- bundler (~> 1.0.0)
117
- jeweler (~> 1.8.3)
118
- rails (>= 3.0.0)
119
- rdoc (~> 3.12)
120
- rspec (~> 2.8.0)
121
- rspec-rails (~> 2.8.1)
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
- yaml_waml
125
- yard (~> 0.7)
106
+ yard
data/README.rdoc CHANGED
@@ -1,4 +1,4 @@
1
- = SchemaComments
1
+ = SchemaComments {<img src="https://secure.travis-ci.org/akm/schema_comments.png" />}[http://travis-ci.org/akm/schema_comments]
2
2
 
3
3
  == Install
4
4
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0.alpha5
1
+ 0.2.0
@@ -1,18 +1,18 @@
1
1
  require 'active_support/core_ext/module'
2
2
 
3
3
  module SchemaComments
4
- VERSION = '0.1.0'
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
- private
6
- def tables(stream)
7
- result = super(stream)
8
- # ビューはtableの後に実行するようにしないと rake db:schema:load で失敗します。
9
- mysql_views(stream) if adapter_name == "mysql"
10
- result
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 mysql_view?(table)
14
- return false unless adapter_name == 'mysql'
15
- config = ActiveRecord::Base.configurations[Rails.env]
16
- match_count = @connection.select_value(
17
- "select count(*) from information_schema.TABLES where TABLE_TYPE = 'VIEW' AND TABLE_SCHEMA = '%s' AND TABLE_NAME = '%s'" % [
18
- config["database"], table])
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
- def table(table, stream)
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 mysql_views(stream)
122
- config = ActiveRecord::Base.configurations[Rails.env]
123
- view_names = @connection.select_values(
124
- "select TABLE_NAME from information_schema.TABLES where TABLE_TYPE = 'VIEW' AND TABLE_SCHEMA = '%s'" % config["database"])
125
- view_names.each do |view_name|
126
- mysql_view(view_name, stream)
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 mysql_view(view_name, stream)
131
- ddl = @connection.select_value("show create view #{view_name}")
132
- ddl.gsub!(/^CREATE .+? VIEW /i, "CREATE OR REPLACE VIEW ")
133
- ddl.gsub!(/AS select/, "AS \n select\n")
134
- ddl.gsub!(/( AS \`.+?\`\,)/){ "#{$1}\n" }
135
- ddl.gsub!(/ from /i , "\n from \n")
136
- ddl.gsub!(/ where /i , "\n where \n")
137
- ddl.gsub!(/ order by /i , "\n order by \n")
138
- ddl.gsub!(/ having /i , "\n having \n")
139
- ddl.gsub!(/ union /i , "\n union \n")
140
- ddl.gsub!(/ and /i , "\n and ")
141
- ddl.gsub!(/ or /i , "\n or ")
142
- ddl.gsub!(/inner join/i , "\n inner join")
143
- ddl.gsub!(/left join/i , "\n left join")
144
- ddl.gsub!(/left outer join/i, "\n left outer join")
145
- stream.print(" ActiveRecord::Base.connection.execute(<<-EOS)\n")
146
- stream.print(ddl.split(/\n/).map{|line| ' ' << line.strip}.join("\n"))
147
- stream.print("\n EOS\n")
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