active_record_shards 3.18.0 → 3.19.0
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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 24b77105aa8df10b1e79313f01b54fe87dba293938c9d41dc103f41cac64ec84
|
4
|
+
data.tar.gz: ec1da959a6dc2adbb6f287f73a3346c68fd49db30f7922dbc9adca7368532af2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ccae049b9c4a450f04cc2ae6b0cfca9eba75ac72d5f795c0c49ae5fc19e37fad1341d14f3ba34f75c684696131586a663fb306bcd35c2dad9fc625ad36955f3
|
7
|
+
data.tar.gz: 0b46d1cafa4fecae447a01106bfc4de592b7271fc17fef4c254a44a80cc22b22f5155e460d6aba036baad1a229f6f0b6935c3d108c935c5fd5cec9e6271eab83
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
[](https://github.com/zendesk/active_record_shards/actions?query=workflow%3ACI)
|
2
2
|
|
3
3
|
# ActiveRecord Shards
|
4
4
|
|
data/lib/active_record_shards.rb
CHANGED
@@ -32,8 +32,68 @@ ActiveRecord::SchemaDumper.prepend(ActiveRecordShards::SchemaDumperExtension)
|
|
32
32
|
case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
|
33
33
|
when '4.2'
|
34
34
|
require 'active_record_shards/patches-4-2'
|
35
|
-
|
36
|
-
|
35
|
+
|
36
|
+
# https://github.com/rails/rails/blob/v4.2.11.3/activerecord/lib/active_record/associations/association.rb#L97
|
37
|
+
ActiveRecord::Associations::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationAssociationScopePatch)
|
38
|
+
|
39
|
+
# https://github.com/rails/rails/blob/v4.2.11.3/activerecord/lib/active_record/associations/singular_association.rb#L44-L53
|
40
|
+
ActiveRecord::Associations::SingularAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationGetRecordsPatch)
|
41
|
+
|
42
|
+
# https://github.com/rails/rails/blob/v4.2.11.3/activerecord/lib/active_record/associations/collection_association.rb#L447-L456
|
43
|
+
ActiveRecord::Associations::CollectionAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationGetRecordsPatch)
|
44
|
+
|
45
|
+
# https://github.com/rails/rails/blob/v4.2.11.3/activerecord/lib/active_record/associations/preloader/association.rb#L89
|
46
|
+
ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsPreloaderAssociationAssociatedRecordsByOwnerPatch)
|
47
|
+
when '5.0'
|
48
|
+
# https://github.com/rails/rails/blob/v5.0.7/activerecord/lib/active_record/associations/association.rb#L97
|
49
|
+
ActiveRecord::Associations::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationAssociationScopePatch)
|
50
|
+
|
51
|
+
# https://github.com/rails/rails/blob/v5.0.7/activerecord/lib/active_record/associations/singular_association.rb#L56-L65
|
52
|
+
ActiveRecord::Associations::SingularAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationGetRecordsPatch)
|
53
|
+
|
54
|
+
# https://github.com/rails/rails/blob/v5.0.7/activerecord/lib/active_record/associations/collection_association.rb#L442-L451
|
55
|
+
ActiveRecord::Associations::CollectionAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationGetRecordsPatch)
|
56
|
+
|
57
|
+
# https://github.com/rails/rails/blob/v5.0.7/activerecord/lib/active_record/associations/preloader/association.rb#L120
|
58
|
+
ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsPreloaderAssociationLoadRecordsPatch)
|
59
|
+
when '5.1'
|
60
|
+
# https://github.com/rails/rails/blob/v5.1.7/activerecord/lib/active_record/associations/association.rb#L97
|
61
|
+
ActiveRecord::Associations::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationAssociationScopePatch)
|
62
|
+
|
63
|
+
# https://github.com/rails/rails/blob/v5.1.7/activerecord/lib/active_record/associations/singular_association.rb#L41
|
64
|
+
ActiveRecord::Associations::SingularAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationFindTargetPatch)
|
65
|
+
|
66
|
+
# https://github.com/rails/rails/blob/v5.1.7/activerecord/lib/active_record/associations/collection_association.rb#L305
|
67
|
+
ActiveRecord::Associations::CollectionAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationFindTargetPatch)
|
68
|
+
|
69
|
+
# https://github.com/rails/rails/blob/v5.1.7/activerecord/lib/active_record/associations/preloader/association.rb#L120
|
70
|
+
ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsPreloaderAssociationLoadRecordsPatch)
|
71
|
+
when '5.2'
|
72
|
+
# https://github.com/rails/rails/blob/v5.2.6/activerecord/lib/active_record/relation.rb#L530
|
73
|
+
# But the #exec_queries method also calls #connection, and I don't know if we should patch that one, too...
|
74
|
+
ActiveRecord::Relation.prepend(ActiveRecordShards::DefaultReplicaPatches::Rails52RelationPatches)
|
75
|
+
|
76
|
+
# https://github.com/rails/rails/blob/v5.2.6/activerecord/lib/active_record/associations/singular_association.rb#L42
|
77
|
+
ActiveRecord::Associations::SingularAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationFindTargetPatch)
|
78
|
+
|
79
|
+
# https://github.com/rails/rails/blob/v5.2.6/activerecord/lib/active_record/associations/collection_association.rb#L308
|
80
|
+
ActiveRecord::Associations::CollectionAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationFindTargetPatch)
|
81
|
+
|
82
|
+
# https://github.com/rails/rails/blob/v5.2.6/activerecord/lib/active_record/associations/preloader/association.rb#L96
|
83
|
+
ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsPreloaderAssociationLoadRecordsPatch)
|
84
|
+
when '6.0'
|
85
|
+
# https://github.com/rails/rails/blob/v6.0.4/activerecord/lib/active_record/type_caster/connection.rb#L28
|
86
|
+
ActiveRecord::TypeCaster::Connection.prepend(ActiveRecordShards::DefaultReplicaPatches::TypeCasterConnectionConnectionPatch)
|
87
|
+
|
88
|
+
# https://github.com/rails/rails/blob/v6.0.4/activerecord/lib/active_record/schema.rb#L53-L54
|
89
|
+
ActiveRecord::Schema.prepend(ActiveRecordShards::DefaultReplicaPatches::SchemaDefinePatch)
|
90
|
+
|
91
|
+
# https://github.com/rails/rails/blob/v6.0.4/activerecord/lib/active_record/relation.rb#L739
|
92
|
+
# But the #exec_queries and #compute_cache_version methods also call #connection, and I don't know if we should patch those, too...
|
93
|
+
ActiveRecord::Relation.prepend(ActiveRecordShards::DefaultReplicaPatches::Rails52RelationPatches)
|
94
|
+
|
95
|
+
# https://github.com/rails/rails/blob/v6.0.4/activerecord/lib/active_record/associations/association.rb#L213
|
96
|
+
ActiveRecord::Associations::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationFindTargetPatch)
|
37
97
|
else
|
38
98
|
raise "ActiveRecordShards is not compatible with #{ActiveRecord::VERSION::STRING}"
|
39
99
|
end
|
@@ -64,8 +124,6 @@ ActiveRecordShards::Deprecation.deprecate_methods(
|
|
64
124
|
|
65
125
|
ActiveRecordShards::Deprecation.deprecate_methods(
|
66
126
|
ActiveRecordShards::DefaultReplicaPatches,
|
67
|
-
columns_with_force_slave: :columns_with_force_replica,
|
68
|
-
table_exists_with_force_slave?: :table_exists_with_force_replica?,
|
69
127
|
transaction_with_slave_off: :transaction_with_replica_off,
|
70
128
|
on_slave_unless_tx: :on_replica_unless_tx
|
71
129
|
)
|
@@ -187,6 +187,8 @@ module ActiveRecordShards
|
|
187
187
|
ActiveRecordShards.rails_env
|
188
188
|
end
|
189
189
|
|
190
|
+
# Make these few schema related methods available before having switched to
|
191
|
+
# a shard.
|
190
192
|
def with_default_shard(&block)
|
191
193
|
if is_sharded? && current_shard_id.nil? && table_name != ActiveRecord::SchemaMigration.table_name
|
192
194
|
on_first_shard(&block)
|
@@ -37,28 +37,14 @@ module ActiveRecordShards
|
|
37
37
|
wrap_method_in_on_replica(*args)
|
38
38
|
end
|
39
39
|
|
40
|
-
def columns_with_force_replica(*args, &block)
|
41
|
-
on_cx_switch_block(:replica, construct_ro_scope: false, force: true) do
|
42
|
-
columns_without_force_replica(*args, &block)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
alias_method :columns_with_force_slave, :columns_with_force_replica
|
46
|
-
|
47
|
-
def table_exists_with_force_replica?(*args, &block)
|
48
|
-
on_cx_switch_block(:replica, construct_ro_scope: false, force: true) do
|
49
|
-
table_exists_without_force_replica?(*args, &block)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
alias_method :table_exists_with_force_slave?, :table_exists_with_force_replica?
|
53
|
-
|
54
40
|
def transaction_with_replica_off(*args, &block)
|
55
41
|
if on_replica_by_default?
|
56
42
|
begin
|
57
|
-
old_val = Thread.current[:
|
58
|
-
Thread.current[:
|
43
|
+
old_val = Thread.current[:_active_record_shards_in_tx]
|
44
|
+
Thread.current[:_active_record_shards_in_tx] = true
|
59
45
|
transaction_without_replica_off(*args, &block)
|
60
46
|
ensure
|
61
|
-
Thread.current[:
|
47
|
+
Thread.current[:_active_record_shards_in_tx] = old_val
|
62
48
|
end
|
63
49
|
else
|
64
50
|
transaction_without_replica_off(*args, &block)
|
@@ -71,20 +57,26 @@ module ActiveRecordShards
|
|
71
57
|
def quote_value(*args, &block)
|
72
58
|
self.class.quote_value(*args, &block)
|
73
59
|
end
|
60
|
+
|
61
|
+
def on_replica_unless_tx
|
62
|
+
self.class.on_replica_unless_tx { yield }
|
63
|
+
end
|
74
64
|
end
|
75
65
|
|
76
66
|
CLASS_REPLICA_METHODS = [
|
77
67
|
:calculate,
|
78
68
|
:count_by_sql,
|
79
69
|
:exists?,
|
70
|
+
:find,
|
71
|
+
:find_by,
|
80
72
|
:find_by_sql,
|
81
73
|
:find_every,
|
82
74
|
:find_one,
|
83
|
-
:find_some
|
75
|
+
:find_some,
|
76
|
+
:get_primary_key
|
84
77
|
].freeze
|
85
78
|
|
86
79
|
CLASS_FORCE_REPLICA_METHODS = [
|
87
|
-
:columns,
|
88
80
|
:replace_bind_variable,
|
89
81
|
:replace_bind_variables,
|
90
82
|
:sanitize_sql_array,
|
@@ -97,7 +89,15 @@ module ActiveRecordShards
|
|
97
89
|
|
98
90
|
def self.extended(base)
|
99
91
|
CLASS_REPLICA_METHODS.each { |m| ActiveRecordShards::DefaultReplicaPatches.wrap_method_in_on_replica(true, base, m) }
|
100
|
-
|
92
|
+
CLASS_FORCE_REPLICA_METHODS.each { |m| ActiveRecordShards::DefaultReplicaPatches.wrap_method_in_on_replica(true, base, m, force_on_replica: true) }
|
93
|
+
|
94
|
+
if ActiveRecord::VERSION::MAJOR >= 5
|
95
|
+
ActiveRecordShards::DefaultReplicaPatches.wrap_method_in_on_replica(true, base, :load_schema!, force_on_replica: true)
|
96
|
+
else
|
97
|
+
ActiveRecordShards::DefaultReplicaPatches.wrap_method_in_on_replica(true, base, :columns, force_on_replica: true)
|
98
|
+
end
|
99
|
+
|
100
|
+
ActiveRecordShards::DefaultReplicaPatches.wrap_method_in_on_replica(false, base, :reload)
|
101
101
|
|
102
102
|
base.class_eval do
|
103
103
|
include InstanceMethods
|
@@ -107,15 +107,14 @@ module ActiveRecordShards
|
|
107
107
|
alias_method :transaction, :transaction_with_replica_off
|
108
108
|
end
|
109
109
|
end
|
110
|
-
if ActiveRecord::Associations.const_defined?(:HasAndBelongsToManyAssociation)
|
111
|
-
ActiveRecordShards::DefaultReplicaPatches.wrap_method_in_on_replica(false, ActiveRecord::Associations::HasAndBelongsToManyAssociation, :construct_sql)
|
112
|
-
ActiveRecordShards::DefaultReplicaPatches.wrap_method_in_on_replica(false, ActiveRecord::Associations::HasAndBelongsToManyAssociation, :construct_find_options!)
|
113
|
-
end
|
114
110
|
end
|
115
111
|
|
116
|
-
def on_replica_unless_tx
|
117
|
-
|
118
|
-
|
112
|
+
def on_replica_unless_tx(&block)
|
113
|
+
return yield if Thread.current[:_active_record_shards_in_migration]
|
114
|
+
return yield if Thread.current[:_active_record_shards_in_tx]
|
115
|
+
|
116
|
+
if on_replica_by_default?
|
117
|
+
on_replica(&block)
|
119
118
|
else
|
120
119
|
yield
|
121
120
|
end
|
@@ -123,6 +122,8 @@ module ActiveRecordShards
|
|
123
122
|
alias_method :on_slave_unless_tx, :on_replica_unless_tx
|
124
123
|
|
125
124
|
def force_on_replica(&block)
|
125
|
+
return yield if Thread.current[:_active_record_shards_in_migration]
|
126
|
+
|
126
127
|
on_cx_switch_block(:replica, construct_ro_scope: false, force: true, &block)
|
127
128
|
end
|
128
129
|
|
@@ -145,6 +146,19 @@ module ActiveRecordShards
|
|
145
146
|
end
|
146
147
|
end
|
147
148
|
|
149
|
+
module Rails52RelationPatches
|
150
|
+
def connection
|
151
|
+
return super if Thread.current[:_active_record_shards_in_migration]
|
152
|
+
return super if Thread.current[:_active_record_shards_in_tx]
|
153
|
+
|
154
|
+
if @klass.on_replica_by_default?
|
155
|
+
@klass.on_replica.connection
|
156
|
+
else
|
157
|
+
super
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
148
162
|
# in rails 4.1+, they create a join class that's used to pull in records for HABTM.
|
149
163
|
# this simplifies the hell out of our existence, because all we have to do is inerit on-replica-by-default
|
150
164
|
# down from the parent now.
|
@@ -167,5 +181,98 @@ module ActiveRecordShards
|
|
167
181
|
model
|
168
182
|
end
|
169
183
|
end
|
184
|
+
|
185
|
+
module AssociationsAssociationAssociationScopePatch
|
186
|
+
def association_scope
|
187
|
+
if klass
|
188
|
+
on_replica_unless_tx { super }
|
189
|
+
else
|
190
|
+
super
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def on_replica_unless_tx
|
195
|
+
klass.on_replica_unless_tx { yield }
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
module AssociationsAssociationFindTargetPatch
|
200
|
+
def find_target
|
201
|
+
if klass
|
202
|
+
on_replica_unless_tx { super }
|
203
|
+
else
|
204
|
+
super
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def on_replica_unless_tx
|
209
|
+
klass.on_replica_unless_tx { yield }
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
module AssociationsAssociationGetRecordsPatch
|
214
|
+
def get_records # rubocop:disable Naming/AccessorMethodName
|
215
|
+
if klass
|
216
|
+
on_replica_unless_tx { super }
|
217
|
+
else
|
218
|
+
super
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def on_replica_unless_tx
|
223
|
+
klass.on_replica_unless_tx { yield }
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
module AssociationsPreloaderAssociationAssociatedRecordsByOwnerPatch
|
228
|
+
def associated_records_by_owner(preloader)
|
229
|
+
if klass
|
230
|
+
on_replica_unless_tx { super }
|
231
|
+
else
|
232
|
+
super
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def on_replica_unless_tx
|
237
|
+
klass.on_replica_unless_tx { yield }
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
module AssociationsPreloaderAssociationLoadRecordsPatch
|
242
|
+
def load_records
|
243
|
+
if klass
|
244
|
+
on_replica_unless_tx { super }
|
245
|
+
else
|
246
|
+
super
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
def on_replica_unless_tx
|
251
|
+
klass.on_replica_unless_tx { yield }
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
module TypeCasterConnectionConnectionPatch
|
256
|
+
def connection
|
257
|
+
return super if Thread.current[:_active_record_shards_in_migration]
|
258
|
+
return super if Thread.current[:_active_record_shards_in_tx]
|
259
|
+
|
260
|
+
if @klass.on_replica_by_default?
|
261
|
+
@klass.on_replica.connection
|
262
|
+
else
|
263
|
+
super
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
module SchemaDefinePatch
|
269
|
+
def define(info, &block)
|
270
|
+
old_val = Thread.current[:_active_record_shards_in_migration]
|
271
|
+
Thread.current[:_active_record_shards_in_migration] = true
|
272
|
+
super
|
273
|
+
ensure
|
274
|
+
Thread.current[:_active_record_shards_in_migration] = old_val
|
275
|
+
end
|
276
|
+
end
|
170
277
|
end
|
171
278
|
end
|
@@ -3,8 +3,11 @@ module ActiveRecordShards
|
|
3
3
|
module SqlComments
|
4
4
|
module Methods
|
5
5
|
def execute(query, name = nil)
|
6
|
+
shard = ActiveRecord::Base.current_shard_selection.shard
|
7
|
+
shard_text = shard ? "shard #{shard}" : 'unsharded'
|
6
8
|
replica = ActiveRecord::Base.current_shard_selection.on_replica?
|
7
|
-
|
9
|
+
replica_text = replica ? 'replica' : 'primary'
|
10
|
+
query = "/* #{shard_text} #{replica_text} */ " + query
|
8
11
|
super(query, name)
|
9
12
|
end
|
10
13
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_record_shards
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.19.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Benjamin Quorning
|
@@ -13,7 +13,7 @@ authors:
|
|
13
13
|
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
date: 2021-
|
16
|
+
date: 2021-07-09 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: activerecord
|
@@ -125,20 +125,6 @@ dependencies:
|
|
125
125
|
- - ">="
|
126
126
|
- !ruby/object:Gem::Version
|
127
127
|
version: '0'
|
128
|
-
- !ruby/object:Gem::Dependency
|
129
|
-
name: phenix
|
130
|
-
requirement: !ruby/object:Gem::Requirement
|
131
|
-
requirements:
|
132
|
-
- - ">="
|
133
|
-
- !ruby/object:Gem::Version
|
134
|
-
version: 0.6.0
|
135
|
-
type: :development
|
136
|
-
prerelease: false
|
137
|
-
version_requirements: !ruby/object:Gem::Requirement
|
138
|
-
requirements:
|
139
|
-
- - ">="
|
140
|
-
- !ruby/object:Gem::Version
|
141
|
-
version: 0.6.0
|
142
128
|
- !ruby/object:Gem::Dependency
|
143
129
|
name: rake
|
144
130
|
requirement: !ruby/object:Gem::Requirement
|