db_structure_ext 0.0.1
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/.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
|