valkey-glide-rb 0.9.1 → 0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/lib/valkey/bindings.rb +57 -0
- data/lib/valkey/commands/cluster_commands.rb +28 -14
- data/lib/valkey/commands/connection_commands.rb +21 -12
- data/lib/valkey/commands/function_commands.rb +30 -20
- data/lib/valkey/commands/generic_commands.rb +17 -9
- data/lib/valkey/commands/scripting_commands.rb +53 -22
- data/lib/valkey/commands/server_commands.rb +72 -50
- data/lib/valkey/commands/string_commands.rb +27 -15
- data/lib/valkey/commands/transaction_commands.rb +79 -10
- data/lib/valkey/future.rb +85 -0
- data/lib/valkey/native/aarch64-apple-darwin/libglide_ffi.dylib +0 -0
- data/lib/valkey/native/aarch64-unknown-linux-gnu/libglide_ffi.so +0 -0
- data/lib/valkey/native/aarch64-unknown-linux-musl/libglide_ffi.so +0 -0
- data/lib/valkey/native/x86_64-unknown-linux-gnu/libglide_ffi.so +0 -0
- data/lib/valkey/native/x86_64-unknown-linux-musl/libglide_ffi.so +0 -0
- data/lib/valkey/pipeline.rb +29 -1
- data/lib/valkey/route.rb +106 -0
- data/lib/valkey/utils.rb +5 -0
- data/lib/valkey/version.rb +1 -1
- data/lib/valkey.rb +118 -49
- metadata +6 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e3c28ac646b9b41dc630b6a28396af105cf70e38c20cdd2e74ac7dde1245b952
|
|
4
|
+
data.tar.gz: a417f802a018a41a16c8cfbfb1a12ba68af48eb4d6e176b48e936558a87a4bcf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '08c8c01d41da6be96ea35fbf0a582dd0676a63a96a69244d3ec14d58cbbf496935a6beafe992d750d65c100f43c54fd00bf3f0c69352b407808578821fc7eab9'
|
|
7
|
+
data.tar.gz: 606d32093482a5827a216bd77c371aec94b6de684cedcdeb9181dae117e1abef9feb6f5ff2d8ccda78c954504752d57dfed44a3296a46175fc4b709a50e45330
|
data/.rubocop.yml
CHANGED
data/lib/valkey/bindings.rb
CHANGED
|
@@ -123,6 +123,33 @@ class Valkey
|
|
|
123
123
|
)
|
|
124
124
|
end
|
|
125
125
|
|
|
126
|
+
# Mirrors Rust's `RouteType` enum (valkey-glide/ffi/src/lib.rs)
|
|
127
|
+
RouteType = enum(
|
|
128
|
+
:all_nodes, 0,
|
|
129
|
+
:all_primaries,
|
|
130
|
+
:random,
|
|
131
|
+
:slot_id,
|
|
132
|
+
:slot_key,
|
|
133
|
+
:by_address
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
# Mirrors Rust's `SlotType` enum (a mirror of `SlotAddr`)
|
|
137
|
+
SlotType = enum(
|
|
138
|
+
:primary, 0,
|
|
139
|
+
:replica
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
class RouteInfo < FFI::Struct
|
|
143
|
+
layout(
|
|
144
|
+
:route_type, RouteType,
|
|
145
|
+
:slot_id, :int32, # slot number (for SlotId route)
|
|
146
|
+
:slot_key, :pointer, # *const c_char (for SlotKey route; NULL otherwise)
|
|
147
|
+
:slot_type, SlotType,
|
|
148
|
+
:hostname, :pointer, # *const c_char (for ByAddress route; NULL otherwise)
|
|
149
|
+
:port, :int32 # port number (for ByAddress route)
|
|
150
|
+
)
|
|
151
|
+
end
|
|
152
|
+
|
|
126
153
|
class BatchOptionsInfo < FFI::Struct
|
|
127
154
|
layout(
|
|
128
155
|
:retry_server_error, :bool,
|
|
@@ -226,6 +253,23 @@ class Valkey
|
|
|
226
253
|
:pointer # *mut ConnectionResponse
|
|
227
254
|
], :void
|
|
228
255
|
|
|
256
|
+
attach_function :free_command_result, [
|
|
257
|
+
:pointer # *mut CommandResult
|
|
258
|
+
], :void
|
|
259
|
+
|
|
260
|
+
attach_function :free_script_hash_buffer, [
|
|
261
|
+
:pointer # *mut ScriptHashBuffer
|
|
262
|
+
], :void
|
|
263
|
+
|
|
264
|
+
attach_function :drop_script, [
|
|
265
|
+
:pointer, # *mut u8 (hash bytes)
|
|
266
|
+
:ulong # usize (hash length)
|
|
267
|
+
], :pointer # returns *mut c_char (null on success, error string on failure)
|
|
268
|
+
|
|
269
|
+
attach_function :free_drop_script_error, [
|
|
270
|
+
:pointer # *mut c_char (error from drop_script)
|
|
271
|
+
], :void
|
|
272
|
+
|
|
229
273
|
attach_function :close_client, [
|
|
230
274
|
:pointer # client_adapter_ptr
|
|
231
275
|
], :void
|
|
@@ -242,6 +286,19 @@ class Valkey
|
|
|
242
286
|
:ulong # span_ptr (u64)
|
|
243
287
|
], :pointer, blocking: true # returns *mut CommandResult, releases GVL during I/O
|
|
244
288
|
|
|
289
|
+
attach_function :command_with_route_info, [
|
|
290
|
+
:pointer, # client_adapter_ptr
|
|
291
|
+
:ulong, # request_id
|
|
292
|
+
:int, # command_type (RequestType)
|
|
293
|
+
:ulong, # arg_count
|
|
294
|
+
:pointer, # args (pointer to usize[])
|
|
295
|
+
:pointer, # args_len (pointer to c_ulong[])
|
|
296
|
+
:pointer, # route_info (*const RouteInfo, or NULL for no route)
|
|
297
|
+
:pointer, # response_buf (NULL = normal response path)
|
|
298
|
+
:ulong, # response_buf_len (0 if response_buf is NULL)
|
|
299
|
+
:ulong # span_ptr (u64)
|
|
300
|
+
], :pointer, blocking: true # returns *mut CommandResult, releases GVL during I/O
|
|
301
|
+
|
|
245
302
|
attach_function :batch, [
|
|
246
303
|
:pointer, # client_ptr
|
|
247
304
|
:ulong, # callback_index
|
|
@@ -124,10 +124,15 @@ class Valkey
|
|
|
124
124
|
|
|
125
125
|
# Get information about the cluster.
|
|
126
126
|
#
|
|
127
|
+
# @param route [Valkey::Route, nil] cluster routing. When routed, may return a Hash of node => value.
|
|
127
128
|
# @return [Hash<String, String>] cluster information
|
|
128
|
-
def cluster_info
|
|
129
|
-
send_command(RequestType::CLUSTER_INFO) do |reply|
|
|
130
|
-
|
|
129
|
+
def cluster_info(route: nil)
|
|
130
|
+
send_command(RequestType::CLUSTER_INFO, [], route: route) do |reply|
|
|
131
|
+
if reply.is_a?(Hash)
|
|
132
|
+
reply.transform_values { |v| Utils::HashifyInfo.call(v) }
|
|
133
|
+
else
|
|
134
|
+
Utils::HashifyInfo.call(reply)
|
|
135
|
+
end
|
|
131
136
|
end
|
|
132
137
|
end
|
|
133
138
|
|
|
@@ -141,9 +146,10 @@ class Valkey
|
|
|
141
146
|
|
|
142
147
|
# Get information about cluster links.
|
|
143
148
|
#
|
|
149
|
+
# @param route [Valkey::Route, nil] cluster routing. When routed, may return a Hash of node => value.
|
|
144
150
|
# @return [Array<Hash>] array of link information
|
|
145
|
-
def cluster_links
|
|
146
|
-
send_command(RequestType::CLUSTER_LINKS)
|
|
151
|
+
def cluster_links(route: nil)
|
|
152
|
+
send_command(RequestType::CLUSTER_LINKS, [], route: route)
|
|
147
153
|
end
|
|
148
154
|
|
|
149
155
|
# Meet another node in the cluster.
|
|
@@ -157,24 +163,31 @@ class Valkey
|
|
|
157
163
|
|
|
158
164
|
# Get the ID of the current node.
|
|
159
165
|
#
|
|
166
|
+
# @param route [Valkey::Route, nil] cluster routing. When routed, may return a Hash of node => value.
|
|
160
167
|
# @return [String] node ID
|
|
161
|
-
def cluster_myid
|
|
162
|
-
send_command(RequestType::CLUSTER_MY_ID)
|
|
168
|
+
def cluster_myid(route: nil)
|
|
169
|
+
send_command(RequestType::CLUSTER_MY_ID, [], route: route)
|
|
163
170
|
end
|
|
164
171
|
|
|
165
172
|
# Get the shard ID of the current node.
|
|
166
173
|
#
|
|
174
|
+
# @param route [Valkey::Route, nil] cluster routing. When routed, may return a Hash of node => value.
|
|
167
175
|
# @return [String] shard ID
|
|
168
|
-
def cluster_myshardid
|
|
169
|
-
send_command(RequestType::CLUSTER_MY_SHARD_ID)
|
|
176
|
+
def cluster_myshardid(route: nil)
|
|
177
|
+
send_command(RequestType::CLUSTER_MY_SHARD_ID, [], route: route)
|
|
170
178
|
end
|
|
171
179
|
|
|
172
180
|
# Get information about all nodes in the cluster.
|
|
173
181
|
#
|
|
182
|
+
# @param route [Valkey::Route, nil] cluster routing. When routed, may return a Hash of node => value.
|
|
174
183
|
# @return [Array<Hash>] array of node information
|
|
175
|
-
def cluster_nodes
|
|
176
|
-
send_command(RequestType::CLUSTER_NODES) do |reply|
|
|
177
|
-
|
|
184
|
+
def cluster_nodes(route: nil)
|
|
185
|
+
send_command(RequestType::CLUSTER_NODES, [], route: route) do |reply|
|
|
186
|
+
if reply.is_a?(Hash)
|
|
187
|
+
reply.transform_values { |v| Utils::HashifyClusterNodes.call(v) }
|
|
188
|
+
else
|
|
189
|
+
Utils::HashifyClusterNodes.call(reply)
|
|
190
|
+
end
|
|
178
191
|
end
|
|
179
192
|
end
|
|
180
193
|
|
|
@@ -235,9 +248,10 @@ class Valkey
|
|
|
235
248
|
|
|
236
249
|
# Get information about cluster shards.
|
|
237
250
|
#
|
|
251
|
+
# @param route [Valkey::Route, nil] cluster routing. When routed, may return a Hash of node => value.
|
|
238
252
|
# @return [Array<Hash>] array of shard information
|
|
239
|
-
def cluster_shards
|
|
240
|
-
send_command(RequestType::CLUSTER_SHARDS)
|
|
253
|
+
def cluster_shards(route: nil)
|
|
254
|
+
send_command(RequestType::CLUSTER_SHARDS, [], route: route)
|
|
241
255
|
end
|
|
242
256
|
|
|
243
257
|
# Get information about slave nodes (deprecated, use cluster_replicas).
|
|
@@ -18,18 +18,25 @@ class Valkey
|
|
|
18
18
|
|
|
19
19
|
# Ping the server.
|
|
20
20
|
#
|
|
21
|
-
# @param [
|
|
22
|
-
# @
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
# @param message [String, nil] optional message to echo back
|
|
22
|
+
# @param route [Valkey::Route, nil] cluster routing. When routed, may return a Hash of node => value.
|
|
23
|
+
# @return [String]
|
|
24
|
+
#
|
|
25
|
+
# @example
|
|
26
|
+
# ping #=> "PONG"
|
|
27
|
+
# ping("hello") #=> "hello"
|
|
28
|
+
# ping(route: Valkey::Route.all_nodes) #=> Hash (multi-node)
|
|
29
|
+
def ping(message = nil, route: nil)
|
|
30
|
+
send_command(RequestType::PING, [message].compact, route: route)
|
|
25
31
|
end
|
|
26
32
|
|
|
27
33
|
# Echo the given string.
|
|
28
34
|
#
|
|
29
|
-
# @param [String]
|
|
35
|
+
# @param value [String]
|
|
36
|
+
# @param route [Valkey::Route, nil] cluster routing. When routed, may return a Hash of node => value.
|
|
30
37
|
# @return [String]
|
|
31
|
-
def echo(value)
|
|
32
|
-
send_command(RequestType::ECHO, [value])
|
|
38
|
+
def echo(value, route: nil)
|
|
39
|
+
send_command(RequestType::ECHO, [value], route: route)
|
|
33
40
|
end
|
|
34
41
|
|
|
35
42
|
# Change the selected database for the current connection.
|
|
@@ -99,9 +106,10 @@ class Valkey
|
|
|
99
106
|
|
|
100
107
|
# Get the current client's ID.
|
|
101
108
|
#
|
|
102
|
-
# @
|
|
103
|
-
|
|
104
|
-
|
|
109
|
+
# @param route [Valkey::Route, nil] cluster routing. When routed, may return a Hash of node => value.
|
|
110
|
+
# @return [Integer]
|
|
111
|
+
def client_id(route: nil)
|
|
112
|
+
send_command(RequestType::CLIENT_ID, [], route: route)
|
|
105
113
|
end
|
|
106
114
|
|
|
107
115
|
# Get the current client's name.
|
|
@@ -205,9 +213,10 @@ class Valkey
|
|
|
205
213
|
|
|
206
214
|
# Unpause client processing.
|
|
207
215
|
#
|
|
216
|
+
# @param route [Valkey::Route, nil] cluster routing.
|
|
208
217
|
# @return [String] `OK`
|
|
209
|
-
def client_unpause
|
|
210
|
-
send_command(RequestType::CLIENT_UNPAUSE)
|
|
218
|
+
def client_unpause(route: nil)
|
|
219
|
+
send_command(RequestType::CLIENT_UNPAUSE, [], route: route)
|
|
211
220
|
end
|
|
212
221
|
|
|
213
222
|
# Configure client reply mode.
|
|
@@ -14,11 +14,12 @@ class Valkey
|
|
|
14
14
|
# # => "OK"
|
|
15
15
|
#
|
|
16
16
|
# @param [String] library_name the library name to delete
|
|
17
|
+
# @param route [Valkey::Route, nil] cluster routing.
|
|
17
18
|
# @return [String] "OK"
|
|
18
19
|
#
|
|
19
20
|
# @see https://valkey.io/commands/function-delete/
|
|
20
|
-
def function_delete(library_name)
|
|
21
|
-
send_command(RequestType::FUNCTION_DELETE, [library_name])
|
|
21
|
+
def function_delete(library_name, route: nil)
|
|
22
|
+
send_command(RequestType::FUNCTION_DELETE, [library_name], route: route)
|
|
22
23
|
end
|
|
23
24
|
|
|
24
25
|
# Return the serialized payload of loaded libraries.
|
|
@@ -27,11 +28,12 @@ class Valkey
|
|
|
27
28
|
# valkey.function_dump
|
|
28
29
|
# # => <binary string>
|
|
29
30
|
#
|
|
31
|
+
# @param route [Valkey::Route, nil] cluster routing. When routed, may return a Hash of node => value.
|
|
30
32
|
# @return [String] the serialized payload
|
|
31
33
|
#
|
|
32
34
|
# @see https://valkey.io/commands/function-dump/
|
|
33
|
-
def function_dump
|
|
34
|
-
send_command(RequestType::FUNCTION_DUMP)
|
|
35
|
+
def function_dump(route: nil)
|
|
36
|
+
send_command(RequestType::FUNCTION_DUMP, [], route: route)
|
|
35
37
|
end
|
|
36
38
|
|
|
37
39
|
# Delete all libraries.
|
|
@@ -48,10 +50,11 @@ class Valkey
|
|
|
48
50
|
#
|
|
49
51
|
# @param [Boolean] async flush asynchronously
|
|
50
52
|
# @param [Boolean] sync flush synchronously
|
|
53
|
+
# @param route [Valkey::Route, nil] cluster routing.
|
|
51
54
|
# @return [String] "OK"
|
|
52
55
|
#
|
|
53
56
|
# @see https://valkey.io/commands/function-flush/
|
|
54
|
-
def function_flush(async: false, sync: false)
|
|
57
|
+
def function_flush(async: false, sync: false, route: nil)
|
|
55
58
|
args = []
|
|
56
59
|
|
|
57
60
|
if async
|
|
@@ -60,7 +63,7 @@ class Valkey
|
|
|
60
63
|
args << "SYNC"
|
|
61
64
|
end
|
|
62
65
|
|
|
63
|
-
send_command(RequestType::FUNCTION_FLUSH, args)
|
|
66
|
+
send_command(RequestType::FUNCTION_FLUSH, args, route: route)
|
|
64
67
|
end
|
|
65
68
|
|
|
66
69
|
# Kill a function that is currently executing.
|
|
@@ -69,11 +72,12 @@ class Valkey
|
|
|
69
72
|
# valkey.function_kill
|
|
70
73
|
# # => "OK"
|
|
71
74
|
#
|
|
75
|
+
# @param route [Valkey::Route, nil] cluster routing.
|
|
72
76
|
# @return [String] "OK"
|
|
73
77
|
#
|
|
74
78
|
# @see https://valkey.io/commands/function-kill/
|
|
75
|
-
def function_kill
|
|
76
|
-
send_command(RequestType::FUNCTION_KILL)
|
|
79
|
+
def function_kill(route: nil)
|
|
80
|
+
send_command(RequestType::FUNCTION_KILL, [], route: route)
|
|
77
81
|
end
|
|
78
82
|
|
|
79
83
|
# Return information about the functions and libraries.
|
|
@@ -90,10 +94,11 @@ class Valkey
|
|
|
90
94
|
#
|
|
91
95
|
# @param [String] library_name filter by library name pattern
|
|
92
96
|
# @param [Boolean] with_code include the library code in the response
|
|
97
|
+
# @param route [Valkey::Route, nil] cluster routing. When routed, may return a Hash of node => value.
|
|
93
98
|
# @return [Array<Hash>] array of library information
|
|
94
99
|
#
|
|
95
100
|
# @see https://valkey.io/commands/function-list/
|
|
96
|
-
def function_list(library_name: nil, with_code: false)
|
|
101
|
+
def function_list(library_name: nil, with_code: false, route: nil)
|
|
97
102
|
args = []
|
|
98
103
|
|
|
99
104
|
if library_name
|
|
@@ -103,7 +108,7 @@ class Valkey
|
|
|
103
108
|
|
|
104
109
|
args << "WITHCODE" if with_code
|
|
105
110
|
|
|
106
|
-
send_command(RequestType::FUNCTION_LIST, args)
|
|
111
|
+
send_command(RequestType::FUNCTION_LIST, args, route: route)
|
|
107
112
|
end
|
|
108
113
|
|
|
109
114
|
# Load a library to Valkey.
|
|
@@ -118,15 +123,16 @@ class Valkey
|
|
|
118
123
|
#
|
|
119
124
|
# @param [String] function_code the source code
|
|
120
125
|
# @param [Boolean] replace replace the library if it exists
|
|
126
|
+
# @param route [Valkey::Route, nil] cluster routing.
|
|
121
127
|
# @return [String] the library name that was loaded
|
|
122
128
|
#
|
|
123
129
|
# @see https://valkey.io/commands/function-load/
|
|
124
|
-
def function_load(function_code, replace: false)
|
|
130
|
+
def function_load(function_code, replace: false, route: nil)
|
|
125
131
|
args = []
|
|
126
132
|
args << "REPLACE" if replace
|
|
127
133
|
args << function_code
|
|
128
134
|
|
|
129
|
-
send_command(RequestType::FUNCTION_LOAD, args)
|
|
135
|
+
send_command(RequestType::FUNCTION_LOAD, args, route: route)
|
|
130
136
|
end
|
|
131
137
|
|
|
132
138
|
# Restore libraries from a payload.
|
|
@@ -147,15 +153,16 @@ class Valkey
|
|
|
147
153
|
#
|
|
148
154
|
# @param [String] serialized_value the serialized payload from FUNCTION DUMP
|
|
149
155
|
# @param [String] policy the restore policy: "FLUSH", "APPEND", or "REPLACE"
|
|
156
|
+
# @param route [Valkey::Route, nil] cluster routing.
|
|
150
157
|
# @return [String] "OK"
|
|
151
158
|
#
|
|
152
159
|
# @see https://valkey.io/commands/function-restore/
|
|
153
|
-
def function_restore(serialized_value, policy: nil)
|
|
160
|
+
def function_restore(serialized_value, policy: nil, route: nil)
|
|
154
161
|
args = [serialized_value]
|
|
155
162
|
|
|
156
163
|
args << policy.to_s.upcase if policy
|
|
157
164
|
|
|
158
|
-
send_command(RequestType::FUNCTION_RESTORE, args)
|
|
165
|
+
send_command(RequestType::FUNCTION_RESTORE, args, route: route)
|
|
159
166
|
end
|
|
160
167
|
|
|
161
168
|
# Return information about the function that's currently running.
|
|
@@ -164,11 +171,12 @@ class Valkey
|
|
|
164
171
|
# valkey.function_stats
|
|
165
172
|
# # => {"running_script" => {...}, "engines" => {...}}
|
|
166
173
|
#
|
|
174
|
+
# @param route [Valkey::Route, nil] cluster routing. When routed, may return a Hash of node => value.
|
|
167
175
|
# @return [Hash] function execution statistics
|
|
168
176
|
#
|
|
169
177
|
# @see https://valkey.io/commands/function-stats/
|
|
170
|
-
def function_stats
|
|
171
|
-
send_command(RequestType::FUNCTION_STATS)
|
|
178
|
+
def function_stats(route: nil)
|
|
179
|
+
send_command(RequestType::FUNCTION_STATS, [], route: route)
|
|
172
180
|
end
|
|
173
181
|
|
|
174
182
|
# Invoke a function.
|
|
@@ -183,12 +191,13 @@ class Valkey
|
|
|
183
191
|
# @param [String] function the function name
|
|
184
192
|
# @param [Array<String>] keys the keys to pass to the function
|
|
185
193
|
# @param [Array<String>] args the arguments to pass to the function
|
|
194
|
+
# @param route [Valkey::Route, nil] cluster routing. When routed, may return a Hash of node => value.
|
|
186
195
|
# @return [Object] the function result
|
|
187
196
|
#
|
|
188
197
|
# @see https://valkey.io/commands/fcall/
|
|
189
|
-
def fcall(function, keys: [], args: [])
|
|
198
|
+
def fcall(function, keys: [], args: [], route: nil)
|
|
190
199
|
command_args = [function, keys.size] + keys + args
|
|
191
|
-
send_command(RequestType::FCALL, command_args)
|
|
200
|
+
send_command(RequestType::FCALL, command_args, route: route)
|
|
192
201
|
end
|
|
193
202
|
|
|
194
203
|
# Invoke a read-only function.
|
|
@@ -200,12 +209,13 @@ class Valkey
|
|
|
200
209
|
# @param [String] function the function name
|
|
201
210
|
# @param [Array<String>] keys the keys to pass to the function
|
|
202
211
|
# @param [Array<String>] args the arguments to pass to the function
|
|
212
|
+
# @param route [Valkey::Route, nil] cluster routing. When routed, may return a Hash of node => value.
|
|
203
213
|
# @return [Object] the function result
|
|
204
214
|
#
|
|
205
215
|
# @see https://valkey.io/commands/fcall_ro/
|
|
206
|
-
def fcall_ro(function, keys: [], args: [])
|
|
216
|
+
def fcall_ro(function, keys: [], args: [], route: nil)
|
|
207
217
|
command_args = [function, keys.size] + keys + args
|
|
208
|
-
send_command(RequestType::FCALL_READ_ONLY, command_args)
|
|
218
|
+
send_command(RequestType::FCALL_READ_ONLY, command_args, route: route)
|
|
209
219
|
end
|
|
210
220
|
|
|
211
221
|
# Control function registry (convenience method).
|
|
@@ -394,9 +394,10 @@ class Valkey
|
|
|
394
394
|
|
|
395
395
|
# Return a random key from the keyspace.
|
|
396
396
|
#
|
|
397
|
-
# @
|
|
398
|
-
|
|
399
|
-
|
|
397
|
+
# @param route [Valkey::Route, nil] cluster routing. When routed, may return a Hash of node => value.
|
|
398
|
+
# @return [String, nil]
|
|
399
|
+
def randomkey(route: nil)
|
|
400
|
+
send_command(RequestType::RANDOM_KEY, [], route: route)
|
|
400
401
|
end
|
|
401
402
|
|
|
402
403
|
# Rename a key. If the new key already exists it is overwritten.
|
|
@@ -552,11 +553,12 @@ class Valkey
|
|
|
552
553
|
# @param [Array<String, Integer, Float, Array, Hash>] argv command name and its arguments
|
|
553
554
|
# @param [Hash] kwargs trailing command flags; truthy values emit the upcased flag name,
|
|
554
555
|
# non-boolean values also emit the stringified value; falsy/nil values are dropped
|
|
556
|
+
# @param route [Valkey::Route, nil] cluster routing. When routed, may return a Hash of node => value.
|
|
555
557
|
# @return [Object] the raw reply, with no type-casting based on the command name
|
|
556
558
|
#
|
|
557
559
|
# @see https://valkey.io/commands/
|
|
558
|
-
def call(*argv, **kwargs)
|
|
559
|
-
send_command(RequestType::CUSTOM_COMMAND, flatten_call_args(argv).concat(call_flags(kwargs)))
|
|
560
|
+
def call(*argv, route: nil, **kwargs)
|
|
561
|
+
send_command(RequestType::CUSTOM_COMMAND, flatten_call_args(argv).concat(call_flags(kwargs)), route: route)
|
|
560
562
|
end
|
|
561
563
|
|
|
562
564
|
# Send any command as a single Array of arguments and get the raw reply back.
|
|
@@ -568,17 +570,21 @@ class Valkey
|
|
|
568
570
|
# valkey.call_v(["MGET"] + keys)
|
|
569
571
|
#
|
|
570
572
|
# @param [Array<String, Integer, Float, Array, Hash>] argv command name and its arguments
|
|
573
|
+
# @param route [Valkey::Route, nil] cluster routing. When routed, may return a Hash of node => value.
|
|
571
574
|
# @return [Object] the raw reply, with no type-casting based on the command name
|
|
572
575
|
#
|
|
573
576
|
# @see https://valkey.io/commands/
|
|
574
|
-
def call_v(argv)
|
|
575
|
-
send_command(RequestType::CUSTOM_COMMAND, flatten_call_args(argv))
|
|
577
|
+
def call_v(argv, route: nil)
|
|
578
|
+
send_command(RequestType::CUSTOM_COMMAND, flatten_call_args(argv), route: route)
|
|
576
579
|
end
|
|
577
580
|
|
|
578
581
|
private
|
|
579
582
|
|
|
580
583
|
# Flattens Arrays and Hashes (to alternating key/value) and stringifies
|
|
581
|
-
# Integers/Floats, matching `redis-client`'s documented
|
|
584
|
+
# Integers/Floats/Symbols, matching `redis-client`'s documented
|
|
585
|
+
# `#call`/`#call_v` behavior - including its type check: any leaf that
|
|
586
|
+
# isn't a String/Symbol/Integer/Float (e.g. `nil`) raises `TypeError`
|
|
587
|
+
# instead of being silently coerced to `""` via `#to_s`.
|
|
582
588
|
#
|
|
583
589
|
# @example
|
|
584
590
|
# flatten_call_args(["CMD", [1, [2, 3]], { "a" => 1, "b" => [2, 3] }])
|
|
@@ -597,8 +603,10 @@ class Valkey
|
|
|
597
603
|
stack.concat(arg.reverse)
|
|
598
604
|
when Hash
|
|
599
605
|
arg.to_a.reverse_each { |pair| stack.concat(pair.reverse) }
|
|
600
|
-
|
|
606
|
+
when String, Symbol, Integer, Float
|
|
601
607
|
acc << arg.to_s
|
|
608
|
+
else
|
|
609
|
+
raise TypeError, "Unsupported command argument type: #{arg.class}"
|
|
602
610
|
end
|
|
603
611
|
end
|
|
604
612
|
|
|
@@ -108,8 +108,12 @@ class Valkey
|
|
|
108
108
|
|
|
109
109
|
result = Bindings.store_script(buf, script.bytesize)
|
|
110
110
|
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
begin
|
|
112
|
+
hash_buffer = Bindings::ScriptHashBuffer.new(result)
|
|
113
|
+
hash_buffer[:ptr].read_string(hash_buffer[:len])
|
|
114
|
+
ensure
|
|
115
|
+
Bindings.free_script_hash_buffer(result) if result && !result.null?
|
|
116
|
+
end
|
|
113
117
|
end
|
|
114
118
|
|
|
115
119
|
# Execute a Lua script on the server.
|
|
@@ -133,13 +137,22 @@ class Valkey
|
|
|
133
137
|
# @example Execute script that returns different data types
|
|
134
138
|
# valkey.eval("return {1, 'hello', true, nil}")
|
|
135
139
|
# # => [1, "hello", true, nil]
|
|
140
|
+
# @example Positional form, matching redis-rb's eval(script, keys, argv)
|
|
141
|
+
# valkey.eval("return KEYS[1] .. ARGV[1]", ["mykey"], ["myarg"])
|
|
142
|
+
# # => "mykeynyarg"
|
|
136
143
|
# Since the eval is not available in the rust backend
|
|
137
144
|
# using the load and invoke script
|
|
138
|
-
def eval(script, keys:
|
|
145
|
+
def eval(script, *rest, keys: nil, args: nil)
|
|
139
146
|
# Validate script parameter
|
|
140
147
|
raise ArgumentError, "script must be a string" unless script.is_a?(String)
|
|
141
148
|
raise ArgumentError, "script cannot be empty" if script.empty?
|
|
142
149
|
|
|
150
|
+
# Accept redis-rb's flexible positional form - eval(script, keys, argv)
|
|
151
|
+
# - in addition to the keyword form, mirroring the same treatment
|
|
152
|
+
# applied to evalsha (see that method for the full rationale).
|
|
153
|
+
keys ||= rest[0] || []
|
|
154
|
+
args ||= rest[1] || []
|
|
155
|
+
|
|
143
156
|
# Validate and convert keys and args to strings
|
|
144
157
|
begin
|
|
145
158
|
keys = Array(keys).map(&:to_s)
|
|
@@ -177,13 +190,22 @@ class Valkey
|
|
|
177
190
|
# rescue Valkey::CommandError => e
|
|
178
191
|
# puts "Script not found: #{e.message}"
|
|
179
192
|
# end
|
|
193
|
+
# @example Positional form, matching redis-rb's evalsha(sha, keys, argv)
|
|
194
|
+
# valkey.evalsha(sha, ["user"], ["123"])
|
|
195
|
+
# # => "user:123"
|
|
180
196
|
# Since evalsha is not available in rust backend
|
|
181
197
|
# using invoke script
|
|
182
|
-
def evalsha(sha, keys:
|
|
198
|
+
def evalsha(sha, *rest, keys: nil, args: nil)
|
|
183
199
|
# Validate SHA1 hash parameter
|
|
184
200
|
raise ArgumentError, "sha1 hash must be a string" unless sha.is_a?(String)
|
|
185
201
|
raise ArgumentError, "sha1 hash must be a 40-character hexadecimal string" unless valid_sha1?(sha)
|
|
186
202
|
|
|
203
|
+
# Accept redis-rb's flexible positional form - evalsha(sha, keys, argv)
|
|
204
|
+
# - in addition to the keyword form, so code written against redis-rb's
|
|
205
|
+
# API (e.g. redis_display_id) doesn't need to special-case this client.
|
|
206
|
+
keys ||= rest[0] || []
|
|
207
|
+
args ||= rest[1] || []
|
|
208
|
+
|
|
187
209
|
# Validate and convert keys and args to strings
|
|
188
210
|
begin
|
|
189
211
|
keys = Array(keys).map(&:to_s)
|
|
@@ -249,8 +271,13 @@ class Valkey
|
|
|
249
271
|
end
|
|
250
272
|
|
|
251
273
|
def invoke_script(script, args: [], keys: [])
|
|
252
|
-
|
|
253
|
-
keys_ptrs,
|
|
274
|
+
# Must hold onto the returned buffers (_arg_bufs/_keys_bufs) for the
|
|
275
|
+
# lifetime of this method - they back arg_ptrs/keys_ptrs, and letting
|
|
276
|
+
# them go out of scope (e.g. by only capturing the first 2 return
|
|
277
|
+
# values) makes them eligible for GC before the native call below
|
|
278
|
+
# reads through those pointers, corrupting ARGV/KEYS with freed memory.
|
|
279
|
+
arg_ptrs, arg_lens, _arg_bufs, flattened_args = build_command_args(args)
|
|
280
|
+
keys_ptrs, keys_lens, _keys_bufs, flattened_keys = build_command_args(keys)
|
|
254
281
|
|
|
255
282
|
route = ""
|
|
256
283
|
route_buf = FFI::MemoryPointer.from_string(route)
|
|
@@ -258,22 +285,26 @@ class Valkey
|
|
|
258
285
|
# Use from_string to ensure proper null termination
|
|
259
286
|
sha = FFI::MemoryPointer.from_string(script)
|
|
260
287
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
288
|
+
begin
|
|
289
|
+
res = Bindings.invoke_script(
|
|
290
|
+
@connection,
|
|
291
|
+
0,
|
|
292
|
+
sha,
|
|
293
|
+
flattened_keys.size,
|
|
294
|
+
keys_ptrs,
|
|
295
|
+
keys_lens,
|
|
296
|
+
flattened_args.size,
|
|
297
|
+
arg_ptrs,
|
|
298
|
+
arg_lens,
|
|
299
|
+
route_buf,
|
|
300
|
+
route.bytesize,
|
|
301
|
+
0 # span_ptr for OpenTelemetry (0 = no span)
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
convert_response(res)
|
|
305
|
+
ensure
|
|
306
|
+
Bindings.free_command_result(res) if res && !res.null?
|
|
307
|
+
end
|
|
277
308
|
end
|
|
278
309
|
|
|
279
310
|
private
|