-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4441efa
commit b64de51
Showing
23 changed files
with
813 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
/.bundle/ | ||
/.yardoc | ||
/Gemfile.lock | ||
/_yardoc/ | ||
/coverage/ | ||
/doc/ | ||
/pkg/ | ||
/spec/reports/ | ||
/tmp/ | ||
gemfiles/ | ||
spec/internal/config/database.yml | ||
spec/internal/test_other | ||
spec/internal/test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
--format documentation | ||
--color |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
appraise 'rails3.1' do | ||
gem 'rails', '~> 3.1.0' | ||
end | ||
|
||
appraise 'rails3.2' do | ||
gem 'rails', '~> 3.2.0' | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
source 'https://rubygems.org' | ||
|
||
gemspec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
The MIT License (MIT) | ||
|
||
Copyright (c) 2015 Denis Korobitcin | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in | ||
all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
BUNDLE = bundle | ||
BUNDLE_OPTIONS = -j 3 | ||
RSPEC = ${APPRAISAL} rspec | ||
APPRAISAL = ${BUNDLE} exec appraisal | ||
|
||
all: test | ||
|
||
test: configs bundler appraisal | ||
${RSPEC} 2>&1 | ||
|
||
define DATABASE_YML | ||
test: | ||
adapter: sqlite3 | ||
database: test | ||
test_other: | ||
adapter: sqlite3 | ||
database: test_other | ||
endef | ||
export DATABASE_YML | ||
|
||
configs: | ||
echo "$${DATABASE_YML}" > spec/internal/config/database.yml | ||
|
||
bundler: | ||
if ! gem list bundler -i > /dev/null; then \ | ||
gem install bundler; \ | ||
fi | ||
${BUNDLE} install ${BUNDLE_OPTIONS} | ||
|
||
appraisal: | ||
${APPRAISAL} install |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,119 @@ | ||
# slaver | ||
[![Dolly](http://dolly.railsc.ru/badges/abak-press/slaver/master)](http://dolly.railsc.ru/projects/129/builds/latest/?ref=master) | ||
|
||
# Slaver | ||
|
||
Welcome to slaver! | ||
|
||
It's a simple gem for rails application within multi-database environment. | ||
It allows you to change your current connection to other database configuration. | ||
Some ideas was inspired by [octopus](https://github.com/tchandy/octopus). | ||
|
||
## WARNING | ||
|
||
It was tested only on `rails 3` and `ruby 1.9.3`. Other configurations may work or may not:) | ||
|
||
## Installation | ||
|
||
Add this line to your application's Gemfile: | ||
|
||
```ruby | ||
gem 'slaver' | ||
``` | ||
|
||
And then execute: | ||
|
||
$ bundle | ||
|
||
Or install it yourself as: | ||
|
||
$ gem install slaver | ||
|
||
## Usage | ||
|
||
### Config | ||
You must have other connection on your database.yml file. For example: | ||
|
||
```yml | ||
production: | ||
adapter: pg | ||
host: master | ||
database: master | ||
post: 11111 | ||
|
||
production_slave: | ||
adapter: sqlite3 | ||
host: slave | ||
database: slave | ||
post: 11113 | ||
|
||
production_mysql: | ||
adapter: mysql | ||
user: me | ||
host: somewhere_else | ||
post: 11112 | ||
database: mysql | ||
``` | ||
### Chain with AR | ||
Only works with class/scope methods. Connection changed until query is perfomed. After that it'll swiched back to default connection. | ||
```ruby | ||
SomeModel.on(:production_mysql).where(name: 'me').first | ||
|
||
|
||
# or, if you name starting with you Rails.env it can be skipped | ||
SomeModel.on(:mysql).where(name: 'me').to_a | ||
``` | ||
### Execute block on other connection | ||
Connection will be switched only for required class. | ||
```ruby | ||
SomeModel.within(:slave) do | ||
SomeModel.where(name: 'me') | ||
end | ||
|
||
# It also can be combined with "on" method | ||
|
||
SomeModel.within(:mysql) do | ||
me = SomeModel.find_by_name('me') | ||
SomeModel.on(:slave).find_by_name('me').update_attributes(me.attributes) | ||
end | ||
|
||
# ACTUNG!! | ||
Somemodel.within(:slave) do | ||
#!!! Will be executed on default connection for OtherModel | ||
OtherModel.where(name: 'me').first | ||
end | ||
``` | ||
### ACTUNG!!!! | ||
|
||
If you connection does not exists, behavior may change dependent of you current Rails environment: | ||
- `Rails.env == production`: It'll raise `ArgumentError` | ||
- otherwise: It'll try to switch to default connection - `Rails.env` | ||
|
||
### Missing features | ||
|
||
1. 'on' with assosiations | ||
2. Transaction safety | ||
3. `on` method on instance | ||
|
||
## Development | ||
|
||
To run test on local machine use `make` command. For more info please reffer to Makefile. | ||
|
||
## Contributing | ||
|
||
1. Fork it ( https://github.com/abak-press/slaver/fork ) | ||
2. Create your feature branch (git checkout -b my-new-feature) | ||
3. Commit your changes (git commit -am 'Add some feature') | ||
4. Push to the branch (git push origin my-new-feature) | ||
5. Create new Pull Request | ||
|
||
|
||
|
||
## License | ||
|
||
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
require "bundler/gem_tasks" | ||
require "rspec/core/rake_task" | ||
|
||
RSpec::Core::RakeTask.new(:spec) | ||
|
||
task :default => :spec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
require 'rubygems' | ||
require 'bundler' | ||
|
||
Bundler.require :default, :development | ||
|
||
Combustion.initialize! :all | ||
run Combustion::Application |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
require 'rails' | ||
require 'slaver/version' | ||
require 'slaver/proxy' | ||
require 'slaver/proxy_methods' | ||
require 'slaver/connection' | ||
require 'slaver/railtie' | ||
|
||
module Slaver | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
module Slaver | ||
module Connection | ||
extend ActiveSupport::Concern | ||
|
||
included do | ||
include ProxyMethods | ||
end | ||
|
||
module ClassMethods | ||
# TODO: Make it work with associations | ||
# Public: Change database connection for next query | ||
# WARNING: It'll change current DB connection until | ||
# insert, select or execute methods call | ||
# | ||
# config_name - String or Symbol, name of config_section | ||
# | ||
# NOTE: | ||
# if config was not found: | ||
# 1) On production | ||
# throws ArgumentError | ||
# 2) Uses default configuration for current environment | ||
# | ||
# Exception safety: | ||
# throws ArgumentError if no configuration was found | ||
# | ||
# Examples | ||
# | ||
# SomeModel.on(:slave).create(...) | ||
# SomeModel.on(:slave).where(...).first | ||
# | ||
# It also can be chained with other 'on' methods | ||
# SomeModel.on(:slave).on(:other).find_by(...) | ||
# | ||
# Returns self | ||
def on(config_name) | ||
@saved_config ||= @current_config | ||
@saved_block ||= @block | ||
@block = false | ||
|
||
@current_config = prepare(config_name) | ||
|
||
initialize_pool(@current_config) unless pools[@current_config] | ||
|
||
self | ||
end | ||
|
||
# Public: Changes model's connection to database temporarily to execute block. | ||
# | ||
# config_name - String or Symbol, name of config_section | ||
# | ||
# NOTE: | ||
# if config was not found: | ||
# 1) On production | ||
# throws ArgumentError | ||
# 2) Uses default configuration for current environment | ||
# | ||
# Exception safety: | ||
# throws ArgumentError if no configuration was found | ||
# | ||
# Examples | ||
# | ||
# SomeModel.within :test_slave do | ||
# # do some computations here | ||
# end | ||
# => will execute given block with different db_connection | ||
# | ||
# It is also possible to nest database connection code | ||
# | ||
# SomeModel.within :slave do | ||
# do some computations here | ||
# SomeModel.within :slave2 do | ||
# # some other computations go here | ||
# end | ||
# end | ||
# => will execute given block with different db_connection | ||
# | ||
# Returns noting | ||
def within(config_name) | ||
config_name = prepare(config_name) | ||
|
||
initialize_pool(config_name) unless pools[config_name] | ||
|
||
with_config(config_name) do | ||
keep_block do | ||
yield | ||
end | ||
end | ||
end | ||
|
||
def clear_config | ||
@block = @saved_block if @saved_block | ||
@saved_block = nil | ||
@current_config = @block && @saved_config | ||
@saved_config = nil | ||
end | ||
|
||
def pools | ||
@pools ||= {} | ||
end | ||
|
||
def within_block? | ||
!!@block | ||
end | ||
|
||
private | ||
|
||
def with_config(config_name) | ||
last_config = @current_config | ||
@current_config = config_name | ||
|
||
begin | ||
yield | ||
ensure | ||
@current_config = last_config | ||
end | ||
end | ||
|
||
def keep_block | ||
last_block = @block | ||
@block = true | ||
|
||
begin | ||
yield | ||
ensure | ||
@block = last_block | ||
end | ||
end | ||
|
||
def initialize_pool(config_name) | ||
if config_name == default_config | ||
pools[config_name] = connection_pool_without_proxy | ||
else | ||
pools[config_name] = create_connection_pool(config_name) | ||
end | ||
end | ||
|
||
def prepare(config_name) | ||
config_name = config_name.to_s | ||
|
||
return config_name if ::ActiveRecord::Base.configurations[config_name].present? | ||
|
||
config_name = "#{Rails.env}_#{config_name}" | ||
|
||
if (::ActiveRecord::Base.configurations[config_name]).blank? | ||
if Rails.env.production? | ||
raise ArgumentError, "Can't find #{config_name} on database configurations" | ||
else | ||
config_name = default_config | ||
end | ||
end | ||
|
||
config_name | ||
end | ||
|
||
def default_config | ||
Rails.env | ||
end | ||
|
||
def create_connection_pool(config_name) | ||
config = ::ActiveRecord::Base.configurations[config_name] | ||
config.symbolize_keys! | ||
arg = ActiveRecord::Base::ConnectionSpecification.new(config, "#{config[:adapter]}_connection") | ||
|
||
ActiveRecord::ConnectionAdapters::ConnectionPool.new(arg) | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.