Module: Semian::ActiveRecordAdapter

Included in:
ActiveRecordPostgreSQLAdapter, ActiveRecordTrilogyAdapter
Defined in:
lib/semian/activerecord_adapter.rb

Defined Under Namespace

Modules: ClassMethods

Constant Summary collapse

QUERY_ALLOWLIST =
%r{\A(?:/\*.*?\*/)?\s*(ROLLBACK|COMMIT|RELEASE\s+SAVEPOINT)}i

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object



33
34
35
36
37
38
# File 'lib/semian/activerecord_adapter.rb', line 33

def included(base)
  base.extend(ClassMethods)
  base.class_eval do
    attr_reader(:raw_semian_options, :semian_identifier)
  end
end

Instance Method Details

#active?Boolean

Returns:

  • (Boolean)


95
96
97
98
99
100
101
# File 'lib/semian/activerecord_adapter.rb', line 95

def active?
  acquire_semian_resource(adapter: semian_adapter_name, scope: :ping) do
    super
  end
rescue resource_busy_error_class, circuit_open_error_class
  false
end

#execute_intent(intent) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/semian/activerecord_adapter.rb', line 58

def execute_intent(intent)
  return super if self.class.query_allowlisted?(intent.processed_sql)

  result = nil
  delivered_error = nil

  acquire_semian_resource(adapter: semian_adapter_name, scope: :query) do
    result = super

    # In Rails 8.2 execute_intent no longer raises errors. Instead, they are stored on the intent
    # and handled later by the caller to better enable asynchronous execution. However, we need to raise
    # any errors here to trip the circuit breaker. Then we can swallow the error and return the result for
    # Rails to continue with.
    if intent.respond_to?(:error)
      delivered_error = intent.error
      raise delivered_error if delivered_error
    end
  end
rescue => error
  if error.equal?(delivered_error)
    result
  else
    raise
  end
end

#initialize(*options) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/semian/activerecord_adapter.rb', line 41

def initialize(*options)
  *, config = options
  config = config.dup
  @raw_semian_options = config.delete(:semian)
  @semian_identifier = begin
    name = semian_options && semian_options[:name]
    unless name
      host = config[:host] || "localhost"
      port = config[:port] || semian_adapter_default_port
      name = "#{host}:#{port}"
    end
    :"#{semian_adapter_identifier_prefix}_#{name}"
  end
  super
end

#raw_execute(sql, *args, **kwargs, &block) ⇒ Object



84
85
86
87
88
89
90
91
92
# File 'lib/semian/activerecord_adapter.rb', line 84

def raw_execute(sql, *args, **kwargs, &block)
  if self.class.query_allowlisted?(sql)
    super
  else
    acquire_semian_resource(adapter: semian_adapter_name, scope: :query) do
      super(sql, *args, **kwargs, &block)
    end
  end
end

#with_resource_timeoutObject

Raises:

  • (NotImplementedError)


103
104
105
# File 'lib/semian/activerecord_adapter.rb', line 103

def with_resource_timeout
  raise NotImplementedError, "#{self.class} must implement a `with_resource_timeout` method"
end