lib/switch_point/model.rb
# frozen_string_literal: true
require 'switch_point/error'
require 'switch_point/proxy_repository'
module SwitchPoint
module Model
def self.included(model)
super
model.singleton_class.class_eval do
include ClassMethods
prepend MonkeyPatch
end
end
def with_readonly(&block)
self.class.with_readonly(&block)
end
def with_writable(&block)
self.class.with_writable(&block)
end
def transaction_with(*models, &block)
self.class.transaction_with(*models, &block)
end
module ClassMethods
def with_readonly(&block)
if switch_point_proxy
switch_point_proxy.with_readonly(&block)
else
raise UnconfiguredError.new("#{name} isn't configured to use switch_point")
end
end
def with_writable(&block)
if switch_point_proxy
switch_point_proxy.with_writable(&block)
else
raise UnconfiguredError.new("#{name} isn't configured to use switch_point")
end
end
def use_switch_point(name)
assert_existing_switch_point!(name)
@switch_point_name = name
end
def switch_point_proxy
if defined?(@switch_point_name)
ProxyRepository.checkout(@switch_point_name)
elsif self == ActiveRecord::Base
nil
else
superclass.switch_point_proxy
end
end
def transaction_with(*models, &block)
unless can_transaction_with?(*models)
raise Error.new("switch_point's model names must be consistent")
end
with_writable do
transaction(&block)
end
end
private
def assert_existing_switch_point!(name)
SwitchPoint.config.fetch(name)
end
def can_transaction_with?(*models)
writable_switch_points = [self, *models].map do |model|
if model.instance_variable_defined?(:@switch_point_name)
SwitchPoint.config.model_name(
model.instance_variable_get(:@switch_point_name),
:writable
)
end
end
writable_switch_points.uniq.size == 1
end
end
module MonkeyPatch
def connection
if switch_point_proxy
switch_point_proxy.connection
else
super
end
end
def cache(&block)
if switch_point_proxy
switch_point_proxy.cache(&block)
else
super
end
end
def uncached(&block)
if switch_point_proxy
switch_point_proxy.uncached(&block)
else
super
end
end
end
end
end