Class: SwitchConnection::Proxy

Inherits:
Object
  • Object
show all
Defined in:
lib/switch_connection/proxy.rb

Constant Summary collapse

AVAILABLE_MODES =
%i[master slave].freeze
DEFAULT_MODE =
:master

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name) ⇒ Proxy

Returns a new instance of Proxy.



11
12
13
14
15
16
17
# File 'lib/switch_connection/proxy.rb', line 11

def initialize(name)
  @initial_name = name
  @current_name = name
  define_master_model(name)
  define_slave_model(name)
  @global_mode = DEFAULT_MODE
end

Instance Attribute Details

#initial_nameObject (readonly)

Returns the value of attribute initial_name.



6
7
8
# File 'lib/switch_connection/proxy.rb', line 6

def initial_name
  @initial_name
end

Instance Method Details

#cache(&block) ⇒ Object



171
172
173
174
175
# File 'lib/switch_connection/proxy.rb', line 171

def cache(&block)
  r = with_slave { model_for_connection }
  w = with_master { model_for_connection }
  r.cache { w.cache(&block) }
end

#connected?Boolean

Returns:

  • (Boolean)


167
168
169
# File 'lib/switch_connection/proxy.rb', line 167

def connected?
  model_for_connection.connected?
end

#connectionObject



163
164
165
# File 'lib/switch_connection/proxy.rb', line 163

def connection
  model_for_connection.connection
end

#db_specific(db_name) ⇒ Object



47
48
49
50
51
52
# File 'lib/switch_connection/proxy.rb', line 47

def db_specific(db_name)
  base_config = ::ActiveRecord::Base.configurations.fetch(SwitchConnection.config.env)
  return base_config if db_name == :default

  db_name.to_s.split('.').inject(base_config) { |h, n| h[n] }
end

#define_master_model(name) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/switch_connection/proxy.rb', line 19

def define_master_model(name)
  model_name = SwitchConnection.config.master_model_name(name)
  if model_name
    model = Class.new(ActiveRecord::Base)
    Proxy.const_set(model_name, model)
    master_database_name = SwitchConnection.config.master_database_name(name)
    model.establish_connection(db_specific(master_database_name))
    model
  else
    ActiveRecord::Base
  end
end

#define_slave_model(name) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/switch_connection/proxy.rb', line 32

def define_slave_model(name)
  return unless SwitchConnection.config.slave_exist?(name)

  slave_count = SwitchConnection.config.slave_count(name)
  (0..(slave_count - 1)).map do |index|
    model_name = SwitchConnection.config.slave_mode_name(name, index)
    next ActiveRecord::Base unless model_name

    model = Class.new(ActiveRecord::Base)
    Proxy.const_set(model_name, model)
    model.establish_connection(db_specific(SwitchConnection.config.slave_database_name(name, index)))
    model
  end
end

#master!Object



91
92
93
94
95
96
97
# File 'lib/switch_connection/proxy.rb', line 91

def master!
  if thread_local_mode
    self.thread_local_mode = :master
  else
    @global_mode = :master
  end
end

#master?Boolean

Returns:

  • (Boolean)


99
100
101
# File 'lib/switch_connection/proxy.rb', line 99

def master?
  mode == :master
end

#modeObject



63
64
65
# File 'lib/switch_connection/proxy.rb', line 63

def mode
  thread_local_mode || @global_mode
end

#model_for_connectionObject



148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/switch_connection/proxy.rb', line 148

def model_for_connection
  ProxyRepository.checkout(@current_name) # Ensure the target proxy is created
  model_name = SwitchConnection.config.model_name(@current_name, mode)
  if model_name
    Proxy.const_get(model_name)
  elsif mode == :slave
    # When only master is specified, re-use master connection.
    with_master do
      model_for_connection
    end
  else
    ActiveRecord::Base
  end
end

#reset_name!Object



144
145
146
# File 'lib/switch_connection/proxy.rb', line 144

def reset_name!
  @current_name = @initial_name
end

#slave!Object



79
80
81
82
83
84
85
# File 'lib/switch_connection/proxy.rb', line 79

def slave!
  if thread_local_mode
    self.thread_local_mode = :slave
  else
    @global_mode = :slave
  end
end

#slave?Boolean

Returns:

  • (Boolean)


87
88
89
# File 'lib/switch_connection/proxy.rb', line 87

def slave?
  mode == :slave
end

#switch_connection_levelObject



71
72
73
# File 'lib/switch_connection/proxy.rb', line 71

def switch_connection_level
  Thread.current[:"switch_point_#{@current_name}_level"] || 0
end

#switch_connection_level=(level) ⇒ Object



67
68
69
# File 'lib/switch_connection/proxy.rb', line 67

def switch_connection_level=(level)
  Thread.current[:"switch_point_#{@current_name}_level"] = level
end

#switch_name(new_name, &block) ⇒ Object



130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/switch_connection/proxy.rb', line 130

def switch_name(new_name, &block)
  if block
    begin
      old_name = @current_name
      @current_name = new_name
      block.call
    ensure
      @current_name = old_name
    end
  else
    @current_name = new_name
  end
end

#switch_top_level_connection?Boolean

Returns:

  • (Boolean)


75
76
77
# File 'lib/switch_connection/proxy.rb', line 75

def switch_top_level_connection?
  switch_connection_level.zero?
end

#thread_local_modeObject



54
55
56
# File 'lib/switch_connection/proxy.rb', line 54

def thread_local_mode
  Thread.current[:"switch_point_#{@current_name}_mode"]
end

#uncached(&block) ⇒ Object



177
178
179
180
181
# File 'lib/switch_connection/proxy.rb', line 177

def uncached(&block)
  r = with_slave { model_for_connection }
  w = with_master { model_for_connection }
  r.uncached { w.uncached(&block) }
end

#with_master(&block) ⇒ Object



107
108
109
# File 'lib/switch_connection/proxy.rb', line 107

def with_master(&block)
  with_mode(:master, &block)
end

#with_mode(new_mode, &block) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/switch_connection/proxy.rb', line 111

def with_mode(new_mode, &block)
  unless AVAILABLE_MODES.include?(new_mode)
    self.switch_connection_level += 1
    raise ArgumentError.new("Unknown mode: #{new_mode}")
  end

  saved_mode = thread_local_mode
  if new_mode == :slave && switch_top_level_connection?
    self.thread_local_mode = :slave
  elsif new_mode == :master
    self.thread_local_mode = :master
  end
  self.switch_connection_level += 1
  block.call
ensure
  self.thread_local_mode = saved_mode
  self.switch_connection_level -= 1
end

#with_slave(&block) ⇒ Object



103
104
105
# File 'lib/switch_connection/proxy.rb', line 103

def with_slave(&block)
  with_mode(:slave, &block)
end