multiple_connection_handler 0.1.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/README +53 -0
- data/lib/multiple_connection_handler.rb +135 -0
- metadata +65 -0
data/README
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
multiple_connection_handler
|
2
|
+
=========
|
3
|
+
|
4
|
+
A gem for Rails that provides a class, MultipleConnectionHandler, that allows
|
5
|
+
for access to connections to any databases in the database.yml file for your
|
6
|
+
Rails application. Quick and dirty implementation to let us do dirty things.
|
7
|
+
|
8
|
+
|
9
|
+
Full disclosure
|
10
|
+
=========
|
11
|
+
|
12
|
+
Implemented as a singleton accessed solely through the class methods. Some
|
13
|
+
instance methods are exposed, but you should NOT use them directly. You should
|
14
|
+
also NOT try to instantiate multiple MultipleConnectionHandler objects.
|
15
|
+
|
16
|
+
Have NOT evaluated any thread-safety of this code. In fact, it's probably
|
17
|
+
not safe to multithread code that's will use the MultipleConnectionHandler,
|
18
|
+
as there is no locking on cached db connections.
|
19
|
+
|
20
|
+
NOTE NOTE NOTE NOTE NOTE NOTE
|
21
|
+
-----------------------------
|
22
|
+
This should only be used if you're being bad and are executing queries via
|
23
|
+
raw SQL, and not using ActiveRecord methods. If you just want to specify
|
24
|
+
different databases for your various models, see ActiveRecord::Base
|
25
|
+
documentation.
|
26
|
+
|
27
|
+
I admit up front this is pretty hacky in how we're piggy-backing on
|
28
|
+
ActiveRecord's connection pooling and ConnectionHandler. So please read
|
29
|
+
through the code (esp. the connection() instance method) before proceeding.
|
30
|
+
|
31
|
+
|
32
|
+
Example (yes, this is a terrible example)
|
33
|
+
========
|
34
|
+
|
35
|
+
dev_migrations = MultipleConnectionHandler.connection(:development).execute(
|
36
|
+
"SELECT * FROM schema_migrations")
|
37
|
+
staging_migrations = MultipleConnectionHandler.connection(:staging).execute(
|
38
|
+
"SELECT * FROM schema_migrations")
|
39
|
+
|
40
|
+
if dev_migrations != staging_migrations
|
41
|
+
Rails.logger.error "Can't push data from staging to dev right now cause " +
|
42
|
+
"they're on different migrations"
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
Testing
|
47
|
+
=========
|
48
|
+
|
49
|
+
You may notice the lack of unit tests. Yeah, we just tested this manually.
|
50
|
+
Probably the best, as you basically need acess to multiple dbs in order to test
|
51
|
+
whether this functionality is working. I guess if you'd like, you could create
|
52
|
+
some models tied to different db instances, use this to directly modify those
|
53
|
+
models and then use the models to verify the changes. Meh.
|
@@ -0,0 +1,135 @@
|
|
1
|
+
# grants access to db connections for several environments at once.
|
2
|
+
# implemented as a singleton accessed through class methods.
|
3
|
+
class MultipleConnectionHandler
|
4
|
+
|
5
|
+
# raised when the requested connection isn't recognized from the db config
|
6
|
+
# file
|
7
|
+
#-----------------------------------------------------------------------------
|
8
|
+
class UnrecognizedDatabaseError < Exception
|
9
|
+
def initialize(unrecognized_db_name, db_config_filename)
|
10
|
+
super("Database specification for '#{unrecognized_db_name}' not found " +
|
11
|
+
" in '#{db_config_filename}'.")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# raised when attempting to re-initialize the handler after it's already
|
16
|
+
# been initialized. prevents competition between two clients of the class
|
17
|
+
# who may attempt to change the database config file on top of one another
|
18
|
+
#-----------------------------------------------------------------------------
|
19
|
+
class DoubleInitializationError < Exception
|
20
|
+
def initialize
|
21
|
+
super("Re-initializing MultipleConnectionHandler not allowed")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
# just a little token class to hand to the ActiveRecord ConnectionHandler
|
27
|
+
# so we can piggy-back on its connection management infrastructure. it just
|
28
|
+
# requires an object that you can call .name on...though it's sort of
|
29
|
+
# expecting a (model) class object...
|
30
|
+
#-----------------------------------------------------------------------------
|
31
|
+
class DbKey
|
32
|
+
attr_accessor :name
|
33
|
+
def initialize(name)
|
34
|
+
self.name = name
|
35
|
+
end
|
36
|
+
def ==(other)
|
37
|
+
self.name == other.name
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# return a db connection for the specified name, establishing new pools
|
42
|
+
# with the AR connection handler if necessary
|
43
|
+
#-----------------------------------------------------------------------------
|
44
|
+
def self.connection(spec_name)
|
45
|
+
instance.connection(spec_name)
|
46
|
+
end
|
47
|
+
|
48
|
+
# returns the db name for the given spec name
|
49
|
+
#-----------------------------------------------------------------------------
|
50
|
+
def self.db_name(spec_name)
|
51
|
+
instance.configurations[spec_name.to_s]['database']
|
52
|
+
end
|
53
|
+
|
54
|
+
@@static_initialized = false
|
55
|
+
# initialize the connections handler. only necessary to be called if
|
56
|
+
# overriding any default configuration. recommend against using this
|
57
|
+
# method explicitly and just allowing default.
|
58
|
+
#
|
59
|
+
# options:
|
60
|
+
# - :config_file => the database config file to use. default is the
|
61
|
+
# rails default of ..../config/database.yml
|
62
|
+
#-----------------------------------------------------------------------------
|
63
|
+
def self.init(options = {})
|
64
|
+
# don't allow re-initializing. just ignore if we're already initialized
|
65
|
+
# unless we're asked to use a different config file
|
66
|
+
if @@static_initialized
|
67
|
+
if @@instantiated && options[:config_file] &&
|
68
|
+
options[:config_file] != instance.db_config_file
|
69
|
+
|
70
|
+
raise DoubleInitializationError
|
71
|
+
end
|
72
|
+
else
|
73
|
+
@@db_config_file = options[:config_file] || "#{RAILS_ROOT}/config/database.yml"
|
74
|
+
@@static_initialized = true
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
attr_accessor :db_config_file, :configurations, :handler
|
80
|
+
attr_accessor :established_connections
|
81
|
+
|
82
|
+
# NOTE: this method is not declared protected so that the class method can
|
83
|
+
# call it...but really shouldn't ever be called by external code.
|
84
|
+
|
85
|
+
# the meat of the work is done here. retrieve a connection using cached
|
86
|
+
# connections or get a new one.
|
87
|
+
#-----------------------------------------------------------------------------
|
88
|
+
def connection(spec_name)
|
89
|
+
db_key = DbKey.new(spec_name.to_s)
|
90
|
+
|
91
|
+
unless established_connections.member? db_key
|
92
|
+
unless configurations.include? db_key.name
|
93
|
+
raise UnrecognizedDatabaseError.new(db_key.name, db_config_file)
|
94
|
+
end
|
95
|
+
|
96
|
+
spec = configurations[db_key.name]
|
97
|
+
|
98
|
+
handler.establish_connection(db_key.name,
|
99
|
+
ActiveRecord::Base::ConnectionSpecification.new(spec,
|
100
|
+
"#{spec['adapter']}_connection"))
|
101
|
+
|
102
|
+
established_connections.add db_key.name
|
103
|
+
end # end connection not established yet
|
104
|
+
|
105
|
+
handler.retrieve_connection db_key
|
106
|
+
end
|
107
|
+
|
108
|
+
protected
|
109
|
+
|
110
|
+
# constructor
|
111
|
+
# arguments:
|
112
|
+
# - db_config_file: filename of database configurations file (in yaml).
|
113
|
+
#-----------------------------------------------------------------------------
|
114
|
+
def initialize(config_file)
|
115
|
+
self.db_config_file = config_file
|
116
|
+
self.configurations = YAML::load(File.open(self.db_config_file))
|
117
|
+
self.handler = ActiveRecord::ConnectionAdapters::ConnectionHandler.new
|
118
|
+
self.established_connections = Set.new
|
119
|
+
end
|
120
|
+
|
121
|
+
@@db_config_file = nil
|
122
|
+
@@instantiated = false
|
123
|
+
# the singleton instance. create if not already created, using
|
124
|
+
# config filename specified in init()
|
125
|
+
#-----------------------------------------------------------------------------
|
126
|
+
def self.instance
|
127
|
+
unless @@instantiated
|
128
|
+
self.init
|
129
|
+
@@instance = self.new(@@db_config_file)
|
130
|
+
@@instantiated = true
|
131
|
+
end
|
132
|
+
@@instance
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: multiple_connection_handler
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- bmpercy
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-15 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: activerecord
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ~>
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "2.1"
|
24
|
+
version:
|
25
|
+
description: " Hacky utility to access dbs listed in Rails' database.yml. See README for more info.\n"
|
26
|
+
email:
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files: []
|
32
|
+
|
33
|
+
files:
|
34
|
+
- lib/multiple_connection_handler.rb
|
35
|
+
- README
|
36
|
+
has_rdoc: true
|
37
|
+
homepage:
|
38
|
+
licenses: []
|
39
|
+
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 1.8.1
|
50
|
+
version:
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
version:
|
57
|
+
requirements: []
|
58
|
+
|
59
|
+
rubyforge_project:
|
60
|
+
rubygems_version: 1.3.5
|
61
|
+
signing_key:
|
62
|
+
specification_version: 3
|
63
|
+
summary: Rails utility for accessing arbitrary db connection listed in database.yml
|
64
|
+
test_files: []
|
65
|
+
|