Class: Familia::StringKey

Inherits:
DataType show all
Defined in:
lib/familia/data_type/types/stringkey.rb

Direct Known Subclasses

Counter, Lock

Instance Attribute Summary collapse

Attributes included from Settings

#current_key_version, #default_expiration, #delim, #encryption_keys, #encryption_personalization, #logical_database, #prefix, #schema_path, #schema_validator, #schemas, #strict_write_order, #suffix, #transaction_mode

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Features::Autoloader

autoload_files, included, normalize_to_config_name

Methods included from DataType::Serialization

#deserialize_values, #deserialize_values_with_nil

Methods included from DataType::DatabaseCommands

#current_expiration, #delete!, #echo, #exists?, #expire, #expireat, #move, #persist, #rename, #renamenx, #type

Methods included from DataType::Connection

#dbclient, #dbkey, #uri

Methods included from Connection::Behavior

#connect, #create_dbclient, #multi, #normalize_uri, #pipeline, #pipelined, #transaction, #uri=, #url, #url=

Methods included from Settings

#configure, #default_suffix, #pipelined_mode, #pipelined_mode=

Methods included from Base

add_feature, #as_json, #expired?, #expires?, find_feature, #generate_id, #to_json, #ttl, #update_expiration, #uuid

Constructor Details

This class inherits a constructor from Familia::DataType

Instance Attribute Details

#features_enabledObject (readonly) Originally defined in module Features

Returns the value of attribute features_enabled.

#logical_database(val = nil) ⇒ Object Originally defined in module DataType::ClassMethods

#parentObject Originally defined in module DataType::ClassMethods

Returns the value of attribute parent.

#prefixObject Originally defined in module DataType::ClassMethods

Returns the value of attribute prefix.

#suffixObject Originally defined in module DataType::ClassMethods

Returns the value of attribute suffix.

#uri(val = nil) ⇒ Object Originally defined in module DataType::ClassMethods

Returns the value of attribute uri.

Class Method Details

.bitop(operation, destkey, *keys, client: nil) ⇒ Integer

Note:

This method is a raw Redis passthrough and does NOT apply Familia's serialization pipeline or expiration hooks. All key arguments are used as-is (no dbkey prefixing). The destination key will not have a TTL applied automatically.

Perform bitwise operations between strings and store result

Examples:

StringKey.bitop(:and, 'result', 'key1', 'key2')

Parameters:

  • operation (String, Symbol)

    Bitwise operation: AND, OR, XOR, NOT

  • destkey (String)

    Destination key to store result

  • keys (Array<String>)

    Source keys for the operation

  • client (Redis, nil) (defaults to: nil)

    Optional Redis client (uses Familia.dbclient if nil)

Returns:

  • (Integer)

    Size of the resulting string in bytes



303
304
305
306
# File 'lib/familia/data_type/types/stringkey.rb', line 303

def bitop(operation, destkey, *keys, client: nil)
  client ||= Familia.dbclient
  client.bitop(operation.to_s.upcase, destkey, *keys)
end

.mget(*keys, client: nil) ⇒ Array

Note:

This method is a raw Redis passthrough and does NOT apply Familia's serialization pipeline. Keys are used as-is (no dbkey prefixing) and returned values are raw Redis strings. If you need round-trip compatibility with StringKey instances, read via the instance #value getter or a Familia.dbclient.get(instance.dbkey) call.

Get values for multiple keys

Examples:

StringKey.mget('user:1:name', 'user:2:name')

Parameters:

  • keys (Array<String>)

    Full Redis key names

  • client (Redis, nil) (defaults to: nil)

    Optional Redis client (uses Familia.dbclient if nil)

Returns:

  • (Array)

    Values for each key (nil for non-existent keys)



250
251
252
253
# File 'lib/familia/data_type/types/stringkey.rb', line 250

def mget(*keys, client: nil)
  client ||= Familia.dbclient
  client.mget(*keys)
end

.mset(hash, client: nil) ⇒ String

Note:

This method is a raw Redis passthrough and does NOT apply Familia's serialization pipeline or expiration hooks. Keys are used as-is (no dbkey prefixing) and values are written as-is. For round-trip compatibility with StringKey instances, write via the instance #value= setter (which calls serialize_value and update_expiration).

Set multiple keys atomically. Keys and values are extracted from the hash for the Redis MSET command.

Examples:

StringKey.mset('user:1:name' => 'Alice', 'user:2:name' => 'Bob')

Parameters:

  • hash (Hash)

    Key-value pairs to set

  • client (Redis, nil) (defaults to: nil)

    Optional Redis client (uses Familia.dbclient if nil)

Returns:

  • (String)

    "OK" on success



268
269
270
271
# File 'lib/familia/data_type/types/stringkey.rb', line 268

def mset(hash, client: nil)
  client ||= Familia.dbclient
  client.mset(*hash.flatten)
end

.msetnx(hash, client: nil) ⇒ Boolean

Note:

This method is a raw Redis passthrough and does NOT apply Familia's serialization pipeline or expiration hooks. Keys are used as-is (no dbkey prefixing) and values are written as-is. For round-trip compatibility with StringKey instances, write via the instance #value= setter (which calls serialize_value and update_expiration).

Set multiple keys only if none of them exist. Keys and values are extracted from the hash for the Redis MSETNX command.

Examples:

StringKey.msetnx('user:1:name' => 'Alice', 'user:2:name' => 'Bob')

Parameters:

  • hash (Hash)

    Key-value pairs to set

  • client (Redis, nil) (defaults to: nil)

    Optional Redis client (uses Familia.dbclient if nil)

Returns:

  • (Boolean)

    true if all keys were set, false if none were set



286
287
288
289
# File 'lib/familia/data_type/types/stringkey.rb', line 286

def msetnx(hash, client: nil)
  client ||= Familia.dbclient
  client.msetnx(*hash.flatten)
end

Instance Method Details

#append(val) ⇒ Object Also known as: <<



107
108
109
110
111
# File 'lib/familia/data_type/types/stringkey.rb', line 107

def append(val)
  ret = dbclient.append dbkey, val
  update_expiration
  ret
end

#bitcount(start_pos = nil, end_pos = nil) ⇒ Integer

Count the number of set bits (population counting)

Parameters:

  • start_pos (Integer, nil) (defaults to: nil)

    Start byte position (optional)

  • end_pos (Integer, nil) (defaults to: nil)

    End byte position (optional)

Returns:

  • (Integer)

    Number of bits set to 1



194
195
196
197
198
199
200
201
202
# File 'lib/familia/data_type/types/stringkey.rb', line 194

def bitcount(start_pos = nil, end_pos = nil)
  if start_pos && end_pos
    dbclient.bitcount(dbkey, start_pos, end_pos)
  elsif start_pos
    dbclient.bitcount(dbkey, start_pos)
  else
    dbclient.bitcount(dbkey)
  end
end

#bitfield(*args) ⇒ Array

Perform bitfield operations on this string

Examples:

Get an unsigned 8-bit integer at offset 0

str.bitfield('GET', 'u8', 0)

Set and increment

str.bitfield('SET', 'u8', 0, 100, 'INCRBY', 'i5', 100, 1)

Parameters:

  • args (Array)

    Bitfield subcommands and arguments

Returns:

  • (Array)

    Results of the bitfield operations



226
227
228
229
230
# File 'lib/familia/data_type/types/stringkey.rb', line 226

def bitfield(*args)
  ret = dbclient.bitfield(dbkey, *args)
  update_expiration
  ret
end

#bitpos(bit, start_pos = nil, end_pos = nil) ⇒ Integer

Find the position of the first bit set to 0 or 1

Parameters:

  • bit (Integer)

    The bit value to search for (0 or 1)

  • start_pos (Integer, nil) (defaults to: nil)

    Start byte position (optional)

  • end_pos (Integer, nil) (defaults to: nil)

    End byte position (optional)

Returns:

  • (Integer)

    Position of the first bit, or -1 if not found



209
210
211
212
213
214
215
216
217
# File 'lib/familia/data_type/types/stringkey.rb', line 209

def bitpos(bit, start_pos = nil, end_pos = nil)
  if start_pos && end_pos
    dbclient.bitpos(dbkey, bit, start_pos, end_pos)
  elsif start_pos
    dbclient.bitpos(dbkey, bit, start_pos)
  else
    dbclient.bitpos(dbkey, bit)
  end
end

#char_countInteger Also known as: size, length

Returns the number of elements in the list

Returns:

  • (Integer)

    number of elements



33
34
35
# File 'lib/familia/data_type/types/stringkey.rb', line 33

def char_count
  to_s.size
end

#decrementObject Also known as: decr



93
94
95
96
97
# File 'lib/familia/data_type/types/stringkey.rb', line 93

def decrement
  ret = dbclient.decr dbkey
  update_expiration
  ret
end

#decrementby(val) ⇒ Object Also known as: decrby



100
101
102
103
104
# File 'lib/familia/data_type/types/stringkey.rb', line 100

def decrementby(val)
  ret = dbclient.decrby dbkey, val.to_i
  update_expiration
  ret
end

#delObject



232
233
234
235
# File 'lib/familia/data_type/types/stringkey.rb', line 232

def del
  ret = dbclient.del dbkey
  ret.positive?
end

#deserialize_value(val) ⇒ Object

StringKey returns raw values (not JSON parsed)



25
26
27
28
29
# File 'lib/familia/data_type/types/stringkey.rb', line 25

def deserialize_value(val)
  return val if val.is_a?(Redis::Future)
  return @opts[:default] if val.nil?
  val
end

#empty?Boolean

Returns:

  • (Boolean)


39
40
41
# File 'lib/familia/data_type/types/stringkey.rb', line 39

def empty?
  char_count.zero?
end

#getbit(offset) ⇒ Object



114
115
116
# File 'lib/familia/data_type/types/stringkey.rb', line 114

def getbit(offset)
  dbclient.getbit dbkey, offset
end

#getdelString?

Atomically get and delete the value

Returns:

  • (String, nil)

    The value before deletion, or nil if key didn't exist



142
143
144
# File 'lib/familia/data_type/types/stringkey.rb', line 142

def getdel
  dbclient.getdel(dbkey)
end

#getex(ex: nil, px: nil, exat: nil, pxat: nil, persist: false) ⇒ String?

Get value and optionally set expiration atomically

Parameters:

  • ex (Integer, nil) (defaults to: nil)

    Set expiration in seconds

  • px (Integer, nil) (defaults to: nil)

    Set expiration in milliseconds

  • exat (Integer, nil) (defaults to: nil)

    Set expiration at Unix timestamp (seconds)

  • pxat (Integer, nil) (defaults to: nil)

    Set expiration at Unix timestamp (milliseconds)

  • persist (Boolean) (defaults to: false)

    Remove existing expiration

Returns:

  • (String, nil)

    The value



153
154
155
156
157
158
159
160
161
162
# File 'lib/familia/data_type/types/stringkey.rb', line 153

def getex(ex: nil, px: nil, exat: nil, pxat: nil, persist: false)
  options = {}
  options[:ex] = ex if ex
  options[:px] = px if px
  options[:exat] = exat if exat
  options[:pxat] = pxat if pxat
  options[:persist] = persist if persist

  dbclient.getex(dbkey, **options)
end

#getrange(spoint, epoint) ⇒ Object



124
125
126
# File 'lib/familia/data_type/types/stringkey.rb', line 124

def getrange(spoint, epoint)
  dbclient.getrange dbkey, spoint, epoint
end

#getset(val) ⇒ Object



134
135
136
137
138
# File 'lib/familia/data_type/types/stringkey.rb', line 134

def getset(val)
  ret = dbclient.getset dbkey, val
  update_expiration
  ret
end

#incrbyfloat(val) ⇒ Float Also known as: incrfloat

Increment value by a float amount

Parameters:

  • val (Float, Numeric)

    The amount to increment by

Returns:

  • (Float)

    The new value after increment



167
168
169
170
171
# File 'lib/familia/data_type/types/stringkey.rb', line 167

def incrbyfloat(val)
  ret = dbclient.incrbyfloat(dbkey, val.to_f)
  update_expiration
  ret
end

#incrementObject Also known as: incr



79
80
81
82
83
# File 'lib/familia/data_type/types/stringkey.rb', line 79

def increment
  ret = dbclient.incr(dbkey)
  update_expiration
  ret
end

#incrementby(val) ⇒ Object Also known as: incrby



86
87
88
89
90
# File 'lib/familia/data_type/types/stringkey.rb', line 86

def incrementby(val)
  ret = dbclient.incrby(dbkey, val.to_i)
  update_expiration
  ret
end

#initObject



7
# File 'lib/familia/data_type/types/stringkey.rb', line 7

def init; end

#psetex(milliseconds, val) ⇒ String

Set value with expiration in milliseconds

Parameters:

  • milliseconds (Integer)

    Expiration time in milliseconds

  • val (Object)

    The value to set

Returns:

  • (String)

    "OK" on success



186
187
188
# File 'lib/familia/data_type/types/stringkey.rb', line 186

def psetex(milliseconds, val)
  dbclient.psetex(dbkey, milliseconds.to_i, serialize_value(val))
end

#serialize_value(val) ⇒ Object

StringKey uses raw string serialization (not JSON) because Redis string operations like INCR, DECR, APPEND operate on raw values. This overrides the base JSON serialization from DataType.



12
13
14
15
16
17
18
19
20
21
22
# File 'lib/familia/data_type/types/stringkey.rb', line 12

def serialize_value(val)
  Familia.trace :TOREDIS, nil, "#{val}<#{val.class}>" if Familia.debug?

  # Handle Familia object references - extract identifier
  if val.is_a?(Familia::Base) || (val.is_a?(Class) && val.ancestors.include?(Familia::Base))
    return val.is_a?(Class) ? val.name : val.identifier
  end

  # StringKey uses raw string conversion for Redis compatibility
  val.to_s
end

#setbit(offset, val) ⇒ Object



118
119
120
121
122
# File 'lib/familia/data_type/types/stringkey.rb', line 118

def setbit(offset, val)
  ret = dbclient.setbit dbkey, offset, val
  update_expiration
  ret
end

#setex(seconds, val) ⇒ String

Set value with expiration in seconds

Parameters:

  • seconds (Integer)

    Expiration time in seconds

  • val (Object)

    The value to set

Returns:

  • (String)

    "OK" on success



178
179
180
# File 'lib/familia/data_type/types/stringkey.rb', line 178

def setex(seconds, val)
  dbclient.setex(dbkey, seconds.to_i, serialize_value(val))
end

#setnx(val) ⇒ Object



73
74
75
76
77
# File 'lib/familia/data_type/types/stringkey.rb', line 73

def setnx(val)
  ret = dbclient.setnx(dbkey, serialize_value(val))
  update_expiration
  ret
end

#setrange(offset, val) ⇒ Object



128
129
130
131
132
# File 'lib/familia/data_type/types/stringkey.rb', line 128

def setrange(offset, val)
  ret = dbclient.setrange dbkey, offset, val
  update_expiration
  ret
end

#to_iObject



57
58
59
# File 'lib/familia/data_type/types/stringkey.rb', line 57

def to_i
  value.to_i
end

#to_sObject



51
52
53
54
55
# File 'lib/familia/data_type/types/stringkey.rb', line 51

def to_s
  return super if value.to_s.empty?

  value.to_s
end

#valueObject Also known as: content, get



43
44
45
46
47
# File 'lib/familia/data_type/types/stringkey.rb', line 43

def value
  echo :value, Familia.pretty_stack(limit: 1) if Familia.debug
  dbclient.setnx dbkey, @opts[:default] if @opts[:default]
  deserialize_value dbclient.get(dbkey)
end

#value=(val) ⇒ Object Also known as: replace, set

Note:

This method executes a Redis SET immediately, unlike scalar field setters which are deferred until save. If the parent object has unsaved scalar field changes, consider calling save first to avoid split-brain state.



64
65
66
67
68
69
# File 'lib/familia/data_type/types/stringkey.rb', line 64

def value=(val)
  warn_if_dirty!
  ret = dbclient.set(dbkey, serialize_value(val))
  update_expiration
  ret
end