Module: Familia::Horreum::DatabaseCommands

Included in:
Familia::Horreum
Defined in:
lib/familia/horreum/database_commands.rb

Overview

DatabaseCommands - Instance-level methods for horreum models that call Database commands

NOTE: There is no hgetall for Horreum. This is because Horreum is a single hash in Database that we aren't meant to have be working on in memory for more than, making changes -> committing. To emphasize this, instead of "refreshing" the object with hgetall, just load the object again.

Instance Method Summary collapse

Instance Method Details

#current_expirationInteger

Retrieves the remaining time to live (TTL) for the object's dbkey.

This method accesses the objects Database client to obtain the TTL of dbkey. If debugging is enabled, it logs the TTL retrieval operation using Familia.trace.

Returns:

  • (Integer)

    The TTL of the key in seconds. Returns -1 if the key does not exist or has no associated expire time.



88
89
90
91
# File 'lib/familia/horreum/database_commands.rb', line 88

def current_expiration
  Familia.trace :CURRENT_EXPIRATION, nil, self.class.uri if Familia.debug?
  dbclient.ttl dbkey
end

#data_typeString

Returns the Redis data type of the key.

Returns:

  • (String)

    The data type (e.g., 'hash', 'string', 'list')



106
107
108
109
# File 'lib/familia/horreum/database_commands.rb', line 106

def data_type
  Familia.trace :DATATYPE, nil, self.class.uri if Familia.debug?
  dbclient.type dbkey(suffix)
end

#decr(field) ⇒ Integer Also known as: decrement

Decrements the integer value of a hash field by 1.

Parameters:

  • field (String)

    The field name

Returns:

  • (Integer)

    The value after decrementing



222
223
224
# File 'lib/familia/horreum/database_commands.rb', line 222

def decr(field)
  dbclient.hdecr field
end

#decrby(field, decrement) ⇒ Integer Also known as: decrementby

Decrements the integer value of a hash field by the given amount.

Parameters:

  • field (String)

    The field name

  • decrement (Integer)

    The decrement value

Returns:

  • (Integer)

    The value after decrementing



213
214
215
# File 'lib/familia/horreum/database_commands.rb', line 213

def decrby(field, decrement)
  dbclient.decrby dbkey(suffix), field, decrement
end

#delete!Boolean Also known as: clear

Deletes the dbkey for this horreum :object.

It does not delete the related fields keys. See destroy!

Returns:

  • (Boolean)

    true if the key was deleted, false otherwise



250
251
252
253
254
255
# File 'lib/familia/horreum/database_commands.rb', line 250

def delete!
  Familia.trace :DELETE!, nil, self.class.uri if Familia.debug?

  # Delete the main object key
  dbclient.del dbkey
end

#discardString

Flushes all previously queued commands in a transaction and all watched keys

NOTE: This command operates on the connection itself; not a specific key

Returns:

  • (String)

    'OK' always



300
# File 'lib/familia/horreum/database_commands.rb', line 300

def discard(...) = dbclient.discard(...)

#echo(*args) ⇒ String

Echoes a message through the Redis connection.

Parameters:

  • args (Array)

    Arguments to join and echo

Returns:

  • (String)

    The echoed message



306
307
308
# File 'lib/familia/horreum/database_commands.rb', line 306

def echo(*args)
  dbclient.echo "[#{self.class}] #{args.join(' ')}"
end

#exists?(check_size: true) ⇒ Boolean

Note:

The default behavior maintains backward compatibility by treating empty hashes as non-existent. Use check_size: false for pure key existence checking.

Checks if the calling object's key exists in the database.

Examples:

Check existence with size validation (default behavior)

some_object.exists?                    # => false for empty hashes
some_object.exists?(check_size: true)  # => false for empty hashes

Check existence only

some_object.exists?(check_size: false)  # => true for empty hashes

Parameters:

  • check_size (Boolean) (defaults to: true)

    When true (default), also verifies the hash has a non-zero size. When false, only checks key existence regardless of content.

Returns:

  • (Boolean)

    Returns true if the key exists in the database. When check_size is true, also requires the hash to have at least one field.



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/familia/horreum/database_commands.rb', line 43

def exists?(check_size: true)
  key_exists = self.class.exists?(identifier)
  return key_exists unless check_size

  # Handle Redis::Future in transactions - skip size check
  if key_exists.is_a?(Redis::Future)
    return key_exists
  end

  current_size = size
  # Handle Redis::Future from size call too
  if current_size.is_a?(Redis::Future)
    return current_size
  end

  key_exists && !current_size.zero?
end

#expire(default_expiration = nil) ⇒ Integer

Sets a timeout on key. After the timeout has expired, the key will automatically be deleted. Returns 1 if the timeout was set, 0 if key does not exist or the timeout could not be set.

Parameters:

  • default_expiration (Integer) (defaults to: nil)

    TTL in seconds (uses class default if nil)

Returns:

  • (Integer)

    1 if timeout was set, 0 otherwise



75
76
77
78
79
# File 'lib/familia/horreum/database_commands.rb', line 75

def expire(default_expiration = nil)
  default_expiration ||= self.class.default_expiration
  Familia.trace :EXPIRE, nil, default_expiration if Familia.debug?
  dbclient.expire dbkey, default_expiration.to_i
end

#field_countInteger Also known as: size, length

Returns the number of fields in the main object hash

Returns:

  • (Integer)

    number of fields



63
64
65
# File 'lib/familia/horreum/database_commands.rb', line 63

def field_count
  dbclient.hlen dbkey
end

#hget(field) ⇒ String?

Gets the value of a hash field.

Parameters:

  • field (String)

    The field name

Returns:

  • (String, nil)

    The value of the field, or nil if field doesn't exist



125
126
127
128
# File 'lib/familia/horreum/database_commands.rb', line 125

def hget(field)
  Familia.trace :HGET, nil, field if Familia.debug?
  dbclient.hget dbkey(suffix), field
end

#hgetallHash Also known as: all

Note:

For parity with DataType#hgetall

Returns all fields and values in the hash.

Returns:

  • (Hash)

    All field-value pairs in the hash



115
116
117
118
# File 'lib/familia/horreum/database_commands.rb', line 115

def hgetall
  Familia.trace :HGETALL, nil, self.class.uri if Familia.debug?
  dbclient.hgetall dbkey(suffix)
end

#hkeysArray<String>

Returns all field names in the hash.

Returns:

  • (Array<String>)

    Array of field names



167
168
169
170
# File 'lib/familia/horreum/database_commands.rb', line 167

def hkeys
  Familia.trace :HKEYS, nil, self.class.uri if Familia.debug?
  dbclient.hkeys dbkey(suffix)
end

#hmset(hsh = {}) ⇒ String

Sets multiple hash fields to multiple values.

Parameters:

  • hsh (Hash) (defaults to: {})

    Hash of field-value pairs to set

Returns:

  • (String)

    'OK' on success



158
159
160
161
162
# File 'lib/familia/horreum/database_commands.rb', line 158

def hmset(hsh = {})
  hsh ||= to_h_for_storage
  Familia.trace :HMSET, nil, hsh if Familia.debug?
  dbclient.hmset dbkey(suffix), hsh
end

#hset(field, value) ⇒ Integer

Sets the value of a hash field.

Parameters:

  • field (String)

    The field name

  • value (String)

    The value to set

Returns:

  • (Integer)

    The number of fields that were added to the hash. If the field already exists, this will return 0.



136
137
138
139
# File 'lib/familia/horreum/database_commands.rb', line 136

def hset(field, value)
  Familia.trace :HSET, nil, field if Familia.debug?
  dbclient.hset dbkey, field, value
end

#hsetnx(field, value) ⇒ Integer

Sets field in the hash stored at key to value, only if field does not yet exist. If key does not exist, a new key holding a hash is created. If field already exists, this operation has no effect.

Parameters:

  • field (String)

    The field to set in the hash

  • value (String)

    The value to set for the field

Returns:

  • (Integer)

    1 if the field is a new field in the hash and the value was set, 0 if the field already exists in the hash and no operation was performed



149
150
151
152
# File 'lib/familia/horreum/database_commands.rb', line 149

def hsetnx(field, value)
  Familia.trace :HSETNX, nil, field if Familia.debug?
  dbclient.hsetnx dbkey, field, value
end

#hstrlen(field) ⇒ Integer Also known as: hstrlength

Returns the string length of the value associated with field in the hash.

Parameters:

  • field (String)

    The field name

Returns:

  • (Integer)

    The string length of the field value, or 0 if field doesn't exist



231
232
233
# File 'lib/familia/horreum/database_commands.rb', line 231

def hstrlen(field)
  dbclient.hstrlen dbkey(suffix), field
end

#hvalsArray<String>

Returns all values in the hash.

Returns:

  • (Array<String>)

    Array of values



175
176
177
# File 'lib/familia/horreum/database_commands.rb', line 175

def hvals
  dbclient.hvals dbkey(suffix)
end

#incr(field) ⇒ Integer Also known as: increment

Increments the integer value of a hash field by 1.

Parameters:

  • field (String)

    The field name

Returns:

  • (Integer)

    The value after incrementing



183
184
185
# File 'lib/familia/horreum/database_commands.rb', line 183

def incr(field)
  dbclient.hincrby dbkey(suffix), field, 1
end

#incrby(field, increment) ⇒ Integer Also known as: incrementby

Increments the integer value of a hash field by the given amount.

Parameters:

  • field (String)

    The field name

  • increment (Integer)

    The increment value

Returns:

  • (Integer)

    The value after incrementing



193
194
195
# File 'lib/familia/horreum/database_commands.rb', line 193

def incrby(field, increment)
  dbclient.hincrby dbkey(suffix), field, increment
end

#incrbyfloat(field, increment) ⇒ Float Also known as: incrementbyfloat

Increments the float value of a hash field by the given amount.

Parameters:

  • field (String)

    The field name

  • increment (Float)

    The increment value

Returns:

  • (Float)

    The value after incrementing



203
204
205
# File 'lib/familia/horreum/database_commands.rb', line 203

def incrbyfloat(field, increment)
  dbclient.hincrbyfloat dbkey(suffix), field, increment
end

#key?(field) ⇒ Boolean Also known as: has_key?

Determines if a hash field exists.

Parameters:

  • field (String)

    The field name

Returns:

  • (Boolean)

    true if the field exists, false otherwise



240
241
242
# File 'lib/familia/horreum/database_commands.rb', line 240

def key?(field)
  dbclient.hexists dbkey(suffix), field
end

#move(logical_database) ⇒ Boolean

Moves the object's key to a different logical database.

Parameters:

  • logical_database (Integer)

    The target database number

Returns:

  • (Boolean)

    true if the key was moved successfully



23
24
25
# File 'lib/familia/horreum/database_commands.rb', line 23

def move(logical_database)
  dbclient.move dbkey, logical_database
end

#remove_field(field) ⇒ Integer Also known as: remove

Removes a field from the hash stored at the dbkey.

Parameters:

  • field (String)

    The field to remove from the hash.

Returns:

  • (Integer)

    The number of fields that were removed from the hash (0 or 1).



97
98
99
100
# File 'lib/familia/horreum/database_commands.rb', line 97

def remove_field(field)
  Familia.trace :HDEL, nil, field if Familia.debug?
  dbclient.hdel dbkey, field
end

#unwatchString

Flushes all the previously watched keys for a transaction.

If a transaction completes successfully or discard is called, there's no need to manually call unwatch.

NOTE: This command operates on the connection itself; not a specific key

Returns:

  • (String)

    'OK' always, regardless of whether the key was watched or not



293
# File 'lib/familia/horreum/database_commands.rb', line 293

def unwatch(...) = dbclient.unwatch(...)

#watchString

Watches the key for changes during a MULTI/EXEC transaction.

Decision Matrix:

| Scenario | Use | Why | |----------|-----|-----| | Check if exists, then create | WATCH | Must prevent duplicate creation | | Read value, update conditionally | WATCH | Decision depends on current state | | Compare-and-swap operations | WATCH | Need optimistic locking | | Version-based updates | WATCH | Must detect concurrent changes | | Batch field updates | MULTI only | No conditional logic | | Increment + timestamp together | MULTI only | Concurrent increments OK | | Save object atomically | MULTI only | Just need atomicity | | Update indexes with save | MULTI only | No state checking needed |

Parameters:

  • suffix_override (String, nil)

    Optional suffix override

Returns:

  • (String)

    'OK' on success



275
276
277
278
279
280
281
282
283
# File 'lib/familia/horreum/database_commands.rb', line 275

def watch(...)
  raise ArgumentError, 'Block required' unless block_given?

  # Forward all arguments including the block to the watch command
  dbclient.watch(dbkey, ...)

rescue Redis::BaseError => e
  raise OptimisticLockError, "Redis error: #{e.message}"
end