Aviram Netanel
Aviram Netanel

Reputation: 13645

how to define functions in redis \ lua?

I'm using Node.js, and the 'redis-scripto' module, and I'm trying to define a function in Lua:

 var redis = require("redis");  
 var redisClient = redis.createClient("6379","127.0.0.1");   

 var Scripto = require('redis-scripto');
 var scriptManager = new Scripto(redisClient);
 var scripts = {'add_script':'function add(i,j) return (i+j) end add(i,j)'};

 scriptManager.load(scripts);
 scriptManager.run('add_script', [], [1,1], function(err, result){
                    console.log(err || result);
 });

so I'm getting this error:

[Error: ERR Error running script (call to .... @enable_strict_lua:7: user_script:1: Script attempted to create global variable 'add']

so I've found that it's a protection, as explained in this thread:

"The doc-string of scriptingEnableGlobalsProtection indicates that intent is to notify script authors of common mistake (not using local)."

but I still didn't understand - where is this scripting.c ? and the solution of changing global tables seems risky to me.

Is there no simple way of setting functions to redis - using lua ?

Upvotes: 6

Views: 7355

Answers (3)

Waylon Flinn
Waylon Flinn

Reputation: 20257

You have to assign an anonymous function to a variable (using local).

local just_return_it = function(value) 
    return value
end 

--// result contains the string "hello world"
local result = just_return_it("hello world")

Alternately, you can create a table and add functions as fields on the table. This allows a more object oriented style.

local obj = {}

function obj.name()
    return "my name is Tom"
end

--// result contains "my name is Tom" 
local result = obj.name()

Redis requires this to prevent access to the global scope. The entire scripting mechanism is designed to keep persistence out of the scripting layer. Allowing things in the global scope would create an easy way to subvert this, making it much more difficult to track and manage state on the server.

Note: this means you'll have to add the same functions to every script that uses them. They aren't persistent on the server.

Upvotes: 5

Aviram Netanel
Aviram Netanel

Reputation: 13645

This worked for me: (change line 5 from the question above):

var scripts = {
'add_script':'local function add(i,j) return (i+j) end return(add(ARGV[1],ARGV[2]))'};

to pass variables to the script use KEYS[] and ARGV[], as explained in the redis-scripto guide and also there's a good example in here: "Lua: A Guide for Redis Users"

Upvotes: 2

Alex
Alex

Reputation: 1017

It looks like the script runner is running your code in a function. So when you create function add(), it thinks you're doing it inside a function by accident. It'll also, likely, have a similar issue with the arguments to the call to add(i,j). If this is correct then this should work:

local function add(i,j) return (i+j) end return add(1,1)

and if THAT works then hopefully this will too with your arguments passed from the js:

local function add(i,j) return (i+j) end return add(...)

Upvotes: 7

Related Questions