octoball 0.1.3 → 0.1.6.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.
- checksums.yaml +4 -4
- data/.github/Gemfile +8 -0
- data/.github/workflows/rspec.yml +38 -0
- data/lib/octoball/association.rb +7 -0
- data/lib/octoball/connection_handling.rb +9 -7
- data/lib/octoball/log_subscriber.rb +5 -1
- data/lib/octoball/using_shard.rb +17 -0
- data/lib/octoball/version.rb +1 -1
- data/lib/octoball.rb +10 -24
- data/spec/octoball/model_spec.rb +4 -4
- data/spec/octoball/relation_proxy_spec.rb +14 -0
- data/spec/octoball/scope_proxy_spec.rb +4 -4
- metadata +9 -7
- data/.circleci/config.yml +0 -46
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 973c85322876fbc5cbe08b6500c6baa749d62c24cfa3903b33844de8db585250
|
4
|
+
data.tar.gz: 0a14fdace9ea1b64c14a6473d1b1064333058cf21e9ce52ebc267ec6b7a9a943
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a7d59a53be55e87dc67295f4116bad650ca0c9583bc23cdad34369d39d3aa173fd0f86b328c7aa989ab498f06627c996e9235e0b9e1ec35e5d1039b0d595412
|
7
|
+
data.tar.gz: faa9f389bb5277d3e094c7f9146aea3688ddeb639b489655c3f4ffce726c958e2c4b47dcd984dd33ea327d17bcb0d6eec4316cd778c82ead1287fe49cc2f9d11
|
data/.github/Gemfile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
name: rspec
|
2
|
+
on: push
|
3
|
+
jobs:
|
4
|
+
rspec:
|
5
|
+
runs-on: ubuntu-latest
|
6
|
+
services:
|
7
|
+
mysql:
|
8
|
+
image: mysql:5
|
9
|
+
ports:
|
10
|
+
- 3306:3306
|
11
|
+
env:
|
12
|
+
MYSQL_ALLOW_EMPTY_PASSWORD: yes
|
13
|
+
options: >-
|
14
|
+
--health-cmd "mysqladmin ping"
|
15
|
+
--health-interval 5s
|
16
|
+
--health-timeout 3s
|
17
|
+
strategy:
|
18
|
+
fail-fast: true
|
19
|
+
matrix:
|
20
|
+
ruby: ["2.7","3.0","3.1","3.2"]
|
21
|
+
env:
|
22
|
+
BUNDLE_GEMFILE: .github/Gemfile
|
23
|
+
MYSQL_HOST: 127.0.0.1
|
24
|
+
RAILS_ENV: test
|
25
|
+
steps:
|
26
|
+
- name: Checkout
|
27
|
+
uses: actions/checkout@v3
|
28
|
+
- name: Setup ruby
|
29
|
+
uses: ruby/setup-ruby@v1
|
30
|
+
with:
|
31
|
+
ruby-version: ${{ matrix.ruby }}
|
32
|
+
bundler-cache: true
|
33
|
+
- name: Install rake
|
34
|
+
run: gem install rake
|
35
|
+
- name: Setup database
|
36
|
+
run: bundle exec rake db:prepare
|
37
|
+
- name: run rspec
|
38
|
+
run: bundle exec rspec
|
data/lib/octoball/association.rb
CHANGED
@@ -5,6 +5,12 @@ class Octoball
|
|
5
5
|
attr_accessor :current_shard
|
6
6
|
end
|
7
7
|
|
8
|
+
module RelationProxyIsARelation
|
9
|
+
def ===(other)
|
10
|
+
other.is_a?(self)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
8
14
|
module ShardedCollectionAssociation
|
9
15
|
[:writer, :ids_reader, :ids_writer, :create, :create!,
|
10
16
|
:build, :include?, :load_target, :reload, :size, :select].each do |method|
|
@@ -71,6 +77,7 @@ class Octoball
|
|
71
77
|
end
|
72
78
|
|
73
79
|
::ActiveRecord::Relation.prepend(RelationCurrentShard)
|
80
|
+
::ActiveRecord::Relation.singleton_class.prepend(RelationProxyIsARelation)
|
74
81
|
::ActiveRecord::QueryMethods::WhereChain.prepend(RelationCurrentShard)
|
75
82
|
::ActiveRecord::Associations::CollectionAssociation.prepend(ShardedCollectionAssociation)
|
76
83
|
::ActiveRecord::Associations::CollectionProxy.singleton_class.prepend(ShardedCollectionProxyCreate)
|
@@ -4,13 +4,15 @@ class Octoball
|
|
4
4
|
module ConnectionHandlingAvoidAutoLoadProxy
|
5
5
|
private
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
7
|
+
if ActiveRecord.gem_version < Gem::Version.new('7.1.0')
|
8
|
+
def swap_connection_handler(handler, &blk)
|
9
|
+
old_handler, ActiveRecord::Base.connection_handler = ActiveRecord::Base.connection_handler, handler
|
10
|
+
return_value = yield
|
11
|
+
return_value.load if !return_value.respond_to?(:ar_relation) && return_value.is_a?(ActiveRecord::Relation)
|
12
|
+
return_value
|
13
|
+
ensure
|
14
|
+
ActiveRecord::Base.connection_handler = old_handler
|
15
|
+
end
|
14
16
|
end
|
15
17
|
end
|
16
18
|
|
@@ -12,7 +12,11 @@ class Octoball
|
|
12
12
|
private
|
13
13
|
|
14
14
|
def debug(progname = nil, &block)
|
15
|
-
|
15
|
+
if ActiveRecord.gem_version >= Gem::Version.new('7.1.0')
|
16
|
+
conn = current_shard ? color("[Shard: #{current_shard}]", ActiveSupport::LogSubscriber::GREEN, bold: true) : ''
|
17
|
+
else
|
18
|
+
conn = current_shard ? color("[Shard: #{current_shard}]", ActiveSupport::LogSubscriber::GREEN, true) : ''
|
19
|
+
end
|
16
20
|
super(conn + progname.to_s, &block)
|
17
21
|
end
|
18
22
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Octoball
|
2
|
+
def self.using(shard, &block)
|
3
|
+
ActiveRecord::Base.connected_to(role: current_role, shard: shard&.to_sym, &block)
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.current_role
|
7
|
+
ActiveRecord::Base.current_role || ActiveRecord::Base.writing_role
|
8
|
+
end
|
9
|
+
|
10
|
+
module UsingShard
|
11
|
+
def using(shard)
|
12
|
+
Octoball::RelationProxy.new(all, shard&.to_sym)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
::ActiveRecord::Base.singleton_class.prepend(UsingShard)
|
17
|
+
end
|
data/lib/octoball/version.rb
CHANGED
data/lib/octoball.rb
CHANGED
@@ -2,29 +2,15 @@
|
|
2
2
|
|
3
3
|
require 'active_record'
|
4
4
|
require 'octoball/version'
|
5
|
-
require 'octoball/relation_proxy'
|
6
|
-
require 'octoball/connection_adapters'
|
7
|
-
require 'octoball/connection_handling'
|
8
|
-
require 'octoball/current_shard_tracker'
|
9
|
-
require 'octoball/association'
|
10
|
-
require 'octoball/association_shard_check'
|
11
|
-
require 'octoball/persistence'
|
12
|
-
require 'octoball/log_subscriber'
|
13
5
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
def using(shard)
|
25
|
-
Octoball::RelationProxy.new(all, shard&.to_sym)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
::ActiveRecord::Base.singleton_class.prepend(UsingShard)
|
6
|
+
ActiveSupport.on_load(:active_record) do
|
7
|
+
require 'octoball/relation_proxy'
|
8
|
+
require 'octoball/connection_adapters'
|
9
|
+
require 'octoball/connection_handling'
|
10
|
+
require 'octoball/current_shard_tracker'
|
11
|
+
require 'octoball/association_shard_check'
|
12
|
+
require 'octoball/persistence'
|
13
|
+
require 'octoball/association'
|
14
|
+
require 'octoball/log_subscriber'
|
15
|
+
require 'octoball/using_shard'
|
30
16
|
end
|
data/spec/octoball/model_spec.rb
CHANGED
@@ -123,7 +123,7 @@ describe Octoball do
|
|
123
123
|
|
124
124
|
it 'should clean #current_shard from proxy when using execute' do
|
125
125
|
User.using(:canada).connection.execute('select * from users limit 1;')
|
126
|
-
expect(User.connection.current_shard).to eq(:
|
126
|
+
expect(User.connection.current_shard).to eq(:master)
|
127
127
|
end
|
128
128
|
|
129
129
|
it 'should allow scoping dynamically' do
|
@@ -264,7 +264,7 @@ describe Octoball do
|
|
264
264
|
|
265
265
|
describe 'AR basic methods' do
|
266
266
|
it 'connects_to' do
|
267
|
-
expect(CustomConnection.connection.current_database).to eq('
|
267
|
+
expect(CustomConnection.connection.current_database).to eq('octoball_shard_3')
|
268
268
|
end
|
269
269
|
|
270
270
|
it 'reuses parent model connection' do
|
@@ -590,7 +590,7 @@ describe Octoball do
|
|
590
590
|
describe 'custom connection' do
|
591
591
|
context 'by default' do
|
592
592
|
it 'with plain call should use custom connection' do
|
593
|
-
expect(CustomConnection.connection.current_database).to eq('
|
593
|
+
expect(CustomConnection.connection.current_database).to eq('octoball_shard_3')
|
594
594
|
end
|
595
595
|
|
596
596
|
it 'should use model-specific shard' do
|
@@ -618,7 +618,7 @@ describe Octoball do
|
|
618
618
|
CustomConnection.create(:value => 'custom value')
|
619
619
|
|
620
620
|
# This is what Rails, Sidekiq etc call--this normally handles all connection pools in the app
|
621
|
-
expect { ActiveRecord::Base.clear_active_connections! }
|
621
|
+
expect { ActiveRecord::Base.connection_handler.clear_active_connections! }
|
622
622
|
.to change { CustomConnection.connection_pool.active_connection? }
|
623
623
|
|
624
624
|
expect(CustomConnection.connection_pool.active_connection?).to be_falsey
|
@@ -52,6 +52,20 @@ describe Octoball::RelationProxy do
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
+
context 'when a relation is used in where clause' do
|
56
|
+
it 'specifies the scope without a shard' do
|
57
|
+
client = Client.where(id: @client.id)
|
58
|
+
items = Item.using(:canada).where(client: client)
|
59
|
+
expect(items.to_a).to eq(@client.items.to_a)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'specifies the scope with a shard' do
|
63
|
+
client = Client.using(:canada).where(id: @client.id)
|
64
|
+
items = Item.using(:canada).where(client: client)
|
65
|
+
expect(items.to_a).to eq(@client.items.to_a)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
55
69
|
context 'when comparing to other Relation objects' do
|
56
70
|
before :each do
|
57
71
|
@relation.reset
|
@@ -39,19 +39,19 @@ describe Octoball do
|
|
39
39
|
end
|
40
40
|
|
41
41
|
it 'allows multiple selection by string' do
|
42
|
-
expect(@evan.select('id, name').first.id).to be_a(
|
42
|
+
expect(@evan.select('id, name').first.id).to be_a(Integer)
|
43
43
|
end
|
44
44
|
|
45
45
|
it 'allows multiple selection by array' do
|
46
|
-
expect(@evan.select(%w(id name)).first.id).to be_a(
|
46
|
+
expect(@evan.select(%w(id name)).first.id).to be_a(Integer)
|
47
47
|
end
|
48
48
|
|
49
49
|
it 'allows multiple selection by symbol' do
|
50
|
-
expect(@evan.select(:id, :name).first.id).to be_a(
|
50
|
+
expect(@evan.select(:id, :name).first.id).to be_a(Integer)
|
51
51
|
end
|
52
52
|
|
53
53
|
it 'allows multiple selection by string and symbol' do
|
54
|
-
expect(@evan.select(:id, 'name').first.id).to be_a(
|
54
|
+
expect(@evan.select(:id, 'name').first.id).to be_a(Integer)
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: octoball
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tomoki Sekiyama
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-05-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -116,7 +116,8 @@ executables: []
|
|
116
116
|
extensions: []
|
117
117
|
extra_rdoc_files: []
|
118
118
|
files:
|
119
|
-
- ".
|
119
|
+
- ".github/Gemfile"
|
120
|
+
- ".github/workflows/rspec.yml"
|
120
121
|
- ".gitignore"
|
121
122
|
- Gemfile
|
122
123
|
- README.md
|
@@ -130,6 +131,7 @@ files:
|
|
130
131
|
- lib/octoball/log_subscriber.rb
|
131
132
|
- lib/octoball/persistence.rb
|
132
133
|
- lib/octoball/relation_proxy.rb
|
134
|
+
- lib/octoball/using_shard.rb
|
133
135
|
- lib/octoball/version.rb
|
134
136
|
- octoball.gemspec
|
135
137
|
- spec/migration/1_test_tables.rb
|
@@ -152,7 +154,7 @@ homepage: https://github.com/aktsk/octoball
|
|
152
154
|
licenses:
|
153
155
|
- MIT
|
154
156
|
metadata: {}
|
155
|
-
post_install_message:
|
157
|
+
post_install_message:
|
156
158
|
rdoc_options: []
|
157
159
|
require_paths:
|
158
160
|
- lib
|
@@ -167,8 +169,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
167
169
|
- !ruby/object:Gem::Version
|
168
170
|
version: '0'
|
169
171
|
requirements: []
|
170
|
-
rubygems_version: 3.1.
|
171
|
-
signing_key:
|
172
|
+
rubygems_version: 3.1.6
|
173
|
+
signing_key:
|
172
174
|
specification_version: 4
|
173
175
|
summary: Octopus-like Database Sharding Helper for ActiveRecord 6.1+
|
174
176
|
test_files: []
|
data/.circleci/config.yml
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
version: 2.1
|
2
|
-
|
3
|
-
executors:
|
4
|
-
ruby:
|
5
|
-
parameters:
|
6
|
-
version:
|
7
|
-
type: string
|
8
|
-
docker:
|
9
|
-
- image: circleci/ruby:<< parameters.version >>
|
10
|
-
- image: circleci/mysql:5
|
11
|
-
environment:
|
12
|
-
- RAILS_ENV: test
|
13
|
-
- MYSQL_HOST: 127.0.0.1
|
14
|
-
|
15
|
-
jobs:
|
16
|
-
rspec:
|
17
|
-
parameters:
|
18
|
-
version:
|
19
|
-
type: string
|
20
|
-
executor:
|
21
|
-
name: ruby
|
22
|
-
version: << parameters.version >>
|
23
|
-
steps:
|
24
|
-
- checkout
|
25
|
-
- run:
|
26
|
-
name: bundle install
|
27
|
-
command: |
|
28
|
-
gem update bundler
|
29
|
-
bundle config --local path vendor/bundle
|
30
|
-
bundle install --jobs=4 --retry=3
|
31
|
-
- run:
|
32
|
-
name: Setup databases
|
33
|
-
command: bundle exec rake db:prepare
|
34
|
-
- run:
|
35
|
-
name: Run tests
|
36
|
-
command: bundle exec rspec
|
37
|
-
|
38
|
-
workflows:
|
39
|
-
version: 2
|
40
|
-
rspecs:
|
41
|
-
jobs:
|
42
|
-
- rspec:
|
43
|
-
matrix:
|
44
|
-
parameters:
|
45
|
-
version:
|
46
|
-
- "2.7"
|