janus-ar 0.5.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +6 -2
- data/.github/workflows/publish.yml +20 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +7 -0
- data/Gemfile.lock +26 -1
- data/README.md +2 -1
- data/janus-ar.gemspec +9 -5
- data/lib/active_record/connection_adapters/janus_mysql2_adapter.rb +12 -7
- data/lib/janus/logging/subscriber.rb +1 -1
- data/lib/janus/version.rb +1 -1
- data/spec/lib/active_record/connection_adapters/janus_mysql_adapter_spec.rb +125 -0
- data/spec/spec_helper.rb +37 -0
- metadata +62 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c7f4d589060d390c2a1c0697cdde34bb36e92a4daed4ab477d8fa543de113ae1
|
4
|
+
data.tar.gz: dd3e5fc8957cc36e5a06684934b7a9e41f37b5f5a2c749c686e42d77d49a650b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 68e6fab5ad4a07f4b872f9ddd76d0c74847380d6a2f690d98646a7d2b2d9110eb4fb9a095b8f42bd7912aaeb0774e239bbd9a9cbef9c65fa9fb6e9a9b386b54e
|
7
|
+
data.tar.gz: df1f1b37c36dea944d5ce6c1f05080eb119461f0e180edd6dcdb63768bf1f16101644eebc41d302f46c414219fd5cf28cddf6c7a2e9a3ac0632b2cd46627e494
|
data/.github/workflows/ci.yml
CHANGED
@@ -19,8 +19,10 @@ jobs:
|
|
19
19
|
mysql:
|
20
20
|
image: mysql:5.7
|
21
21
|
env:
|
22
|
-
|
23
|
-
|
22
|
+
MYSQL_DATABASE: test
|
23
|
+
MYSQL_ROOT_PASSWORD: password
|
24
|
+
MYSQL_USER: primary
|
25
|
+
MYSQL_PASSWORD: primary_password
|
24
26
|
ports:
|
25
27
|
- 3306:3306
|
26
28
|
options: >-
|
@@ -34,6 +36,8 @@ jobs:
|
|
34
36
|
with:
|
35
37
|
ruby-version: ${{ matrix.ruby }}
|
36
38
|
bundler-cache: true
|
39
|
+
- run: |
|
40
|
+
mysql -u root -p${{ env.MYSQL_PASSWORD || 'password' }} -h 127.0.0.1 -e "CREATE USER 'replica'@'%' IDENTIFIED BY 'replica_password';GRANT SELECT ON test.* TO 'replica'@'%';FLUSH PRIVILEGES;"
|
37
41
|
- run: |
|
38
42
|
bundle exec rspec
|
39
43
|
env:
|
@@ -0,0 +1,20 @@
|
|
1
|
+
name: Publish GEM
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
tags:
|
6
|
+
- v*
|
7
|
+
jobs:
|
8
|
+
build:
|
9
|
+
runs-on: ubuntu-latest
|
10
|
+
|
11
|
+
steps:
|
12
|
+
- uses: actions/checkout@v3
|
13
|
+
|
14
|
+
- name: Release GEM
|
15
|
+
if: contains(github.ref, 'refs/tags/v')
|
16
|
+
uses: cadwallion/publish-rubygems-action@master
|
17
|
+
env:
|
18
|
+
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
19
|
+
RUBYGEMS_API_KEY: ${{secrets.RUBYGEMS_API_KEY}}
|
20
|
+
RELEASE_COMMAND: gem build && gem push janus-ar-*.gem
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
inherit_from:
|
2
|
+
- https://tech.olioex.com/.support/rubocop-styling-v1.0
|
3
|
+
|
1
4
|
require:
|
2
5
|
- rubocop-rails
|
3
6
|
|
@@ -11,5 +14,9 @@ Metrics/BlockLength:
|
|
11
14
|
Exclude:
|
12
15
|
- spec/**/*
|
13
16
|
|
17
|
+
Style/GlobalVars:
|
18
|
+
Exclude:
|
19
|
+
- 'spec/**/*'
|
20
|
+
|
14
21
|
Metrics/AbcSize:
|
15
22
|
Max: 22
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
janus-ar (0.
|
4
|
+
janus-ar (0.7.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: http://rubygems.org/
|
@@ -25,6 +25,7 @@ GEM
|
|
25
25
|
ast (2.4.2)
|
26
26
|
base64 (0.2.0)
|
27
27
|
bigdecimal (3.1.7)
|
28
|
+
coderay (1.1.3)
|
28
29
|
concurrent-ruby (1.2.3)
|
29
30
|
connection_pool (2.4.1)
|
30
31
|
diff-lcs (1.5.1)
|
@@ -33,6 +34,7 @@ GEM
|
|
33
34
|
concurrent-ruby (~> 1.0)
|
34
35
|
json (2.7.2)
|
35
36
|
language_server-protocol (3.17.0.3)
|
37
|
+
method_source (1.0.0)
|
36
38
|
minitest (5.22.3)
|
37
39
|
mutex_m (0.2.0)
|
38
40
|
mysql2 (0.5.6)
|
@@ -40,6 +42,9 @@ GEM
|
|
40
42
|
parser (3.3.0.5)
|
41
43
|
ast (~> 2.4.1)
|
42
44
|
racc
|
45
|
+
pry (0.14.2)
|
46
|
+
coderay (~> 1.1)
|
47
|
+
method_source (~> 1.0)
|
43
48
|
racc (1.7.3)
|
44
49
|
rack (3.0.10)
|
45
50
|
rainbow (3.1.1)
|
@@ -72,11 +77,27 @@ GEM
|
|
72
77
|
unicode-display_width (>= 2.4.0, < 3.0)
|
73
78
|
rubocop-ast (1.31.2)
|
74
79
|
parser (>= 3.3.0.4)
|
80
|
+
rubocop-capybara (2.20.0)
|
81
|
+
rubocop (~> 1.41)
|
82
|
+
rubocop-factory_bot (2.25.1)
|
83
|
+
rubocop (~> 1.41)
|
84
|
+
rubocop-performance (1.21.0)
|
85
|
+
rubocop (>= 1.48.1, < 2.0)
|
86
|
+
rubocop-ast (>= 1.31.1, < 2.0)
|
75
87
|
rubocop-rails (2.24.1)
|
76
88
|
activesupport (>= 4.2.0)
|
77
89
|
rack (>= 1.1)
|
78
90
|
rubocop (>= 1.33.0, < 2.0)
|
79
91
|
rubocop-ast (>= 1.31.1, < 2.0)
|
92
|
+
rubocop-rspec (2.29.1)
|
93
|
+
rubocop (~> 1.40)
|
94
|
+
rubocop-capybara (~> 2.17)
|
95
|
+
rubocop-factory_bot (~> 2.22)
|
96
|
+
rubocop-rspec_rails (~> 2.28)
|
97
|
+
rubocop-rspec_rails (2.28.3)
|
98
|
+
rubocop (~> 1.40)
|
99
|
+
rubocop-thread_safety (0.5.1)
|
100
|
+
rubocop (>= 0.90.0)
|
80
101
|
ruby-progressbar (1.13.0)
|
81
102
|
timeout (0.4.1)
|
82
103
|
tzinfo (2.0.6)
|
@@ -92,10 +113,14 @@ DEPENDENCIES
|
|
92
113
|
activesupport (>= 7.1.0)
|
93
114
|
janus-ar!
|
94
115
|
mysql2
|
116
|
+
pry
|
95
117
|
rake
|
96
118
|
rspec (~> 3)
|
97
119
|
rubocop (~> 1.63.0)
|
120
|
+
rubocop-performance
|
98
121
|
rubocop-rails (~> 2.24.0)
|
122
|
+
rubocop-rspec
|
123
|
+
rubocop-thread_safety
|
99
124
|
|
100
125
|
BUNDLED WITH
|
101
126
|
2.4.22
|
data/README.md
CHANGED
@@ -6,7 +6,8 @@
|
|
6
6
|
style="float: left; margin: 0 auto; height: 500px;" />
|
7
7
|
</p>
|
8
8
|
|
9
|
-
![
|
9
|
+
[![CI](https://github.com/OLIOEX/janus-ar/actions/workflows/ci.yml/badge.svg)](https://github.com/OLIOEX/janus-ar/actions/workflows/ci.yml)
|
10
|
+
[![Gem Version](https://badge.fury.io/rb/janus-ar.svg)](https://badge.fury.io/rb/janus-ar)
|
10
11
|
|
11
12
|
> In ancient Roman religion and myth, Janus (/ˈdʒeɪnəs/ JAY-nəs; Latin: Ianvs [ˈi̯aːnʊs]) is the god of beginnings, gates, transitions, time, duality, doorways,[2] passages, frames, and endings. [(wikipedia)](https://en.wikipedia.org/wiki/Janus)
|
12
13
|
|
data/janus-ar.gemspec
CHANGED
@@ -5,18 +5,18 @@ require File.expand_path('lib/janus/version.rb', __dir__)
|
|
5
5
|
Gem::Specification.new do |gem|
|
6
6
|
gem.authors = ['Lloyd Watkin']
|
7
7
|
gem.email = ['lloyd@olioex.com']
|
8
|
-
gem.description = 'Read/Write proxy for ActiveRecord using primary/
|
9
|
-
gem.summary = 'Read/Write proxy for ActiveRecord using primary/
|
8
|
+
gem.description = 'Read/Write proxy for ActiveRecord using primary/replica databases'
|
9
|
+
gem.summary = 'Read/Write proxy for ActiveRecord using primary/replica databases'
|
10
10
|
gem.homepage = 'https://github.com/olioex/janus-ar'
|
11
|
-
gem.licenses =
|
11
|
+
gem.licenses = %w(MIT)
|
12
12
|
gem.metadata = {
|
13
|
-
'source_code_uri' => 'https://github.com/olioex/janus-ar'
|
13
|
+
'source_code_uri' => 'https://github.com/olioex/janus-ar',
|
14
14
|
}
|
15
15
|
|
16
16
|
gem.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
|
17
17
|
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
18
18
|
gem.name = 'janus-ar'
|
19
|
-
gem.require_paths =
|
19
|
+
gem.require_paths = %w(lib)
|
20
20
|
gem.version = Janus::VERSION
|
21
21
|
|
22
22
|
gem.required_ruby_version = '>= 3.2.0'
|
@@ -24,8 +24,12 @@ Gem::Specification.new do |gem|
|
|
24
24
|
gem.add_development_dependency 'activerecord', '>= 7.1.0'
|
25
25
|
gem.add_development_dependency 'activesupport', '>= 7.1.0'
|
26
26
|
gem.add_development_dependency 'mysql2'
|
27
|
+
gem.add_development_dependency 'pry'
|
27
28
|
gem.add_development_dependency 'rake'
|
28
29
|
gem.add_development_dependency 'rspec', '~> 3'
|
29
30
|
gem.add_development_dependency 'rubocop', '~> 1.63.0'
|
30
31
|
gem.add_development_dependency 'rubocop-rails', '~> 2.24.0'
|
32
|
+
gem.add_development_dependency 'rubocop-rspec'
|
33
|
+
gem.add_development_dependency 'rubocop-thread_safety'
|
34
|
+
gem.add_development_dependency 'rubocop-performance'
|
31
35
|
end
|
@@ -15,6 +15,7 @@ end
|
|
15
15
|
module ActiveRecord
|
16
16
|
module ConnectionAdapters
|
17
17
|
class JanusMysql2Adapter < ActiveRecord::ConnectionAdapters::Mysql2Adapter
|
18
|
+
FOUND_ROWS = 'FOUND_ROWS'
|
18
19
|
SQL_PRIMARY_MATCHERS = [
|
19
20
|
/\A\s*select.+for update\Z/i, /select.+lock in share mode\Z/i,
|
20
21
|
/\A\s*select.+(nextval|currval|lastval|get_lock|release_lock|pg_advisory_lock|pg_advisory_unlock)\(/i,
|
@@ -23,6 +24,9 @@ module ActiveRecord
|
|
23
24
|
SQL_REPLICA_MATCHERS = [/\A\s*(select|with.+\)\s*select)\s/i].freeze
|
24
25
|
SQL_ALL_MATCHERS = [/\A\s*set\s/i].freeze
|
25
26
|
SQL_SKIP_ALL_MATCHERS = [/\A\s*set\s+local\s/i].freeze
|
27
|
+
WRITE_PREFIXES = %w(INSERT UPDATE DELETE LOCK CREATE GRANT DROP).freeze
|
28
|
+
|
29
|
+
attr_reader :config
|
26
30
|
|
27
31
|
def initialize(*args)
|
28
32
|
args[0][:janus]['replica']['database'] = args[0][:database]
|
@@ -30,6 +34,7 @@ module ActiveRecord
|
|
30
34
|
|
31
35
|
@replica_config = args[0][:janus]['replica']
|
32
36
|
args[0] = args[0][:janus]['primary']
|
37
|
+
|
33
38
|
super(*args)
|
34
39
|
@connection_parameters ||= args[0]
|
35
40
|
update_config
|
@@ -48,7 +53,7 @@ module ActiveRecord
|
|
48
53
|
super(sql)
|
49
54
|
end
|
50
55
|
|
51
|
-
def execute_and_free(sql, name = nil, async: false)
|
56
|
+
def execute_and_free(sql, name = nil, async: false)
|
52
57
|
if should_send_to_all?(sql)
|
53
58
|
send_to_replica(sql, name, connection: :all)
|
54
59
|
return super(sql, name, async:)
|
@@ -81,6 +86,10 @@ module ActiveRecord
|
|
81
86
|
super
|
82
87
|
end
|
83
88
|
|
89
|
+
def replica_connection
|
90
|
+
@replica_connection ||= ActiveRecord::ConnectionAdapters::Mysql2Adapter.new(@replica_config)
|
91
|
+
end
|
92
|
+
|
84
93
|
private
|
85
94
|
|
86
95
|
def should_send_to_all?(sql)
|
@@ -108,18 +117,14 @@ module ActiveRecord
|
|
108
117
|
end
|
109
118
|
|
110
119
|
def write_query?(sql)
|
111
|
-
|
112
|
-
end
|
113
|
-
|
114
|
-
def replica_connection
|
115
|
-
@replica_connection ||= ActiveRecord::ConnectionAdapters::Mysql2Adapter.new(@replica_config)
|
120
|
+
WRITE_PREFIXES.include?(sql.split(' ').first)
|
116
121
|
end
|
117
122
|
|
118
123
|
def update_config
|
119
124
|
@config[:flags] ||= 0
|
120
125
|
|
121
126
|
if @config[:flags].is_a? Array
|
122
|
-
@config[:flags].push
|
127
|
+
@config[:flags].push FOUND_ROWS
|
123
128
|
else
|
124
129
|
@config[:flags] |= ::Mysql2::Client::FOUND_ROWS
|
125
130
|
end
|
data/lib/janus/version.rb
CHANGED
@@ -0,0 +1,125 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe ActiveRecord::ConnectionAdapters::JanusMysql2Adapter do
|
4
|
+
subject { described_class.new(config) }
|
5
|
+
|
6
|
+
it { expect(described_class::FOUND_ROWS).to eq 'FOUND_ROWS' }
|
7
|
+
it { expect(described_class::SQL_SKIP_ALL_MATCHERS).to eq [/\A\s*set\s+local\s/i] }
|
8
|
+
it {
|
9
|
+
expect(described_class::SQL_PRIMARY_MATCHERS).to eq(
|
10
|
+
[
|
11
|
+
/\A\s*select.+for update\Z/i, /select.+lock in share mode\Z/i,
|
12
|
+
/\A\s*select.+(nextval|currval|lastval|get_lock|release_lock|pg_advisory_lock|pg_advisory_unlock)\(/i,
|
13
|
+
/\A\s*show/i
|
14
|
+
]
|
15
|
+
)
|
16
|
+
}
|
17
|
+
it { expect(described_class::SQL_REPLICA_MATCHERS).to eq([/\A\s*(select|with.+\)\s*select)\s/i]) }
|
18
|
+
it { expect(described_class::SQL_ALL_MATCHERS).to eq([/\A\s*set\s/i]) }
|
19
|
+
it { expect(described_class::WRITE_PREFIXES).to eq %w(INSERT UPDATE DELETE LOCK CREATE GRANT DROP) }
|
20
|
+
|
21
|
+
let(:database) { 'test' }
|
22
|
+
let(:primary_config) do
|
23
|
+
{
|
24
|
+
'username' => 'primary',
|
25
|
+
'password' => 'primary_password',
|
26
|
+
'host' => '127.0.0.1',
|
27
|
+
}
|
28
|
+
end
|
29
|
+
let(:replica_config) do
|
30
|
+
{
|
31
|
+
'username' => 'replica',
|
32
|
+
'password' => 'replica_password',
|
33
|
+
'host' => '127.0.0.1',
|
34
|
+
'pool' => 500,
|
35
|
+
}
|
36
|
+
end
|
37
|
+
let(:config) do
|
38
|
+
{
|
39
|
+
database:,
|
40
|
+
adapter: 'janus_mysql2',
|
41
|
+
janus: {
|
42
|
+
'primary' => primary_config,
|
43
|
+
'replica' => replica_config,
|
44
|
+
},
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
describe 'Configuration' do
|
49
|
+
it 'creates primary connection as expected' do
|
50
|
+
config = primary_config.dup.freeze
|
51
|
+
expect(subject.config).to eq config.merge('database' => database,
|
52
|
+
'flags' => ::Mysql2::Client::FOUND_ROWS).symbolize_keys
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'creates replica connection as expected' do
|
56
|
+
config = replica_config.dup.freeze
|
57
|
+
expect(
|
58
|
+
subject.replica_connection.instance_variable_get(:@config)
|
59
|
+
).to eq config.merge('database' => database, 'flags' => ::Mysql2::Client::FOUND_ROWS).symbolize_keys
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'Rails sets empty database for server connection' do
|
63
|
+
let(:database) { nil }
|
64
|
+
|
65
|
+
it 'creates primary connection as expected' do
|
66
|
+
config = primary_config.dup.freeze
|
67
|
+
expect(subject.config).to eq config.merge(
|
68
|
+
'database' => nil,
|
69
|
+
'flags' => ::Mysql2::Client::FOUND_ROWS
|
70
|
+
).symbolize_keys
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'creates replica connection as expected' do
|
74
|
+
config = replica_config.dup.freeze
|
75
|
+
expect(
|
76
|
+
subject.replica_connection.instance_variable_get(:@config)
|
77
|
+
).to eq config.merge('database' => nil, 'flags' => ::Mysql2::Client::FOUND_ROWS).symbolize_keys
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe 'Integration tests' do
|
83
|
+
let(:create_test_table) { ActiveRecord::Base.connection.execute('CREATE TABLE test_table (id INT);') }
|
84
|
+
|
85
|
+
before(:each) do
|
86
|
+
$query_logger.flush_all
|
87
|
+
ActiveRecord::Base.establish_connection(config)
|
88
|
+
end
|
89
|
+
|
90
|
+
after(:each) do
|
91
|
+
ActiveRecord::Base.connection.execute(<<-SQL
|
92
|
+
SELECT CONCAT('DROP TABLE IF EXISTS `', table_name, '`;')
|
93
|
+
FROM information_schema.tables
|
94
|
+
WHERE table_schema = '#{database}';
|
95
|
+
SQL
|
96
|
+
).to_a.map { |row| ActiveRecord::Base.connection.execute(row[0]) }
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'can list tables' do
|
100
|
+
expect(ActiveRecord::Base.connection.execute('SHOW TABLES;').to_a).to eq []
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'can create table' do
|
104
|
+
create_test_table
|
105
|
+
expect(ActiveRecord::Base.connection.execute('SHOW TABLES;').to_a).to eq [%w(test_table)]
|
106
|
+
end
|
107
|
+
|
108
|
+
describe 'SELECT' do
|
109
|
+
it 'reads from `replica` by default' do
|
110
|
+
create_test_table
|
111
|
+
Janus::Context.release_all
|
112
|
+
$query_logger.flush_all
|
113
|
+
ActiveRecord::Base.connection.execute('SELECT * FROM test_table;')
|
114
|
+
expect($query_logger.queries.first).to include '[replica]'
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'will read from primary after a write operation' do
|
118
|
+
create_test_table
|
119
|
+
$query_logger.flush_all
|
120
|
+
ActiveRecord::Base.connection.execute('SELECT * FROM test_table;')
|
121
|
+
expect($query_logger.queries.first).to include '[primary]'
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,3 +1,40 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'pry'
|
4
|
+
|
5
|
+
require 'active_record'
|
6
|
+
|
3
7
|
require './lib/janus'
|
8
|
+
require './lib/active_record/connection_adapters/janus_mysql2_adapter'
|
9
|
+
|
10
|
+
class QueryLogger
|
11
|
+
def initialize
|
12
|
+
@_logs = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def flush_all
|
16
|
+
@_logs = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def log(level, message)
|
20
|
+
@_logs << "#{level}: #{message}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def error(message)
|
24
|
+
log('error', message)
|
25
|
+
end
|
26
|
+
|
27
|
+
def queries
|
28
|
+
@_logs
|
29
|
+
end
|
30
|
+
|
31
|
+
def debug?
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
def debug(message)
|
36
|
+
log('debug', message)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
$query_logger = ActiveRecord::Base.logger = QueryLogger.new
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: janus-ar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lloyd Watkin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-04-
|
11
|
+
date: 2024-04-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: rake
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,7 +122,49 @@ dependencies:
|
|
108
122
|
- - "~>"
|
109
123
|
- !ruby/object:Gem::Version
|
110
124
|
version: 2.24.0
|
111
|
-
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rubocop-rspec
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rubocop-thread_safety
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: rubocop-performance
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
description: Read/Write proxy for ActiveRecord using primary/replica databases
|
112
168
|
email:
|
113
169
|
- lloyd@olioex.com
|
114
170
|
executables: []
|
@@ -117,6 +173,7 @@ extra_rdoc_files: []
|
|
117
173
|
files:
|
118
174
|
- ".github/dependabot.yml"
|
119
175
|
- ".github/workflows/ci.yml"
|
176
|
+
- ".github/workflows/publish.yml"
|
120
177
|
- ".gitignore"
|
121
178
|
- ".rspec"
|
122
179
|
- ".rubocop.yml"
|
@@ -134,6 +191,7 @@ files:
|
|
134
191
|
- lib/janus/logging/logger.rb
|
135
192
|
- lib/janus/logging/subscriber.rb
|
136
193
|
- lib/janus/version.rb
|
194
|
+
- spec/lib/active_record/connection_adapters/janus_mysql_adapter_spec.rb
|
137
195
|
- spec/lib/janus/context_spec.rb
|
138
196
|
- spec/lib/janus/logging/logger_spec.rb
|
139
197
|
- spec/spec_helper.rb
|
@@ -160,5 +218,5 @@ requirements: []
|
|
160
218
|
rubygems_version: 3.5.7
|
161
219
|
signing_key:
|
162
220
|
specification_version: 4
|
163
|
-
summary: Read/Write proxy for ActiveRecord using primary/
|
221
|
+
summary: Read/Write proxy for ActiveRecord using primary/replica databases
|
164
222
|
test_files: []
|