ar-multidb 0.4.1 → 0.4.2
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +62 -0
- data/.travis.yml +7 -2
- data/CHANGELOG.md +6 -0
- data/Gemfile +4 -2
- data/README.markdown +18 -18
- data/Rakefile +10 -9
- data/ar-multidb.gemspec +19 -17
- data/gemfiles/activerecord51.gemfile +2 -0
- data/gemfiles/activerecord52.gemfile +2 -0
- data/lib/ar-multidb.rb +2 -0
- data/lib/multidb.rb +2 -0
- data/lib/multidb/balancer.rb +25 -24
- data/lib/multidb/candidate.rb +6 -4
- data/lib/multidb/configuration.rb +7 -10
- data/lib/multidb/log_subscriber.rb +6 -4
- data/lib/multidb/model_extensions.rb +2 -0
- data/lib/multidb/version.rb +3 -1
- data/spec/balancer_spec.rb +30 -30
- data/spec/helpers.rb +20 -20
- data/spec/spec_helper.rb +5 -3
- metadata +45 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3ecd6501582114326efd8452ffe712c79b5667d1ce54a181eff6efeaf40d1897
|
4
|
+
data.tar.gz: 85c3e8b3dc155374ef7d7caed121bf5a140cf64030b760bb6cdcdb3123e8cddc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e2eefe25c89d914367afecce5ebc07f4be668985097969f5a1c9acb563a22c448778b4128caf64e5dd6029437e28b13188097d6c66c111f4b5911543858f50b1
|
7
|
+
data.tar.gz: c83c08a921575803b15ebf473e125ad6da3619b321208766e9f8d058bb8226154cd21255d14aa77be260bfd17da29926be8aa3bdeda547fed0c6f46624370283
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.4
|
3
|
+
Exclude:
|
4
|
+
- '**/vendor/**/*'
|
5
|
+
|
6
|
+
Layout/EmptyLinesAroundAttributeAccessor:
|
7
|
+
Enabled: true
|
8
|
+
Layout/SpaceAroundMethodCallOperator:
|
9
|
+
Enabled: true
|
10
|
+
Layout/LineLength:
|
11
|
+
Exclude:
|
12
|
+
- 'ar-multidb.gemspec'
|
13
|
+
Lint/DeprecatedOpenSSLConstant:
|
14
|
+
Enabled: true
|
15
|
+
Lint/DuplicateElsifCondition:
|
16
|
+
Enabled: true
|
17
|
+
Lint/MixedRegexpCaptureTypes:
|
18
|
+
Enabled: true
|
19
|
+
Lint/RaiseException:
|
20
|
+
Enabled: true
|
21
|
+
Lint/StructNewOverride:
|
22
|
+
Enabled: true
|
23
|
+
Naming/FileName:
|
24
|
+
Exclude:
|
25
|
+
- 'lib/ar-multidb.rb'
|
26
|
+
Metrics:
|
27
|
+
Enabled: false
|
28
|
+
Style/AccessorGrouping:
|
29
|
+
Enabled: true
|
30
|
+
Style/ArrayCoercion:
|
31
|
+
Enabled: true
|
32
|
+
Style/BisectedAttrAccessor:
|
33
|
+
Enabled: true
|
34
|
+
Style/CaseLikeIf:
|
35
|
+
Enabled: true
|
36
|
+
Style/Documentation:
|
37
|
+
Enabled: false
|
38
|
+
Style/ExponentialNotation:
|
39
|
+
Enabled: true
|
40
|
+
Style/HashAsLastArrayItem:
|
41
|
+
Enabled: true
|
42
|
+
Style/HashEachMethods:
|
43
|
+
Enabled: true
|
44
|
+
Style/HashLikeCase:
|
45
|
+
Enabled: true
|
46
|
+
Style/HashTransformKeys:
|
47
|
+
Enabled: true
|
48
|
+
Style/HashTransformValues:
|
49
|
+
Enabled: true
|
50
|
+
Style/RedundantAssignment:
|
51
|
+
Enabled: true
|
52
|
+
Style/RedundantFetchBlock:
|
53
|
+
Enabled: true
|
54
|
+
Style/RedundantFileExtensionInRequire:
|
55
|
+
Enabled: true
|
56
|
+
Style/RedundantRegexpCharacterClass:
|
57
|
+
Enabled: true
|
58
|
+
Style/RedundantRegexpEscape:
|
59
|
+
Enabled: true
|
60
|
+
Style/SlicingWithRange:
|
61
|
+
Enabled: true
|
62
|
+
|
data/.travis.yml
CHANGED
@@ -1,10 +1,15 @@
|
|
1
1
|
sudo: false
|
2
2
|
language: ruby
|
3
|
+
cache: bundler
|
4
|
+
|
5
|
+
script:
|
6
|
+
- bundle exec rubocop
|
7
|
+
- bundle exec rspec
|
3
8
|
|
4
9
|
matrix:
|
5
10
|
fast_finish: true
|
6
11
|
include:
|
7
|
-
- rvm: 2.5
|
12
|
+
- rvm: 2.5
|
8
13
|
gemfile: gemfiles/activerecord51.gemfile
|
9
|
-
- rvm: 2.5
|
14
|
+
- rvm: 2.5
|
10
15
|
gemfile: gemfiles/activerecord52.gemfile
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
5
5
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html)
|
6
6
|
|
7
|
+
## [0.4.2]
|
8
|
+
### Changed
|
9
|
+
- adjust rails restriction to exclude untested rails 6
|
10
|
+
- adjust minimum ruby version to 2.4
|
11
|
+
- add rubocop
|
12
|
+
|
7
13
|
## [0.4.1]
|
8
14
|
### Added
|
9
15
|
- Added support for database aliases ( PR #26 )
|
data/Gemfile
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source 'http://rubygems.org'
|
2
4
|
|
3
5
|
# Specify your gem's dependencies in ar-multidb.gemspec
|
4
6
|
gemspec
|
5
7
|
|
6
|
-
local_gemfile =
|
8
|
+
local_gemfile = 'Gemfile.local'
|
7
9
|
|
8
10
|
if File.exist?(local_gemfile)
|
9
11
|
eval(File.read(local_gemfile)) # rubocop:disable Security/Eval
|
data/README.markdown
CHANGED
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
# Multidb
|
4
4
|
|
5
|
-
A simple, no-nonsense ActiveRecord extension which allows the application to switch between multiple database connections, such as in a
|
5
|
+
A simple, no-nonsense ActiveRecord extension which allows the application to switch between multiple database connections, such as in a primary/replica environment. For example:
|
6
6
|
|
7
|
-
Multidb.use(:
|
7
|
+
Multidb.use(:replica) do
|
8
8
|
@posts = Post.all
|
9
9
|
end
|
10
10
|
|
@@ -14,7 +14,7 @@ Randomized balancing of multiple connections within a group is supported. In the
|
|
14
14
|
|
15
15
|
## Requirements
|
16
16
|
|
17
|
-
* Ruby 2.
|
17
|
+
* Ruby 2.4 or later.
|
18
18
|
* ActiveRecord 5.1 or later.
|
19
19
|
|
20
20
|
## Older releases
|
@@ -32,10 +32,10 @@ Compared to other, more full-featured extensions such as Octopus and Seamless Da
|
|
32
32
|
|
33
33
|
**Orthogonal**. Unlike Octopus, for example, connections follow context:
|
34
34
|
|
35
|
-
Multidb.use(:
|
35
|
+
Multidb.use(:primary) do
|
36
36
|
@post = Post.find(1)
|
37
|
-
Multidb.use(:
|
38
|
-
@post.authors # This will use the
|
37
|
+
Multidb.use(:replica) do
|
38
|
+
@post.authors # This will use the replica
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -60,8 +60,8 @@ All that is needed is to set up your `database.yml` file:
|
|
60
60
|
host: db1
|
61
61
|
multidb:
|
62
62
|
databases:
|
63
|
-
|
64
|
-
host: db-
|
63
|
+
replica:
|
64
|
+
host: db-replica
|
65
65
|
|
66
66
|
Each database entry may be a hash or an array. So this also works:
|
67
67
|
|
@@ -73,9 +73,9 @@ Each database entry may be a hash or an array. So this also works:
|
|
73
73
|
host: db1
|
74
74
|
multidb:
|
75
75
|
databases:
|
76
|
-
|
77
|
-
- host: db-
|
78
|
-
- host: db-
|
76
|
+
replica:
|
77
|
+
- host: db-replica1
|
78
|
+
- host: db-replica2
|
79
79
|
|
80
80
|
If multiple elements are specified, Multidb will use the list to pick a random candidate connection.
|
81
81
|
|
@@ -100,14 +100,14 @@ With the above, `Multidb.use(:main_db)` and `Multidb.use(:secondary_db)` will wo
|
|
100
100
|
|
101
101
|
To use the connection, modify your code by wrapping database access logic in blocks:
|
102
102
|
|
103
|
-
Multidb.use(:
|
103
|
+
Multidb.use(:replica) do
|
104
104
|
@posts = Post.all
|
105
105
|
end
|
106
106
|
|
107
107
|
To wrap entire controller requests, for example:
|
108
108
|
|
109
109
|
class PostsController < ApplicationController
|
110
|
-
around_filter :
|
110
|
+
around_filter :run_using_replica, only: [:index]
|
111
111
|
|
112
112
|
def index
|
113
113
|
@posts = Post.all
|
@@ -117,22 +117,22 @@ To wrap entire controller requests, for example:
|
|
117
117
|
# Won't be wrapped
|
118
118
|
end
|
119
119
|
|
120
|
-
def
|
121
|
-
Multidb.use(:
|
120
|
+
def run_using_replica(&block)
|
121
|
+
Multidb.use(:replica, &block)
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
125
125
|
You can also set the current connection for the remainder of the thread's execution:
|
126
126
|
|
127
|
-
Multidb.use(:
|
127
|
+
Multidb.use(:replica)
|
128
128
|
# Do work
|
129
|
-
Multidb.use(:
|
129
|
+
Multidb.use(:primary)
|
130
130
|
|
131
131
|
Note that the symbol `:default` will (unless you override it) refer to the default top-level ActiveRecord configuration.
|
132
132
|
|
133
133
|
## Development mode
|
134
134
|
|
135
|
-
In development you will typically want `Multidb.use(:
|
135
|
+
In development you will typically want `Multidb.use(:replica)` to still work, but you probably don't want to run multiple databases on your development box. To make `use` silently fall back to using the default connection, Multidb can run in fallback mode.
|
136
136
|
|
137
137
|
If you are using Rails, this will be automatically enabled in `development` and `test` environments. Otherwise, simply set `fallback: true` in `database.yml`:
|
138
138
|
|
data/Rakefile
CHANGED
@@ -1,26 +1,27 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
2
4
|
require 'rspec/core/rake_task'
|
3
5
|
|
4
6
|
RSpec::Core::RakeTask.new
|
5
7
|
|
6
|
-
task :
|
8
|
+
task default: :spec
|
7
9
|
|
8
10
|
desc 'Bump version'
|
9
11
|
task :bump do
|
10
|
-
if `git status -uno -s --porcelain | wc -l`.to_i
|
11
|
-
|
12
|
-
end
|
12
|
+
abort 'You have uncommitted changed.' if `git status -uno -s --porcelain | wc -l`.to_i.positive?
|
13
|
+
|
13
14
|
text = File.read('lib/multidb/version.rb')
|
14
15
|
if text =~ /VERSION = '(.*)'/
|
15
|
-
old_version =
|
16
|
+
old_version = Regexp.last_match(1)
|
16
17
|
version_parts = old_version.split('.')
|
17
18
|
version_parts[-1] = version_parts[-1].to_i + 1
|
18
19
|
new_version = version_parts.join('.')
|
19
20
|
text.gsub!(/VERSION = '(.*)'/, "VERSION = '#{new_version}'")
|
20
21
|
File.open('lib/multidb/version.rb', 'w') { |f| f << text }
|
21
|
-
(system(
|
22
|
-
system("git commit -m 'Bump to #{new_version}.'"))
|
22
|
+
(system('git add lib/multidb/version.rb') &&
|
23
|
+
system("git commit -m 'Bump to #{new_version}.'")) || abort('Failed to commit.')
|
23
24
|
else
|
24
|
-
abort
|
25
|
+
abort 'Could not find version number'
|
25
26
|
end
|
26
27
|
end
|
data/ar-multidb.gemspec
CHANGED
@@ -1,26 +1,28 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.push File.expand_path('lib', __dir__)
|
4
|
+
require 'multidb/version'
|
4
5
|
|
5
6
|
Gem::Specification.new do |s|
|
6
|
-
s.name =
|
7
|
+
s.name = 'ar-multidb'
|
7
8
|
s.version = Multidb::VERSION
|
8
|
-
s.authors = [
|
9
|
-
s.email = [
|
10
|
-
s.homepage =
|
11
|
-
s.summary = s.description =
|
12
|
-
|
13
|
-
s.rubyforge_project = "ar-multidb"
|
9
|
+
s.authors = ['Alexander Staubo', 'Edward Rudd']
|
10
|
+
s.email = ['alex@bengler.no', 'urkle@outoforder.cc']
|
11
|
+
s.homepage = ''
|
12
|
+
s.summary = s.description = 'Multidb is an ActiveRecord extension for switching between multiple database connections, such as primary/replica setups.'
|
14
13
|
|
15
14
|
s.files = `git ls-files`.split("\n")
|
16
15
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
-
s.require_paths = [
|
16
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
17
|
+
s.require_paths = ['lib']
|
18
|
+
|
19
|
+
s.required_ruby_version = '>= 2.4.0'
|
19
20
|
|
20
|
-
s.add_runtime_dependency '
|
21
|
-
s.add_runtime_dependency '
|
21
|
+
s.add_runtime_dependency 'activerecord', '>= 5.1', '< 6.0'
|
22
|
+
s.add_runtime_dependency 'activesupport', '>= 5.1', '< 6.0'
|
22
23
|
|
23
|
-
s.add_development_dependency '
|
24
|
-
s.add_development_dependency '
|
25
|
-
s.add_development_dependency '
|
24
|
+
s.add_development_dependency 'rake', '~> 12.0'
|
25
|
+
s.add_development_dependency 'rspec', '~> 3.8'
|
26
|
+
s.add_development_dependency 'rubocop', '~> 0.88.0'
|
27
|
+
s.add_development_dependency 'sqlite3', '~> 1.3'
|
26
28
|
end
|
data/lib/ar-multidb.rb
CHANGED
data/lib/multidb.rb
CHANGED
data/lib/multidb/balancer.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Multidb
|
2
4
|
class Balancer
|
3
5
|
attr_accessor :fallback
|
@@ -6,34 +8,33 @@ module Multidb
|
|
6
8
|
@candidates = {}.with_indifferent_access
|
7
9
|
@default_configuration = configuration
|
8
10
|
|
9
|
-
|
11
|
+
return unless @default_configuration
|
10
12
|
|
11
|
-
|
13
|
+
append(@default_configuration.raw_configuration[:databases] || {})
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
15
|
+
@fallback = if @default_configuration.raw_configuration.include?(:fallback)
|
16
|
+
@default_configuration.raw_configuration[:fallback]
|
17
|
+
elsif defined?(Rails)
|
18
|
+
%w[development test].include?(Rails.env)
|
19
|
+
else
|
20
|
+
false
|
21
|
+
end
|
22
|
+
|
23
|
+
@default_candidate = Candidate.new('default', @default_configuration.default_handler)
|
24
|
+
|
25
|
+
@candidates[:default] = [@default_candidate] unless @candidates.include?(:default)
|
25
26
|
end
|
26
27
|
|
27
28
|
def append(databases)
|
28
29
|
databases.each_pair do |name, config|
|
29
30
|
configs = config.is_a?(Array) ? config : [config]
|
30
|
-
configs.each do |
|
31
|
-
if
|
32
|
-
@candidates[name] = @candidates[
|
31
|
+
configs.each do |cfg|
|
32
|
+
if cfg['alias']
|
33
|
+
@candidates[name] = @candidates[cfg['alias']]
|
33
34
|
next
|
34
35
|
end
|
35
36
|
|
36
|
-
candidate = Candidate.new(name, @default_configuration.default_adapter.merge(
|
37
|
+
candidate = Candidate.new(name, @default_configuration.default_adapter.merge(cfg))
|
37
38
|
@candidates[name] ||= []
|
38
39
|
@candidates[name].push(candidate)
|
39
40
|
end
|
@@ -44,16 +45,18 @@ module Multidb
|
|
44
45
|
@candidates.values.flatten.each(&:disconnect!)
|
45
46
|
end
|
46
47
|
|
47
|
-
def get(name, &
|
48
|
+
def get(name, &_block)
|
48
49
|
candidates = @candidates[name]
|
49
50
|
candidates ||= @fallback ? @candidates[:default] : []
|
51
|
+
|
50
52
|
raise ArgumentError, "No such database connection '#{name}'" if candidates.empty?
|
51
|
-
|
52
|
-
|
53
|
+
|
54
|
+
candidate = candidates.respond_to?(:sample) ? candidates.sample : candidates[rand(candidates.length)]
|
55
|
+
|
53
56
|
block_given? ? yield(candidate) : candidate
|
54
57
|
end
|
55
58
|
|
56
|
-
def use(name, &
|
59
|
+
def use(name, &_block)
|
57
60
|
result = nil
|
58
61
|
get(name) do |candidate|
|
59
62
|
if block_given?
|
@@ -115,7 +118,5 @@ module Multidb
|
|
115
118
|
Multidb.balancer.disconnect!
|
116
119
|
end
|
117
120
|
end
|
118
|
-
|
119
121
|
end
|
120
|
-
|
121
122
|
end
|
data/lib/multidb/candidate.rb
CHANGED
@@ -1,17 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Multidb
|
2
4
|
class Candidate
|
3
5
|
def initialize(name, target)
|
4
6
|
@name = name
|
5
7
|
|
6
|
-
|
8
|
+
case target
|
9
|
+
when Hash
|
7
10
|
@connection_handler = ActiveRecord::ConnectionAdapters::ConnectionHandler.new
|
8
11
|
@connection_handler.establish_connection(target.merge(name: 'primary'))
|
9
|
-
|
12
|
+
when ActiveRecord::ConnectionAdapters::ConnectionHandler
|
10
13
|
@connection_handler = target
|
11
14
|
else
|
12
15
|
raise ArgumentError, 'Connection handler not passed to target'
|
13
16
|
end
|
14
|
-
|
15
17
|
end
|
16
18
|
|
17
19
|
def connection(&block)
|
@@ -28,4 +30,4 @@ module Multidb
|
|
28
30
|
|
29
31
|
attr_reader :name
|
30
32
|
end
|
31
|
-
end
|
33
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Multidb
|
2
4
|
class << self
|
3
5
|
delegate :use, :get, :disconnect!, to: :balancer
|
@@ -5,17 +7,14 @@ module Multidb
|
|
5
7
|
|
6
8
|
def self.init(config)
|
7
9
|
activerecord_config = config.dup.with_indifferent_access
|
8
|
-
default_adapter
|
10
|
+
default_adapter = activerecord_config
|
11
|
+
configuration_hash = activerecord_config.delete(:multidb)
|
9
12
|
|
10
13
|
@balancer = Balancer.new(Configuration.new(default_adapter, configuration_hash || {}))
|
11
14
|
end
|
12
15
|
|
13
16
|
def self.balancer
|
14
|
-
|
15
|
-
@balancer
|
16
|
-
else
|
17
|
-
raise NotInitializedError, "Balancer not initialized. You need to run Multidb.init first"
|
18
|
-
end
|
17
|
+
@balancer || raise(NotInitializedError, 'Balancer not initialized. You need to run Multidb.init first')
|
19
18
|
end
|
20
19
|
|
21
20
|
def self.reset!
|
@@ -31,8 +30,6 @@ module Multidb
|
|
31
30
|
@raw_configuration = configuration_hash
|
32
31
|
end
|
33
32
|
|
34
|
-
attr_reader :default_handler
|
35
|
-
attr_reader :default_adapter
|
36
|
-
attr_reader :raw_configuration
|
33
|
+
attr_reader :default_handler, :default_adapter, :raw_configuration
|
37
34
|
end
|
38
|
-
end
|
35
|
+
end
|
@@ -1,14 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Multidb
|
2
4
|
module LogSubscriberExtension
|
3
5
|
def sql(event)
|
4
|
-
|
5
|
-
|
6
|
-
end
|
6
|
+
name = Multidb.balancer.current_connection_name
|
7
|
+
event.payload[:db_name] = name if name
|
7
8
|
super
|
8
9
|
end
|
9
10
|
|
10
11
|
def debug(msg)
|
11
|
-
|
12
|
+
name = Multidb.balancer.current_connection_name
|
13
|
+
if name
|
12
14
|
db = color("[DB: #{name}]", ActiveSupport::LogSubscriber::GREEN, true)
|
13
15
|
super(db + msg)
|
14
16
|
else
|
data/lib/multidb/version.rb
CHANGED
data/spec/balancer_spec.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'spec_helper'
|
2
4
|
|
3
5
|
describe 'Multidb.balancer' do
|
4
|
-
|
5
6
|
context 'with no configuration' do
|
6
7
|
it 'raises exception' do
|
7
8
|
-> { Multidb.balancer }.should raise_error(Multidb::NotInitializedError)
|
@@ -10,7 +11,7 @@ describe 'Multidb.balancer' do
|
|
10
11
|
|
11
12
|
context 'with configuration' do
|
12
13
|
before do
|
13
|
-
ActiveRecord::Base.establish_connection(
|
14
|
+
ActiveRecord::Base.establish_connection(configuration_with_replicas)
|
14
15
|
end
|
15
16
|
|
16
17
|
it 'returns balancer' do
|
@@ -28,30 +29,30 @@ describe 'Multidb.balancer' do
|
|
28
29
|
end
|
29
30
|
|
30
31
|
it 'returns default connection name for default connection' do
|
31
|
-
|
32
|
+
ActiveRecord::Base.connection
|
32
33
|
|
33
34
|
Multidb.balancer.current_connection_name.should eq :default
|
34
35
|
end
|
35
|
-
|
36
|
+
|
36
37
|
context 'with additional configurations' do
|
37
38
|
before do
|
38
|
-
additional_configuration = {
|
39
|
+
additional_configuration = { replica4: { database: 'spec/test-replica4.sqlite' } }
|
39
40
|
Multidb.balancer.append(additional_configuration)
|
40
41
|
end
|
41
42
|
|
42
43
|
it 'makes the new database available' do
|
43
|
-
Multidb.use(:
|
44
|
+
Multidb.use(:replica4) do
|
44
45
|
conn = ActiveRecord::Base.connection
|
45
46
|
conn.should eq Multidb.balancer.current_connection
|
46
47
|
list = conn.execute('pragma database_list')
|
47
48
|
list.length.should eq 1
|
48
|
-
File.basename(list[0]['file']).should eq 'test-
|
49
|
+
File.basename(list[0]['file']).should eq 'test-replica4.sqlite'
|
49
50
|
end
|
50
51
|
end
|
51
52
|
|
52
53
|
it 'returns the connection name' do
|
53
|
-
Multidb.use(:
|
54
|
-
Multidb.balancer.current_connection_name.should eq :
|
54
|
+
Multidb.use(:replica4) do
|
55
|
+
Multidb.balancer.current_connection_name.should eq :replica4
|
55
56
|
end
|
56
57
|
end
|
57
58
|
end
|
@@ -60,12 +61,12 @@ describe 'Multidb.balancer' do
|
|
60
61
|
describe '#use' do
|
61
62
|
context 'with configuration' do
|
62
63
|
before do
|
63
|
-
ActiveRecord::Base.establish_connection(
|
64
|
+
ActiveRecord::Base.establish_connection(configuration_with_replicas)
|
64
65
|
end
|
65
66
|
|
66
67
|
context 'undefined connection' do
|
67
68
|
it 'raises exception' do
|
68
|
-
|
69
|
+
lambda {
|
69
70
|
Multidb.use(:something) do
|
70
71
|
end
|
71
72
|
}.should raise_error(ArgumentError)
|
@@ -73,7 +74,7 @@ describe 'Multidb.balancer' do
|
|
73
74
|
end
|
74
75
|
|
75
76
|
it 'returns default connection on :default' do
|
76
|
-
|
77
|
+
ActiveRecord::Base.connection
|
77
78
|
Multidb.use(:default) do
|
78
79
|
conn2 = ActiveRecord::Base.connection
|
79
80
|
conn2.should eq Multidb.balancer.current_connection
|
@@ -84,19 +85,19 @@ describe 'Multidb.balancer' do
|
|
84
85
|
end
|
85
86
|
end
|
86
87
|
|
87
|
-
it 'returns
|
88
|
-
Multidb.use(:
|
88
|
+
it 'returns replica connection' do
|
89
|
+
Multidb.use(:replica1) do
|
89
90
|
conn = ActiveRecord::Base.connection
|
90
91
|
conn.should eq Multidb.balancer.current_connection
|
91
92
|
list = conn.execute('pragma database_list')
|
92
93
|
list.length.should eq 1
|
93
|
-
File.basename(list[0]['file']).should eq 'test-
|
94
|
+
File.basename(list[0]['file']).should eq 'test-replica1.sqlite'
|
94
95
|
end
|
95
96
|
end
|
96
97
|
|
97
98
|
it 'returns results instead of relation' do
|
98
99
|
class FooBar < ActiveRecord::Base; end
|
99
|
-
res = Multidb.use(:
|
100
|
+
res = Multidb.use(:replica1) do
|
100
101
|
ActiveRecord::Migration.verbose = false
|
101
102
|
ActiveRecord::Schema.define(version: 1) { create_table :foo_bars }
|
102
103
|
FooBar.where(id: 42)
|
@@ -104,56 +105,55 @@ describe 'Multidb.balancer' do
|
|
104
105
|
res.should eq []
|
105
106
|
end
|
106
107
|
|
107
|
-
it 'returns supports nested
|
108
|
-
Multidb.use(:
|
109
|
-
Multidb.use(:
|
108
|
+
it 'returns supports nested replica connection' do
|
109
|
+
Multidb.use(:replica1) do
|
110
|
+
Multidb.use(:replica2) do
|
110
111
|
conn = ActiveRecord::Base.connection
|
111
112
|
conn.should eq Multidb.balancer.current_connection
|
112
113
|
list = conn.execute('pragma database_list')
|
113
114
|
list.length.should eq 1
|
114
|
-
File.basename(list[0]['file']).should eq 'test-
|
115
|
+
File.basename(list[0]['file']).should eq 'test-replica2.sqlite'
|
115
116
|
end
|
116
117
|
end
|
117
118
|
end
|
118
119
|
|
119
120
|
it 'returns preserves state when nesting' do
|
120
|
-
Multidb.use(:
|
121
|
-
Multidb.use(:
|
121
|
+
Multidb.use(:replica1) do
|
122
|
+
Multidb.use(:replica2) do
|
122
123
|
conn = ActiveRecord::Base.connection
|
123
124
|
conn.should eq Multidb.balancer.current_connection
|
124
125
|
list = conn.execute('pragma database_list')
|
125
126
|
list.length.should eq 1
|
126
|
-
File.basename(list[0]['file']).should eq 'test-
|
127
|
+
File.basename(list[0]['file']).should eq 'test-replica2.sqlite'
|
127
128
|
end
|
128
129
|
|
129
130
|
conn = ActiveRecord::Base.connection
|
130
131
|
conn.should eq Multidb.balancer.current_connection
|
131
132
|
list = conn.execute('pragma database_list')
|
132
133
|
list.length.should eq 1
|
133
|
-
File.basename(list[0]['file']).should eq 'test-
|
134
|
+
File.basename(list[0]['file']).should eq 'test-replica1.sqlite'
|
134
135
|
end
|
135
136
|
end
|
136
137
|
|
137
138
|
it 'returns the parent connection for aliases' do
|
138
|
-
Multidb.use(:
|
139
|
-
Multidb.use(:
|
139
|
+
Multidb.use(:replica1).should_not eq Multidb.use(:replica_alias)
|
140
|
+
Multidb.use(:replica2).should eq Multidb.use(:replica_alias)
|
140
141
|
end
|
141
142
|
|
142
143
|
it 'returns random candidate' do
|
143
144
|
names = []
|
144
145
|
100.times do
|
145
|
-
Multidb.use(:
|
146
|
+
Multidb.use(:replica3) do
|
146
147
|
list = ActiveRecord::Base.connection.execute('pragma database_list')
|
147
148
|
list.length.should eq 1
|
148
149
|
names.push(File.basename(list[0]['file']))
|
149
150
|
end
|
150
151
|
end
|
151
152
|
names.sort.uniq.should eq [
|
152
|
-
'test-
|
153
|
-
'test-
|
153
|
+
'test-replica3-1.sqlite',
|
154
|
+
'test-replica3-2.sqlite'
|
154
155
|
]
|
155
156
|
end
|
156
157
|
end
|
157
158
|
end
|
158
|
-
|
159
159
|
end
|
data/spec/helpers.rb
CHANGED
@@ -1,23 +1,23 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
3
|
+
module Helpers
|
4
|
+
def configuration_with_replicas
|
5
|
+
YAML.safe_load(<<~YAML)
|
6
|
+
adapter: sqlite3
|
7
|
+
database: spec/test.sqlite
|
8
|
+
encoding: utf-8
|
9
|
+
multidb:
|
10
|
+
databases:
|
11
|
+
replica1:
|
12
|
+
database: spec/test-replica1.sqlite
|
13
|
+
replica2:
|
14
|
+
database: spec/test-replica2.sqlite
|
15
|
+
replica3:
|
16
|
+
- database: spec/test-replica3-1.sqlite
|
17
|
+
- database: spec/test-replica3-2.sqlite
|
18
|
+
replica_alias:
|
19
|
+
database: spec/test-replica2.sqlite
|
20
|
+
alias: replica2
|
21
|
+
YAML
|
21
22
|
end
|
22
|
-
|
23
23
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
ENV['RACK_ENV'] ||= 'test'
|
2
4
|
|
3
5
|
require 'rspec'
|
4
6
|
require 'yaml'
|
5
7
|
require 'active_record'
|
6
8
|
require 'fileutils'
|
7
9
|
|
8
|
-
$LOAD_PATH.unshift(File.expand_path('
|
10
|
+
$LOAD_PATH.unshift(File.expand_path('lib', __dir__))
|
9
11
|
require 'multidb'
|
10
12
|
|
11
13
|
require_relative 'helpers'
|
@@ -18,7 +20,7 @@ RSpec.configure do |config|
|
|
18
20
|
Multidb.reset!
|
19
21
|
end
|
20
22
|
config.after :each do
|
21
|
-
Dir.glob(File.expand_path('
|
23
|
+
Dir.glob(File.expand_path('test*.sqlite', __dir__)).each do |f|
|
22
24
|
FileUtils.rm(f)
|
23
25
|
end
|
24
26
|
end
|
metadata
CHANGED
@@ -1,23 +1,24 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ar-multidb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Staubo
|
8
|
-
|
8
|
+
- Edward Rudd
|
9
|
+
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date:
|
12
|
+
date: 2020-07-20 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
15
|
+
name: activerecord
|
15
16
|
requirement: !ruby/object:Gem::Requirement
|
16
17
|
requirements:
|
17
18
|
- - ">="
|
18
19
|
- !ruby/object:Gem::Version
|
19
20
|
version: '5.1'
|
20
|
-
- - "
|
21
|
+
- - "<"
|
21
22
|
- !ruby/object:Gem::Version
|
22
23
|
version: '6.0'
|
23
24
|
type: :runtime
|
@@ -27,17 +28,17 @@ dependencies:
|
|
27
28
|
- - ">="
|
28
29
|
- !ruby/object:Gem::Version
|
29
30
|
version: '5.1'
|
30
|
-
- - "
|
31
|
+
- - "<"
|
31
32
|
- !ruby/object:Gem::Version
|
32
33
|
version: '6.0'
|
33
34
|
- !ruby/object:Gem::Dependency
|
34
|
-
name:
|
35
|
+
name: activesupport
|
35
36
|
requirement: !ruby/object:Gem::Requirement
|
36
37
|
requirements:
|
37
38
|
- - ">="
|
38
39
|
- !ruby/object:Gem::Version
|
39
40
|
version: '5.1'
|
40
|
-
- - "
|
41
|
+
- - "<"
|
41
42
|
- !ruby/object:Gem::Version
|
42
43
|
version: '6.0'
|
43
44
|
type: :runtime
|
@@ -47,60 +48,76 @@ dependencies:
|
|
47
48
|
- - ">="
|
48
49
|
- !ruby/object:Gem::Version
|
49
50
|
version: '5.1'
|
50
|
-
- - "
|
51
|
+
- - "<"
|
51
52
|
- !ruby/object:Gem::Version
|
52
53
|
version: '6.0'
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: rake
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '12.0'
|
61
|
+
type: :development
|
62
|
+
prerelease: false
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '12.0'
|
53
68
|
- !ruby/object:Gem::Dependency
|
54
69
|
name: rspec
|
55
70
|
requirement: !ruby/object:Gem::Requirement
|
56
71
|
requirements:
|
57
|
-
- - "
|
72
|
+
- - "~>"
|
58
73
|
- !ruby/object:Gem::Version
|
59
|
-
version: '
|
74
|
+
version: '3.8'
|
60
75
|
type: :development
|
61
76
|
prerelease: false
|
62
77
|
version_requirements: !ruby/object:Gem::Requirement
|
63
78
|
requirements:
|
64
|
-
- - "
|
79
|
+
- - "~>"
|
65
80
|
- !ruby/object:Gem::Version
|
66
|
-
version: '
|
81
|
+
version: '3.8'
|
67
82
|
- !ruby/object:Gem::Dependency
|
68
|
-
name:
|
83
|
+
name: rubocop
|
69
84
|
requirement: !ruby/object:Gem::Requirement
|
70
85
|
requirements:
|
71
|
-
- - "
|
86
|
+
- - "~>"
|
72
87
|
- !ruby/object:Gem::Version
|
73
|
-
version:
|
88
|
+
version: 0.88.0
|
74
89
|
type: :development
|
75
90
|
prerelease: false
|
76
91
|
version_requirements: !ruby/object:Gem::Requirement
|
77
92
|
requirements:
|
78
|
-
- - "
|
93
|
+
- - "~>"
|
79
94
|
- !ruby/object:Gem::Version
|
80
|
-
version:
|
95
|
+
version: 0.88.0
|
81
96
|
- !ruby/object:Gem::Dependency
|
82
|
-
name:
|
97
|
+
name: sqlite3
|
83
98
|
requirement: !ruby/object:Gem::Requirement
|
84
99
|
requirements:
|
85
|
-
- - "
|
100
|
+
- - "~>"
|
86
101
|
- !ruby/object:Gem::Version
|
87
|
-
version: '
|
102
|
+
version: '1.3'
|
88
103
|
type: :development
|
89
104
|
prerelease: false
|
90
105
|
version_requirements: !ruby/object:Gem::Requirement
|
91
106
|
requirements:
|
92
|
-
- - "
|
107
|
+
- - "~>"
|
93
108
|
- !ruby/object:Gem::Version
|
94
|
-
version: '
|
109
|
+
version: '1.3'
|
95
110
|
description: Multidb is an ActiveRecord extension for switching between multiple database
|
96
|
-
connections, such as
|
111
|
+
connections, such as primary/replica setups.
|
97
112
|
email:
|
98
113
|
- alex@bengler.no
|
114
|
+
- urkle@outoforder.cc
|
99
115
|
executables: []
|
100
116
|
extensions: []
|
101
117
|
extra_rdoc_files: []
|
102
118
|
files:
|
103
119
|
- ".gitignore"
|
120
|
+
- ".rubocop.yml"
|
104
121
|
- ".travis.yml"
|
105
122
|
- CHANGELOG.md
|
106
123
|
- Gemfile
|
@@ -124,7 +141,7 @@ files:
|
|
124
141
|
homepage: ''
|
125
142
|
licenses: []
|
126
143
|
metadata: {}
|
127
|
-
post_install_message:
|
144
|
+
post_install_message:
|
128
145
|
rdoc_options: []
|
129
146
|
require_paths:
|
130
147
|
- lib
|
@@ -132,7 +149,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
132
149
|
requirements:
|
133
150
|
- - ">="
|
134
151
|
- !ruby/object:Gem::Version
|
135
|
-
version:
|
152
|
+
version: 2.4.0
|
136
153
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
154
|
requirements:
|
138
155
|
- - ">="
|
@@ -140,10 +157,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
140
157
|
version: '0'
|
141
158
|
requirements: []
|
142
159
|
rubygems_version: 3.0.6
|
143
|
-
signing_key:
|
160
|
+
signing_key:
|
144
161
|
specification_version: 4
|
145
162
|
summary: Multidb is an ActiveRecord extension for switching between multiple database
|
146
|
-
connections, such as
|
163
|
+
connections, such as primary/replica setups.
|
147
164
|
test_files:
|
148
165
|
- spec/balancer_spec.rb
|
149
166
|
- spec/helpers.rb
|