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.



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

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.



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

def initial_name
  @initial_name
end

Instance Method Details

#cache(&block) ⇒ Object



153
154
155
156
157
# File 'lib/switch_connection/proxy.rb', line 153

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)


149
150
151
# File 'lib/switch_connection/proxy.rb', line 149

def connected?
  model_for_connection.connected?
end

#connectionObject



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

def connection
  model_for_connection.connection
end

#db_specific(db_name) ⇒ Object



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

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



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

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



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

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



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

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

#master?Boolean

Returns:

  • (Boolean)


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

def master?
  mode == :master
end

#modeObject



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

def mode
  thread_local_mode || @global_mode
end

#model_for_connectionObject



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

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



126
127
128
# File 'lib/switch_connection/proxy.rb', line 126

def reset_name!
  @current_name = @initial_name
end

#slave!Object



68
69
70
71
72
73
74
# File 'lib/switch_connection/proxy.rb', line 68

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

#slave?Boolean

Returns:

  • (Boolean)


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

def slave?
  mode == :slave
end

#switch_name(new_name, &block) ⇒ Object



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

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

#thread_local_modeObject



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

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

#uncached(&block) ⇒ Object



159
160
161
162
163
# File 'lib/switch_connection/proxy.rb', line 159

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



96
97
98
# File 'lib/switch_connection/proxy.rb', line 96

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

#with_mode(new_mode, &block) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
# File 'lib/switch_connection/proxy.rb', line 100

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

  saved_mode = thread_local_mode
  self.thread_local_mode = new_mode
  block.call
ensure
  self.thread_local_mode = saved_mode
end

#with_slave(&block) ⇒ Object



92
93
94
# File 'lib/switch_connection/proxy.rb', line 92

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