Class: Smith::PersistenceAdapters::ActiveRecordStore

Inherits:
Object
  • Object
show all
Defined in:
lib/smith/persistence_adapters/active_record_store.rb

Instance Method Summary collapse

Constructor Details

#initialize(model:, key_column: :key, payload_column: :payload, version_column: :lock_version) ⇒ ActiveRecordStore

AR transient errors resolved via class-name guard so Smith doesn't require activerecord at load time. Hosts that use this adapter already have activerecord in their dep tree.



9
10
11
12
13
14
# File 'lib/smith/persistence_adapters/active_record_store.rb', line 9

def initialize(model:, key_column: :key, payload_column: :payload, version_column: :lock_version)
  @model_source = model.is_a?(String) ? model.dup.freeze : model
  @key_column = normalize_column(key_column)
  @payload_column = normalize_column(payload_column)
  @version_column = normalize_column(version_column)
end

Instance Method Details

#delete(key) ⇒ Object



33
34
35
36
37
# File 'lib/smith/persistence_adapters/active_record_store.rb', line 33

def delete(key)
  Retry.with_retries(operation: :delete, transient: ActiveRecordConnectionErrors.classes) do
    model_class.where(@key_column => key).delete_all
  end
end

#fetch(key) ⇒ Object



27
28
29
30
31
# File 'lib/smith/persistence_adapters/active_record_store.rb', line 27

def fetch(key)
  Retry.with_retries(operation: :fetch, transient: ActiveRecordConnectionErrors.classes) do
    model_class.find_by(@key_column => key)&.public_send(@payload_column)
  end
end

#store(key, payload, ttl: nil) ⇒ Object

rubocop:disable Lint/UnusedMethodArgument



16
17
18
19
20
21
22
23
24
25
# File 'lib/smith/persistence_adapters/active_record_store.rb', line 16

def store(key, payload, ttl: nil) # rubocop:disable Lint/UnusedMethodArgument
  # TTL is deferred for ActiveRecordStore — would require an
  # `expires_at` column + a periodic sweeper job. Ignored here;
  # documented as a known limitation.
  Retry.with_retries(operation: :store, transient: ActiveRecordConnectionErrors.classes) do
    record = model_class.find_or_initialize_by(@key_column => key)
    record.public_send(:"#{@payload_column}=", payload)
    record.save!
  end
end

#store_versioned(key, payload, expected_version:, ttl: nil) ⇒ Object

Optimistic locking via Rails' built-in optimistic locking on the lock_version column. Requires the AR model to have a lock_version (or configured) integer column with default 0. If absent, raises ArgumentError directing the host to migrate.



47
48
49
50
51
52
53
54
# File 'lib/smith/persistence_adapters/active_record_store.rb', line 47

def store_versioned(key, payload, expected_version:, ttl: nil) # rubocop:disable Lint/UnusedMethodArgument
  ensure_version_column!
  ensure_locking_configuration!

  write_versioned(key, payload, expected_version)
rescue *ActiveRecordConnectionErrors.classes => e
  raise Smith::PersistenceIOError.new(operation: :store_versioned, cause: e)
end

#transaction_open?Boolean

Returns:

  • (Boolean)


39
40
41
# File 'lib/smith/persistence_adapters/active_record_store.rb', line 39

def transaction_open?
  model_class.connection.transaction_open?
end