janus-ar 8.0.1 → 8.1.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -3
  3. data/Gemfile.lock +27 -24
  4. data/README.md +69 -3
  5. data/Rakefile +0 -2
  6. data/janus-ar.gemspec +7 -6
  7. data/lib/janus-ar/active_record/connection_adapters/janus_mysql2_adapter.rb +0 -2
  8. data/lib/janus-ar/active_record/connection_adapters/janus_postgresql_adapter.rb +42 -0
  9. data/lib/janus-ar/active_record/connection_adapters/janus_trilogy_adapter.rb +0 -2
  10. data/lib/janus-ar/adapter_extensions.rb +21 -6
  11. data/lib/janus-ar/client.rb +5 -6
  12. data/lib/janus-ar/context.rb +0 -2
  13. data/lib/janus-ar/db_console_config.rb +15 -17
  14. data/lib/janus-ar/logging/logger.rb +13 -15
  15. data/lib/janus-ar/logging/subscriber.rb +25 -27
  16. data/lib/janus-ar/query_director.rb +15 -4
  17. data/lib/janus-ar/railtie.rb +0 -2
  18. data/lib/janus-ar/version.rb +1 -3
  19. data/lib/janus-ar.rb +0 -2
  20. metadata +23 -31
  21. data/.bundle/config +0 -5
  22. data/.github/dependabot.yml +0 -7
  23. data/.github/workflows/ci.yml +0 -68
  24. data/.github/workflows/publish.yml +0 -25
  25. data/.gitignore +0 -3
  26. data/.rspec +0 -3
  27. data/.rubocop.yml +0 -29
  28. data/assets/.gitkeep +0 -1
  29. data/assets/janus-logo.png +0 -0
  30. data/bin/release.sh +0 -4
  31. data/gemfiles/activerecord_8_0.gemfile +0 -7
  32. data/gemfiles/activerecord_8_1.gemfile +0 -7
  33. data/spec/lib/janus-ar/active_record/connection_adapters/janus_mysql_adapter_spec.rb +0 -78
  34. data/spec/lib/janus-ar/active_record/connection_adapters/janus_trilogy_adapter_spec.rb +0 -77
  35. data/spec/lib/janus-ar/client_spec.rb +0 -7
  36. data/spec/lib/janus-ar/context_spec.rb +0 -118
  37. data/spec/lib/janus-ar/db_console_config_spec.rb +0 -28
  38. data/spec/lib/janus-ar/logging/logger_spec.rb +0 -31
  39. data/spec/lib/janus-ar/logging/subscriber_spec.rb +0 -58
  40. data/spec/lib/janus-ar/query_director_spec.rb +0 -141
  41. data/spec/shared_examples/a_mysql_like_server.rb +0 -155
  42. data/spec/spec_helper.rb +0 -46
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 192027338ca77fe74dcf3d4ce10209514d57518e55be909c7d7fdf18c6bfcd44
4
- data.tar.gz: 7d9cb1c366f05c08c19f07a6435673ddbbe8bc9ae07ab495e2f9901973ea932d
3
+ metadata.gz: 1720a88365b20f91d220065128ca260baf91380779a7a1d9a6f9aa8fffc13ae8
4
+ data.tar.gz: 2987d7e690b1038946a489a80df29917a192c1a07b85bc16932fb0bf8c2df531
5
5
  SHA512:
6
- metadata.gz: 6325a5fde59fc041a93182f97d294025a614e99ea974a9a018996af67895fcd28e1f9f156cebffe2366725b37fafca55b11d846dd7fe7ab4a1bd07c369d406f5
7
- data.tar.gz: 1eea960641c63b5ba76e4fe285de967d04e79fea4e5de8eaeeffc082c97596dfcb9c3f0cb4e6524b452b59a8a4df8fc50ae2537c56561880c98f233502e34dc0
6
+ metadata.gz: ae79f4f2c54ea96d6191a2b7597982a558027ed911d894e66bbb205041d2339e0b33bb9004ac8331162c2766ac91c922f1ebd11e125ecd18e2f30db8b8cf173c
7
+ data.tar.gz: 1224b98a5c03641329d47f1eee868247141cfd6299f98a1f364aed01bef7eb4c3897c4a1e3675734a04aabde3b4ca8165ddb58fe07f36c4f97691c8fcec89e17
data/Gemfile CHANGED
@@ -1,4 +1,2 @@
1
- # frozen_string_literal: true
2
-
3
- source 'http://rubygems.org'
1
+ source 'https://rubygems.org'
4
2
  gemspec
data/Gemfile.lock CHANGED
@@ -1,19 +1,19 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- janus-ar (8.0.0)
4
+ janus-ar (8.1.1)
5
5
  activerecord (>= 8.0, < 9.0)
6
6
 
7
7
  GEM
8
- remote: http://rubygems.org/
8
+ remote: https://rubygems.org/
9
9
  specs:
10
- activemodel (8.1.3)
11
- activesupport (= 8.1.3)
12
- activerecord (8.1.3)
13
- activemodel (= 8.1.3)
14
- activesupport (= 8.1.3)
10
+ activemodel (8.1.3.1)
11
+ activesupport (= 8.1.3.1)
12
+ activerecord (8.1.3.1)
13
+ activemodel (= 8.1.3.1)
14
+ activesupport (= 8.1.3.1)
15
15
  timeout (>= 0.4.0)
16
- activesupport (8.1.3)
16
+ activesupport (8.1.3.1)
17
17
  base64
18
18
  bigdecimal
19
19
  concurrent-ruby (~> 1.0, >= 1.3.1)
@@ -30,15 +30,15 @@ GEM
30
30
  base64 (0.3.0)
31
31
  bigdecimal (4.1.2)
32
32
  coderay (1.1.3)
33
- concurrent-ruby (1.3.6)
33
+ concurrent-ruby (1.3.8)
34
34
  connection_pool (3.0.2)
35
35
  diff-lcs (1.6.2)
36
36
  drb (2.2.3)
37
- i18n (1.14.8)
37
+ i18n (1.15.2)
38
38
  concurrent-ruby (~> 1.0)
39
39
  io-console (0.8.2)
40
- json (2.19.9)
41
- language_server-protocol (3.17.0.5)
40
+ json (2.21.2)
41
+ language_server-protocol (3.17.0.6)
42
42
  lint_roller (1.1.0)
43
43
  logger (1.7.0)
44
44
  method_source (1.1.0)
@@ -48,16 +48,18 @@ GEM
48
48
  mysql2 (0.5.7)
49
49
  bigdecimal
50
50
  parallel (1.28.0)
51
- parser (3.3.11.1)
51
+ parser (3.3.12.0)
52
52
  ast (~> 2.4.1)
53
53
  racc
54
+ pg (1.6.3-arm64-darwin)
55
+ pg (1.6.3-x86_64-linux)
54
56
  prism (1.9.0)
55
57
  pry (0.16.0)
56
58
  coderay (~> 1.1)
57
59
  method_source (~> 1.0)
58
60
  reline (>= 0.6.0)
59
61
  racc (1.8.1)
60
- rack (3.2.6)
62
+ rack (3.2.7)
61
63
  rainbow (3.1.1)
62
64
  rake (13.4.2)
63
65
  regexp_parser (2.12.0)
@@ -76,8 +78,8 @@ GEM
76
78
  diff-lcs (>= 1.2.0, < 2.0)
77
79
  rspec-support (~> 3.13.0)
78
80
  rspec-support (3.13.7)
79
- rubocop (1.88.0)
80
- json (~> 2.3)
81
+ rubocop (1.90.0)
82
+ json (>= 2.3)
81
83
  language_server-protocol (~> 3.17.0.2)
82
84
  lint_roller (~> 1.1.0)
83
85
  parallel (>= 1.10)
@@ -87,18 +89,18 @@ GEM
87
89
  rubocop-ast (>= 1.49.0, < 2.0)
88
90
  ruby-progressbar (~> 1.7)
89
91
  unicode-display_width (>= 2.4.0, < 4.0)
90
- rubocop-ast (1.49.1)
92
+ rubocop-ast (1.50.0)
91
93
  parser (>= 3.3.7.2)
92
94
  prism (~> 1.7)
93
- rubocop-performance (1.26.1)
95
+ rubocop-performance (1.27.0)
94
96
  lint_roller (~> 1.1)
95
- rubocop (>= 1.75.0, < 2.0)
97
+ rubocop (>= 1.89.0, < 2.0)
96
98
  rubocop-ast (>= 1.47.1, < 2.0)
97
- rubocop-rails (2.35.4)
99
+ rubocop-rails (2.37.0)
98
100
  activesupport (>= 4.2.0)
99
101
  lint_roller (~> 1.1)
100
102
  rack (>= 1.1)
101
- rubocop (>= 1.75.0, < 2.0)
103
+ rubocop (>= 1.89.0, < 2.0)
102
104
  rubocop-ast (>= 1.44.0, < 2.0)
103
105
  rubocop-rspec (3.10.2)
104
106
  lint_roller (~> 1.1)
@@ -111,7 +113,7 @@ GEM
111
113
  ruby-progressbar (1.13.0)
112
114
  securerandom (0.4.1)
113
115
  timeout (0.6.1)
114
- trilogy (2.12.5)
116
+ trilogy (2.13.0)
115
117
  bigdecimal
116
118
  tzinfo (2.0.6)
117
119
  concurrent-ruby (~> 1.0)
@@ -128,12 +130,13 @@ DEPENDENCIES
128
130
  activesupport (>= 8.0)
129
131
  janus-ar!
130
132
  mysql2
133
+ pg
131
134
  pry
132
135
  rake
133
136
  rspec (~> 3)
134
- rubocop (~> 1.88.0)
137
+ rubocop (~> 1.90.0)
135
138
  rubocop-performance
136
- rubocop-rails (~> 2.35.2)
139
+ rubocop-rails (~> 2.37.0)
137
140
  rubocop-rspec
138
141
  rubocop-thread_safety
139
142
  trilogy
data/README.md CHANGED
@@ -11,13 +11,13 @@
11
11
  [![CI](https://github.com/OLIOEX/janus-ar/actions/workflows/ci.yml/badge.svg)](https://github.com/OLIOEX/janus-ar/actions/workflows/ci.yml)
12
12
  [![Gem Version](https://badge.fury.io/rb/janus-ar.svg)](https://badge.fury.io/rb/janus-ar)
13
13
 
14
- Janus ActiveRecord is a generic primary/replica proxy for ActiveRecord 8 and MySQL (via `mysql2` and `trilogy`). It handles the switching of connections between primary and replica database servers. It comes with an ActiveRecord database adapter implementation.
14
+ Janus ActiveRecord is a generic primary/replica proxy for ActiveRecord 8, supporting MySQL (via `mysql2` and `trilogy`) and PostgreSQL (via `pg`). It handles the switching of connections between primary and replica database servers. It comes with an ActiveRecord database adapter implementation.
15
15
 
16
16
  Janus is heavily inspired by [Makara](https://github.com/instacart/makara) from TaskRabbit and then Instacart. Unfortunately this project is unmaintained and broke for us with Rails 7.1. This is an attempt to start afresh on the project. It is definitely not as fully featured as Makara at this stage.
17
17
 
18
18
  Learn more about its origins: [https://tech.olioex.com/ruby/2024/04/16/introducing-janus.html](https://tech.olioex.com/ruby/2024/04/16/introducing-janus.html).
19
19
 
20
- Notes: the gem requires ActiveRecord `>= 8.0, < 9.0` and Ruby `>= 3.2`, and is tested against MySQL 8.
20
+ Notes: the gem requires ActiveRecord `>= 8.0, < 9.0` and Ruby `>= 3.2`, and is tested against MySQL 8 and PostgreSQL 16 and 17.
21
21
 
22
22
  ## Installation
23
23
 
@@ -45,6 +45,8 @@ require 'rails/all'
45
45
  ActiveRecord::ConnectionAdapters.register("janus_trilogy", "ActiveRecord::ConnectionAdapters::JanusTrilogyAdapter", 'janus-ar/active_record/connection_adapters/janus_trilogy_adapter')
46
46
  # ...or...
47
47
  ActiveRecord::ConnectionAdapters.register("janus_mysql2", "ActiveRecord::ConnectionAdapters::JanusMysql2Adapter", 'janus-ar/active_record/connection_adapters/janus_mysql2_adapter')
48
+ # ...or...
49
+ ActiveRecord::ConnectionAdapters.register("janus_postgresql", "ActiveRecord::ConnectionAdapters::JanusPostgreSQLAdapter", 'janus-ar/active_record/connection_adapters/janus_postgresql_adapter')
48
50
  ```
49
51
 
50
52
  #### Rails <= 7.1
@@ -81,6 +83,45 @@ Note: For `trilogy` please use adapter "janus_trilogy". You'll probably need to
81
83
  Otherwise you will get an error like the following (see https://github.com/trilogy-libraries/trilogy/issues/26):
82
84
  > trilogy_auth_recv: caching_sha2_password requires either TCP with TLS or a unix socket: TRILOGY_UNSUPPORTED"
83
85
 
86
+ #### PostgreSQL
87
+
88
+ Use adapter `janus_postgresql`, and add the `pg` gem to your `Gemfile`:
89
+
90
+ ```yml
91
+ development:
92
+ adapter: janus_postgresql
93
+ database: database_name
94
+ janus:
95
+ primary:
96
+ <<: *default
97
+ host: primary-host.local
98
+ username: app
99
+ password: primary_password
100
+ replica:
101
+ <<: *default
102
+ host: replica-host.local
103
+ username: app_readonly
104
+ password: replica_password
105
+ ```
106
+
107
+ Anything the adapter reads out of its own configuration — `pool`, `prepared_statements`,
108
+ `insert_returning`, `variables`, `schema_search_path`, SSL settings and so on — must go
109
+ inside the `primary:` and `replica:` blocks rather than alongside `adapter:`, because each
110
+ connection is built from its own block.
111
+
112
+ Two things worth knowing about the PostgreSQL adapter specifically:
113
+
114
+ * Unlike MySQL, PostgreSQL never inlines bind values into the statement: reads
115
+ reach the replica as `$1` placeholders plus a separate parameter list, and
116
+ prepared statements are cached per connection. The adapter forwards binds and
117
+ the prepare flag to the replica, so each connection maintains its own
118
+ statement cache.
119
+ * Type OIDs are resolved against whichever connection served the lookup. This is
120
+ correct for a physical (streaming) replica, where OIDs are identical to the
121
+ primary's by construction. If you point Janus at a logical replica whose custom
122
+ types, enums or extensions were created independently, the OIDs can diverge and
123
+ results may be cast with the wrong type.
124
+
84
125
  ### Forcing connections
85
126
 
86
127
  A context is local to the current unit of work (thread or fiber, following ActiveRecord's configured isolation level). This allows you to stick to the primary safely within a single request or job, in systems such as Sidekiq for instance.
@@ -119,7 +160,9 @@ There are some edge cases:
119
160
  * `SET` operations will be sent to all connections
120
161
  * Execution of specific methods such as `connect!`, `disconnect!`, `reconnect!`, and `clear_cache!` are invoked on all underlying connections
121
162
  * Calls inside a transaction will always be sent to the primary (otherwise changes from within the transaction could not be read back on most transaction isolation levels)
122
- * Locking reads (e.g. `SELECT ... FOR UPDATE`) will always be sent to the primary
163
+ * Locking reads (e.g. `SELECT ... FOR UPDATE`, `FOR UPDATE SKIP LOCKED`, `FOR SHARE`, `FOR NO KEY UPDATE`, `FOR KEY SHARE`, `LOCK IN SHARE MODE`) will always be sent to the primary
164
+ * So will reads that call a locking or sequence function — `GET_LOCK(...)`, `IS_FREE_LOCK(...)`, `nextval(...)`, `setval(...)` and PostgreSQL's advisory lock family (`pg_advisory_lock`, `pg_try_advisory_xact_lock_shared`, `pg_advisory_unlock_all`, and so on)
165
+ * PostgreSQL cursor statements (`DECLARE`, `FETCH`, `MOVE`, `CLOSE`) go to the primary, so a cursor is always fetched on the connection that declared it
123
166
 
124
167
  # Notes
125
168
 
@@ -128,3 +171,26 @@ Janus does not support Rails' read/write split or sharding using `with_connectio
128
171
  # Acknowlegements
129
172
 
130
173
  Amazing project logo by @undevelopedbruce.
174
+
175
+ ## Releasing
176
+
177
+ Releases are cut from the [GitHub Releases UI](https://github.com/OLIOEX/janus-ar/releases/new).
178
+ Publishing to RubyGems is automatic — there is nothing to bump by hand, and no
179
+ API key to rotate (authentication uses RubyGems
180
+ [trusted publishing](https://guides.rubygems.org/trusted-publishing/) over OIDC).
181
+
182
+ To release:
183
+
184
+ 1. Create a new release against the head of `main`, with a tag named
185
+ `vMAJOR.MINOR.PATCH` — e.g. `v8.1.0`. Pre-release suffixes use a dot, as
186
+ RubyGems requires: `v8.1.0.rc1`, not `v8.1.0-rc1`.
187
+ 2. Publish it.
188
+
189
+ [`.github/workflows/publish.yml`](.github/workflows/publish.yml) then takes the
190
+ version from the tag, writes it into `lib/janus-ar/version.rb`, refreshes
191
+ `Gemfile.lock`, commits that bump to `main` as `Release vX.Y.Z`, moves the tag
192
+ onto that commit, and pushes the gem.
193
+
194
+ Because the bump is committed to `main`, releases must be created from its head
195
+ — the workflow refuses to publish if the tag sits anywhere else. You never need
196
+ to edit `version.rb` yourself; the tag is the source of truth.
data/Rakefile CHANGED
@@ -1,3 +1 @@
1
- # frozen_string_literal: true
2
-
3
1
  require 'bundler/gem_tasks'
data/janus-ar.gemspec CHANGED
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  require File.expand_path('lib/janus-ar/version.rb', __dir__)
4
2
 
5
3
  Gem::Specification.new do |gem|
@@ -13,8 +11,10 @@ Gem::Specification.new do |gem|
13
11
  'source_code_uri' => 'https://github.com/olioex/janus-ar',
14
12
  }
15
13
 
16
- gem.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
17
- gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
14
+ ignored = %r{^(bin|spec|assets|gemfiles|\.github)/|^\.}
15
+ gem.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR).grep_v(ignored)
16
+ # The gem ships no executables; bin/ holds repository maintenance scripts.
17
+ gem.executables = []
18
18
  gem.name = 'janus-ar'
19
19
  gem.require_paths = %w(lib)
20
20
  gem.version = Janus::VERSION
@@ -24,12 +24,13 @@ Gem::Specification.new do |gem|
24
24
  gem.add_dependency 'activerecord', '>= 8.0', '< 9.0'
25
25
  gem.add_development_dependency 'activesupport', '>= 8.0'
26
26
  gem.add_development_dependency 'mysql2'
27
+ gem.add_development_dependency 'pg'
27
28
  gem.add_development_dependency 'trilogy'
28
29
  gem.add_development_dependency 'pry'
29
30
  gem.add_development_dependency 'rake'
30
31
  gem.add_development_dependency 'rspec', '~> 3'
31
- gem.add_development_dependency 'rubocop', '~> 1.88.0'
32
- gem.add_development_dependency 'rubocop-rails', '~> 2.35.2'
32
+ gem.add_development_dependency 'rubocop', '~> 1.90.0'
33
+ gem.add_development_dependency 'rubocop-rails', '~> 2.37.0'
33
34
  gem.add_development_dependency 'rubocop-rspec'
34
35
  gem.add_development_dependency 'rubocop-thread_safety'
35
36
  gem.add_development_dependency 'rubocop-performance'
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  require 'active_record/connection_adapters/abstract_adapter'
4
2
  require 'active_record/connection_adapters/mysql2_adapter'
5
3
  require_relative '../../../janus-ar'
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_record/connection_adapters/abstract_adapter'
4
+ require 'active_record/connection_adapters/postgresql_adapter'
5
+ require_relative '../../../janus-ar'
6
+ require_relative '../../adapter_extensions'
7
+
8
+ module ActiveRecord
9
+ module ConnectionHandling
10
+ def janus_postgresql_connection(config)
11
+ ActiveRecord::ConnectionAdapters::JanusPostgreSQLAdapter.new(config)
12
+ end
13
+ end
14
+
15
+ class Base
16
+ def self.janus_postgresql_adapter_class
17
+ ActiveRecord::ConnectionAdapters::JanusPostgreSQLAdapter
18
+ end
19
+ end
20
+
21
+ module ConnectionAdapters
22
+ class JanusPostgreSQLAdapter < ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
23
+ include Janus::AdapterExtensions
24
+
25
+ private
26
+
27
+ def replica_adapter_class
28
+ ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
29
+ end
30
+
31
+ # PostgreSQL compiles statements to `$1` placeholders and passes the values
32
+ # separately, so the replica needs the whole call, not just the SQL.
33
+ #
34
+ # `raw_execute` is private on a stock adapter, hence the `send`. It is the
35
+ # right target rather than the public `execute`: the statement has already
36
+ # been through `preprocess_query`, which we do not want applied twice.
37
+ def forward_raw_execute(sql, ...)
38
+ replica_connection.send(:raw_execute, sql, ...)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  require 'active_record/connection_adapters/abstract_adapter'
4
2
  require 'active_record/connection_adapters/trilogy_adapter'
5
3
  require_relative '../../../janus-ar'
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  module Janus
4
2
  # Behaviour shared by the Janus MySQL2 and Trilogy adapters.
5
3
  #
@@ -34,17 +32,17 @@ module Janus
34
32
  @connection_parameters ||= args[0]
35
33
  end
36
34
 
37
- # The argument lists below intentionally use anonymous splats and a bare
35
+ # The argument lists below intentionally use argument forwarding and a bare
38
36
  # `super`: ActiveRecord's `raw_execute`/`execute` signatures differ between
39
37
  # versions, so we forward whatever we are given unchanged rather than
40
38
  # restating (and pinning ourselves to) the current signature.
41
- def raw_execute(sql, *, **)
39
+ def raw_execute(sql, ...)
42
40
  case where_to_send?(sql)
43
41
  when :all
44
- send_to_replica(sql, :all)
42
+ send_raw_to_replica(sql, :all, ...)
45
43
  super
46
44
  when :replica
47
- send_to_replica(sql, :replica)
45
+ send_raw_to_replica(sql, :replica, ...)
48
46
  else
49
47
  mark_primary(sql)
50
48
  super
@@ -74,6 +72,11 @@ module Janus
74
72
  super
75
73
  end
76
74
 
75
+ def discard!(...)
76
+ replica_connection.discard!(...)
77
+ super
78
+ end
79
+
77
80
  def disconnect!(...)
78
81
  replica_connection.disconnect!(...)
79
82
  super
@@ -103,5 +106,17 @@ module Janus
103
106
  Janus::Context.used_connection(connection)
104
107
  replica_connection.execute(sql)
105
108
  end
109
+
110
+ def send_raw_to_replica(sql, connection, ...)
111
+ Janus::Context.used_connection(connection)
112
+ forward_raw_execute(sql, ...)
113
+ end
114
+
115
+ # The MySQL adapters inline bind values into the SQL string, so replaying the
116
+ # statement alone is enough. Adapters that keep binds separate must override
117
+ # this to carry them across.
118
+ def forward_raw_execute(sql, *, **)
119
+ replica_connection.execute(sql)
120
+ end
106
121
  end
107
122
  end
@@ -1,6 +1,5 @@
1
- # frozen_string_literal: true
2
- module Janus
3
- class Client
4
- FOUND_ROWS = 2
5
- end
6
- end
1
+ module Janus
2
+ class Client
3
+ FOUND_ROWS = 2
4
+ end
5
+ end
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  require 'active_support/isolated_execution_state'
4
2
 
5
3
  module Janus
@@ -1,17 +1,15 @@
1
- # frozen_string_literal: true
2
-
3
- module Janus
4
- class DbConsoleConfig
5
- def initialize(config)
6
- @_config = config.configuration_hash
7
- end
8
-
9
- def configuration_hash
10
- @_config[:janus]['replica'].symbolize_keys
11
- end
12
-
13
- def database
14
- @_config[:database]
15
- end
16
- end
17
- end
1
+ module Janus
2
+ class DbConsoleConfig
3
+ def initialize(config)
4
+ @_config = config.configuration_hash
5
+ end
6
+
7
+ def configuration_hash
8
+ @_config[:janus]['replica'].symbolize_keys
9
+ end
10
+
11
+ def database
12
+ @_config[:database]
13
+ end
14
+ end
15
+ end
@@ -1,15 +1,13 @@
1
- # frozen_string_literal: true
2
-
3
- module Janus
4
- module Logging
5
- class Logger
6
- class << self
7
- def log(message, format = :info)
8
- logger&.send(format, "[Janus] #{message}")
9
- end
10
-
11
- attr_accessor :logger
12
- end
13
- end
14
- end
15
- end
1
+ module Janus
2
+ module Logging
3
+ class Logger
4
+ class << self
5
+ def log(message, format = :info)
6
+ logger&.send(format, "[Janus] #{message}")
7
+ end
8
+
9
+ attr_accessor :logger
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,27 +1,25 @@
1
- # frozen_string_literal: true
2
-
3
- module Janus
4
- module Logging
5
- module Subscriber
6
- IGNORE_PAYLOAD_NAMES = %w(SCHEMA EXPLAIN).freeze
7
-
8
- def sql(event)
9
- name = event.payload[:name]
10
- unless IGNORE_PAYLOAD_NAMES.include?(name)
11
- name = [current_wrapper_name(event), name].compact.join(' ')
12
- event.payload[:name] = name
13
- end
14
- super(event)
15
- end
16
-
17
- protected
18
-
19
- def current_wrapper_name(_event)
20
- connection = Janus::Context.last_used_connection
21
- return nil unless connection
22
-
23
- "[#{connection}]"
24
- end
25
- end
26
- end
27
- end
1
+ module Janus
2
+ module Logging
3
+ module Subscriber
4
+ IGNORE_PAYLOAD_NAMES = %w(SCHEMA EXPLAIN).freeze
5
+
6
+ def sql(event)
7
+ name = event.payload[:name]
8
+ unless IGNORE_PAYLOAD_NAMES.include?(name)
9
+ name = [current_wrapper_name(event), name].compact.join(' ')
10
+ event.payload[:name] = name
11
+ end
12
+ super(event)
13
+ end
14
+
15
+ protected
16
+
17
+ def current_wrapper_name(_event)
18
+ connection = Janus::Context.last_used_connection
19
+ return nil unless connection
20
+
21
+ "[#{connection}]"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,14 +1,25 @@
1
- # frozen_string_literal: true
2
1
  module Janus
3
2
  class QueryDirector
4
3
  ALL = :all
5
4
  REPLICA = :replica
6
5
  PRIMARY = :primary
7
6
 
7
+ # Regexp fragments, not literal names: PostgreSQL's advisory lock family has
8
+ # too many members to list.
9
+ LOCK_FUNCTIONS = %w(
10
+ nextval currval lastval setval get_lock release_lock is_free_lock is_used_lock
11
+ pg_(?:try_)?advisory_(?:xact_)?(?:un)?lock(?:_shared|_all)?
12
+ ).freeze
13
+
14
+ # A string rather than a Regexp: interpolating a Regexp below would wrap it in
15
+ # a group that resets the /im flags, so `FOR UPDATE` would stop matching.
16
+ ROW_LOCK_STRENGTHS = 'no\s+key\s+update|key\s+share|update|share'
17
+
8
18
  SQL_PRIMARY_MATCHERS = [
9
- /\A\s*select.+for update\Z/i, /select.+lock in share mode\Z/i,
10
- /\A\s*select.+(nextval|currval|lastval|get_lock|release_lock|pg_advisory_lock|pg_advisory_unlock)\(/i,
11
- /\A\s*show/i
19
+ /\A\s*select\b.*\bfor\s+(?:#{ROW_LOCK_STRENGTHS})\b/im,
20
+ /\A\s*select\b.*\block\s+in\s+share\s+mode\b/im,
21
+ /\A\s*select\b.*\b(#{LOCK_FUNCTIONS.join('|')})\s*\(/im,
22
+ /\A\s*show\b/i,
12
23
  ].freeze
13
24
  SQL_REPLICA_MATCHERS = [/\A\s*(select|with.+\)\s*select)\s/i].freeze
14
25
  SQL_ALL_MATCHERS = [/\A\s*set\s/i].freeze
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  require 'rails/railtie'
4
2
 
5
3
  module Janus
@@ -1,10 +1,8 @@
1
- # frozen_string_literal: true
2
-
3
1
  module Janus
4
2
  unless defined?(::Janus::VERSION)
5
3
  module VERSION
6
4
  MAJOR = 8
7
- MINOR = 0
5
+ MINOR = 1
8
6
  PATCH = 1
9
7
  PRE = nil
10
8
 
data/lib/janus-ar.rb CHANGED
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  require 'active_support'
4
2
 
5
3
  module Janus