improve and add models
This commit is contained in:
201
heromodels/src/models/circle/rhai.rs
Normal file
201
heromodels/src/models/circle/rhai.rs
Normal file
@@ -0,0 +1,201 @@
|
||||
use rhai::plugin::*;
|
||||
use rhai::{Engine, EvalAltResult, Position, Module, INT, Dynamic, Array, CustomType};
|
||||
use std::sync::Arc;
|
||||
use std::mem;
|
||||
use crate::db::Db;
|
||||
|
||||
use super::circle::{Circle};
|
||||
type RhaiCircle = Circle;
|
||||
use crate::db::hero::OurDB;
|
||||
use crate::db::Collection;
|
||||
use serde::Serialize;
|
||||
use std::collections::HashMap;
|
||||
use serde_json;
|
||||
|
||||
/// Registers a `.json()` method for any type `T` that implements the required traits.
|
||||
fn register_json_method<T>(engine: &mut Engine)
|
||||
where
|
||||
// The type must be:
|
||||
T: CustomType + Clone + Serialize, // A clonable, serializable, custom type for Rhai
|
||||
{
|
||||
// This is the function that will be called when a script runs '.json()'
|
||||
let to_json_fn = |obj: &mut T| -> Result<String, Box<EvalAltResult>> {
|
||||
// Use serde_json to serialize the object to a pretty-formatted string.
|
||||
// The '?' will automatically convert any serialization error into a Rhai error.
|
||||
serde_json::to_string(obj).map_err(|e| e.to_string().into())
|
||||
};
|
||||
|
||||
// Register the function as a method named "json" for the type 'T'.
|
||||
engine.build_type::<T>().register_fn("json", to_json_fn);
|
||||
}
|
||||
|
||||
// Helper to convert i64 from Rhai to u32 for IDs
|
||||
fn id_from_i64_to_u32(id_i64: i64) -> Result<u32, Box<EvalAltResult>> {
|
||||
u32::try_from(id_i64).map_err(|_|
|
||||
Box::new(EvalAltResult::ErrorArithmetic(
|
||||
format!("Failed to convert ID '{}' to u32", id_i64).into(),
|
||||
Position::NONE
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
#[export_module]
|
||||
mod rhai_circle_module {
|
||||
// --- Circle Functions ---
|
||||
#[rhai_fn(name = "new_circle")]
|
||||
pub fn new_circle() -> RhaiCircle {
|
||||
Circle::new()
|
||||
}
|
||||
|
||||
/// Sets the circle title
|
||||
#[rhai_fn(name = "title", return_raw, global, pure)]
|
||||
pub fn circle_title(circle: &mut RhaiCircle, title: String) -> Result<RhaiCircle, Box<EvalAltResult>> {
|
||||
let owned_circle = mem::take(circle);
|
||||
*circle = owned_circle.title(title);
|
||||
Ok(circle.clone())
|
||||
}
|
||||
|
||||
/// Sets the circle ws_url
|
||||
#[rhai_fn(name = "ws_url", return_raw, global, pure)]
|
||||
pub fn circle_ws_url(circle: &mut RhaiCircle, ws_url: String) -> Result<RhaiCircle, Box<EvalAltResult>> {
|
||||
let owned_circle = mem::take(circle);
|
||||
*circle = owned_circle.ws_url(ws_url);
|
||||
Ok(circle.clone())
|
||||
}
|
||||
|
||||
/// Sets the circle description
|
||||
#[rhai_fn(name = "description", return_raw, global, pure)]
|
||||
pub fn circle_description(circle: &mut RhaiCircle, description: String) -> Result<RhaiCircle, Box<EvalAltResult>> {
|
||||
let owned_circle = mem::take(circle);
|
||||
*circle = owned_circle.description(description);
|
||||
Ok(circle.clone())
|
||||
}
|
||||
|
||||
/// Sets the circle logo
|
||||
#[rhai_fn(name = "logo", return_raw, global, pure)]
|
||||
pub fn circle_logo(circle: &mut RhaiCircle, logo: String) -> Result<RhaiCircle, Box<EvalAltResult>> {
|
||||
let owned_circle = mem::take(circle);
|
||||
*circle = owned_circle.logo(logo);
|
||||
Ok(circle.clone())
|
||||
}
|
||||
|
||||
/// Sets the circle theme
|
||||
#[rhai_fn(name = "theme", return_raw, global, pure)]
|
||||
pub fn circle_theme(circle: &mut RhaiCircle, theme: HashMap<String, String>) -> Result<RhaiCircle, Box<EvalAltResult>> {
|
||||
let owned_circle = mem::take(circle);
|
||||
*circle = owned_circle.theme(theme);
|
||||
Ok(circle.clone())
|
||||
}
|
||||
|
||||
/// Adds an attendee to the circle
|
||||
#[rhai_fn(name = "add_circle", return_raw, global, pure)]
|
||||
pub fn circle_add_circle(circle: &mut RhaiCircle, added_circle: String) -> Result<RhaiCircle, Box<EvalAltResult>> {
|
||||
// Use take to get ownership of the circle
|
||||
let owned_circle = mem::take(circle);
|
||||
*circle = owned_circle.add_circle(added_circle);
|
||||
Ok(circle.clone())
|
||||
}
|
||||
|
||||
// Circle Getters
|
||||
#[rhai_fn(get = "id", pure)]
|
||||
pub fn get_circle_id(circle: &mut RhaiCircle) -> i64 { circle.base_data.id as i64 }
|
||||
#[rhai_fn(get = "created_at", pure)]
|
||||
pub fn get_circle_created_at(circle: &mut RhaiCircle) -> i64 { circle.base_data.created_at }
|
||||
#[rhai_fn(get = "modified_at", pure)]
|
||||
pub fn get_circle_modified_at(circle: &mut RhaiCircle) -> i64 { circle.base_data.modified_at }
|
||||
|
||||
#[rhai_fn(get = "title", pure)]
|
||||
pub fn get_circle_title(circle: &mut RhaiCircle) -> String { circle.title.clone() }
|
||||
#[rhai_fn(get = "description", pure)]
|
||||
pub fn get_circle_description(circle: &mut RhaiCircle) -> Option<String> { circle.description.clone() }
|
||||
#[rhai_fn(get = "circles", pure)]
|
||||
pub fn get_circle_circles(circle: &mut RhaiCircle) -> Vec<String> { circle.circles.clone() }
|
||||
#[rhai_fn(get = "ws_url", pure)]
|
||||
pub fn get_circle_ws_url(circle: &mut RhaiCircle) -> String { circle.ws_url.clone() }
|
||||
#[rhai_fn(get = "logo", pure)]
|
||||
pub fn get_circle_logo(circle: &mut RhaiCircle) -> Option<String> { circle.logo.clone() }
|
||||
#[rhai_fn(get = "theme", pure)]
|
||||
pub fn get_circle_theme(circle: &mut RhaiCircle) -> HashMap<String, String> { circle.theme.clone() }
|
||||
}
|
||||
|
||||
pub fn register_circle_rhai_module(engine: &mut Engine, db: Arc<OurDB>) {
|
||||
// Register the exported module globally
|
||||
let module = exported_module!(rhai_circle_module);
|
||||
engine.register_global_module(module.into());
|
||||
|
||||
// Create a module for database functions
|
||||
let mut db_module = Module::new();
|
||||
|
||||
// Manually register database functions as they need to capture 'db'
|
||||
let db_clone_set_circle = db.clone();
|
||||
db_module.set_native_fn("save_circle", move |circle: Circle| -> Result<Circle, Box<EvalAltResult>> {
|
||||
// Use the Collection trait method directly
|
||||
let result = db_clone_set_circle.set(&circle)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("DB Error set_circle: {}", e).into(), Position::NONE)))?;
|
||||
|
||||
// Return the updated circle with the correct ID
|
||||
Ok(result.1)
|
||||
});
|
||||
|
||||
register_json_method::<Circle>(engine);
|
||||
|
||||
// Manually register database functions as they need to capture 'db'
|
||||
let db_clone_delete_circle = db.clone();
|
||||
db_module.set_native_fn("delete_circle", move |circle: Circle| -> Result<(), Box<EvalAltResult>> {
|
||||
// Use the Collection trait method directly
|
||||
let result = db_clone_delete_circle.collection::<Circle>()
|
||||
.expect("can open circle collection")
|
||||
.delete_by_id(circle.base_data.id)
|
||||
.expect("can delete circle");
|
||||
|
||||
// Return the updated circle with the correct ID
|
||||
Ok(result)
|
||||
});
|
||||
|
||||
let db_clone_get_circle = db.clone();
|
||||
db_module.set_native_fn("get_circle", move || -> Result<Circle, Box<EvalAltResult>> {
|
||||
// Use the Collection trait method directly
|
||||
let all_circles: Vec<Circle> = db_clone_get_circle.get_all()
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("DB Error get_circle: {}", e).into(), Position::NONE)))?;
|
||||
|
||||
if let Some(first_circle) = all_circles.first() {
|
||||
Ok(first_circle.clone())
|
||||
} else {
|
||||
Err(Box::new(EvalAltResult::ErrorRuntime("Circle not found".into(), Position::NONE)))
|
||||
}
|
||||
});
|
||||
|
||||
let db_clone_get_circle_by_id = db.clone();
|
||||
db_module.set_native_fn("get_circle_by_id", move |id_i64: INT| -> Result<Circle, Box<EvalAltResult>> {
|
||||
let id_u32 = id_from_i64_to_u32(id_i64)?;
|
||||
// Use the Collection trait method directly
|
||||
db_clone_get_circle_by_id.get_by_id(id_u32)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("DB Error get_circle_by_id: {}", e).into(), Position::NONE)))?
|
||||
.ok_or_else(|| Box::new(EvalAltResult::ErrorRuntime(format!("Circle with ID {} not found", id_u32).into(), Position::NONE)))
|
||||
});
|
||||
|
||||
// Add list_circles function to get all circles
|
||||
let db_clone_list_circles = db.clone();
|
||||
db_module.set_native_fn("list_circles", move || -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let collection = db_clone_list_circles.collection::<Circle>()
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to get circle collection: {:?}", e).into(),
|
||||
Position::NONE
|
||||
)))?;
|
||||
let circles = collection.get_all()
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
|
||||
format!("Failed to get all circles: {:?}", e).into(),
|
||||
Position::NONE
|
||||
)))?;
|
||||
let mut array = Array::new();
|
||||
for circle in circles {
|
||||
array.push(Dynamic::from(circle));
|
||||
}
|
||||
Ok(Dynamic::from(array))
|
||||
});
|
||||
|
||||
// Register the database module globally
|
||||
engine.register_global_module(db_module.into());
|
||||
|
||||
println!("Successfully registered circle Rhai module using export_module approach.");
|
||||
}
|
Reference in New Issue
Block a user