1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
use mlua::{AnyUserData, Lua, Table, UserData, UserDataMethods, Value};
use rusqlite::Connection;
use std::sync::{Arc, Mutex};
use crate::error::{Context, Result};
pub(crate) struct LuaDatabase(Arc<Mutex<Connection>>);
impl UserData for LuaDatabase {
fn add_methods<'lua, M: UserDataMethods<Self>>(methods: &mut M) {
methods.add_method_mut("execute", |_, db, args: (String, Option<Table>)| {
let sql = args.0;
let conn = db.0.clone();
// TODO: figure it out how to pass arguments to `execute`
// let params = args.1;
// let mut positional_params: Vec<Value> = vec![];
// let mut named_params: Vec<(String, Value)> = vec![];
// if let Some(params_table) = params {
// let len = params_table.raw_len();
// if len > 0 {
// // Assume positional parameters if it has a sequence part
// for i in 1..=len {
// positional_params.push(params_table.raw_get(i)?);
// }
// } else {
// // Assume named parameters if it has no sequence part
// for pair in params_table.pairs::<String, Value>() {
// let (k, v) = pair?;
// named_params.push((k, v));
// }
// }
// }
match conn.clone().lock().unwrap().execute(sql.as_str(), ()) {
Ok(affected) => Ok(Value::Integer(affected as i64)),
Err(err) => Err(mlua::Error::RuntimeError(err.to_string())),
}
});
}
}
/// Templating function support.
pub(crate) fn create_database_fn(lua: &Lua, path: &str) -> Result<AnyUserData> {
let db =
Connection::open(path).with_context(|| format!("Failed to open database at {}", path))?;
let conn = Arc::new(Mutex::new(db));
lua.create_userdata(LuaDatabase(conn))
.with_context(|| "database_fn: failed to initialize database")
}