Class: Smith::PersistenceAdapters::ActiveRecordStore

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

Instance Attribute Summary

Attributes included from ActiveRecordExactStore

#persistence_identity

Instance Method Summary collapse

Methods included from ActiveRecordExactStore

#replace_exact

Constructor Details

#initialize(model:, key_column: :key, payload_column: :payload, version_column: :lock_version, identity: nil) ⇒ 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.



11
12
13
14
15
16
17
# File 'lib/smith/persistence_adapters/active_record_store.rb', line 11

def initialize(model:, key_column: :key, payload_column: :payload, version_column: :lock_version, identity: nil)
  @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)
  @persistence_identity = identity.to_s.dup.freeze if identity
end

Instance Method Details

#delete(key) ⇒ Object



36
37
38
39
40
# File 'lib/smith/persistence_adapters/active_record_store.rb', line 36

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



30
31
32
33
34
# File 'lib/smith/persistence_adapters/active_record_store.rb', line 30

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



19
20
21
22
23
24
25
26
27
28
# File 'lib/smith/persistence_adapters/active_record_store.rb', line 19

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.



50
51
52
53
54
55
56
57
# File 'lib/smith/persistence_adapters/active_record_store.rb', line 50

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_identityObject



44
# File 'lib/smith/persistence_adapters/active_record_store.rb', line 44

def transaction_identity = model_class.respond_to?(:current_transaction) && model_class.current_transaction.uuid

#transaction_open?Boolean

Returns:

  • (Boolean)


42
# File 'lib/smith/persistence_adapters/active_record_store.rb', line 42

def transaction_open? = model_class.connection.transaction_open?