active_record_shards 4.0.0.beta9 → 5.0.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,136 +0,0 @@
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
- force_cx_switch_slave_block do
30
- columns_without_force_slave(*args, &block)
31
- end
32
- end
33
-
34
- def table_exists_with_force_slave?(*args, &block)
35
- force_cx_switch_slave_block 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
75
-
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
- # in rails 4.1+, they create a join class that's used to pull in records for HABTM.
114
- # this simplifies the hell out of our existence, because all we have to do is inerit on-slave-by-default
115
- # down from the parent now.
116
- module HasAndBelongsToManyBuilderExtension
117
- def self.included(base)
118
- base.class_eval do
119
- alias_method :through_model_without_inherit_default_slave_from_lhs, :through_model
120
- alias_method :through_model, :through_model_with_inherit_default_slave_from_lhs
121
- end
122
- end
123
-
124
- def through_model_with_inherit_default_slave_from_lhs
125
- model = through_model_without_inherit_default_slave_from_lhs
126
- def model.on_slave_by_default?
127
- left_reflection.klass.on_slave_by_default?
128
- end
129
-
130
- model.extend(ActiveRecordShards::Ext::ShardedModel) if model.left_reflection.klass.is_sharded?
131
-
132
- model
133
- end
134
- end
135
- end
136
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
- module ActiveRecordShards
3
- class NoShardSelection
4
- class NoShardSelected < RuntimeError; end
5
-
6
- def shard
7
- raise NoShardSelected, "Missing shard information on connection"
8
- end
9
-
10
- def connection_config
11
- raise NoShardSelected, "No shard selected, can't connect"
12
- end
13
-
14
- def on_shard?
15
- false
16
- end
17
- end
18
- end
@@ -1,31 +0,0 @@
1
- module ActiveRecordShards
2
- module Ext
3
- module ShardedModel
4
- def self.extended(base)
5
- base.extend(ActiveRecordShards::ConnectionSwitcher)
6
- base.include(InstanceMethods)
7
- base.after_initialize :initialize_shard
8
- end
9
-
10
- def is_sharded? # rubocop:disable Naming/PredicateName
11
- true
12
- end
13
-
14
- module InstanceMethods
15
- def initialize_shard
16
- @from_shard = self.class.current_shard_selection.shard
17
- end
18
-
19
- def from_shard
20
- @from_shard
21
- end
22
- end
23
- end
24
- end
25
-
26
- class ShardedModel < ActiveRecord::Base
27
- self.abstract_class = true
28
-
29
- extend ActiveRecordShards::Ext::ShardedModel
30
- end
31
- end
@@ -1,105 +0,0 @@
1
- module ActiveRecordShards
2
- module SlaveDb
3
- def on_slave_if(condition, &block)
4
- condition ? on_slave(&block) : yield
5
- end
6
-
7
- def on_slave_unless(condition, &block)
8
- on_slave_if(!condition, &block)
9
- end
10
-
11
- def on_master_if(condition, &block)
12
- condition ? on_master(&block) : yield
13
- end
14
-
15
- def on_master_unless(condition, &block)
16
- on_master_if(!condition, &block)
17
- end
18
-
19
- def on_master_or_slave(which, &block)
20
- if block_given?
21
- on_cx_switch_block(which, &block)
22
- else
23
- MasterSlaveProxy.new(self, which)
24
- end
25
- end
26
-
27
- def on_slave?
28
- current_slave_selection
29
- end
30
-
31
- # Executes queries using the slave database. Fails over to master if no slave is found.
32
- # if you want to execute a block of code on the slave you can go:
33
- # Account.on_slave do
34
- # Account.first
35
- # end
36
- # the first account will be found on the slave DB
37
- #
38
- # For one-liners you can simply do
39
- # Account.on_slave.first
40
- def on_slave(&block)
41
- on_master_or_slave(:slave, &block)
42
- end
43
-
44
- def on_master(&block)
45
- on_master_or_slave(:master, &block)
46
- end
47
-
48
- def force_cx_switch_slave_block
49
- old_options = current_slave_selection
50
- switch_slave_connection(slave: true)
51
- yield
52
- ensure
53
- switch_slave_connection(slave: old_options)
54
- end
55
-
56
- def on_cx_switch_block(which, &block)
57
- @disallow_slave ||= 0
58
- @disallow_slave += 1 if which == :master
59
-
60
- switch_to_slave = @disallow_slave.zero?
61
- old_options = current_slave_selection
62
-
63
- switch_slave_connection(slave: switch_to_slave)
64
-
65
- # we avoid_readonly_scope to prevent some stack overflow problems, like when
66
- # .columns calls .with_scope which calls .columns and onward, endlessly.
67
- if self == ActiveRecord::Base || !switch_to_slave
68
- yield
69
- else
70
- readonly.scoping(&block)
71
- end
72
- ensure
73
- @disallow_slave -= 1 if which == :master
74
- switch_slave_connection(slave: old_options)
75
- end
76
-
77
- def current_slave_selection=(on_slave)
78
- Thread.current[:slave_selection] = on_slave
79
- end
80
-
81
- def current_slave_selection
82
- !!Thread.current[:slave_selection]
83
- end
84
-
85
- def connection_config
86
- super.merge(slave: current_slave_selection)
87
- end
88
-
89
- def switch_slave_connection(options)
90
- self.current_slave_selection = options[:slave]
91
- ensure_shard_connection
92
- end
93
-
94
- class MasterSlaveProxy
95
- def initialize(target, which)
96
- @target = target
97
- @which = which
98
- end
99
-
100
- def method_missing(method, *args, &block) # rubocop:disable Style/MethodMissing
101
- @target.on_master_or_slave(@which) { @target.send(method, *args, &block) }
102
- end
103
- end
104
- end
105
- end