use_db 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in use_db.gemspec
4
+ gemspec
data/README.rdoc ADDED
@@ -0,0 +1,107 @@
1
+ = UseDb
2
+
3
+ A multi-database connection scheme for Rails 3, supporting testing and migrations
4
+
5
+ == Features
6
+
7
+ === Easy to use
8
+ 1. Bundle the gem
9
+ 2. Define a second set of databases in your database.yml file. Use a prefix to differentiate from the core database.
10
+ 3. Add "use_db :prefix => 'your_other_database_prefix_" to the Model
11
+
12
+ == Supported versions
13
+
14
+ * Ruby 1.9.2
15
+
16
+ * Rails 3.0.x
17
+
18
+ == Install
19
+
20
+ Put this line in your Gemfile:
21
+ gem 'use_db'
22
+
23
+ Then bundle:
24
+ % bundle
25
+
26
+ == Usage
27
+
28
+ === ACTIVERECORD
29
+
30
+ Insert a reference to use_db in your model, with a :prefix and/or :suffix
31
+
32
+ class MyModel < ActiveRecord::Base
33
+ use_db :prefix => "your_other_database_prefix_", :suffix => "_is_legacy"
34
+ end
35
+
36
+ This maps to a database in database.yml named:
37
+ your_other_database_prefix_[::Rails.env]_is_legacy
38
+
39
+ So this is what your database.yml should look like:
40
+
41
+ your_other_database_prefix_test_is_legacy
42
+ adapter: mysql
43
+ database: other_test_db
44
+ ...
45
+ your_other_database_prefix_development_is_legacy
46
+ adapter: mysql
47
+ database: other_dev_db
48
+ ...
49
+
50
+ You may find it useful (and more DRY) to define an abstract model to inherit from to avoid littering use_db in multiple places:
51
+
52
+ class LegacyDataBase < ActiveRecord::Base
53
+ use_db :prefix => "your_other_database_prefix_", :suffix => "_is_legacy"
54
+ self.abstract_class = true
55
+ end
56
+
57
+ class MyModel < LegacyDataBase
58
+ end
59
+
60
+ === MIGRATIONS
61
+
62
+ Each migration intended for a different database needs to be told which to use. Do this by adding a method "self.database_model" and returning the class name which defines the other database. If you don't, it defaults to the core database like normal.
63
+
64
+ class ChangeOtherDatabaseTable < ActiveRecord::Migration
65
+
66
+ # For clarity leave me at the top of the class.
67
+ def self.database_model
68
+ # Examples depending if you're using an abstract class or not:
69
+ # return "LegacyDataBase"
70
+ # return "MyModel"
71
+ end
72
+
73
+ end
74
+
75
+ === TESTING
76
+
77
+ In order to test multiple databases, you must invoke a task which clones the development database
78
+ structure and copies it into the test database, clearing out the existing test data. There is a single
79
+ helper method which executes this task and you invoke it as follows:
80
+
81
+ UseDbTestSetup.prepare_test_db(:prefix => "your_other_database_prefix_", :suffix => "_is_legacy")
82
+
83
+ Even though it might not be the best place for it, I put this in my test_helper.
84
+ You don't want it to execute for every test, so put something like this around it:
85
+
86
+ unless defined?(CLONED_OTHER_DB_FOR_TESTING)
87
+ UseDbTestSetup.prepare_test_db(:prefix => "your_other_database_prefix_", :suffix => "_is_legacy")
88
+ CLONED_OTHER_DB_FOR_TESTING = true
89
+ end
90
+
91
+ === DEBUGGING
92
+
93
+ Add this statement in your test_helper or whereever you like such things.
94
+
95
+ UseDb.debug_print = true
96
+
97
+ === FIXTURES
98
+
99
+ Nope. I don't use them and you probably shouldn't either, so this gem doesn't support them. See factory_girl.
100
+
101
+ == Giving Back
102
+
103
+ Have a change or improvement? Fork it, fix it, then send a pull request.
104
+
105
+ == Credits
106
+
107
+ David Stevenson (ds@elctech.com) originally wrote the code for this as a plugin for Rails 2. I wanted it to be a gem for Rails 3, so that's what I did. I renamed a few things here and there, added some additional debugging statements, but it's largely what he wrote. Thanks David.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
data/lib/migration.rb ADDED
@@ -0,0 +1,21 @@
1
+ module ActiveRecord
2
+ class Migration
3
+ class << self
4
+ def method_missing(method, *arguments, &block)
5
+ say_with_time "#{method}(#{arguments.map { |a| a.inspect }.join(", ")})" do
6
+ arguments[0] = Migrator.proper_table_name(arguments.first) unless arguments.empty? || method == :execute
7
+ if (self.respond_to?(:database_model))
8
+ write "Using custom database model's connection (#{self.database_model}) for this migration"
9
+ eval("#{self.database_model}.connection.send(method, *arguments, &block)")
10
+ else
11
+ ActiveRecord::Base.connection.send(method, *arguments, &block)
12
+ end
13
+ end
14
+ end
15
+
16
+ def uses_db?
17
+ true
18
+ end
19
+ end
20
+ end
21
+ end
data/lib/test_model.rb ADDED
@@ -0,0 +1,10 @@
1
+ def create_test_model(model_name, prefix="", suffix="", rails_env=::Rails.env)
2
+ # puts "Creating test model '#{model_name}', :prefix => '#{prefix}', :suffix => '#{suffix}'"
3
+ str = <<-EOF
4
+ require "use_db"
5
+ class #{model_name} < ActiveRecord::Base
6
+ use_db :prefix => "#{prefix}", :suffix => "#{suffix}", :rails_env => "#{rails_env}"
7
+ end
8
+ EOF
9
+ eval(str)
10
+ end
@@ -0,0 +1,3 @@
1
+ module UseDb
2
+ VERSION = "0.1.1"
3
+ end
data/lib/use_db.rb ADDED
@@ -0,0 +1,63 @@
1
+ module UseDb
2
+ # Options (recommended to use one or both):
3
+ # :prefix - Specify the prefix to append to ::Rails.env when finding the adapter specification in database.yml
4
+ # :suffix - Just like :prefix, only concatentated to the end
5
+ # OR
6
+ # :adapter
7
+ # :host
8
+ # :username
9
+ # :password
10
+ # ... etc ... same as the options in establish_connection
11
+
12
+ @@use_dbs = [ActiveRecord::Base]
13
+ @@debug_print = false
14
+
15
+ def use_db(options)
16
+ options_dup = options.dup
17
+ conn_spec = get_use_db_conn_spec(options)
18
+ puts "Establishing connecting on behalf of #{self.to_s} to #{conn_spec.inspect}" if UseDb.debug_print
19
+ establish_connection(conn_spec)
20
+ extend ClassMixin
21
+ @@use_dbs << self unless @@use_dbs.include?(self) || self.to_s.starts_with?("TestModel")
22
+ end
23
+
24
+ def self.all_use_dbs
25
+ return @@use_dbs
26
+ end
27
+
28
+ def self.debug_print
29
+ return @@debug_print
30
+ end
31
+
32
+ def self.debug_print=(newval)
33
+ @@debug_print = newval
34
+ end
35
+
36
+ module ClassMixin
37
+ def uses_db?
38
+ true
39
+ end
40
+ end
41
+
42
+ def get_use_db_conn_spec(options)
43
+ options.symbolize_keys
44
+ puts "get_use_db_conn_spec OPTIONS=#{options.inspect}" if UseDb.debug_print
45
+ suffix = options.delete(:suffix)
46
+ prefix = options.delete(:prefix)
47
+ rails_env = options.delete(:rails_env) || ::Rails.env
48
+ if (options[:adapter])
49
+ return options
50
+ else
51
+ str = "#{prefix}#{rails_env}#{suffix}"
52
+ puts "get_use_db_conn_spec STR=#{str.inspect}" if UseDb.debug_print
53
+ connections = YAML.load(ERB.new(IO.read("#{::Rails.root.to_s}/config/database.yml"), nil, nil, '_use_db_erbout').result)
54
+ puts "get_use_db_conn_spec CONNECTIONS read. need connections[str]! #{connections.inspect}" if UseDb.debug_print
55
+ raise "Cannot find database specification. Configuration '#{str}' expected in config/database.yml" if (connections[str].nil?)
56
+ return connections[str]
57
+ end
58
+ end
59
+ end
60
+
61
+ ActiveRecord::Base.extend UseDb
62
+
63
+ require 'use_db_test_setup'
@@ -0,0 +1,158 @@
1
+ require "use_db.rb"
2
+ require "test_model.rb"
3
+
4
+ class UseDbTestSetup
5
+
6
+ extend UseDb
7
+
8
+ # Used in rake tasks, not normal testing
9
+ def self.other_databases
10
+ YAML.load(File.read("#{::Rails.root.to_s}/config/use_db.yml")).values.collect(&:symbolize_keys!)
11
+ end
12
+
13
+ def self.prepare_test_db(options)
14
+ dump_db_structure(options)
15
+ purge_db(options)
16
+ clone_db_structure(options)
17
+ end
18
+
19
+ def self.dump_db_structure(options)
20
+ options_dup = options.dup
21
+ options_dup[:rails_env] = "development"
22
+ conn_spec = get_use_db_conn_spec(options_dup)
23
+ #establish_connection(conn_spec)
24
+
25
+ test_class = setup_test_model(options[:prefix], options[:suffix], "ForDumpStructure")
26
+
27
+ puts "Dumping DB structure #{test_class.inspect}..." if UseDb.debug_print
28
+
29
+ case conn_spec["adapter"]
30
+ when "mysql", "oci", "oracle"
31
+ test_class.establish_connection(conn_spec)
32
+ File.open("#{::Rails.root.to_s}/db/#{::Rails.env}_structure.sql", "w+") { |f| f << test_class.connection.structure_dump }
33
+ =begin when "postgresql"
34
+ ENV['PGHOST'] = abcs[::Rails.env]["host"] if abcs[::Rails.env]["host"]
35
+ ENV['PGPORT'] = abcs[::Rails.env]["port"].to_s if abcs[::Rails.env]["port"]
36
+ ENV['PGPASSWORD'] = abcs[::Rails.env]["password"].to_s if abcs[::Rails.env]["password"]
37
+ search_path = abcs[::Rails.env]["schema_search_path"]
38
+ search_path = "--schema=#{search_path}" if search_path
39
+ `pg_dump -i -U "#{abcs[::Rails.env]["username"]}" -s -x -O -f db/#{::Rails.env}_structure.sql #{search_path} #{abcs[::Rails.env]["database"]}`
40
+ raise "Error dumping database" if $?.exitstatus == 1
41
+ when "sqlite", "sqlite3"
42
+ dbfile = abcs[::Rails.env]["database"] || abcs[::Rails.env]["dbfile"]
43
+ `#{abcs[::Rails.env]["adapter"]} #{dbfile} .schema > db/#{::Rails.env}_structure.sql`
44
+ when "sqlserver"
45
+ `scptxfr /s #{abcs[::Rails.env]["host"]} /d #{abcs[::Rails.env]["database"]} /I /f db\\#{::Rails.env}_structure.sql /q /A /r`
46
+ `scptxfr /s #{abcs[::Rails.env]["host"]} /d #{abcs[::Rails.env]["database"]} /I /F db\ /q /A /r`
47
+ when "firebird"
48
+ set_firebird_env(abcs[::Rails.env])
49
+ db_string = firebird_db_string(abcs[::Rails.env])
50
+ sh "isql -a #{db_string} > db/#{::Rails.env}_structure.sql"
51
+ =end
52
+ else
53
+ raise "Task not supported by '#{conn_spec["adapter"]}'"
54
+ end
55
+
56
+ #if test_class.connection.supports_migrations?
57
+ # File.open("db/#{::Rails.env}_structure.sql", "a") { |f| f << ActiveRecord::Base.connection.dump_schema_information }
58
+ #end
59
+
60
+ test_class.connection.disconnect!
61
+ end
62
+
63
+ def self.clone_db_structure(options)
64
+ options_dup = options.dup
65
+ conn_spec = get_use_db_conn_spec(options_dup)
66
+ #establish_connection(conn_spec)
67
+
68
+ test_class = setup_test_model(options[:prefix], options[:suffix], "ForClone")
69
+
70
+ puts "Cloning DB structure #{test_class.inspect}..." if UseDb.debug_print
71
+
72
+ case conn_spec["adapter"]
73
+ when "mysql"
74
+ test_class.connection.execute('SET foreign_key_checks = 0')
75
+ IO.readlines("#{::Rails.root.to_s}/db/#{::Rails.env}_structure.sql").join.split("\n\n").each do |table|
76
+ test_class.connection.execute(table)
77
+ end
78
+ when "oci", "oracle"
79
+ IO.readlines("#{::Rails.root.to_s}/db/#{::Rails.env}_structure.sql").join.split(";\n\n").each do |ddl|
80
+ test_class.connection.execute(ddl)
81
+ end
82
+ =begin when "postgresql"
83
+ ENV['PGHOST'] = abcs["test"]["host"] if abcs["test"]["host"]
84
+ ENV['PGPORT'] = abcs["test"]["port"].to_s if abcs["test"]["port"]
85
+ ENV['PGPASSWORD'] = abcs["test"]["password"].to_s if abcs["test"]["password"]
86
+ `psql -U "#{abcs["test"]["username"]}" -f db/#{::Rails.env}_structure.sql #{abcs["test"]["database"]}`
87
+ when "sqlite", "sqlite3"
88
+ dbfile = abcs["test"]["database"] || abcs["test"]["dbfile"]
89
+ `#{abcs["test"]["adapter"]} #{dbfile} < db/#{::Rails.env}_structure.sql`
90
+ when "sqlserver"
91
+ `osql -E -S #{abcs["test"]["host"]} -d #{abcs["test"]["database"]} -i db\\#{::Rails.env}_structure.sql`
92
+ when "firebird"
93
+ set_firebird_env(abcs["test"])
94
+ db_string = firebird_db_string(abcs["test"])
95
+ sh "isql -i db/#{::Rails.env}_structure.sql #{db_string}"
96
+ =end
97
+ else
98
+ raise "Task not supported by '#{conn_spec["adapter"]}'"
99
+ end
100
+
101
+ test_class.connection.disconnect!
102
+ end
103
+
104
+ def self.purge_db(options)
105
+ options_dup = options.dup
106
+ conn_spec = get_use_db_conn_spec(options_dup)
107
+ #establish_connection(conn_spec)
108
+
109
+ test_class = setup_test_model(options[:prefix], options[:suffix], "ForPurge")
110
+
111
+ case conn_spec["adapter"]
112
+ when "mysql"
113
+ test_class.connection.recreate_database(conn_spec["database"])
114
+ when "oci", "oracle"
115
+ test_class.connection.structure_drop.split(";\n\n").each do |ddl|
116
+ test_class.connection.execute(ddl)
117
+ end
118
+ when "firebird"
119
+ test_class.connection.recreate_database!
120
+ =begin
121
+ when "postgresql"
122
+ ENV['PGHOST'] = abcs["test"]["host"] if abcs["test"]["host"]
123
+ ENV['PGPORT'] = abcs["test"]["port"].to_s if abcs["test"]["port"]
124
+ ENV['PGPASSWORD'] = abcs["test"]["password"].to_s if abcs["test"]["password"]
125
+ enc_option = "-E #{abcs["test"]["encoding"]}" if abcs["test"]["encoding"]
126
+
127
+ ActiveRecord::Base.clear_active_connections!
128
+ `dropdb -U "#{abcs["test"]["username"]}" #{abcs["test"]["database"]}`
129
+ `createdb #{enc_option} -U "#{abcs["test"]["username"]}" #{abcs["test"]["database"]}`
130
+ when "sqlite","sqlite3"
131
+ dbfile = abcs["test"]["database"] || abcs["test"]["dbfile"]
132
+ File.delete(dbfile) if File.exist?(dbfile)
133
+ when "sqlserver"
134
+ dropfkscript = "#{abcs["test"]["host"]}.#{abcs["test"]["database"]}.DP1".gsub(/\\/,'-')
135
+ `osql -E -S #{abcs["test"]["host"]} -d #{abcs["test"]["database"]} -i db\\#{dropfkscript}`
136
+ `osql -E -S #{abcs["test"]["host"]} -d #{abcs["test"]["database"]} -i db\\#{::Rails.env}_structure.sql`
137
+ =end
138
+ else
139
+ raise "Task not supported by '#{conn_spec["adapter"]}'"
140
+ end
141
+
142
+ test_class.connection.disconnect!
143
+ end
144
+
145
+ def self.setup_test_model(prefix="", suffix="", model_suffix="", rails_env=::Rails.env)
146
+ puts "PREFIX= #{prefix}" if UseDb.debug_print
147
+ puts "SUFFIX= #{suffix}" if UseDb.debug_print
148
+ puts "MODEL SUFFIX= #{model_suffix}" if UseDb.debug_print
149
+ puts "rails_env= #{rails_env}" if UseDb.debug_print
150
+ prefix ||= ""
151
+ suffix ||= ""
152
+ model_name = "TestModel#{prefix.camelize}#{suffix.camelize}#{model_suffix}".gsub("_","").gsub("-","")
153
+ puts "model_name = #{model_name}" if UseDb.debug_print
154
+ return eval(model_name) if eval("defined?(#{model_name})")
155
+ create_test_model(model_name, prefix, suffix, rails_env)
156
+ return eval(model_name)
157
+ end
158
+ end
data/use_db.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "use_db/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "use_db"
7
+ s.version = UseDb::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Ron Guarisco"]
10
+ s.email = ["ron@guarisco.net"]
11
+ s.homepage = "https://github.com/guarisco/use_db"
12
+ s.summary = %q{Multi-database AR connections for Rails 3}
13
+ s.description = %q{Multi-database AR connections for Rails 3 models, tests, and migrations.}
14
+
15
+ s.rubyforge_project = "use_db"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: use_db
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.1.1
6
+ platform: ruby
7
+ authors:
8
+ - Ron Guarisco
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-05-11 00:00:00 -05:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description: Multi-database AR connections for Rails 3 models, tests, and migrations.
18
+ email:
19
+ - ron@guarisco.net
20
+ executables: []
21
+
22
+ extensions: []
23
+
24
+ extra_rdoc_files: []
25
+
26
+ files:
27
+ - .gitignore
28
+ - Gemfile
29
+ - README.rdoc
30
+ - Rakefile
31
+ - lib/migration.rb
32
+ - lib/test_model.rb
33
+ - lib/use_db.rb
34
+ - lib/use_db/version.rb
35
+ - lib/use_db_test_setup.rb
36
+ - use_db.gemspec
37
+ has_rdoc: true
38
+ homepage: https://github.com/guarisco/use_db
39
+ licenses: []
40
+
41
+ post_install_message:
42
+ rdoc_options: []
43
+
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ requirements: []
59
+
60
+ rubyforge_project: use_db
61
+ rubygems_version: 1.6.2
62
+ signing_key:
63
+ specification_version: 3
64
+ summary: Multi-database AR connections for Rails 3
65
+ test_files: []
66
+