Module: Valkey::Commands::ScriptingCommands
- Included in:
- Valkey::Commands
- Defined in:
- lib/valkey/commands/scripting_commands.rb
Overview
this module contains commands related to list data type.
Instance Method Summary collapse
-
#eval(script, *rest, keys: nil, args: nil) ⇒ Object
Execute a Lua script on the server.
-
#eval_ro(script, keys: [], args: []) ⇒ Object
Execute a read-only Lua script on the server.
-
#evalsha(sha, *rest, keys: nil, args: nil) ⇒ Object
Execute a cached Lua script by its SHA1 hash.
-
#evalsha_ro(sha, keys: [], args: []) ⇒ Object
Execute a cached read-only Lua script by its SHA1 hash.
- #invoke_script(script, args: [], keys: []) ⇒ Object
-
#script(subcommand, args = nil, options: {}) ⇒ String, ...
Control remote script registry.
-
#script_debug(mode) ⇒ String
Set the debug mode for subsequent scripts executed with EVAL.
- #script_exists(args) ⇒ Object
- #script_flush(sync: false, async: false) ⇒ Object
- #script_kill ⇒ Object
- #script_load(script) ⇒ Object
Instance Method Details
#eval(script, *rest, keys: nil, args: nil) ⇒ Object
Execute a Lua script on the server.
Since the eval is not available in the rust backend using the load and invoke script
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/valkey/commands/scripting_commands.rb', line 145 def eval(script, *rest, keys: nil, args: nil) # Validate script parameter raise ArgumentError, "script must be a string" unless script.is_a?(String) raise ArgumentError, "script cannot be empty" if script.empty? # Accept redis-rb's flexible positional form - eval(script, keys, argv) # - in addition to the keyword form, mirroring the same treatment # applied to evalsha (see that method for the full rationale). keys ||= rest[0] || [] args ||= rest[1] || [] # Validate and convert keys and args to strings begin keys = Array(keys).map(&:to_s) args = Array(args).map(&:to_s) rescue StandardError => e raise ArgumentError, "failed to convert keys or args to strings: #{e.}" end # Load script to get SHA1 hash, then execute via invoke_script sha = script_load(script) invoke_script(sha, keys: keys, args: args) end |
#eval_ro(script, keys: [], args: []) ⇒ Object
Execute a read-only Lua script on the server.
This is a read-only variant of EVAL that cannot execute commands that modify data. It can be routed to read replicas.
236 237 238 239 240 241 242 243 244 245 |
# File 'lib/valkey/commands/scripting_commands.rb', line 236 def eval_ro(script, keys: [], args: []) raise ArgumentError, "script must be a string" unless script.is_a?(String) raise ArgumentError, "script cannot be empty" if script.empty? keys = Array(keys).map(&:to_s) args = Array(args).map(&:to_s) sha = script_load(script) invoke_script(sha, keys: keys, args: args) end |
#evalsha(sha, *rest, keys: nil, args: nil) ⇒ Object
Execute a cached Lua script by its SHA1 hash.
Since evalsha is not available in rust backend using invoke script
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/valkey/commands/scripting_commands.rb', line 198 def evalsha(sha, *rest, keys: nil, args: nil) # Validate SHA1 hash parameter raise ArgumentError, "sha1 hash must be a string" unless sha.is_a?(String) raise ArgumentError, "sha1 hash must be a 40-character hexadecimal string" unless valid_sha1?(sha) # Accept redis-rb's flexible positional form - evalsha(sha, keys, argv) # - in addition to the keyword form, so code written against redis-rb's # API (e.g. redis_display_id) doesn't need to special-case this client. keys ||= rest[0] || [] args ||= rest[1] || [] # Validate and convert keys and args to strings begin keys = Array(keys).map(&:to_s) args = Array(args).map(&:to_s) rescue StandardError => e raise ArgumentError, "failed to convert keys or args to strings: #{e.}" end # Execute cached script via invoke_script invoke_script(sha, keys: keys, args: args) end |
#evalsha_ro(sha, keys: [], args: []) ⇒ Object
Execute a cached read-only Lua script by its SHA1 hash.
This is a read-only variant of EVALSHA that cannot execute commands that modify data. It can be routed to read replicas.
263 264 265 266 267 268 269 270 271 |
# File 'lib/valkey/commands/scripting_commands.rb', line 263 def evalsha_ro(sha, keys: [], args: []) raise ArgumentError, "sha1 hash must be a string" unless sha.is_a?(String) raise ArgumentError, "sha1 hash must be a 40-character hexadecimal string" unless valid_sha1?(sha) keys = Array(keys).map(&:to_s) args = Array(args).map(&:to_s) invoke_script(sha, keys: keys, args: args) end |
#invoke_script(script, args: [], keys: []) ⇒ Object
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
# File 'lib/valkey/commands/scripting_commands.rb', line 273 def invoke_script(script, args: [], keys: []) # Must hold onto the returned buffers (_arg_bufs/_keys_bufs) for the # lifetime of this method - they back arg_ptrs/keys_ptrs, and letting # them go out of scope (e.g. by only capturing the first 2 return # values) makes them eligible for GC before the native call below # reads through those pointers, corrupting ARGV/KEYS with freed memory. arg_ptrs, arg_lens, _arg_bufs, flattened_args = build_command_args(args) keys_ptrs, keys_lens, _keys_bufs, flattened_keys = build_command_args(keys) route = "" route_buf = FFI::MemoryPointer.from_string(route) # Use from_string to ensure proper null termination sha = FFI::MemoryPointer.from_string(script) begin res = Bindings.invoke_script( @connection, 0, sha, flattened_keys.size, keys_ptrs, keys_lens, flattened_args.size, arg_ptrs, arg_lens, route_buf, route.bytesize, 0 # span_ptr for OpenTelemetry (0 = no span) ) convert_response(res) ensure Bindings.free_command_result(res) if res && !res.null? end end |
#script(subcommand, args = nil, options: {}) ⇒ String, ...
Control remote script registry.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/valkey/commands/scripting_commands.rb', line 34 def script(subcommand, args = nil, options: {}) subcommand = subcommand.to_s.downcase if args.nil? send("script_#{subcommand}", **) else send("script_#{subcommand}", args) end # if subcommand == "exists" # arg = args.first # # send_command([:script, :exists, arg]) do |reply| # reply = reply.map { |r| Boolify.call(r) } # # if arg.is_a?(Array) # reply # else # reply.first # end # end # else # send_command([:script, subcommand] + args) # end end |
#script_debug(mode) ⇒ String
Set the debug mode for subsequent scripts executed with EVAL.
99 100 101 |
# File 'lib/valkey/commands/scripting_commands.rb', line 99 def script_debug(mode) send_command(RequestType::SCRIPT_DEBUG, [mode.to_s.upcase]) end |
#script_exists(args) ⇒ Object
72 73 74 75 76 77 78 79 80 |
# File 'lib/valkey/commands/scripting_commands.rb', line 72 def script_exists(args) send_command(RequestType::SCRIPT_EXISTS, Array(args)) do |reply| if args.is_a?(Array) reply else reply.first end end end |
#script_flush(sync: false, async: false) ⇒ Object
60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/valkey/commands/scripting_commands.rb', line 60 def script_flush(sync: false, async: false) args = [] if async args << "async" elsif sync args << "sync" end send_command(RequestType::SCRIPT_FLUSH, args) end |
#script_kill ⇒ Object
82 83 84 |
# File 'lib/valkey/commands/scripting_commands.rb', line 82 def script_kill send_command(RequestType::SCRIPT_KILL) end |
#script_load(script) ⇒ Object
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/valkey/commands/scripting_commands.rb', line 103 def script_load(script) script = script.first if script.is_a?(Array) buf = FFI::MemoryPointer.new(:char, script.bytesize) buf.put_bytes(0, script) result = Bindings.store_script(buf, script.bytesize) begin hash_buffer = Bindings::ScriptHashBuffer.new(result) hash_buffer[:ptr].read_string(hash_buffer[:len]) ensure Bindings.free_script_hash_buffer(result) if result && !result.null? end end |