use_db 0.1.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 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
+