#redis #lua #lua-script #helper #scripting #variables

redis-lua-macro

Redis Lua 脚本辅助工具的宏组件

3 个版本 (重大更新)

0.4.0 2020年6月16日
0.3.0 2020年6月11日
0.2.0 2020年3月27日

#lua-script 中排名第 22


redis-lua 中使用

BSD-3-Clause

36KB
1K SLoC

redis-lua

Lua 脚本辅助工具,用于 redis-rs

Latest version Documentation License Actions Status

  • Redis Lua 脚本的编译时检查。
  • 在 Lua 脚本中捕获 Rust 变量。
  • 安全的参数替换。
use redis_lua::lua;

fn main() {
    let client = redis::Client::open("redis://127.0.0.1/").unwrap();
    let mut con = client.get_connection().unwrap();

    let msg = "Hello Lua";
    let num = 42;

    let script = lua!(
        return @msg .. " / " .. @num
    );

    let v: String = script.invoke(&mut con).unwrap();
    println!("result: {}", v);
}

使用方法

将以下内容添加到您的 Cargo.toml

redis-lua = "0.2"

错误报告

脚本中的错误(如未定义变量)在编译时检测。

let script = lua!(
    return @msg .. " / " .. @num .. x
);
$ cargo build
...
error: in lua: `x` is not defined (undefined_variable)     
  --> redis-lua/examples/simple.rs:11:41                   
   |                         
11 |         return @msg .. " / " .. @num .. x             
   |                                         ^             

error: aborting due to previous error                      

参数替换

支持两种从 Rust 传递值到脚本的方式。

  • @x 用于捕获 Rust 变量(通过移动)。
  • $x 用于稍后替换值。
let x = 50;

let script = lua!(
    local v = $a * $b * $c
    if v > @x then
        return v .. " is large"
    else
        return v .. " is small"
    end
);

for i in 0..4 {
    // You can `clone()` the script to call it multiple times with different parameters.
    let r: String = script.clone().a(15).b(i).c(3).invoke(&mut con).unwrap();
    println!("{}", r);
}

脚本重用性

通过 lua! 返回的脚本对象如果是可克隆的,则可克隆。

连接脚本

+ 运算符连接两个脚本。脚本被视为单个脚本,并在 Redis 中原子性地评估。第一个脚本的返回值被丢弃。只有最后一个脚本的返回值由 Redis 返回。

let script1 = redis_lua::lua!(
    return redis.call("set", "a", $x);
);
let script2 = redis_lua::lua!(
    return redis.call("set", "b", $y);
);
let script = script1 + script2;

let mut cli = redis::Client::open("redis://127.0.0.1").unwrap();
let res: String = script.x(20).y(2).invoke(&mut cli).unwrap();
assert_eq!(res, "OK");

脚本特质

任何完成替换的脚本都实现了 Script 特质。您可以像 Box<dyn Script> 一样传递它们。

let script1 = lua! {
    return 1 + 2;
};

let x = 10;
let script2 = lua! {
    return @x + 2;
};

let incomplete_script = lua! {
    return $x + 2;
};
let script3 = incomplete_script.x(2);

let boxed1 = Box::new(script1) as Box<dyn redis_lua::Script>;
let boxed2 = Box::new(script2) as Box<dyn redis_lua::Script>;
let boxed3 = Box::new(script3) as Box<dyn redis_lua::Script>;

如果您想连接boxed脚本,请使用 join 方法。

let joined_boxed = boxed1.join(boxed2).join(boxed3);

异步支持

支持 async-await。

use redis_lua::lua;

#[tokio::main]
async fn main() {
    let client = redis::Client::open("redis://127.0.0.1/").unwrap();
    let mut con = client.get_multiplexed_tokio_connection().await.unwrap();

    let msg = "Hello Lua";
    let num = 42;

    let script = lua!(
        return @msg .. " / " .. @num
    );

    let v: String = script.invoke_async(&mut con).await.unwrap();
    println!("result: {}", v);
}

依赖项

~8–17MB
~219K SLoC