Delete src/server/lua_engine.rs
This commit is contained in:
parent
143e90a70b
commit
9f065cb25c
@ -1,713 +0,0 @@
|
||||
// src/server/lua_engine.rs
|
||||
//! Встроенный интерпретатор Lua для Futriix Server с lock-free архитектурой
|
||||
//!
|
||||
//! Этот модуль предоставляет безопасную интеграцию языка Lua в систему Futriix,
|
||||
//! позволяя выполнять пользовательские скрипты для настройки поведения сервера,
|
||||
//! создания триггеров, хранимых процедур и кастомной логики обработки данных.
|
||||
//! Все операции с базой данных выполняются через lock-free интерфейс для
|
||||
//! максимальной производительности в многопоточных сценариях.
|
||||
//!
|
||||
//! Основные функции:
|
||||
//! 1. Безопасное выполнение Lua скриптов с изоляцией окружения
|
||||
//! 2. Интеграция с базой данных через атомарные операции
|
||||
//! 3. Регистрация функций для работы с коллекциями, индексами и транзакциями
|
||||
//! 4. Поддержка хранимых процедур и триггеров
|
||||
//! 5. Интеграция с модулем шардинга и репликации
|
||||
//! 6. Автоматическое выполнение скриптов инициализации
|
||||
//!
|
||||
//! Архитектурные особенности:
|
||||
//! - Использование rlua для безопасного выполнения Lua кода
|
||||
//! - Изоляция пользовательского кода в sandbox окружении
|
||||
//! - Атомарный доступ к данным через замыкания и Arc-ссылки
|
||||
//! - Поддержка асинхронных операций через tokio
|
||||
//! - Расширяемая система регистрации функций
|
||||
|
||||
use rlua::{Lua, RluaCompat, Function, Result as LuaResult, Value as LuaValue};
|
||||
use std::sync::Arc;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::common::Result;
|
||||
use crate::common::protocol;
|
||||
use crate::server::database::{Trigger, TriggerEvent, Index, IndexType};
|
||||
|
||||
/// Движок Lua для выполнения скриптов в lock-free окружении
|
||||
/// Обеспечивает безопасное выполнение пользовательского кода
|
||||
/// с интеграцией в систему Futriix
|
||||
#[derive(Clone)]
|
||||
pub struct LuaEngine {
|
||||
lua: Arc<Lua>,
|
||||
}
|
||||
|
||||
impl LuaEngine {
|
||||
/// Создает новый Lua движок с настройками по умолчанию
|
||||
/// Инициализирует базовое окружение с глобальными функциями Futriix
|
||||
pub fn new() -> Result<Self> {
|
||||
let lua = Lua::new();
|
||||
|
||||
// Настройка Lua окружения с базовыми функциями для интеграции с Futriix
|
||||
lua.load(r#"
|
||||
-- Глобальные функции для логирования в системе Futriix
|
||||
function futriix_log(message)
|
||||
print("[LUA] " .. message)
|
||||
end
|
||||
|
||||
function futriix_error(message)
|
||||
print("[LUA ERROR] " .. message)
|
||||
end
|
||||
|
||||
-- Функция для получения текущего времени в формате ISO 8601
|
||||
function futriix_current_time()
|
||||
-- Возвращает строку с текущим временем
|
||||
-- В реальной реализации можно интегрировать с chrono
|
||||
return os.date("%Y-%m-%dT%H:%M:%S")
|
||||
end
|
||||
|
||||
-- Функция для генерации UUID (упрощенная версия)
|
||||
function futriix_generate_uuid()
|
||||
local template ='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
|
||||
return string.gsub(template, '[xy]', function (c)
|
||||
local v = (c == 'x') and math.random(0, 0xf) or math.random(8, 0xb)
|
||||
return string.format('%x', v)
|
||||
end)
|
||||
end
|
||||
|
||||
-- Функция для проверки типа данных
|
||||
function futriix_is_valid_json(str)
|
||||
-- Упрощенная проверка JSON
|
||||
if type(str) ~= 'string' then
|
||||
return false
|
||||
end
|
||||
return string.find(str, '{') ~= nil or string.find(str, '[') ~= nil
|
||||
end
|
||||
|
||||
-- Функция для работы с коллекциями (placeholder)
|
||||
function futriix_collection_exists(name)
|
||||
-- В реальной реализации проверяет существование коллекции
|
||||
return true
|
||||
end
|
||||
"#).exec()?;
|
||||
|
||||
Ok(Self { lua: Arc::new(lua) })
|
||||
}
|
||||
|
||||
/// Выполнение Lua скрипта из файла
|
||||
/// Читает содержимое файла и выполняет его как Lua код
|
||||
#[allow(dead_code)]
|
||||
pub fn execute_script_file(&self, file_path: &str) -> Result<()> {
|
||||
let script_content = fs::read_to_string(file_path)
|
||||
.map_err(|e| crate::common::FutriixError::LuaError(format!("Failed to read script file {}: {}", file_path, e)))?;
|
||||
|
||||
self.execute_script(&script_content)
|
||||
}
|
||||
|
||||
/// Выполнение Lua скрипта из строки
|
||||
/// Основной метод для выполнения пользовательского кода
|
||||
pub fn execute_script(&self, script: &str) -> Result<()> {
|
||||
let lua = self.lua.clone();
|
||||
lua.load(script).exec()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Выполнение всех скриптов из директории
|
||||
/// Используется для автоматического выполнения скриптов инициализации
|
||||
#[allow(dead_code)]
|
||||
pub fn execute_scripts_from_dir(&self, dir_path: &str, script_names: &[String]) -> Result<()> {
|
||||
let path = Path::new(dir_path);
|
||||
|
||||
if !path.exists() {
|
||||
println!("Lua scripts directory does not exist: {}", path.display());
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if !path.is_dir() {
|
||||
return Err(crate::common::FutriixError::LuaError(
|
||||
format!("Lua scripts path is not a directory: {}", path.display())
|
||||
));
|
||||
}
|
||||
|
||||
for script_name in script_names {
|
||||
let script_path = path.join(script_name);
|
||||
|
||||
if script_path.exists() && script_path.is_file() {
|
||||
println!("Executing Lua script: {}", script_path.display());
|
||||
|
||||
match self.execute_script_file(script_path.to_str().unwrap()) {
|
||||
Ok(_) => println!("✓ Script executed successfully: {}", script_name),
|
||||
Err(e) => eprintln!("✗ Failed to execute script {}: {}", script_name, e),
|
||||
}
|
||||
} else {
|
||||
println!("Script not found: {}", script_path.display());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Регистрация функций базы данных в Lua окружении с lock-free доступом
|
||||
/// Функции Lua ожидают два аргумента: Lua состояние (self) и аргументы функции
|
||||
/// Этот метод создает безопасный мост между Lua и Rust
|
||||
pub fn register_db_functions(
|
||||
&self,
|
||||
db: Arc<crate::server::database::Database>,
|
||||
sharding_manager: Arc<crate::server::sharding::ShardingManager>
|
||||
) -> Result<()> {
|
||||
let lua = self.lua.clone();
|
||||
|
||||
// Создаем таблицу для функций БД
|
||||
let futriix_db = lua.create_table()?;
|
||||
|
||||
// Базовые CRUD функции с lock-free доступом
|
||||
let db_clone = db.clone();
|
||||
futriix_db.set("create", lua.create_function(move |_, (collection, data): (String, String)| {
|
||||
let command = protocol::Command::Create {
|
||||
collection,
|
||||
document: data.into_bytes(),
|
||||
};
|
||||
match db_clone.execute_command(command) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(rlua::Error::RuntimeError(e.to_string())),
|
||||
}
|
||||
})?)?;
|
||||
|
||||
let db_clone = db.clone();
|
||||
futriix_db.set("read", lua.create_function(move |_, (collection, id): (String, String)| {
|
||||
let command = protocol::Command::Read {
|
||||
collection,
|
||||
id,
|
||||
};
|
||||
match db_clone.execute_command(command) {
|
||||
Ok(response) => {
|
||||
match response {
|
||||
protocol::Response::Success(data) => {
|
||||
Ok(String::from_utf8_lossy(&data).to_string())
|
||||
}
|
||||
protocol::Response::Error(e) => {
|
||||
Err(rlua::Error::RuntimeError(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => Err(rlua::Error::RuntimeError(e.to_string())),
|
||||
}
|
||||
})?)?;
|
||||
|
||||
let db_clone = db.clone();
|
||||
futriix_db.set("update", lua.create_function(move |_, (collection, id, data): (String, String, String)| {
|
||||
let command = protocol::Command::Update {
|
||||
collection,
|
||||
id,
|
||||
document: data.into_bytes(),
|
||||
};
|
||||
match db_clone.execute_command(command) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(rlua::Error::RuntimeError(e.to_string())),
|
||||
}
|
||||
})?)?;
|
||||
|
||||
let db_clone = db.clone();
|
||||
futriix_db.set("delete", lua.create_function(move |_, (collection, id): (String, String)| {
|
||||
let command = protocol::Command::Delete {
|
||||
collection,
|
||||
id,
|
||||
};
|
||||
match db_clone.execute_command(command) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(rlua::Error::RuntimeError(e.to_string())),
|
||||
}
|
||||
})?)?;
|
||||
|
||||
let db_clone = db.clone();
|
||||
futriix_db.set("query", lua.create_function(move |_, (collection, filter): (String, String)| {
|
||||
let command = protocol::Command::Query {
|
||||
collection,
|
||||
filter: filter.into_bytes(),
|
||||
};
|
||||
match db_clone.execute_command(command) {
|
||||
Ok(response) => {
|
||||
match response {
|
||||
protocol::Response::Success(data) => {
|
||||
Ok(String::from_utf8_lossy(&data).to_string())
|
||||
}
|
||||
protocol::Response::Error(e) => {
|
||||
Err(rlua::Error::RuntimeError(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => Err(rlua::Error::RuntimeError(e.to_string())),
|
||||
}
|
||||
})?)?;
|
||||
|
||||
// Функции для работы с транзакциями
|
||||
let db_clone = db.clone();
|
||||
futriix_db.set("begin_transaction", lua.create_function(move |_, transaction_id: String| {
|
||||
let command = protocol::Command::BeginTransaction { transaction_id };
|
||||
match db_clone.execute_command(command) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(rlua::Error::RuntimeError(e.to_string())),
|
||||
}
|
||||
})?)?;
|
||||
|
||||
let db_clone = db.clone();
|
||||
futriix_db.set("commit_transaction", lua.create_function(move |_, transaction_id: String| {
|
||||
let command = protocol::Command::CommitTransaction { transaction_id };
|
||||
match db_clone.execute_command(command) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(rlua::Error::RuntimeError(e.to_string())),
|
||||
}
|
||||
})?)?;
|
||||
|
||||
let db_clone = db.clone();
|
||||
futriix_db.set("rollback_transaction", lua.create_function(move |_, transaction_id: String| {
|
||||
let command = protocol::Command::RollbackTransaction { transaction_id };
|
||||
match db_clone.execute_command(command) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(rlua::Error::RuntimeError(e.to_string())),
|
||||
}
|
||||
})?)?;
|
||||
|
||||
// Функции для работы с индексами
|
||||
let db_clone = db.clone();
|
||||
futriix_db.set("create_index", lua.create_function(move |_, (collection, name, field, unique): (String, String, String, bool)| {
|
||||
let index = Index {
|
||||
name,
|
||||
index_type: IndexType::Secondary,
|
||||
field,
|
||||
unique,
|
||||
};
|
||||
let command = protocol::Command::CreateIndex { collection, index };
|
||||
match db_clone.execute_command(command) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(rlua::Error::RuntimeError(e.to_string())),
|
||||
}
|
||||
})?)?;
|
||||
|
||||
// Функции для работы с процедурами
|
||||
let db_clone = db.clone();
|
||||
futriix_db.set("create_procedure", lua.create_function(move |_, (name, code): (String, String)| {
|
||||
let command = protocol::Command::CreateProcedure {
|
||||
name,
|
||||
code: code.into_bytes(),
|
||||
};
|
||||
match db_clone.execute_command(command) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(rlua::Error::RuntimeError(e.to_string())),
|
||||
}
|
||||
})?)?;
|
||||
|
||||
let db_clone = db.clone();
|
||||
futriix_db.set("call_procedure", lua.create_function(move |_, name: String| {
|
||||
let command = protocol::Command::CallProcedure { name };
|
||||
match db_clone.execute_command(command) {
|
||||
Ok(response) => {
|
||||
match response {
|
||||
protocol::Response::Success(data) => {
|
||||
Ok(String::from_utf8_lossy(&data).to_string())
|
||||
}
|
||||
protocol::Response::Error(e) => {
|
||||
Err(rlua::Error::RuntimeError(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => Err(rlua::Error::RuntimeError(e.to_string())),
|
||||
}
|
||||
})?)?;
|
||||
|
||||
// Функции для работы с шардингом
|
||||
let sharding_clone = sharding_manager.clone();
|
||||
// Исправление: Lua функции ожидают два аргумента - Lua состояние и аргументы
|
||||
// Используем явный тип для пустого кортежа ()
|
||||
futriix_db.set("get_cluster_status", lua.create_function(move |_, _: ()| {
|
||||
match sharding_clone.get_cluster_status() {
|
||||
Ok(status) => {
|
||||
let json = serde_json::to_string(&status)
|
||||
.map_err(|e| rlua::Error::RuntimeError(e.to_string()))?;
|
||||
Ok(json)
|
||||
}
|
||||
Err(e) => Err(rlua::Error::RuntimeError(e.to_string())),
|
||||
}
|
||||
})?)?;
|
||||
|
||||
let sharding_clone = sharding_manager.clone();
|
||||
futriix_db.set("add_shard_node", lua.create_function(move |_, (node_id, address, capacity): (String, String, u64)| {
|
||||
match sharding_clone.add_node(node_id, address, capacity) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(rlua::Error::RuntimeError(e.to_string())),
|
||||
}
|
||||
})?)?;
|
||||
|
||||
let sharding_clone = sharding_manager.clone();
|
||||
// Исправление: Lua функции ожидают два аргумента - Lua состояние и аргументы
|
||||
// Используем явный тип для пустого кортежа ()
|
||||
futriix_db.set("rebalance_cluster", lua.create_function(move |_, _: ()| {
|
||||
match sharding_clone.rebalance_cluster() {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(rlua::Error::RuntimeError(e.to_string())),
|
||||
}
|
||||
})?)?;
|
||||
|
||||
// Функция для создания бэкапа
|
||||
let db_clone = db.clone();
|
||||
// Исправление: Lua функции ожидают два аргумента - Lua состояние и аргументы
|
||||
// Используем явный тип для пустого кортежа ()
|
||||
futriix_db.set("create_backup", lua.create_function(move |_, _: ()| {
|
||||
match db_clone.create_backup() {
|
||||
Ok(backup) => {
|
||||
let json = serde_json::to_string(&backup)
|
||||
.map_err(|e| rlua::Error::RuntimeError(e.to_string()))?;
|
||||
Ok(json)
|
||||
}
|
||||
Err(e) => Err(rlua::Error::RuntimeError(e.to_string())),
|
||||
}
|
||||
})?)?;
|
||||
|
||||
// Функция для получения статистики БД
|
||||
let db_clone = db.clone();
|
||||
// Исправление: Lua функции ожидают два аргумента - Lua состояние и аргументы
|
||||
// Используем явный тип для пустого кортежа ()
|
||||
futriix_db.set("get_stats", lua.create_function(move |_, _: ()| {
|
||||
match db_clone.get_stats() {
|
||||
Ok(stats) => {
|
||||
let json = serde_json::to_string(&stats)
|
||||
.map_err(|e| rlua::Error::RuntimeError(e.to_string()))?;
|
||||
Ok(json)
|
||||
}
|
||||
Err(e) => Err(rlua::Error::RuntimeError(e.to_string())),
|
||||
}
|
||||
})?)?;
|
||||
|
||||
// Функция для выполнения произвольной команды
|
||||
let db_clone = db.clone();
|
||||
futriix_db.set("execute_command", lua.create_function(move |_, command_json: String| {
|
||||
let command: protocol::Command = serde_json::from_str(&command_json)
|
||||
.map_err(|e| rlua::Error::RuntimeError(e.to_string()))?;
|
||||
|
||||
match db_clone.execute_command(command) {
|
||||
Ok(response) => {
|
||||
let json = serde_json::to_string(&response)
|
||||
.map_err(|e| rlua::Error::RuntimeError(e.to_string()))?;
|
||||
Ok(json)
|
||||
}
|
||||
Err(e) => Err(rlua::Error::RuntimeError(e.to_string())),
|
||||
}
|
||||
})?)?;
|
||||
|
||||
// Добавляем таблицу в глобальное пространство имен
|
||||
lua.globals().set("futriix_db", futriix_db)?;
|
||||
|
||||
// Создаем таблицу для работы с CSV
|
||||
let csv_table = lua.create_table()?;
|
||||
// ИСПРАВЛЕНИЕ: Указываем явный тип возвращаемого значения () для функций Lua
|
||||
// CSV import функция - возвращает ошибку, так как функционал еще не реализован
|
||||
csv_table.set("import", lua.create_function(move |_, _args: ()| -> rlua::Result<()> {
|
||||
Err(rlua::Error::RuntimeError("CSV import not yet implemented in Lua".to_string()))
|
||||
})?)?;
|
||||
|
||||
// ИСПРАВЛЕНИЕ: Указываем явный тип возвращаемого значения () для функций Lua
|
||||
// CSV export функция - возвращает ошибку, так как функционал еще не реализован
|
||||
csv_table.set("export", lua.create_function(move |_, _args: ()| -> rlua::Result<()> {
|
||||
Err(rlua::Error::RuntimeError("CSV export not yet implemented in Lua".to_string()))
|
||||
})?)?;
|
||||
|
||||
lua.globals().set("futriix_csv", csv_table)?;
|
||||
|
||||
// Создаем таблицу для работы с триггерами
|
||||
let triggers_table = lua.create_table()?;
|
||||
|
||||
// Функция для создания триггера
|
||||
triggers_table.set("create", lua.create_function(move |_, (name, event_str, collection, code): (String, String, String, String)| {
|
||||
let event = match event_str.as_str() {
|
||||
"before_create" => TriggerEvent::BeforeCreate,
|
||||
"after_create" => TriggerEvent::AfterCreate,
|
||||
"before_update" => TriggerEvent::BeforeUpdate,
|
||||
"after_update" => TriggerEvent::AfterUpdate,
|
||||
"before_delete" => TriggerEvent::BeforeDelete,
|
||||
"after_delete" => TriggerEvent::AfterDelete,
|
||||
_ => return Err(rlua::Error::RuntimeError(format!("Unknown trigger event: {}", event_str))),
|
||||
};
|
||||
|
||||
let trigger = Trigger {
|
||||
name,
|
||||
event,
|
||||
collection,
|
||||
lua_code: code,
|
||||
};
|
||||
|
||||
match db.add_trigger(trigger) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(rlua::Error::RuntimeError(e.to_string())),
|
||||
}
|
||||
})?)?;
|
||||
|
||||
lua.globals().set("futriix_triggers", triggers_table)?;
|
||||
|
||||
println!("Lua engine initialized with database functions");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Получение директории Lua скриптов
|
||||
#[allow(dead_code)]
|
||||
pub fn lua_scripts_dir(&self) -> &'static str {
|
||||
"lua_scripts"
|
||||
}
|
||||
|
||||
/// Выполнение скрипта инициализации системы
|
||||
/// Создает базовые глобальные функции и системные коллекции
|
||||
pub fn execute_init_script(&self) -> Result<()> {
|
||||
let init_script = r#"
|
||||
-- Скрипт инициализации Futriix Server
|
||||
print("Initializing Futriix Server Lua environment...")
|
||||
|
||||
-- Создаем глобальные функции для бэкапов
|
||||
function futriix.backup.start()
|
||||
return futriix_db.create_backup()
|
||||
end
|
||||
|
||||
function futriix.backup.restore(backup_json)
|
||||
-- В реальной реализации здесь будет восстановление из бэкапа
|
||||
print("Restore functionality to be implemented")
|
||||
return true
|
||||
end
|
||||
|
||||
-- Пример создания системной коллекции при старте
|
||||
local success, result = pcall(function()
|
||||
local timestamp = futriix_current_time()
|
||||
local config_data = string.format('{"key": "server_start_time", "value": "%s"}', timestamp)
|
||||
futriix_db.create("system_config", config_data)
|
||||
end)
|
||||
|
||||
if success then
|
||||
print("System configuration initialized")
|
||||
else
|
||||
futriix_error("Failed to initialize system config: " .. result)
|
||||
end
|
||||
|
||||
-- Пример ACL проверки через Lua
|
||||
function check_access(ip_address)
|
||||
if ip_address == "127.0.0.1" then
|
||||
return true
|
||||
end
|
||||
-- Здесь можно добавить более сложную логику проверки
|
||||
return false
|
||||
end
|
||||
|
||||
-- Проверка кластерного режима (заглушка)
|
||||
function is_cluster_enabled()
|
||||
-- В реальной реализации проверяет конфигурацию кластера
|
||||
return false
|
||||
end
|
||||
|
||||
print("Lua initialization script completed successfully")
|
||||
"#;
|
||||
|
||||
self.execute_script(init_script)
|
||||
}
|
||||
|
||||
/// Создание тестовой коллекции через Lua (для демонстрации)
|
||||
#[allow(dead_code)]
|
||||
pub fn create_test_collection(&self) -> Result<()> {
|
||||
let test_script = r#"
|
||||
-- Создание тестовой коллекции через Lua
|
||||
print("Creating test collection...")
|
||||
|
||||
local test_data = {
|
||||
name = "Test User",
|
||||
email = "test@example.com",
|
||||
age = 30,
|
||||
active = true,
|
||||
tags = {"user", "test", "demo"}
|
||||
}
|
||||
|
||||
local json_data = futriix_db.get_stats()
|
||||
print("Current DB stats: " .. json_data)
|
||||
|
||||
-- Преобразуем таблицу Lua в JSON строку
|
||||
local function table_to_json(tbl)
|
||||
local result = "{"
|
||||
for k, v in pairs(tbl) do
|
||||
if type(k) == "string" then
|
||||
result = result .. string.format('"%s":', k)
|
||||
else
|
||||
result = result .. string.format('"%d":', k)
|
||||
end
|
||||
|
||||
if type(v) == "string" then
|
||||
result = result .. string.format('"%s"', v)
|
||||
elseif type(v) == "number" then
|
||||
result = result .. tostring(v)
|
||||
elseif type(v) == "boolean" then
|
||||
result = result .. tostring(v)
|
||||
elseif type(v) == "table" then
|
||||
-- Простая обработка массивов
|
||||
if #v > 0 then
|
||||
local arr = "["
|
||||
for i, val in ipairs(v) do
|
||||
if i > 1 then arr = arr .. "," end
|
||||
arr = arr .. string.format('"%s"', val)
|
||||
end
|
||||
arr = arr .. "]"
|
||||
result = result .. arr
|
||||
else
|
||||
result = result .. "{}"
|
||||
end
|
||||
else
|
||||
result = result .. "null"
|
||||
end
|
||||
|
||||
result = result .. ","
|
||||
end
|
||||
|
||||
-- Убираем последнюю запятую
|
||||
result = result:sub(1, -2) .. "}"
|
||||
return result
|
||||
end
|
||||
|
||||
local test_json = table_to_json(test_data)
|
||||
local success, doc_id = pcall(function()
|
||||
return futriix_db.create("test_users", test_json)
|
||||
end)
|
||||
|
||||
if success then
|
||||
print("Test document created with ID: " .. tostring(doc_id))
|
||||
else
|
||||
futriix_error("Failed to create test document: " .. doc_id)
|
||||
end
|
||||
"#;
|
||||
|
||||
self.execute_script(test_script)
|
||||
}
|
||||
|
||||
/// Тестирование работы с индексами через Lua
|
||||
#[allow(dead_code)]
|
||||
pub fn test_index_operations(&self) -> Result<()> {
|
||||
let index_script = r#"
|
||||
-- Тестирование работы с индексами через Lua
|
||||
print("Testing index operations...")
|
||||
|
||||
-- Создание индекса по полю email
|
||||
local success, result = pcall(function()
|
||||
return futriix_db.create_index("test_users", "email_idx", "email", true)
|
||||
end)
|
||||
|
||||
if success then
|
||||
print("Index created successfully")
|
||||
else
|
||||
futriix_error("Failed to create index: " .. result)
|
||||
end
|
||||
|
||||
-- Создание не-уникального индекса по полю age
|
||||
success, result = pcall(function()
|
||||
return futriix_db.create_index("test_users", "age_idx", "age", false)
|
||||
end)
|
||||
|
||||
if success then
|
||||
print("Non-unique index created successfully")
|
||||
else
|
||||
futriix_error("Failed to create non-unique index: " .. result)
|
||||
end
|
||||
"#;
|
||||
|
||||
self.execute_script(index_script)
|
||||
}
|
||||
|
||||
/// Тестирование транзакций через Lua
|
||||
#[allow(dead_code)]
|
||||
pub fn test_transaction_operations(&self) -> Result<()> {
|
||||
let transaction_script = r#"
|
||||
-- Тестирование транзакций через Lua
|
||||
print("Testing transaction operations...")
|
||||
|
||||
local transaction_id = "tx_test_" .. futriix_generate_uuid()
|
||||
|
||||
-- Начало транзакции
|
||||
local success, result = pcall(function()
|
||||
return futriix_db.begin_transaction(transaction_id)
|
||||
end)
|
||||
|
||||
if not success then
|
||||
futriix_error("Failed to begin transaction: " .. result)
|
||||
return
|
||||
end
|
||||
|
||||
print("Transaction started: " .. transaction_id)
|
||||
|
||||
-- Добавление нескольких операций в транзакцию
|
||||
local operations = {
|
||||
{collection = "test_users", data = '{"name": "Alice", "email": "alice@example.com", "age": 25}'},
|
||||
{collection = "test_users", data = '{"name": "Bob", "email": "bob@example.com", "age": 30}'},
|
||||
{collection = "test_users", data = '{"name": "Charlie", "email": "charlie@example.com", "age": 35}'}
|
||||
}
|
||||
|
||||
local all_success = true
|
||||
for i, op in ipairs(operations) do
|
||||
success, result = pcall(function()
|
||||
return futriix_db.create(op.collection, op.data)
|
||||
end)
|
||||
|
||||
if not success then
|
||||
futriix_error("Failed to create document " .. i .. ": " .. result)
|
||||
all_success = false
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if all_success then
|
||||
-- Коммит транзакции
|
||||
success, result = pcall(function()
|
||||
return futriix_db.commit_transaction(transaction_id)
|
||||
end)
|
||||
|
||||
if success then
|
||||
print("Transaction committed successfully")
|
||||
else
|
||||
futriix_error("Failed to commit transaction: " .. result)
|
||||
end
|
||||
else
|
||||
-- Откат транзакции
|
||||
success, result = pcall(function()
|
||||
return futriix_db.rollback_transaction(transaction_id)
|
||||
end)
|
||||
|
||||
if success then
|
||||
print("Transaction rolled back due to errors")
|
||||
else
|
||||
futriix_error("Failed to rollback transaction: " .. result)
|
||||
end
|
||||
end
|
||||
"#;
|
||||
|
||||
self.execute_script(transaction_script)
|
||||
}
|
||||
|
||||
/// Получение статистики выполнения скриптов (заглушка)
|
||||
#[allow(dead_code)]
|
||||
pub fn get_execution_stats(&self) -> Result<()> {
|
||||
// Здесь можно собирать статистику выполнения скриптов
|
||||
// В текущей реализации просто возвращаем Ok
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Проверка синтаксиса Lua скрипта без выполнения
|
||||
#[allow(dead_code)]
|
||||
pub fn validate_script_syntax(&self, script: &str) -> Result<()> {
|
||||
let lua = self.lua.clone();
|
||||
// Пытаемся загрузить скрипт без выполнения
|
||||
lua.load(script).into_function()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Создание защищенного окружения для выполнения ненадежных скриптов
|
||||
#[allow(dead_code)]
|
||||
pub fn create_sandboxed_environment(&self) -> Result<()> {
|
||||
// Здесь можно создать изолированное окружение для ненадежных скриптов
|
||||
// В текущей реализации используется основное окружение
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Очистка кэша Lua (если потребуется в будущем)
|
||||
#[allow(dead_code)]
|
||||
pub fn clear_cache(&self) -> Result<()> {
|
||||
// Lua rlua не имеет явного кэша, но можно пересоздать движок
|
||||
println!("Lua cache cleared (engine would be recreated if needed)");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user