active_record_shards 3.11.2 → 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.
@@ -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