Module: Valkey::Commands::GenericCommands

Included in:
Valkey::Commands
Defined in:
lib/valkey/commands/generic_commands.rb

Overview

this module contains generic commands that are not specific to any data type

Instance Method Summary collapse

Instance Method Details

#_scan(command, cursor, args, match: nil, count: nil, type: nil, &block) ⇒ Object



526
527
528
529
530
531
532
533
534
535
# File 'lib/valkey/commands/generic_commands.rb', line 526

def _scan(command, cursor, args, match: nil, count: nil, type: nil, &block)
  # SSCAN/ZSCAN/HSCAN already prepend the key to +args+.

  args << cursor
  args << "MATCH" << match if match
  args << "COUNT" << Integer(count) if count
  args << "TYPE" << type if type

  send_command(command, args, &block)
end

#call(*argv, route: nil, **kwargs) ⇒ Object

Send any command as plain arguments and get the raw reply back, with no per-command method needed. Escape hatch for commands without a dedicated method yet, matching redis-client's #call.

Examples:

Basic dispatch

valkey.call("SET", "mykey", "value")
  # => "OK"

Integers/Floats auto-stringify

valkey.call("SET", "mykey", 42)
  # equivalent to call("SET", "mykey", "42")

Arrays flatten

valkey.call("LPUSH", "list", [1, 2, 3])
  # equivalent to call("LPUSH", "list", "1", "2", "3")

Hashes flatten to alternating key/value

valkey.call("HMSET", "hash", { "foo" => "1" })
  # equivalent to call("HMSET", "hash", "foo", "1")

Keyword args become command flags; falsy/nil flags are dropped

valkey.call("SET", "k", "v", nx: true, ex: 60)
  # equivalent to call("SET", "k", "v", "NX", "EX", "60")

Parameters:

  • argv (Array<String, Integer, Float, Array, Hash>)

    command name and its arguments

  • kwargs (Hash)

    trailing command flags; truthy values emit the upcased flag name, non-boolean values also emit the stringified value; falsy/nil values are dropped

  • route (Valkey::Route, nil) (defaults to: nil)

    cluster routing. When routed, may return a Hash of node => value.

Returns:

  • (Object)

    the raw reply, with no type-casting based on the command name

See Also:



564
565
566
# File 'lib/valkey/commands/generic_commands.rb', line 564

def call(*argv, route: nil, **kwargs)
  send_command(RequestType::CUSTOM_COMMAND, flatten_call_args(argv).concat(call_flags(kwargs)), route: route)
end

#call_v(argv, route: nil) ⇒ Object

Send any command as a single Array of arguments and get the raw reply back. Same as #call but takes the whole command as one Array instead of splatted args, useful when the command is built dynamically. Matches redis-client's #call_v — no keyword flags.

Examples:

valkey.call_v(["MGET"] + keys)

Parameters:

  • argv (Array<String, Integer, Float, Array, Hash>)

    command name and its arguments

  • route (Valkey::Route, nil) (defaults to: nil)

    cluster routing. When routed, may return a Hash of node => value.

Returns:

  • (Object)

    the raw reply, with no type-casting based on the command name

See Also:



581
582
583
# File 'lib/valkey/commands/generic_commands.rb', line 581

def call_v(argv, route: nil)
  send_command(RequestType::CUSTOM_COMMAND, flatten_call_args(argv), route: route)
end

#copy(source, destination, db: nil, replace: false) ⇒ Boolean

Copy a value from one key to another.

Examples:

Copy a value to another key

valkey.set "foo", "value"
  # => "OK"
valkey.copy "foo", "bar"
  # => true
valkey.get "bar"
  # => "value"

Copy a value to a key in another database

valkey.set "foo", "value"
  # => "OK"
valkey.copy "foo", "bar", db: 2
  # => true
valkey.select 2
  # => "OK"
valkey.get "bar"
  # => "value"

Parameters:

  • source (String)
  • destination (String)
  • db (Integer) (defaults to: nil)
  • replace (Boolean) (defaults to: false)

    removes the destination key before copying value to it

Returns:

  • (Boolean)

    whether the key was copied or not



380
381
382
383
384
385
386
# File 'lib/valkey/commands/generic_commands.rb', line 380

def copy(source, destination, db: nil, replace: false)
  args = [source, destination]
  args << "DB" << db if db
  args << "REPLACE" if replace

  send_command(RequestType::COPY, args)
end

#del(*keys) ⇒ Integer

Delete one or more keys.

Parameters:

  • keys (String, Array<String>)

Returns:

  • (Integer)

    number of keys that were deleted



301
302
303
304
305
306
# File 'lib/valkey/commands/generic_commands.rb', line 301

def del(*keys)
  keys.flatten!(1)
  return 0 if keys.empty?

  send_command(RequestType::DEL, keys)
end

#dump(key) ⇒ String

Return a serialized version of the value stored at a key.

Parameters:

  • key (String)

Returns:

  • (String)

    serialized_value



217
218
219
# File 'lib/valkey/commands/generic_commands.rb', line 217

def dump(key)
  send_command(RequestType::DUMP, [key])
end

#exists(*keys) ⇒ Integer

Determine how many of the keys exists.

Parameters:

  • keys (String, Array<String>)

Returns:

  • (Integer)


320
321
322
# File 'lib/valkey/commands/generic_commands.rb', line 320

def exists(*keys)
  send_command(RequestType::EXISTS, keys.flatten)
end

#exists?(*keys) ⇒ Boolean

Determine if any of the keys exists.

Parameters:

  • keys (String, Array<String>)

Returns:

  • (Boolean)


328
329
330
# File 'lib/valkey/commands/generic_commands.rb', line 328

def exists?(*keys)
  send_command(RequestType::EXISTS, keys.flatten, &:positive?)
end

#expire(key, seconds, nx: nil, xx: nil, gt: nil, lt: nil) ⇒ Boolean

Set a key's time to live in seconds.

Parameters:

  • key (String)
  • seconds (Integer)

    time to live

  • options (Hash)
    • :nx => true: Set expiry only when the key has no expiry.
    • :xx => true: Set expiry only when the key has an existing expiry.
    • :gt => true: Set expiry only when the new expiry is greater than current one.
    • :lt => true: Set expiry only when the new expiry is less than current one.

Returns:

  • (Boolean)

    whether the timeout was set or not



96
97
98
99
100
101
102
103
104
# File 'lib/valkey/commands/generic_commands.rb', line 96

def expire(key, seconds, nx: nil, xx: nil, gt: nil, lt: nil)
  args = [key, Integer(seconds)]
  args << "NX" if nx
  args << "XX" if xx
  args << "GT" if gt
  args << "LT" if lt

  send_command(RequestType::EXPIRE, args)
end

#expireat(key, unix_time, nx: nil, xx: nil, gt: nil, lt: nil) ⇒ Boolean

Set the expiration for a key as a UNIX timestamp.

Parameters:

  • key (String)
  • unix_time (Integer)

    expiry time specified as a UNIX timestamp

  • options (Hash)
    • :nx => true: Set expiry only when the key has no expiry.
    • :xx => true: Set expiry only when the key has an existing expiry.
    • :gt => true: Set expiry only when the new expiry is greater than current one.
    • :lt => true: Set expiry only when the new expiry is less than current one.

Returns:

  • (Boolean)

    whether the timeout was set or not



116
117
118
119
120
121
122
123
124
# File 'lib/valkey/commands/generic_commands.rb', line 116

def expireat(key, unix_time, nx: nil, xx: nil, gt: nil, lt: nil)
  args = [key, Integer(unix_time)]
  args << "NX" if nx
  args << "XX" if xx
  args << "GT" if gt
  args << "LT" if lt

  send_command(RequestType::EXPIRE_AT, args)
end

#expiretime(key) ⇒ Integer

Get a key's expiry time specified as number of seconds from UNIX Epoch

Parameters:

  • key (String)

Returns:

  • (Integer)

    expiry time specified as number of seconds from UNIX Epoch



130
131
132
# File 'lib/valkey/commands/generic_commands.rb', line 130

def expiretime(key)
  send_command(RequestType::EXPIRE_TIME, [key])
end

#keys(pattern = "*") ⇒ Array<String>

Find all keys matching the given pattern.

Examples:

Find all keys

valkey.keys
  # => ["key1", "key2", ...]

Find keys matching a pattern

valkey.keys("user:*")
  # => ["user:1", "user:2"]

Parameters:

  • pattern (String) (defaults to: "*")

    glob-style pattern (default: "*")

Returns:

  • (Array<String>)

    array of matching keys

See Also:



287
288
289
290
291
292
293
294
295
# File 'lib/valkey/commands/generic_commands.rb', line 287

def keys(pattern = "*")
  send_command(RequestType::KEYS, [pattern]) do |reply|
    if reply.is_a?(String)
      reply.split
    else
      reply
    end
  end
end

#migrate(key, options) ⇒ String

Transfer a key from the connected instance to another instance.

Examples:

Migrate a single key

valkey.migrate("mykey", host: "127.0.0.1", port: 6380)
  # => "OK"

Migrate with copy and replace

valkey.migrate("mykey", host: "127.0.0.1", port: 6380, copy: true, replace: true)
  # => "OK"

Migrate multiple keys

valkey.migrate(["key1", "key2"], host: "127.0.0.1", port: 6380)
  # => "OK"

Parameters:

  • key (String, Array<String>)

    single key or array of keys to migrate

  • options (Hash)
    • :host => String: host of instance to migrate to (required)
    • :port => Integer: port of instance to migrate to (required)
    • :db => Integer: database to migrate to (default: 0)
    • :timeout => Integer: timeout in milliseconds (default: 0)
    • :copy => Boolean: do not remove the key from the local instance
    • :replace => Boolean: replace existing key on the remote instance

Returns:

  • (String)

    "OK"

See Also:



260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/valkey/commands/generic_commands.rb', line 260

def migrate(key, options)
  args = []
  args << (options[:host] || raise(ArgumentError, ':host not specified'))
  args << (options[:port] || raise(ArgumentError, ':port not specified')).to_s
  args << (key.is_a?(String) ? key : '')
  args << (options[:db] || 0).to_s
  args << (options[:timeout] || 0).to_s
  args << 'COPY' if options[:copy]
  args << 'REPLACE' if options[:replace]
  args += ['KEYS', *key] if key.is_a?(Array)

  send_command(RequestType::MIGRATE, args)
end

#move(key, db) ⇒ Boolean

Move a key to another database.

Examples:

Move a key to another database

valkey.set "foo", "bar"
  # => "OK"
valkey.move "foo", 2
  # => true
valkey.exists "foo"
  # => false
valkey.select 2
  # => "OK"
valkey.exists "foo"
  # => true
valkey.get "foo"
  # => "bar"

Parameters:

  • key (String)
  • db (Integer)

Returns:

  • (Boolean)

    whether the key was moved or not



351
352
353
# File 'lib/valkey/commands/generic_commands.rb', line 351

def move(key, db)
  send_command(RequestType::MOVE, [key, db])
end

#object(subcommand, *args) ⇒ Object



388
389
390
391
392
393
394
395
396
397
# File 'lib/valkey/commands/generic_commands.rb', line 388

def object(subcommand, *args)
  map = {
    refcount: RequestType::OBJECT_REF_COUNT,
    encoding: RequestType::OBJECT_ENCODING,
    idletime: RequestType::OBJECT_IDLE_TIME,
    freq: RequestType::OBJECT_FREQ
  }

  send_command(map[subcommand.to_sym], args.flatten)
end

#persist(key) ⇒ Boolean

Remove the expiration from a key.

Parameters:

  • key (String)

Returns:

  • (Boolean)

    whether the timeout was removed or not



82
83
84
# File 'lib/valkey/commands/generic_commands.rb', line 82

def persist(key)
  send_command(RequestType::PERSIST, [key])
end

#pexpire(key, milliseconds, nx: nil, xx: nil, gt: nil, lt: nil) ⇒ Boolean

Set a key's time to live in milliseconds.

Parameters:

  • key (String)
  • milliseconds (Integer)

    time to live

  • options (Hash)
    • :nx => true: Set expiry only when the key has no expiry.
    • :xx => true: Set expiry only when the key has an existing expiry.
    • :gt => true: Set expiry only when the new expiry is greater than current one.
    • :lt => true: Set expiry only when the new expiry is less than current one.

Returns:

  • (Boolean)

    whether the timeout was set or not



160
161
162
163
164
165
166
167
168
# File 'lib/valkey/commands/generic_commands.rb', line 160

def pexpire(key, milliseconds, nx: nil, xx: nil, gt: nil, lt: nil)
  args = [key, Integer(milliseconds)]
  args << "NX" if nx
  args << "XX" if xx
  args << "GT" if gt
  args << "LT" if lt

  send_command(RequestType::PEXPIRE, args)
end

#pexpireat(key, ms_unix_time, nx: nil, xx: nil, gt: nil, lt: nil) ⇒ Boolean

Set the expiration for a key as number of milliseconds from UNIX Epoch.

Parameters:

  • key (String)
  • ms_unix_time (Integer)

    expiry time specified as number of milliseconds from UNIX Epoch.

  • options (Hash)
    • :nx => true: Set expiry only when the key has no expiry.
    • :xx => true: Set expiry only when the key has an existing expiry.
    • :gt => true: Set expiry only when the new expiry is greater than current one.
    • :lt => true: Set expiry only when the new expiry is less than current one.

Returns:

  • (Boolean)

    whether the timeout was set or not



180
181
182
183
184
185
186
187
188
# File 'lib/valkey/commands/generic_commands.rb', line 180

def pexpireat(key, ms_unix_time, nx: nil, xx: nil, gt: nil, lt: nil)
  args = [key, Integer(ms_unix_time)]
  args << "NX" if nx
  args << "XX" if xx
  args << "GT" if gt
  args << "LT" if lt

  send_command(RequestType::PEXPIRE_AT, args)
end

#pexpiretime(key) ⇒ Integer

Get a key's expiry time specified as number of milliseconds from UNIX Epoch

Parameters:

  • key (String)

Returns:

  • (Integer)

    expiry time specified as number of milliseconds from UNIX Epoch



194
195
196
# File 'lib/valkey/commands/generic_commands.rb', line 194

def pexpiretime(key)
  send_command(RequestType::PEXPIRE_TIME, [key])
end

#pttl(key) ⇒ Integer

Get the time to live (in milliseconds) for a key.

In valkey 2.6 or older the command returns -1 if the key does not exist or if the key exist but has no associated expire.

Starting with valkey 2.8 the return value in case of error changed:

- The command returns -2 if the key does not exist.
- The command returns -1 if the key exists but has no associated expire.

Parameters:

  • key (String)

Returns:

  • (Integer)

    remaining time to live in milliseconds



209
210
211
# File 'lib/valkey/commands/generic_commands.rb', line 209

def pttl(key)
  send_command(RequestType::PTTL, [key])
end

#randomkey(route: nil) ⇒ String?

Return a random key from the keyspace.

Parameters:

  • route (Valkey::Route, nil) (defaults to: nil)

    cluster routing. When routed, may return a Hash of node => value.

Returns:

  • (String, nil)


403
404
405
# File 'lib/valkey/commands/generic_commands.rb', line 403

def randomkey(route: nil)
  send_command(RequestType::RANDOM_KEY, [], route: route)
end

#rename(old_name, new_name) ⇒ String

Rename a key. If the new key already exists it is overwritten.

Parameters:

  • old_name (String)
  • new_name (String)

Returns:

  • (String)

    OK



412
413
414
# File 'lib/valkey/commands/generic_commands.rb', line 412

def rename(old_name, new_name)
  send_command(RequestType::RENAME, [old_name, new_name])
end

#renamenx(old_name, new_name) ⇒ Boolean

Rename a key, only if the new key does not exist.

Parameters:

  • old_name (String)
  • new_name (String)

Returns:

  • (Boolean)

    whether the key was renamed or not



421
422
423
# File 'lib/valkey/commands/generic_commands.rb', line 421

def renamenx(old_name, new_name)
  send_command(RequestType::RENAME_NX, [old_name, new_name])
end

#restore(key, ttl, serialized_value, replace: nil) ⇒ String

Create a key using the serialized value, previously obtained using DUMP.

Parameters:

  • key (String)
  • ttl (String)
  • serialized_value (String)
  • options (Hash)
    • :replace => Boolean: if false, raises an error if key already exists

Returns:

  • (String)

    "OK"

Raises:

  • (valkey::CommandError)


230
231
232
233
234
235
# File 'lib/valkey/commands/generic_commands.rb', line 230

def restore(key, ttl, serialized_value, replace: nil)
  args = [key, ttl, serialized_value]
  args << 'REPLACE' if replace

  send_command(RequestType::RESTORE, args)
end

#scan(cursor, **options) ⇒ String+

Note:

Standalone mode only. In cluster mode this returns ["0", []] (a finished cursor and no keys) rather than iterating a single shard with an undefined route. A cluster-aware scan API is tracked in TODO: https://github.com/valkey-io/valkey-glide-ruby/issues/133

Scan the keyspace

Examples:

Retrieve the first batch of keys

valkey.scan(0)
  # => ["4", ["key:21", "key:47", "key:42"]]

Retrieve a batch of keys matching a pattern

valkey.scan(4, :match => "key:1?")
  # => ["92", ["key:13", "key:18"]]

Retrieve a batch of keys of a certain type

valkey.scan(92, :type => "zset")
  # => ["173", ["sortedset:14", "sortedset:78"]]

Parameters:

  • cursor (String, Integer)

    the cursor of the iteration

  • options (Hash)
    • :match => String: only return keys matching the pattern
    • :count => Integer: return count keys at most per iteration
    • :type => String: return keys only of the given type

Returns:

  • (String, Array<String>)

    the next cursor and all found keys



35
36
37
38
39
# File 'lib/valkey/commands/generic_commands.rb', line 35

def scan(cursor, **options)
  return ["0", []] if @cluster_mode

  _scan(RequestType::SCAN, cursor, [], **options)
end

#scan_each(**options, &block) ⇒ Enumerator

Note:

Standalone mode only. In cluster mode this yields nothing and returns immediately, matching #scan's cluster behavior. See TODO: https://github.com/valkey-io/valkey-glide-ruby/issues/133

Scan the keyspace

Examples:

Retrieve all of the keys (with possible duplicates)

valkey.scan_each.to_a
  # => ["key:21", "key:47", "key:42"]

Execute block for each key matching a pattern

valkey.scan_each(:match => "key:1?") {|key| puts key}
  # => key:13
  # => key:18

Execute block for each key of a type

valkey.scan_each(:type => "hash") {|key| puts valkey.type(key)}
  # => "hash"
  # => "hash"

Parameters:

  • options (Hash)
    • :match => String: only return keys matching the pattern
    • :count => Integer: return count keys at most per iteration
    • :type => String: return keys only of the given type

Returns:

  • (Enumerator)

    an enumerator for all found keys



66
67
68
69
70
71
72
73
74
75
76
# File 'lib/valkey/commands/generic_commands.rb', line 66

def scan_each(**options, &block)
  return to_enum(:scan_each, **options) unless block_given?
  return if @cluster_mode

  cursor = 0
  loop do
    cursor, keys = scan(cursor, **options)
    keys.each(&block)
    break if cursor == "0"
  end
end

#sort(key, by: nil, limit: nil, get: nil, order: nil, store: nil) ⇒ Array<String>, ...

Sort the elements in a list, set or sorted set.

Examples:

Retrieve the first 2 elements from an alphabetically sorted "list"

valkey.sort("list", :order => "alpha", :limit => [0, 2])
  # => ["a", "b"]

Store an alphabetically descending list in "target"

valkey.sort("list", :order => "desc alpha", :store => "target")
  # => 26

Parameters:

  • key (String)
  • options (Hash)
    • :by => String: use external key to sort elements by
    • :limit => [offset, count]: skip offset elements, return a maximum of count elements
    • :get => [String, Array<String>]: single key or array of keys to retrieve per element in the result
    • :order => String: combination of ASC, DESC and optionally ALPHA
    • :store => String: key to store the result at

Returns:

  • (Array<String>, Array<Array<String>>, Integer)
    • when :get is not specified, or holds a single element, an array of elements
    • when :get is specified, and holds more than one element, an array of elements where every element is an array with the result for every element specified in :get
    • when :store is specified, the number of elements in the stored result


450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
# File 'lib/valkey/commands/generic_commands.rb', line 450

def sort(key, by: nil, limit: nil, get: nil, order: nil, store: nil)
  args = [key]
  args << "BY" << by if by

  if limit
    args << "LIMIT"
    args.concat(limit)
  end

  get = Array(get)
  get.each do |item|
    args << "GET" << item
  end

  args.concat(order.split) if order
  args << "STORE" << store if store

  send_command(RequestType::SORT, args) do |reply|
    if get.size > 1 && !store
      reply.each_slice(get.size).to_a if reply
    else
      reply
    end
  end
end

#touch(*keys) ⇒ Object



476
477
478
# File 'lib/valkey/commands/generic_commands.rb', line 476

def touch(*keys)
  send_command(RequestType::TOUCH, keys.flatten)
end

#ttl(key) ⇒ Integer

Get the time to live (in seconds) for a key.

In valkey 2.6 or older the command returns -1 if the key does not exist or if the key exist but has no associated expire.

Starting with valkey 2.8 the return value in case of error changed:

- The command returns -2 if the key does not exist.
- The command returns -1 if the key exists but has no associated expire.

Parameters:

  • key (String)

Returns:

  • (Integer)

    remaining time to live in seconds.



146
147
148
# File 'lib/valkey/commands/generic_commands.rb', line 146

def ttl(key)
  send_command(RequestType::TTL, [key])
end

#type(key) ⇒ String

Determine the type stored at key.

Parameters:

  • key (String)

Returns:

  • (String)

    string, list, set, zset, hash or none



522
523
524
# File 'lib/valkey/commands/generic_commands.rb', line 522

def type(key)
  send_command(RequestType::TYPE, [key])
end

Unlink one or more keys.

Parameters:

  • keys (String, Array<String>)

Returns:

  • (Integer)

    number of keys that were unlinked



312
313
314
# File 'lib/valkey/commands/generic_commands.rb', line 312

def unlink(*keys)
  send_command(RequestType::UNLINK, keys.flatten)
end

#wait(numreplicas, timeout) ⇒ Integer

Block until all the previous write commands are successfully transferred and acknowledged by at least the specified number of replicas.

Examples:

Wait for 1 replica with 1 second timeout

valkey.wait(1, 1000)
  # => 1

Parameters:

  • numreplicas (Integer)

    minimum number of replicas to acknowledge

  • timeout (Integer)

    timeout in milliseconds (0 means block forever)

Returns:

  • (Integer)

    number of replicas that acknowledged

See Also:



492
493
494
# File 'lib/valkey/commands/generic_commands.rb', line 492

def wait(numreplicas, timeout)
  send_command(RequestType::WAIT, [numreplicas.to_s, timeout.to_s])
end

#waitaof(numlocal, numreplicas, timeout) ⇒ Array<Integer>

Block until all previous write commands are fsynced to the AOF of the local server and/or at least the specified number of replicas.

Examples:

Wait for local AOF fsync with no timeout

valkey.waitaof(1, 0, 0)
  # => [1, 0]

Wait for 1 replica fsync with 1 second timeout

valkey.waitaof(0, 1, 1000)
  # => [0, 0]

Parameters:

  • numlocal (Integer)

    number of local fsyncs required (0 or 1)

  • numreplicas (Integer)

    minimum number of replicas to fsync

  • timeout (Integer)

    timeout in milliseconds (0 means block forever)

Returns:

  • (Array<Integer>)

    array of two integers:

    • number of local servers (0 or 1) that fsynced
    • number of replicas that fsynced

See Also:



514
515
516
# File 'lib/valkey/commands/generic_commands.rb', line 514

def waitaof(numlocal, numreplicas, timeout)
  send_command(RequestType::WAIT_AOF, [numlocal.to_s, numreplicas.to_s, timeout.to_s])
end