active_record_shards 3.11.2 → 3.19.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'active_record_shards/shard_support'
3
4
 
4
5
  module ActiveRecordShards
5
6
  module ConnectionSwitcher
6
- SHARD_NAMES_CONFIG_KEY = 'shard_names'.freeze
7
+ SHARD_NAMES_CONFIG_KEY = 'shard_names'
7
8
 
8
9
  def self.extended(base)
9
10
  if ActiveRecord::VERSION::MAJOR >= 5
@@ -23,6 +24,10 @@ module ActiveRecordShards
23
24
  switch_connection(shard: new_default_shard)
24
25
  end
25
26
 
27
+ def on_primary_db(&block)
28
+ on_shard(nil, &block)
29
+ end
30
+
26
31
  def on_shard(shard)
27
32
  old_options = current_shard_selection.options
28
33
  switch_connection(shard: shard) if supports_sharding?
@@ -31,9 +36,9 @@ module ActiveRecordShards
31
36
  switch_connection(old_options)
32
37
  end
33
38
 
34
- def on_first_shard
39
+ def on_first_shard(&block)
35
40
  shard_name = shard_names.first
36
- on_shard(shard_name) { yield }
41
+ on_shard(shard_name, &block)
37
42
  end
38
43
 
39
44
  def shards
@@ -54,70 +59,79 @@ module ActiveRecordShards
54
59
  switch_connection(old_options)
55
60
  end
56
61
 
57
- def on_slave_if(condition, &block)
58
- condition ? on_slave(&block) : yield
62
+ def on_replica_if(condition, &block)
63
+ condition ? on_replica(&block) : yield
59
64
  end
65
+ alias_method :on_slave_if, :on_replica_if
60
66
 
61
- def on_slave_unless(condition, &block)
62
- on_slave_if(!condition, &block)
67
+ def on_replica_unless(condition, &block)
68
+ on_replica_if(!condition, &block)
63
69
  end
70
+ alias_method :on_slave_unless, :on_replica_unless
64
71
 
65
- def on_master_if(condition, &block)
66
- condition ? on_master(&block) : yield
72
+ def on_primary_if(condition, &block)
73
+ condition ? on_primary(&block) : yield
67
74
  end
75
+ alias_method :on_master_if, :on_primary_if
68
76
 
69
- def on_master_unless(condition, &block)
70
- on_master_if(!condition, &block)
77
+ def on_primary_unless(condition, &block)
78
+ on_primary_if(!condition, &block)
71
79
  end
80
+ alias_method :on_master_unless, :on_primary_unless
72
81
 
73
- def on_master_or_slave(which, &block)
82
+ def on_primary_or_replica(which, &block)
74
83
  if block_given?
75
84
  on_cx_switch_block(which, &block)
76
85
  else
77
- MasterSlaveProxy.new(self, which)
86
+ PrimaryReplicaProxy.new(self, which)
78
87
  end
79
88
  end
89
+ alias_method :on_master_or_slave, :on_primary_or_replica
80
90
 
81
- # Executes queries using the slave database. Fails over to master if no slave is found.
82
- # if you want to execute a block of code on the slave you can go:
83
- # Account.on_slave do
91
+ # Executes queries using the replica database. Fails over to primary if no replica is found.
92
+ # if you want to execute a block of code on the replica you can go:
93
+ # Account.on_replica do
84
94
  # Account.first
85
95
  # end
86
- # the first account will be found on the slave DB
96
+ # the first account will be found on the replica DB
87
97
  #
88
98
  # For one-liners you can simply do
89
- # Account.on_slave.first
90
- def on_slave(&block)
91
- on_master_or_slave(:slave, &block)
99
+ # Account.on_replica.first
100
+ def on_replica(&block)
101
+ on_primary_or_replica(:replica, &block)
92
102
  end
103
+ alias_method :on_slave, :on_replica
93
104
 
94
- def on_master(&block)
95
- on_master_or_slave(:master, &block)
105
+ def on_primary(&block)
106
+ on_primary_or_replica(:primary, &block)
96
107
  end
108
+ alias_method :on_master, :on_primary
97
109
 
98
110
  # just to ease the transition from replica to active_record_shards
99
- alias_method :with_slave, :on_slave
100
- alias_method :with_slave_if, :on_slave_if
101
- alias_method :with_slave_unless, :on_slave_unless
111
+ alias_method :with_slave, :on_replica
112
+ alias_method :with_slave_if, :on_replica_if
113
+ alias_method :with_slave_unless, :on_replica_unless
102
114
 
103
115
  def on_cx_switch_block(which, force: false, construct_ro_scope: nil, &block)
104
- @disallow_slave ||= 0
105
- @disallow_slave += 1 if which == :master
116
+ @disallow_replica ||= 0
117
+ @disallow_replica += 1 if [:primary, :master].include?(which)
118
+
119
+ ActiveRecordShards::Deprecation.warn('the `:master` option should be replaced with `:primary`!') if which == :master
106
120
 
107
- switch_to_slave = force || @disallow_slave.zero?
121
+ switch_to_replica = force || @disallow_replica.zero?
108
122
  old_options = current_shard_selection.options
109
123
 
110
- switch_connection(slave: switch_to_slave)
124
+ switch_connection(replica: switch_to_replica)
111
125
 
112
126
  # we avoid_readonly_scope to prevent some stack overflow problems, like when
113
127
  # .columns calls .with_scope which calls .columns and onward, endlessly.
114
- if self == ActiveRecord::Base || !switch_to_slave || construct_ro_scope == false
128
+ if self == ActiveRecord::Base || !switch_to_replica || construct_ro_scope == false
115
129
  yield
116
130
  else
117
131
  readonly.scoping(&block)
118
132
  end
119
133
  ensure
120
- @disallow_slave -= 1 if which == :master
134
+ @disallow_replica -= 1 if [:primary, :master].include?(which)
121
135
  switch_connection(old_options) if old_options
122
136
  end
123
137
 
@@ -125,9 +139,10 @@ module ActiveRecordShards
125
139
  shard_names.any?
126
140
  end
127
141
 
128
- def on_slave?
129
- current_shard_selection.on_slave?
142
+ def on_replica?
143
+ current_shard_selection.on_replica?
130
144
  end
145
+ alias_method :on_slave?, :on_replica?
131
146
 
132
147
  def current_shard_selection
133
148
  Thread.current[:shard_selection] ||= ShardSelection.new
@@ -139,8 +154,12 @@ module ActiveRecordShards
139
154
 
140
155
  def shard_names
141
156
  unless config = configurations[shard_env]
142
- raise "Did not find #{shard_env} in configurations, did you forget to add it to your database.yml ? (configurations: #{configurations.inspect})"
157
+ raise "Did not find #{shard_env} in configurations, did you forget to add it to your database config? (configurations: #{configurations.keys.inspect})"
143
158
  end
159
+ unless config.fetch(SHARD_NAMES_CONFIG_KEY, []).all? { |shard_name| shard_name.is_a?(Integer) }
160
+ raise "All shard names must be integers: #{config[SHARD_NAMES_CONFIG_KEY].inspect}."
161
+ end
162
+
144
163
  config[SHARD_NAMES_CONFIG_KEY] || []
145
164
  end
146
165
 
@@ -148,11 +167,15 @@ module ActiveRecordShards
148
167
 
149
168
  def switch_connection(options)
150
169
  if options.any?
151
- if options.key?(:slave)
152
- current_shard_selection.on_slave = options[:slave]
170
+ if options.key?(:replica)
171
+ current_shard_selection.on_replica = options[:replica]
153
172
  end
154
173
 
155
174
  if options.key?(:shard)
175
+ unless configurations[shard_env]
176
+ raise "Did not find #{shard_env} in configurations, did you forget to add it to your database config? (configurations: #{configurations.keys.inspect})"
177
+ end
178
+
156
179
  current_shard_selection.shard = options[:shard]
157
180
  end
158
181
 
@@ -164,21 +187,13 @@ module ActiveRecordShards
164
187
  ActiveRecordShards.rails_env
165
188
  end
166
189
 
167
- if ActiveRecord::VERSION::MAJOR >= 4
168
- def with_default_shard
169
- if is_sharded? && current_shard_id.nil? && table_name != ActiveRecord::SchemaMigration.table_name
170
- on_first_shard { yield }
171
- else
172
- yield
173
- end
174
- end
175
- else
176
- def with_default_shard
177
- if is_sharded? && current_shard_id.nil? && table_name != ActiveRecord::Migrator.schema_migrations_table_name
178
- on_first_shard { yield }
179
- else
180
- yield
181
- end
190
+ # Make these few schema related methods available before having switched to
191
+ # a shard.
192
+ def with_default_shard(&block)
193
+ if is_sharded? && current_shard_id.nil? && table_name != ActiveRecord::SchemaMigration.table_name
194
+ on_first_shard(&block)
195
+ else
196
+ yield
182
197
  end
183
198
  end
184
199
 
@@ -196,25 +211,27 @@ module ActiveRecordShards
196
211
  with_default_shard { table_exists_without_default_shard? }
197
212
  end
198
213
 
199
- class MasterSlaveProxy
214
+ class PrimaryReplicaProxy
200
215
  def initialize(target, which)
201
216
  @target = target
202
217
  @which = which
203
218
  end
204
219
 
205
- def method_missing(method, *args, &block) # rubocop:disable Style/MethodMissing
206
- @target.on_master_or_slave(@which) { @target.send(method, *args, &block) }
220
+ def method_missing(method, *args, &block) # rubocop:disable Style/MethodMissingSuper, Style/MissingRespondToMissing
221
+ @target.on_primary_or_replica(@which) { @target.send(method, *args, &block) }
207
222
  end
208
223
  end
224
+
225
+ MasterSlaveProxy = PrimaryReplicaProxy
209
226
  end
210
227
  end
211
228
 
212
229
  case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
213
- when '3.2', '4.2'
214
- require 'active_record_shards/connection_switcher-4-0'
230
+ when '4.2'
231
+ require 'active_record_shards/connection_switcher-4-2'
215
232
  when '5.0'
216
233
  require 'active_record_shards/connection_switcher-5-0'
217
- when '5.1'
234
+ when '5.1', '5.2', '6.0'
218
235
  require 'active_record_shards/connection_switcher-5-1'
219
236
  else
220
237
  raise "ActiveRecordShards is not compatible with #{ActiveRecord::VERSION::STRING}"
@@ -0,0 +1,278 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecordShards
4
+ module DefaultReplicaPatches
5
+ def self.wrap_method_in_on_replica(class_method, base, method, force_on_replica: false)
6
+ base_methods =
7
+ if class_method
8
+ base.methods + base.private_methods
9
+ else
10
+ base.instance_methods + base.private_instance_methods
11
+ end
12
+
13
+ return unless base_methods.include?(method)
14
+
15
+ _, method, punctuation = method.to_s.match(/^(.*?)([\?\!]?)$/).to_a
16
+ # _ALWAYS_ on replica, or only for on `on_replica_by_default = true` models?
17
+ wrapper = force_on_replica ? 'force_on_replica' : 'on_replica_unless_tx'
18
+ base.class_eval <<-RUBY, __FILE__, __LINE__ + 1
19
+ #{class_method ? 'class << self' : ''}
20
+ def #{method}_with_default_replica#{punctuation}(*args, &block)
21
+ #{wrapper} do
22
+ #{method}_without_default_replica#{punctuation}(*args, &block)
23
+ end
24
+ end
25
+
26
+ alias_method :#{method}_without_default_replica#{punctuation}, :#{method}#{punctuation}
27
+ alias_method :#{method}#{punctuation}, :#{method}_with_default_replica#{punctuation}
28
+ #{class_method ? 'end' : ''}
29
+ RUBY
30
+ end
31
+
32
+ def self.wrap_method_in_on_slave(*args)
33
+ ActiveRecordShards::Deprecation.deprecation_warning(
34
+ :'self.wrap_method_in_on_slave',
35
+ :'self.wrap_method_in_on_replica'
36
+ )
37
+ wrap_method_in_on_replica(*args)
38
+ end
39
+
40
+ def transaction_with_replica_off(*args, &block)
41
+ if on_replica_by_default?
42
+ begin
43
+ old_val = Thread.current[:_active_record_shards_in_tx]
44
+ Thread.current[:_active_record_shards_in_tx] = true
45
+ transaction_without_replica_off(*args, &block)
46
+ ensure
47
+ Thread.current[:_active_record_shards_in_tx] = old_val
48
+ end
49
+ else
50
+ transaction_without_replica_off(*args, &block)
51
+ end
52
+ end
53
+ alias_method :transaction_with_slave_off, :transaction_with_replica_off
54
+
55
+ module InstanceMethods
56
+ # fix ActiveRecord to do the right thing, and use our aliased quote_value
57
+ def quote_value(*args, &block)
58
+ self.class.quote_value(*args, &block)
59
+ end
60
+
61
+ def on_replica_unless_tx
62
+ self.class.on_replica_unless_tx { yield }
63
+ end
64
+ end
65
+
66
+ CLASS_REPLICA_METHODS = [
67
+ :calculate,
68
+ :count_by_sql,
69
+ :exists?,
70
+ :find,
71
+ :find_by,
72
+ :find_by_sql,
73
+ :find_every,
74
+ :find_one,
75
+ :find_some,
76
+ :get_primary_key
77
+ ].freeze
78
+
79
+ CLASS_FORCE_REPLICA_METHODS = [
80
+ :replace_bind_variable,
81
+ :replace_bind_variables,
82
+ :sanitize_sql_array,
83
+ :sanitize_sql_hash_for_assignment,
84
+ :table_exists?
85
+ ].freeze
86
+
87
+ CLASS_SLAVE_METHODS = CLASS_REPLICA_METHODS
88
+ CLASS_FORCE_SLAVE_METHODS = CLASS_FORCE_REPLICA_METHODS
89
+
90
+ def self.extended(base)
91
+ CLASS_REPLICA_METHODS.each { |m| ActiveRecordShards::DefaultReplicaPatches.wrap_method_in_on_replica(true, base, m) }
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
+
102
+ base.class_eval do
103
+ include InstanceMethods
104
+
105
+ class << self
106
+ alias_method :transaction_without_replica_off, :transaction
107
+ alias_method :transaction, :transaction_with_replica_off
108
+ end
109
+ end
110
+ end
111
+
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)
118
+ else
119
+ yield
120
+ end
121
+ end
122
+ alias_method :on_slave_unless_tx, :on_replica_unless_tx
123
+
124
+ def force_on_replica(&block)
125
+ return yield if Thread.current[:_active_record_shards_in_migration]
126
+
127
+ on_cx_switch_block(:replica, construct_ro_scope: false, force: true, &block)
128
+ end
129
+
130
+ module ActiveRelationPatches
131
+ def self.included(base)
132
+ [:calculate, :exists?, :pluck, :load].each do |m|
133
+ ActiveRecordShards::DefaultReplicaPatches.wrap_method_in_on_replica(false, base, m)
134
+ end
135
+
136
+ if ActiveRecord::VERSION::MAJOR == 4
137
+ # `where` and `having` clauses call `create_binds`, which will use the primary connection
138
+ ActiveRecordShards::DefaultReplicaPatches.wrap_method_in_on_replica(false, base, :create_binds, force_on_replica: true)
139
+ end
140
+
141
+ ActiveRecordShards::DefaultReplicaPatches.wrap_method_in_on_replica(false, base, :to_sql, force_on_replica: true)
142
+ end
143
+
144
+ def on_replica_unless_tx
145
+ @klass.on_replica_unless_tx { yield }
146
+ end
147
+ end
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
+
162
+ # in rails 4.1+, they create a join class that's used to pull in records for HABTM.
163
+ # this simplifies the hell out of our existence, because all we have to do is inerit on-replica-by-default
164
+ # down from the parent now.
165
+ module Rails41HasAndBelongsToManyBuilderExtension
166
+ def self.included(base)
167
+ base.class_eval do
168
+ alias_method :through_model_without_inherit_default_replica_from_lhs, :through_model
169
+ alias_method :through_model, :through_model_with_inherit_default_replica_from_lhs
170
+ end
171
+ end
172
+
173
+ def through_model_with_inherit_default_replica_from_lhs
174
+ model = through_model_without_inherit_default_replica_from_lhs
175
+ def model.on_replica_by_default?
176
+ left_reflection.klass.on_replica_by_default?
177
+ end
178
+
179
+ # also transfer the sharded-ness of the left table to the join model
180
+ model.not_sharded unless model.left_reflection.klass.is_sharded?
181
+ model
182
+ end
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
277
+ end
278
+ end
@@ -1,150 +1,5 @@
1
- # frozen_string_literal: true
2
- module ActiveRecordShards
3
- module DefaultSlavePatches
4
- def self.wrap_method_in_on_slave(class_method, base, method)
5
- base_methods =
6
- if class_method
7
- base.methods + base.private_methods
8
- else
9
- base.instance_methods + base.private_instance_methods
10
- end
11
-
12
- return unless base_methods.include?(method)
13
- _, method, punctuation = method.to_s.match(/^(.*?)([\?\!]?)$/).to_a
14
- base.class_eval <<-RUBY, __FILE__, __LINE__ + 1
15
- #{class_method ? 'class << self' : ''}
16
- def #{method}_with_default_slave#{punctuation}(*args, &block)
17
- on_slave_unless_tx do
18
- #{method}_without_default_slave#{punctuation}(*args, &block)
19
- end
20
- end
21
-
22
- alias_method :#{method}_without_default_slave#{punctuation}, :#{method}#{punctuation}
23
- alias_method :#{method}#{punctuation}, :#{method}_with_default_slave#{punctuation}
24
- #{class_method ? 'end' : ''}
25
- RUBY
26
- end
27
-
28
- def columns_with_force_slave(*args, &block)
29
- on_cx_switch_block(:slave, construct_ro_scope: false, force: true) do
30
- columns_without_force_slave(*args, &block)
31
- end
32
- end
33
-
34
- def table_exists_with_force_slave?(*args, &block)
35
- on_cx_switch_block(:slave, construct_ro_scope: false, force: true) do
36
- table_exists_without_force_slave?(*args, &block)
37
- end
38
- end
39
-
40
- def transaction_with_slave_off(*args, &block)
41
- if on_slave_by_default?
42
- begin
43
- old_val = Thread.current[:_active_record_shards_slave_off]
44
- Thread.current[:_active_record_shards_slave_off] = true
45
- transaction_without_slave_off(*args, &block)
46
- ensure
47
- Thread.current[:_active_record_shards_slave_off] = old_val
48
- end
49
- else
50
- transaction_without_slave_off(*args, &block)
51
- end
52
- end
53
-
54
- module InstanceMethods
55
- # fix ActiveRecord to do the right thing, and use our aliased quote_value
56
- def quote_value(*args, &block)
57
- self.class.quote_value(*args, &block)
58
- end
59
-
60
- def reload_with_slave_off(*args, &block)
61
- self.class.on_master { reload_without_slave_off(*args, &block) }
62
- end
63
- end
64
-
65
- CLASS_SLAVE_METHODS = [:find_by_sql, :count_by_sql, :calculate, :find_one, :find_some, :find_every, :exists?].freeze
66
-
67
- def self.extended(base)
68
- CLASS_SLAVE_METHODS.each { |m| ActiveRecordShards::DefaultSlavePatches.wrap_method_in_on_slave(true, base, m) }
69
-
70
- base.class_eval do
71
- include InstanceMethods
72
-
73
- alias_method :reload_without_slave_off, :reload
74
- alias_method :reload, :reload_with_slave_off
1
+ ActiveRecordShards::Deprecation.warn('`DefaultSlavePatches` is deprecated, please use `DefaultReplicaPatches`.')
75
2
 
76
- class << self
77
- alias_method :columns_without_force_slave, :columns
78
- alias_method :columns, :columns_with_force_slave
79
-
80
- alias_method :table_exists_without_force_slave?, :table_exists?
81
- alias_method :table_exists?, :table_exists_with_force_slave?
82
-
83
- alias_method :transaction_without_slave_off, :transaction
84
- alias_method :transaction, :transaction_with_slave_off
85
- end
86
- end
87
- if ActiveRecord::Associations.const_defined?(:HasAndBelongsToManyAssociation)
88
- ActiveRecordShards::DefaultSlavePatches.wrap_method_in_on_slave(false, ActiveRecord::Associations::HasAndBelongsToManyAssociation, :construct_sql)
89
- ActiveRecordShards::DefaultSlavePatches.wrap_method_in_on_slave(false, ActiveRecord::Associations::HasAndBelongsToManyAssociation, :construct_find_options!)
90
- end
91
- end
92
-
93
- def on_slave_unless_tx
94
- if on_slave_by_default? && !Thread.current[:_active_record_shards_slave_off]
95
- on_slave { yield }
96
- else
97
- yield
98
- end
99
- end
100
-
101
- module ActiveRelationPatches
102
- def self.included(base)
103
- [:calculate, :exists?, :pluck, :find_with_associations].each do |m|
104
- ActiveRecordShards::DefaultSlavePatches.wrap_method_in_on_slave(false, base, m)
105
- end
106
- end
107
-
108
- def on_slave_unless_tx
109
- @klass.on_slave_unless_tx { yield }
110
- end
111
- end
112
-
113
- module HasAndBelongsToManyPreloaderPatches
114
- def self.included(base)
115
- ActiveRecordShards::DefaultSlavePatches.wrap_method_in_on_slave(false, base, :records_for) rescue nil # rubocop:disable Style/RescueModifier
116
- end
117
-
118
- def on_slave_unless_tx
119
- klass.on_slave_unless_tx { yield }
120
- end
121
-
122
- def exists_with_default_slave?(*args, &block)
123
- on_slave_unless_tx { exists_without_default_slave?(*args, &block) }
124
- end
125
- end
126
-
127
- # in rails 4.1+, they create a join class that's used to pull in records for HABTM.
128
- # this simplifies the hell out of our existence, because all we have to do is inerit on-slave-by-default
129
- # down from the parent now.
130
- module Rails41HasAndBelongsToManyBuilderExtension
131
- def self.included(base)
132
- base.class_eval do
133
- alias_method :through_model_without_inherit_default_slave_from_lhs, :through_model
134
- alias_method :through_model, :through_model_with_inherit_default_slave_from_lhs
135
- end
136
- end
137
-
138
- def through_model_with_inherit_default_slave_from_lhs
139
- model = through_model_without_inherit_default_slave_from_lhs
140
- def model.on_slave_by_default?
141
- left_reflection.klass.on_slave_by_default?
142
- end
143
-
144
- # also transfer the sharded-ness of the left table to the join model
145
- model.not_sharded unless model.left_reflection.klass.is_sharded?
146
- model
147
- end
148
- end
149
- end
3
+ module ActiveRecordShards
4
+ DefaultSlavePatches = DefaultReplicaPatches
150
5
  end
@@ -0,0 +1,12 @@
1
+ module ActiveRecordShards
2
+ class Deprecation < ActiveSupport::Deprecation
3
+ # This allows us to define separate deprecation behavior for ActiveRecordShards, but defaults to
4
+ # the same behavior globally configured with ActiveSupport.
5
+ #
6
+ # For example, this allows us to silence our own deprecation warnings in test while still being
7
+ # able to fail tests for upstream deprecation warnings.
8
+ def behavior
9
+ @behavior ||= ActiveSupport::Deprecation.behavior
10
+ end
11
+ end
12
+ end