db_structure_ext 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/Gemfile.ar01_r186 +8 -0
- data/Gemfile.ar01_r186.lock +22 -0
- data/Gemfile.ar30_r192 +8 -0
- data/Gemfile.ar30_r192.lock +41 -0
- data/README.md +136 -0
- data/Rakefile +1 -0
- data/config/database.yml +8 -0
- data/db/structure.sql +54 -0
- data/db_structure_ext.gemspec +20 -0
- data/lib/db_structure_ext.rb +9 -0
- data/lib/db_structure_ext/init_mysql_adapter.rb +20 -0
- data/lib/db_structure_ext/mysql_adapter.rb +7 -0
- data/lib/db_structure_ext/mysql_connection_proxy.rb +16 -0
- data/lib/db_structure_ext/mysql_dump_methods.rb +110 -0
- data/lib/db_structure_ext/mysql_load_methods.rb +12 -0
- data/lib/db_structure_ext/railtie.rb +8 -0
- data/lib/db_structure_ext/tasks.rb +1 -0
- data/lib/db_structure_ext/version.rb +3 -0
- data/lib/tasks/database.rake +46 -0
- data/log/.gitkeep +0 -0
- data/spec/db_sctructure_ext/mysql_connection_proxy_spec.rb +122 -0
- data/spec/spec_helper.rb +21 -0
- metadata +89 -0
data/.gitignore
ADDED
data/Gemfile.ar01_r186
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
db_structure_ext (0.0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: http://rubygems.org/
|
8
|
+
specs:
|
9
|
+
activerecord (1.15.6)
|
10
|
+
activesupport (= 1.4.4)
|
11
|
+
activesupport (1.4.4)
|
12
|
+
mysql (2.7)
|
13
|
+
rspec (1.1.12)
|
14
|
+
|
15
|
+
PLATFORMS
|
16
|
+
ruby
|
17
|
+
|
18
|
+
DEPENDENCIES
|
19
|
+
activerecord (= 1.15.6)
|
20
|
+
db_structure_ext!
|
21
|
+
mysql (= 2.7)
|
22
|
+
rspec (= 1.1.12)
|
data/Gemfile.ar30_r192
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
db_structure_ext (0.0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: http://rubygems.org/
|
8
|
+
specs:
|
9
|
+
activemodel (3.0.10)
|
10
|
+
activesupport (= 3.0.10)
|
11
|
+
builder (~> 2.1.2)
|
12
|
+
i18n (~> 0.5.0)
|
13
|
+
activerecord (3.0.10)
|
14
|
+
activemodel (= 3.0.10)
|
15
|
+
activesupport (= 3.0.10)
|
16
|
+
arel (~> 2.0.10)
|
17
|
+
tzinfo (~> 0.3.23)
|
18
|
+
activesupport (3.0.10)
|
19
|
+
arel (2.0.10)
|
20
|
+
builder (2.1.2)
|
21
|
+
diff-lcs (1.1.3)
|
22
|
+
i18n (0.5.0)
|
23
|
+
mysql2 (0.2.11)
|
24
|
+
rspec (2.6.0)
|
25
|
+
rspec-core (~> 2.6.0)
|
26
|
+
rspec-expectations (~> 2.6.0)
|
27
|
+
rspec-mocks (~> 2.6.0)
|
28
|
+
rspec-core (2.6.4)
|
29
|
+
rspec-expectations (2.6.0)
|
30
|
+
diff-lcs (~> 1.1.2)
|
31
|
+
rspec-mocks (2.6.0)
|
32
|
+
tzinfo (0.3.30)
|
33
|
+
|
34
|
+
PLATFORMS
|
35
|
+
ruby
|
36
|
+
|
37
|
+
DEPENDENCIES
|
38
|
+
activerecord (= 3.0.10)
|
39
|
+
db_structure_ext!
|
40
|
+
mysql2 (= 0.2.11)
|
41
|
+
rspec (= 2.6.0)
|
data/README.md
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
# DbStructureExt
|
2
|
+
|
3
|
+
ActiveRecord connection adapter extensions.
|
4
|
+
|
5
|
+
Currently it extends only mysql/mysql2 adapter with structure_dump/structure_load methods.
|
6
|
+
|
7
|
+
Library **does not override** mysql adapter by default.
|
8
|
+
|
9
|
+
So you can use extensions independently (via MysqlConnectionProxy) or include extension methods into adapter.
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
gem install db_structure_ext
|
14
|
+
|
15
|
+
## Using MysqlConnectionProxy
|
16
|
+
|
17
|
+
connection = ActiveRecord::Base.connection
|
18
|
+
connection_proxy = DbStructureExt::MysqlConnectionProxy.new(connection)
|
19
|
+
connection_proxy.structure_dump
|
20
|
+
|
21
|
+
## Extending mysql adapter
|
22
|
+
|
23
|
+
require 'db_structure_ext/init_mysql_adapter'
|
24
|
+
connection.structure_dump
|
25
|
+
|
26
|
+
It automaticaly detects corresponding mysql/mysq2 adapter.
|
27
|
+
So it should works with any rails version including v1.2.6
|
28
|
+
|
29
|
+
## Dump structure
|
30
|
+
|
31
|
+
Extended *structure_dump* for mysql/mysql2 adapter dumps not only *tables*. It dumps:
|
32
|
+
|
33
|
+
* tables
|
34
|
+
* views
|
35
|
+
* triggers
|
36
|
+
* routines (functions and procedures)
|
37
|
+
|
38
|
+
## Load structure
|
39
|
+
|
40
|
+
Method loads sql statements separated by *\n\n*
|
41
|
+
|
42
|
+
### parallel_test support
|
43
|
+
|
44
|
+
It prepends
|
45
|
+
|
46
|
+
ENV['TEST_ENV_NUMBER']
|
47
|
+
|
48
|
+
to any table name with *_test* suffix in name
|
49
|
+
|
50
|
+
## Rails db tasks extensions
|
51
|
+
|
52
|
+
Add to your *Rakefile*
|
53
|
+
|
54
|
+
require 'db_structure_ext/tasks'
|
55
|
+
|
56
|
+
In case Rails3 its loaded automaticaly via railtie mechanizm.
|
57
|
+
|
58
|
+
### db:structure:dump
|
59
|
+
|
60
|
+
Synopsis:
|
61
|
+
|
62
|
+
rake db:structure:dump[env,file] # Dump the database structure to a SQL file
|
63
|
+
|
64
|
+
By default it works as original well-known rails task.
|
65
|
+
It dumps development structure to *db/development_structure.sql*
|
66
|
+
But it dumps to NOT only TABLES. It dumps also VIEWS, TRIGGERS and ROUTINES.
|
67
|
+
|
68
|
+
Additionally you can indicate another *environment* as first argument and optionally another dump *file* as second.
|
69
|
+
By default dump filename is *db/{env}_structure.sql*
|
70
|
+
|
71
|
+
### db:structure:load
|
72
|
+
|
73
|
+
Synopsis:
|
74
|
+
|
75
|
+
rake db:structure:load[env,file] # Load SQL structure file to the database
|
76
|
+
|
77
|
+
Its opposite task to *db:structure:load* that allows to load db structure from specified file to specified db environment.
|
78
|
+
The arguments is the same as for previous task.
|
79
|
+
|
80
|
+
|
81
|
+
### Examples
|
82
|
+
|
83
|
+
Dump *development* structure to db/development_structure.sql file:
|
84
|
+
|
85
|
+
rake db:structure:dump[development,db/development_structure.sql]
|
86
|
+
# or
|
87
|
+
rake db:structure:dump[development]
|
88
|
+
# or
|
89
|
+
RAILS_ENV=development db:structure:dump
|
90
|
+
# or just
|
91
|
+
rake db:structure:dump
|
92
|
+
|
93
|
+
Dump development structure to db/my_structure.sql file:
|
94
|
+
|
95
|
+
rake db:structure:dump[development,db/my_structure.sql]
|
96
|
+
|
97
|
+
Load db/my_structure.sql to test database:
|
98
|
+
|
99
|
+
rake db:structure:load[test,db/my_structure.sql]
|
100
|
+
|
101
|
+
Load db/development_structure.sql to development database:
|
102
|
+
|
103
|
+
rake db:structure:load[development,db/development_structure.sql]
|
104
|
+
# or
|
105
|
+
rake db:structure:load[development]
|
106
|
+
# or
|
107
|
+
RAILS_ENV=development rake db:structure:load[development]
|
108
|
+
# or
|
109
|
+
rake db:structure:load
|
110
|
+
|
111
|
+
|
112
|
+
## Testing
|
113
|
+
|
114
|
+
We have tested library against AR 1.x.x and AR 3.0.x.
|
115
|
+
|
116
|
+
We use [multiversion](https://github.com/railsware/multiversion) gem
|
117
|
+
|
118
|
+
It assumes you use RVM and Bundler.
|
119
|
+
|
120
|
+
### Create rvm aliases
|
121
|
+
|
122
|
+
rvm alias create ar01_r186 ruby-1.8.6-pYOUR_PATCH_LEVEL
|
123
|
+
rvm alias create ar30_r192 ruby-1.9.2-pYOUR_PATCH_LEVEL
|
124
|
+
|
125
|
+
### Install multiversion
|
126
|
+
|
127
|
+
gem install multiversion
|
128
|
+
|
129
|
+
### Install gems
|
130
|
+
|
131
|
+
multiversion all bundle install
|
132
|
+
|
133
|
+
### Run tests
|
134
|
+
|
135
|
+
multiversion all rspec spec
|
136
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
data/config/database.yml
ADDED
data/db/structure.sql
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
CREATE TABLE `users` (
|
2
|
+
`id` int(11) NOT NULL AUTO_INCREMENT,
|
3
|
+
`email` varchar(127) DEFAULT NULL,
|
4
|
+
`state` varchar(127) DEFAULT NULL,
|
5
|
+
`created_at` datetime DEFAULT NULL,
|
6
|
+
`updated_at` datetime DEFAULT NULL,
|
7
|
+
PRIMARY KEY (`id`),
|
8
|
+
KEY `index_review_users_on_email` (`email`)
|
9
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
10
|
+
|
11
|
+
CREATE TABLE `profiles` (
|
12
|
+
`id` int(11) NOT NULL AUTO_INCREMENT,
|
13
|
+
`user_id` int(11) DEFAULT NULL,
|
14
|
+
`address1` varchar(127) DEFAULT NULL,
|
15
|
+
`address2` varchar(127) DEFAULT NULL,
|
16
|
+
PRIMARY KEY (`id`)
|
17
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
18
|
+
|
19
|
+
CREATE TABLE pending_users (
|
20
|
+
`id` int(11),
|
21
|
+
`email` varchar(127)
|
22
|
+
) ENGINE=MyISAM;
|
23
|
+
|
24
|
+
CREATE TABLE active_users (
|
25
|
+
`id` int(11),
|
26
|
+
`email` varchar(127)
|
27
|
+
) ENGINE=MyISAM;
|
28
|
+
|
29
|
+
DROP TABLE IF EXISTS pending_users;
|
30
|
+
|
31
|
+
DROP VIEW IF EXISTS pending_users;
|
32
|
+
|
33
|
+
CREATE VIEW `pending_users` AS select `users`.`id` AS `id`,`users`.`email` AS `email` from `users` where (`users`.`state` = 'pending');
|
34
|
+
|
35
|
+
DROP TABLE IF EXISTS active_users;
|
36
|
+
|
37
|
+
DROP VIEW IF EXISTS active_users;
|
38
|
+
|
39
|
+
CREATE VIEW `active_users` AS select `users`.`id` AS `id`,`users`.`email` AS `email` from `users` where (`users`.`state` = 'active');
|
40
|
+
|
41
|
+
CREATE TRIGGER update_user_state_on_insert BEFORE INSERT ON users FOR EACH ROW begin
|
42
|
+
set NEW.state = 'pending';
|
43
|
+
end;
|
44
|
+
|
45
|
+
CREATE PROCEDURE `fix_user_state`()
|
46
|
+
BEGIN
|
47
|
+
UPDATE users SET users.state = 'pending'
|
48
|
+
WHERE state IS NULL;
|
49
|
+
END;
|
50
|
+
|
51
|
+
CREATE FUNCTION `hello`(s char(20)) RETURNS char(50) CHARSET utf8
|
52
|
+
DETERMINISTIC
|
53
|
+
RETURN CONCAT('Hello, ',s,'!');
|
54
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "db_structure_ext/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "db_structure_ext"
|
7
|
+
s.version = DbStructureExt::VERSION
|
8
|
+
s.authors = ["Andriy Yanko"]
|
9
|
+
s.email = ["andriy.yanko@gmail.com"]
|
10
|
+
s.homepage = "https://github.com/railsware/db_structure_ext/"
|
11
|
+
s.summary = %q{ActiveRecord connection adapter extensions}
|
12
|
+
s.description = %q{Extended rails tasks db:structure:dump/load methods that supports mysql views/triggers/routines}
|
13
|
+
|
14
|
+
s.rubyforge_project = "db_structure_ext"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'db_structure_ext/version'
|
2
|
+
require 'db_structure_ext/railtie' if defined?(Rails::Railtie)
|
3
|
+
|
4
|
+
module DbStructureExt
|
5
|
+
autoload :MysqlAdapter, 'db_structure_ext/mysql_adapter'
|
6
|
+
autoload :MysqlConnectionProxy, 'db_structure_ext/mysql_connection_proxy'
|
7
|
+
autoload :MysqlDumpMethods, 'db_structure_ext/mysql_dump_methods'
|
8
|
+
autoload :MysqlLoadMethods, 'db_structure_ext/mysql_load_methods'
|
9
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
begin
|
2
|
+
require 'mysql2'
|
3
|
+
rescue LoadError
|
4
|
+
end
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'mysql'
|
8
|
+
rescue LoadError
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'active_record'
|
12
|
+
require 'active_record/version'
|
13
|
+
|
14
|
+
if defined?(Mysql2)
|
15
|
+
require 'active_record/connection_adapters/mysql2_adapter'
|
16
|
+
ActiveRecord::ConnectionAdapters::Mysql2Adapter.send :include, DbStructureExt::MysqlAdapter
|
17
|
+
elsif defined?(Mysql)
|
18
|
+
require 'active_record/connection_adapters/mysql_adapter'
|
19
|
+
ActiveRecord::ConnectionAdapters::MysqlAdapter.send :include, DbStructureExt::MysqlAdapter
|
20
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module DbStructureExt
|
2
|
+
class MysqlConnectionProxy
|
3
|
+
|
4
|
+
include DbStructureExt::MysqlAdapter
|
5
|
+
|
6
|
+
def initialize(connection)
|
7
|
+
@connection = connection
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def method_missing(sym, *args, &block)
|
13
|
+
@connection.__send__(sym, *args, &block)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module DbStructureExt
|
2
|
+
module MysqlDumpMethods
|
3
|
+
|
4
|
+
# Dump mysql base tables
|
5
|
+
def tables_dump
|
6
|
+
structure = ""
|
7
|
+
|
8
|
+
sql = supports_views? ?
|
9
|
+
"SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'" : "SHOW TABLES"
|
10
|
+
|
11
|
+
table_names = select_all(sql).map { |table|
|
12
|
+
table.delete('Table_type')
|
13
|
+
table.to_a.first.last
|
14
|
+
}
|
15
|
+
|
16
|
+
table_names.each do |table_name|
|
17
|
+
structure << select_one("SHOW CREATE TABLE `#{table_name}`")["Create Table"]
|
18
|
+
structure << ";\n\n"
|
19
|
+
end
|
20
|
+
|
21
|
+
structure
|
22
|
+
end
|
23
|
+
|
24
|
+
# Dump mysql views
|
25
|
+
def views_dump
|
26
|
+
structure = ""
|
27
|
+
return structure unless supports_views?
|
28
|
+
|
29
|
+
table_names = select_all("SHOW FULL TABLES WHERE Table_type = 'VIEW'").map { |table|
|
30
|
+
table.delete('Table_type')
|
31
|
+
table.to_a.first.last
|
32
|
+
}
|
33
|
+
|
34
|
+
# Temporary structure
|
35
|
+
table_names.each do |table_name|
|
36
|
+
fields = select_all("SHOW FIELDS FROM #{table_name}")
|
37
|
+
structure << "CREATE TABLE #{table_name} (\n"
|
38
|
+
structure << fields.map { |field| " #{quote_column_name(field['Field'])} #{field['Type']}" }.join(",\n")
|
39
|
+
structure << "\n) ENGINE=MyISAM"
|
40
|
+
structure << ";\n\n"
|
41
|
+
end
|
42
|
+
|
43
|
+
# Final structure
|
44
|
+
table_names.each do |table_name|
|
45
|
+
structure << "DROP TABLE IF EXISTS #{table_name}"
|
46
|
+
structure << ";\n\n"
|
47
|
+
structure << "DROP VIEW IF EXISTS #{table_name}"
|
48
|
+
structure << ";\n\n"
|
49
|
+
structure << select_one("SHOW CREATE VIEW #{table_name}")["Create View"]
|
50
|
+
structure << ";\n\n"
|
51
|
+
end
|
52
|
+
|
53
|
+
structure.gsub!(/^(CREATE).+(VIEW)/, '\1 \2')
|
54
|
+
|
55
|
+
structure
|
56
|
+
end
|
57
|
+
|
58
|
+
# dump mysql triggers
|
59
|
+
def triggers_dump
|
60
|
+
structure = ""
|
61
|
+
return structure unless supports_triggers?
|
62
|
+
|
63
|
+
sql = "SHOW TRIGGERS"
|
64
|
+
|
65
|
+
select_all(sql).each do |row|
|
66
|
+
structure << "CREATE TRIGGER #{row['Trigger']} #{row['Timing']} #{row['Event']} ON #{row['Table']} FOR EACH ROW #{row['Statement']}"
|
67
|
+
structure << ";\n\n"
|
68
|
+
end
|
69
|
+
|
70
|
+
structure
|
71
|
+
end
|
72
|
+
|
73
|
+
# dump mysql routines: procedures and functions
|
74
|
+
def routines_dump
|
75
|
+
structure = ""
|
76
|
+
return structure unless supports_routines?
|
77
|
+
|
78
|
+
sql = "SELECT ROUTINE_TYPE as type, ROUTINE_NAME as name FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA='#{current_database}'"
|
79
|
+
|
80
|
+
select_all(sql).each do |row|
|
81
|
+
structure << select_one("SHOW CREATE #{row['type']} #{row['name']}")["Create #{row['type'].capitalize}"]
|
82
|
+
structure.gsub!(/^(CREATE).+(PROCEDURE|FUNCTION)/, '\1 \2')
|
83
|
+
structure << ";\n\n"
|
84
|
+
end
|
85
|
+
|
86
|
+
structure
|
87
|
+
end
|
88
|
+
|
89
|
+
def structure_dump
|
90
|
+
structure = ""
|
91
|
+
structure << tables_dump
|
92
|
+
structure << views_dump
|
93
|
+
structure << triggers_dump
|
94
|
+
structure << routines_dump
|
95
|
+
structure
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
# Does mysql support triggers?
|
101
|
+
def supports_triggers?
|
102
|
+
version[0] >= 5
|
103
|
+
end
|
104
|
+
|
105
|
+
# Does mysql support routines?
|
106
|
+
def supports_routines?
|
107
|
+
version[0] >= 5
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module DbStructureExt
|
2
|
+
module MysqlLoadMethods
|
3
|
+
|
4
|
+
def structure_load(schema_file)
|
5
|
+
IO.readlines(schema_file).join.split("\n\n").each do |statement|
|
6
|
+
statement.gsub!(/`([\w\d_]+)_test`\./, "`\\1_test#{ENV['TEST_ENV_NUMBER']}`.")
|
7
|
+
execute(statement)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
load File.expand_path('../../tasks/database.rake', __FILE__)
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# Remove standard rails tasks
|
2
|
+
original_db_structure_dump_task = Rake.application.instance_variable_get(:@tasks).delete('db:structure:dump')
|
3
|
+
|
4
|
+
namespace :db do
|
5
|
+
namespace :structure do
|
6
|
+
|
7
|
+
desc "Dump the database structure to a SQL file"
|
8
|
+
task :dump, [:env, :file] => :environment do |t, args|
|
9
|
+
env = args[:env] || ENV['RAILS_ENV'] || 'development'
|
10
|
+
file = args[:file] || "db/#{env}_structure.sql"
|
11
|
+
|
12
|
+
ActiveRecord::Base.establish_connection(env)
|
13
|
+
|
14
|
+
puts "Dumping #{env} database to #{file}"
|
15
|
+
|
16
|
+
case adapter_name = ActiveRecord::Base.connection.adapter_name
|
17
|
+
when /mysql/i
|
18
|
+
require 'db_structure_ext/mysql_connection_proxy'
|
19
|
+
connection_proxy = DbStructureExt::MysqlConnectionProxy.new(ActiveRecord::Base.connection)
|
20
|
+
File.open(file, "w+") { |f| f << connection_proxy.structure_dump }
|
21
|
+
else
|
22
|
+
original_db_structure_dump_task.invoke
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
desc "Load SQL structure file to the database"
|
27
|
+
task :load, [:env, :file] => :environment do |t, args|
|
28
|
+
env = args[:env] || ENV['RAILS_ENV'] || 'development'
|
29
|
+
file = args[:file] || "db/#{env}_structure.sql"
|
30
|
+
|
31
|
+
ActiveRecord::Base.establish_connection(env)
|
32
|
+
|
33
|
+
puts "Loading #{file} structure to #{env} database"
|
34
|
+
|
35
|
+
case adapter_name = ActiveRecord::Base.connection.adapter_name
|
36
|
+
when /mysql/i
|
37
|
+
require 'db_structure_ext/mysql_connection_proxy'
|
38
|
+
connection_proxy = DbStructureExt::MysqlConnectionProxy.new(ActiveRecord::Base.connection)
|
39
|
+
connection_proxy.structure_load(file)
|
40
|
+
else
|
41
|
+
raise "Task not supported by #{adapter_name.inspect} adapter"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
data/log/.gitkeep
ADDED
File without changes
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DbStructureExt::MysqlConnectionProxy do
|
4
|
+
|
5
|
+
def connection
|
6
|
+
ActiveRecord::Base.connection
|
7
|
+
end
|
8
|
+
|
9
|
+
before(:all) do
|
10
|
+
@connection_proxy = DbStructureExt::MysqlConnectionProxy.new(connection)
|
11
|
+
|
12
|
+
@all_statements = File.read("db/structure.sql").strip.split("\n\n")
|
13
|
+
|
14
|
+
connection.recreate_database "db_structure_ext_test"
|
15
|
+
connection.execute "USE db_structure_ext_test"
|
16
|
+
@all_statements.each { |statement| connection.execute statement }
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#tables_dump" do
|
20
|
+
it "should return 'CREATE TABLE' statements" do
|
21
|
+
statements = @connection_proxy.tables_dump.split("\n\n")
|
22
|
+
|
23
|
+
statements.should have(2).items
|
24
|
+
|
25
|
+
statements.should include(@all_statements[0])
|
26
|
+
statements.should include(@all_statements[1])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#views_dump" do
|
31
|
+
it "should return 'CREATE VIEW' statements" do
|
32
|
+
statements = @connection_proxy.views_dump.split("\n\n")
|
33
|
+
|
34
|
+
statements.should have(8).items
|
35
|
+
|
36
|
+
statements.should include(@all_statements[2])
|
37
|
+
statements.should include(@all_statements[3])
|
38
|
+
statements.should include(@all_statements[4])
|
39
|
+
statements.should include(@all_statements[5])
|
40
|
+
statements.should include(@all_statements[6])
|
41
|
+
statements.should include(@all_statements[7])
|
42
|
+
statements.should include(@all_statements[8])
|
43
|
+
statements.should include(@all_statements[9])
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#triggers_dump" do
|
48
|
+
it "should return 'CREATE TRIGGER' statements" do
|
49
|
+
statements = @connection_proxy.triggers_dump.split("\n\n")
|
50
|
+
|
51
|
+
statements.should have(1).items
|
52
|
+
|
53
|
+
statements.should include(@all_statements[10])
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#routines_dump" do
|
58
|
+
it "should return 'CREATE PROCEDURE' and 'CREATE FUNCTION' statements" do
|
59
|
+
statements = @connection_proxy.routines_dump.split("\n\n")
|
60
|
+
|
61
|
+
statements.should have(2).items
|
62
|
+
|
63
|
+
statements.should include(@all_statements[11])
|
64
|
+
statements.should include(@all_statements[12])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "#structure_dump" do
|
69
|
+
it "should return structure with TABLES VIEWS TRIGGER PROCEDURES and FUNCTIONS statements" do
|
70
|
+
statements = @connection_proxy.structure_dump.split("\n\n")
|
71
|
+
statements.should have(13).items
|
72
|
+
|
73
|
+
# tables
|
74
|
+
tables = statements[0..1]
|
75
|
+
tables.should include(@all_statements[0])
|
76
|
+
tables.should include(@all_statements[1])
|
77
|
+
|
78
|
+
# views
|
79
|
+
views = statements[2..9]
|
80
|
+
views.should include(@all_statements[2])
|
81
|
+
views.should include(@all_statements[3])
|
82
|
+
views.should include(@all_statements[4])
|
83
|
+
views.should include(@all_statements[5])
|
84
|
+
views.should include(@all_statements[6])
|
85
|
+
views.should include(@all_statements[7])
|
86
|
+
views.should include(@all_statements[8])
|
87
|
+
views.should include(@all_statements[9])
|
88
|
+
|
89
|
+
# triggers
|
90
|
+
triggers = statements[10..10]
|
91
|
+
triggers.should include(@all_statements[10])
|
92
|
+
|
93
|
+
# routines
|
94
|
+
routines = statements[11..12]
|
95
|
+
routines.should include(@all_statements[11])
|
96
|
+
routines.should include(@all_statements[12])
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "#structure_load" do
|
101
|
+
before(:all) do
|
102
|
+
connection.recreate_database "db_structure_ext_test"
|
103
|
+
connection.execute "USE db_structure_ext_test"
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should load structures from file to database" do
|
107
|
+
@connection_proxy.structure_load 'db/structure.sql'
|
108
|
+
|
109
|
+
connection.select_values('SHOW TABLES').sort.should == [
|
110
|
+
"active_users", "pending_users", "profiles", "users"
|
111
|
+
]
|
112
|
+
|
113
|
+
connection.select_all('SHOW TRIGGERS').map { |r| r['Trigger'] }.sort.should == [
|
114
|
+
"update_user_state_on_insert"
|
115
|
+
]
|
116
|
+
|
117
|
+
connection.select_values("SELECT ROUTINE_NAME FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA='db_structure_ext_test'").sort.should == [
|
118
|
+
"fix_user_state", "hello"
|
119
|
+
]
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# logging
|
2
|
+
require 'active_record'
|
3
|
+
require 'logger'
|
4
|
+
ActiveRecord::Base.logger = ::Logger.new('log/test.log')
|
5
|
+
|
6
|
+
# mysql adapter
|
7
|
+
require 'active_record/version'
|
8
|
+
case ActiveRecord::VERSION::MAJOR
|
9
|
+
when 1
|
10
|
+
require 'active_record/connection_adapters/mysql_adapter'
|
11
|
+
when 3
|
12
|
+
require 'active_record/connection_adapters/mysql2_adapter'
|
13
|
+
end
|
14
|
+
|
15
|
+
# mysql connection
|
16
|
+
require 'yaml'
|
17
|
+
require 'erb'
|
18
|
+
ActiveRecord::Base.establish_connection YAML::load(ERB.new(IO.read('config/database.yml')).result)['test']
|
19
|
+
|
20
|
+
# lib
|
21
|
+
require 'db_structure_ext'
|
metadata
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: db_structure_ext
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Andriy Yanko
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-10-12 00:00:00 Z
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: Extended rails tasks db:structure:dump/load methods that supports mysql views/triggers/routines
|
22
|
+
email:
|
23
|
+
- andriy.yanko@gmail.com
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
30
|
+
files:
|
31
|
+
- .gitignore
|
32
|
+
- Gemfile.ar01_r186
|
33
|
+
- Gemfile.ar01_r186.lock
|
34
|
+
- Gemfile.ar30_r192
|
35
|
+
- Gemfile.ar30_r192.lock
|
36
|
+
- README.md
|
37
|
+
- Rakefile
|
38
|
+
- config/database.yml
|
39
|
+
- db/structure.sql
|
40
|
+
- db_structure_ext.gemspec
|
41
|
+
- lib/db_structure_ext.rb
|
42
|
+
- lib/db_structure_ext/init_mysql_adapter.rb
|
43
|
+
- lib/db_structure_ext/mysql_adapter.rb
|
44
|
+
- lib/db_structure_ext/mysql_connection_proxy.rb
|
45
|
+
- lib/db_structure_ext/mysql_dump_methods.rb
|
46
|
+
- lib/db_structure_ext/mysql_load_methods.rb
|
47
|
+
- lib/db_structure_ext/railtie.rb
|
48
|
+
- lib/db_structure_ext/tasks.rb
|
49
|
+
- lib/db_structure_ext/version.rb
|
50
|
+
- lib/tasks/database.rake
|
51
|
+
- log/.gitkeep
|
52
|
+
- spec/db_sctructure_ext/mysql_connection_proxy_spec.rb
|
53
|
+
- spec/spec_helper.rb
|
54
|
+
homepage: https://github.com/railsware/db_structure_ext/
|
55
|
+
licenses: []
|
56
|
+
|
57
|
+
post_install_message:
|
58
|
+
rdoc_options: []
|
59
|
+
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
hash: 3
|
68
|
+
segments:
|
69
|
+
- 0
|
70
|
+
version: "0"
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
hash: 3
|
77
|
+
segments:
|
78
|
+
- 0
|
79
|
+
version: "0"
|
80
|
+
requirements: []
|
81
|
+
|
82
|
+
rubyforge_project: db_structure_ext
|
83
|
+
rubygems_version: 1.8.6
|
84
|
+
signing_key:
|
85
|
+
specification_version: 3
|
86
|
+
summary: ActiveRecord connection adapter extensions
|
87
|
+
test_files:
|
88
|
+
- spec/db_sctructure_ext/mysql_connection_proxy_spec.rb
|
89
|
+
- spec/spec_helper.rb
|