active_record_proxy_adapters 0.6.0 → 0.6.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/lib/active_record/connection_adapters/mysql2_proxy_adapter.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql_proxy_adapter.rb +8 -2
- data/lib/active_record/connection_adapters/trilogy_proxy_adapter.rb +8 -2
- data/lib/active_record_proxy_adapters/active_record_context.rb +5 -1
- data/lib/active_record_proxy_adapters/configuration.rb +11 -0
- data/lib/active_record_proxy_adapters/context.rb +42 -0
- data/lib/active_record_proxy_adapters/contextualizer.rb +20 -0
- data/lib/active_record_proxy_adapters/hijackable.rb +4 -2
- data/lib/active_record_proxy_adapters/mixin/configuration.rb +59 -0
- data/lib/active_record_proxy_adapters/primary_replica_proxy.rb +14 -29
- data/lib/active_record_proxy_adapters/transactionable_proxy_a_r_70.rb +31 -0
- data/lib/active_record_proxy_adapters/version.rb +1 -1
- metadata +5 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ea3aa59337aa2ed793bfb2e51666d08ef6b40ad9ccd2008453807baeac862933
|
4
|
+
data.tar.gz: 1e899907a68ecf3c6ca5a51380e2b7be9859d40c0b033f23b872037c6d1fd5a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3b9018059039d65f435a8d4571f5eea8a477e4388728a675b2176252959e5fb6afd0833cb21e65ea5bbd04e77c484f1d2ec3974d698b057c72440f7a9349150a
|
7
|
+
data.tar.gz: 7bf7662851cc2d6b1bcd7fcb59df5216fb87f28c368910da05476b6b734f692f2182de15bb731276f5952690b9ded4840ed2ddd2e35653fb2ff17c9c6e0a7bc4
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_record/tasks/mysql2_proxy_database_tasks"
|
4
|
-
require "active_record/connection_adapters/mysql2_adapter"
|
5
3
|
require "active_record_proxy_adapters/active_record_context"
|
6
4
|
require "active_record_proxy_adapters/hijackable"
|
7
5
|
require "active_record_proxy_adapters/mysql2_proxy"
|
6
|
+
require "active_record/connection_adapters/mysql2_adapter"
|
7
|
+
require "active_record/tasks/mysql2_proxy_database_tasks"
|
8
8
|
|
9
9
|
module ActiveRecord
|
10
10
|
module ConnectionAdapters
|
@@ -13,6 +13,12 @@ module ActiveRecord
|
|
13
13
|
class Mysql2ProxyAdapter < Mysql2Adapter
|
14
14
|
include ActiveRecordProxyAdapters::Hijackable
|
15
15
|
|
16
|
+
if ActiveRecordProxyAdapters::ActiveRecordContext.active_record_v7_0?
|
17
|
+
require "active_record_proxy_adapters/transactionable_proxy_a_r_70"
|
18
|
+
|
19
|
+
include ActiveRecordProxyAdapters::TransactionableProxyAR70
|
20
|
+
end
|
21
|
+
|
16
22
|
ADAPTER_NAME = "Mysql2Proxy"
|
17
23
|
|
18
24
|
delegate_to_proxy(*ActiveRecordProxyAdapters::ActiveRecordContext.hijackable_methods)
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_record/tasks/postgresql_proxy_database_tasks"
|
4
|
-
require "active_record/connection_adapters/postgresql_adapter"
|
5
3
|
require "active_record_proxy_adapters/active_record_context"
|
6
4
|
require "active_record_proxy_adapters/hijackable"
|
7
5
|
require "active_record_proxy_adapters/postgresql_proxy"
|
6
|
+
require "active_record/connection_adapters/postgresql_adapter"
|
7
|
+
require "active_record/tasks/postgresql_proxy_database_tasks"
|
8
8
|
|
9
9
|
module ActiveRecord
|
10
10
|
module ConnectionAdapters
|
@@ -13,6 +13,12 @@ module ActiveRecord
|
|
13
13
|
class PostgreSQLProxyAdapter < PostgreSQLAdapter
|
14
14
|
include ActiveRecordProxyAdapters::Hijackable
|
15
15
|
|
16
|
+
if ActiveRecordProxyAdapters::ActiveRecordContext.active_record_v7_0?
|
17
|
+
require "active_record_proxy_adapters/transactionable_proxy_a_r_70"
|
18
|
+
|
19
|
+
include ActiveRecordProxyAdapters::TransactionableProxyAR70
|
20
|
+
end
|
21
|
+
|
16
22
|
ADAPTER_NAME = "PostgreSQLProxy"
|
17
23
|
|
18
24
|
delegate_to_proxy(*ActiveRecordProxyAdapters::ActiveRecordContext.hijackable_methods)
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_record/tasks/trilogy_proxy_database_tasks"
|
4
|
-
require "active_record/connection_adapters/trilogy_adapter"
|
5
3
|
require "active_record_proxy_adapters/active_record_context"
|
6
4
|
require "active_record_proxy_adapters/hijackable"
|
7
5
|
require "active_record_proxy_adapters/trilogy_proxy"
|
6
|
+
require "active_record/connection_adapters/trilogy_adapter"
|
7
|
+
require "active_record/tasks/trilogy_proxy_database_tasks"
|
8
8
|
|
9
9
|
module ActiveRecord
|
10
10
|
module ConnectionAdapters
|
@@ -13,6 +13,12 @@ module ActiveRecord
|
|
13
13
|
class TrilogyProxyAdapter < TrilogyAdapter
|
14
14
|
include ActiveRecordProxyAdapters::Hijackable
|
15
15
|
|
16
|
+
if ActiveRecordProxyAdapters::ActiveRecordContext.active_record_v7_0?
|
17
|
+
require "active_record_proxy_adapters/transactionable_proxy_a_r_70"
|
18
|
+
|
19
|
+
include ActiveRecordProxyAdapters::TransactionableProxyAR70
|
20
|
+
end
|
21
|
+
|
16
22
|
ADAPTER_NAME = "TrilogyProxy"
|
17
23
|
|
18
24
|
delegate_to_proxy(*ActiveRecordProxyAdapters::ActiveRecordContext.hijackable_methods)
|
@@ -40,7 +40,7 @@ module ActiveRecordProxyAdapters
|
|
40
40
|
def hijackable_methods
|
41
41
|
hijackable = %i[execute exec_query]
|
42
42
|
|
43
|
-
hijackable << :internal_exec_query if
|
43
|
+
hijackable << :internal_exec_query if active_record_v7_1_or_greater?
|
44
44
|
|
45
45
|
hijackable
|
46
46
|
end
|
@@ -49,6 +49,10 @@ module ActiveRecordProxyAdapters
|
|
49
49
|
active_record_version >= Gem::Version.new("7.0") && active_record_version < Gem::Version.new("8.0")
|
50
50
|
end
|
51
51
|
|
52
|
+
def active_record_v7_0?
|
53
|
+
active_record_version >= Gem::Version.new("7.0") && active_record_version < Gem::Version.new("7.1")
|
54
|
+
end
|
55
|
+
|
52
56
|
def active_record_v7_1_or_greater?
|
53
57
|
active_record_version >= Gem::Version.new("7.1")
|
54
58
|
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require "active_support/core_ext/integer/time"
|
4
4
|
require "active_record_proxy_adapters/synchronizable_configuration"
|
5
5
|
require "active_record_proxy_adapters/cache_configuration"
|
6
|
+
require "active_record_proxy_adapters/context"
|
6
7
|
|
7
8
|
module ActiveRecordProxyAdapters
|
8
9
|
# Provides a global configuration object to configure how the proxy should behave.
|
@@ -27,6 +28,9 @@ module ActiveRecordProxyAdapters
|
|
27
28
|
# @return [Proc] Prefix for the log subscriber when the replica database is used. Thread safe.
|
28
29
|
attr_reader :log_subscriber_replica_prefix
|
29
30
|
|
31
|
+
# @return [Class] The context that is used to store the current request's state.
|
32
|
+
attr_reader :context_store
|
33
|
+
|
30
34
|
def initialize
|
31
35
|
@lock = Monitor.new
|
32
36
|
|
@@ -35,6 +39,7 @@ module ActiveRecordProxyAdapters
|
|
35
39
|
self.log_subscriber_primary_prefix = LOG_SUBSCRIBER_PRIMARY_PREFIX
|
36
40
|
self.log_subscriber_replica_prefix = LOG_SUBSCRIBER_REPLICA_PREFIX
|
37
41
|
self.cache_configuration = CacheConfiguration.new(@lock)
|
42
|
+
self.context_store = ActiveRecordProxyAdapters::Context
|
38
43
|
end
|
39
44
|
|
40
45
|
def log_subscriber_primary_prefix=(prefix)
|
@@ -65,6 +70,12 @@ module ActiveRecordProxyAdapters
|
|
65
70
|
end
|
66
71
|
end
|
67
72
|
|
73
|
+
def context_store=(context_store)
|
74
|
+
synchronize_update(:context_store, from: @context_store, to: context_store) do
|
75
|
+
@context_store = context_store
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
68
79
|
def cache
|
69
80
|
block_given? ? yield(cache_configuration) : cache_configuration
|
70
81
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_record_proxy_adapters/mixin/configuration"
|
4
|
+
|
5
|
+
module ActiveRecordProxyAdapters
|
6
|
+
# Context is a simple class that holds a registry of connection names and their last write timestamps.
|
7
|
+
# It is used to track the last time a write operation was performed on each connection.
|
8
|
+
# This allows the proxy to determine whether to route read requests to the primary or replica database
|
9
|
+
class Context
|
10
|
+
include Mixin::Configuration
|
11
|
+
|
12
|
+
# @param hash [Hash] A hash containing the connection names as keys and the last write timestamps as values.
|
13
|
+
# Can be empty.
|
14
|
+
def initialize(hash)
|
15
|
+
@timestamp_registry = hash.transform_values(&:to_f)
|
16
|
+
end
|
17
|
+
|
18
|
+
def recent_write_to_primary?(connection_name)
|
19
|
+
now - self[connection_name] < proxy_delay
|
20
|
+
end
|
21
|
+
|
22
|
+
def update_for(connection_name)
|
23
|
+
self[connection_name] = now
|
24
|
+
end
|
25
|
+
|
26
|
+
def [](connection_name)
|
27
|
+
timestamp_registry[connection_name] || 0
|
28
|
+
end
|
29
|
+
|
30
|
+
def []=(connection_name, timestamp)
|
31
|
+
timestamp_registry[connection_name] = timestamp
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
attr_reader :timestamp_registry
|
37
|
+
|
38
|
+
def now
|
39
|
+
Time.now.utc.to_f
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecordProxyAdapters
|
4
|
+
# A mixin for managing the context of current database connections.
|
5
|
+
module Contextualizer
|
6
|
+
module_function
|
7
|
+
|
8
|
+
# @return [ActiveRecordProxyAdapters::Context]
|
9
|
+
# Retrieves the context for the current thread.
|
10
|
+
def current_context
|
11
|
+
Thread.current.thread_variable_get(:arpa_context)
|
12
|
+
end
|
13
|
+
|
14
|
+
# @param context [ActiveRecordProxyAdapters::Context]
|
15
|
+
# Sets the context for the current thread.
|
16
|
+
def current_context=(context)
|
17
|
+
Thread.current.thread_variable_set(:arpa_context, context)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -52,8 +52,6 @@ module ActiveRecordProxyAdapters
|
|
52
52
|
"_unproxied"
|
53
53
|
end
|
54
54
|
|
55
|
-
private
|
56
|
-
|
57
55
|
def proxy_method_name_for(method_name)
|
58
56
|
:"#{method_name}#{unproxied_method_suffix}"
|
59
57
|
end
|
@@ -63,6 +61,10 @@ module ActiveRecordProxyAdapters
|
|
63
61
|
def unproxied_method_suffix
|
64
62
|
self.class.unproxied_method_suffix
|
65
63
|
end
|
64
|
+
|
65
|
+
def proxy_method_name_for(method_name)
|
66
|
+
self.class.proxy_method_name_for(method_name)
|
67
|
+
end
|
66
68
|
end
|
67
69
|
end
|
68
70
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/integer/time"
|
4
|
+
require "active_record_proxy_adapters/synchronizable_configuration"
|
5
|
+
require "active_record_proxy_adapters/cache_configuration"
|
6
|
+
require "active_record_proxy_adapters/context"
|
7
|
+
|
8
|
+
module ActiveRecordProxyAdapters
|
9
|
+
module Mixin
|
10
|
+
# Provides helpers to access to reduce boilerplate while retrieving configuration properties.
|
11
|
+
module Configuration
|
12
|
+
# Helper to retrieve the proxy delay from the configuration stored in
|
13
|
+
# {ActiveRecordProxyAdapters::Configuration#proxy_delay}.
|
14
|
+
# @return [ActiveSupport::Duration]
|
15
|
+
def proxy_delay
|
16
|
+
proxy_config.proxy_delay
|
17
|
+
end
|
18
|
+
|
19
|
+
# Helper to retrieve the checkout timeout from the configuration stored in
|
20
|
+
# {ActiveRecordProxyAdapters::Configuration#checkout_timeout}.
|
21
|
+
# @return [ActiveSupport::Duration]
|
22
|
+
def checkout_timeout
|
23
|
+
proxy_config.checkout_timeout
|
24
|
+
end
|
25
|
+
|
26
|
+
# Helper to retrieve the context store class from the configuration stored in
|
27
|
+
# {ActiveRecordProxyAdapters::Configuration#context_store}.
|
28
|
+
# @return [Class]
|
29
|
+
def context_store
|
30
|
+
proxy_config.context_store
|
31
|
+
end
|
32
|
+
|
33
|
+
# Helper to retrieve the cache store from the configuration stored in
|
34
|
+
# {ActiveRecordProxyAdapters::CacheConfiguration#store}.
|
35
|
+
# @return [ActiveSupport::Cache::Store]
|
36
|
+
def cache_store
|
37
|
+
cache_config.store
|
38
|
+
end
|
39
|
+
|
40
|
+
# Helper to retrieve the cache key prefix from the configuration stored in
|
41
|
+
# {ActiveRecordProxyAdapters::CacheConfiguration#key_prefix}.
|
42
|
+
# It uses the key builder to generate a cache key for the given SQL string, prepended with the key prefix.
|
43
|
+
# @return [String]
|
44
|
+
def cache_key_for(sql_string)
|
45
|
+
cache_config.key_builder.call(sql_string).prepend(cache_config.key_prefix)
|
46
|
+
end
|
47
|
+
|
48
|
+
# @!visibility private
|
49
|
+
def cache_config
|
50
|
+
proxy_config.cache
|
51
|
+
end
|
52
|
+
|
53
|
+
# @!visibility private
|
54
|
+
def proxy_config
|
55
|
+
ActiveRecordProxyAdapters.config
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -1,17 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_record_proxy_adapters/active_record_context"
|
3
4
|
require "active_record_proxy_adapters/configuration"
|
5
|
+
require "active_record_proxy_adapters/contextualizer"
|
6
|
+
require "active_record_proxy_adapters/hijackable"
|
7
|
+
require "active_record_proxy_adapters/mixin/configuration"
|
4
8
|
require "active_support/core_ext/module/delegation"
|
5
9
|
require "active_support/core_ext/object/blank"
|
6
|
-
require "concurrent-ruby"
|
7
|
-
require "active_record_proxy_adapters/active_record_context"
|
8
|
-
require "active_record_proxy_adapters/hijackable"
|
9
10
|
|
10
11
|
module ActiveRecordProxyAdapters
|
11
12
|
# This is the base class for all proxies. It defines the methods that should be proxied
|
12
13
|
# and the logic to determine which database to use.
|
13
14
|
class PrimaryReplicaProxy # rubocop:disable Metrics/ClassLength
|
14
15
|
include Hijackable
|
16
|
+
include Contextualizer
|
17
|
+
include Mixin::Configuration
|
15
18
|
|
16
19
|
# All queries that match these patterns should be sent to the primary database
|
17
20
|
SQL_PRIMARY_MATCHERS = [
|
@@ -34,6 +37,7 @@ module ActiveRecordProxyAdapters
|
|
34
37
|
WRITE_STATEMENT_MATCHERS = [
|
35
38
|
/\ABEGIN/i,
|
36
39
|
/\ACOMMIT/i,
|
40
|
+
/\AROLLBACK/i,
|
37
41
|
/INSERT\s[\s\S]*INTO\s[\s\S]*/i,
|
38
42
|
/UPDATE\s[\s\S]*/i,
|
39
43
|
/DELETE\s[\s\S]*FROM\s[\s\S]*/i,
|
@@ -50,13 +54,12 @@ module ActiveRecordProxyAdapters
|
|
50
54
|
# @param primary_connection [ActiveRecord::ConnectionAdatpers::AbstractAdapter]
|
51
55
|
def initialize(primary_connection)
|
52
56
|
@primary_connection = primary_connection
|
53
|
-
@last_write_at = 0
|
54
57
|
@active_record_context = ActiveRecordContext.new
|
55
58
|
end
|
56
59
|
|
57
60
|
private
|
58
61
|
|
59
|
-
attr_reader :primary_connection, :
|
62
|
+
attr_reader :primary_connection, :active_record_context
|
60
63
|
|
61
64
|
delegate :connection_handler, to: :connection_class
|
62
65
|
delegate :reading_role, :writing_role, to: :active_record_context
|
@@ -139,10 +142,6 @@ module ActiveRecordProxyAdapters
|
|
139
142
|
[reading_role, writing_role].include?(role) ? role : nil
|
140
143
|
end
|
141
144
|
|
142
|
-
def cache_key_for(sql_string)
|
143
|
-
cache_config.key_builder.call(sql_string).prepend(cache_config.key_prefix)
|
144
|
-
end
|
145
|
-
|
146
145
|
def connected_to_stack
|
147
146
|
return connection_class.connected_to_stack if connection_class.respond_to?(:connected_to_stack)
|
148
147
|
|
@@ -220,11 +219,9 @@ module ActiveRecordProxyAdapters
|
|
220
219
|
proc { |matcher| matcher.match?(sql_string) }
|
221
220
|
end
|
222
221
|
|
223
|
-
# TODO: implement a context API to re-route requests to the primary database if a recent query was sent to it to
|
224
|
-
# avoid replication delay issues
|
225
222
|
# @return Boolean
|
226
223
|
def recent_write_to_primary?
|
227
|
-
|
224
|
+
proxy_context.recent_write_to_primary?(primary_connection_name)
|
228
225
|
end
|
229
226
|
|
230
227
|
def in_transaction?
|
@@ -232,27 +229,15 @@ module ActiveRecordProxyAdapters
|
|
232
229
|
end
|
233
230
|
|
234
231
|
def update_primary_latest_write_timestamp
|
235
|
-
|
236
|
-
end
|
237
|
-
|
238
|
-
def cache_store
|
239
|
-
cache_config.store
|
240
|
-
end
|
241
|
-
|
242
|
-
def cache_config
|
243
|
-
proxy_config.cache
|
244
|
-
end
|
245
|
-
|
246
|
-
def proxy_delay
|
247
|
-
proxy_config.proxy_delay
|
232
|
+
proxy_context.update_for(primary_connection_name)
|
248
233
|
end
|
249
234
|
|
250
|
-
def
|
251
|
-
|
235
|
+
def primary_connection_name
|
236
|
+
@primary_connection_name ||= primary_connection.pool.try(:db_config).try(:name).try(:to_sym)
|
252
237
|
end
|
253
238
|
|
254
|
-
def
|
255
|
-
|
239
|
+
def proxy_context
|
240
|
+
self.current_context ||= context_store.new({})
|
256
241
|
end
|
257
242
|
end
|
258
243
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecordProxyAdapters
|
4
|
+
module TransactionableProxyAR70 # rubocop:disable Style/Documentation
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
def begin_db_transaction # :nodoc:
|
9
|
+
bypass_proxy_or_else("BEGIN", "TRANSACTION") { super }
|
10
|
+
end
|
11
|
+
|
12
|
+
def commit_db_transaction # :nodoc:
|
13
|
+
bypass_proxy_or_else("COMMIT", "TRANSACTION") { super }
|
14
|
+
end
|
15
|
+
|
16
|
+
def exec_rollback_db_transaction # :nodoc:
|
17
|
+
bypass_proxy_or_else("ROLLBACK", "TRANSACTION") { super }
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def bypass_proxy_or_else(*args)
|
23
|
+
method_name = proxy_method_name_for(:execute)
|
24
|
+
|
25
|
+
return public_send(method_name, *args) if respond_to?(method_name)
|
26
|
+
|
27
|
+
yield
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_record_proxy_adapters
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Cruz
|
@@ -94,15 +94,19 @@ files:
|
|
94
94
|
- lib/active_record_proxy_adapters/connection_handling/postgresql.rb
|
95
95
|
- lib/active_record_proxy_adapters/connection_handling/sqlite3.rb
|
96
96
|
- lib/active_record_proxy_adapters/connection_handling/trilogy.rb
|
97
|
+
- lib/active_record_proxy_adapters/context.rb
|
98
|
+
- lib/active_record_proxy_adapters/contextualizer.rb
|
97
99
|
- lib/active_record_proxy_adapters/database_tasks.rb
|
98
100
|
- lib/active_record_proxy_adapters/hijackable.rb
|
99
101
|
- lib/active_record_proxy_adapters/log_subscriber.rb
|
102
|
+
- lib/active_record_proxy_adapters/mixin/configuration.rb
|
100
103
|
- lib/active_record_proxy_adapters/mysql2_proxy.rb
|
101
104
|
- lib/active_record_proxy_adapters/postgresql_proxy.rb
|
102
105
|
- lib/active_record_proxy_adapters/primary_replica_proxy.rb
|
103
106
|
- lib/active_record_proxy_adapters/railtie.rb
|
104
107
|
- lib/active_record_proxy_adapters/sqlite3_proxy.rb
|
105
108
|
- lib/active_record_proxy_adapters/synchronizable_configuration.rb
|
109
|
+
- lib/active_record_proxy_adapters/transactionable_proxy_a_r_70.rb
|
106
110
|
- lib/active_record_proxy_adapters/trilogy_proxy.rb
|
107
111
|
- lib/active_record_proxy_adapters/version.rb
|
108
112
|
homepage: https://github.com/Nasdaq/active_record_proxy_adapters
|