final db models wip

This commit is contained in:
timurgordon
2025-06-03 21:50:08 +03:00
parent 2a2d69dafb
commit abbed9a1a1
43 changed files with 2958 additions and 1410 deletions

View File

@@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
use super::flow_step::FlowStep;
/// Represents a signing flow.
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Default)]
#[model]
pub struct Flow {
/// Base model data (id, created_at, updated_at).
@@ -27,9 +27,9 @@ pub struct Flow {
impl Flow {
/// Create a new flow.
/// The `id` is the database primary key.
/// The `flow_uuid` should be a Uuid::new_v4().to_string().
pub fn new(_id: u32, flow_uuid: impl ToString) -> Self {
/// The ID is managed by `BaseModelData::new()` and the database.
pub fn new(flow_uuid: impl ToString) -> Self {
Self {
base_data: BaseModelData::new(),
flow_uuid: flow_uuid.to_string(),

View File

@@ -1,6 +1,7 @@
use heromodels_core::BaseModelData;
use heromodels_derive::model;
use serde::{Deserialize, Serialize};
use std::default::Default;
/// Represents a step within a signing flow.
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
@@ -20,6 +21,17 @@ pub struct FlowStep {
pub status: String,
}
impl Default for FlowStep {
fn default() -> Self {
Self {
base_data: BaseModelData::new(),
description: None,
step_order: 0,
status: String::from("Pending"), // Default status
}
}
}
impl FlowStep {
/// Create a new flow step.
pub fn new(_id: u32, step_order: u32) -> Self {

View File

@@ -1,140 +1,384 @@
use rhai::{Dynamic, Engine, EvalAltResult, NativeCallContext, Position};
use rhai::plugin::*;
use rhai::{Engine, EvalAltResult, Position, Module, INT, Dynamic, Array};
use std::sync::Arc;
use std::mem;
use heromodels_core::BaseModelData;
use crate::db::hero::OurDB; // Import OurDB for actual DB operations
use crate::db::Collection; // Collection might be needed if we add more specific DB functions
use super::{
flow::Flow,
flow_step::FlowStep,
signature_requirement::SignatureRequirement,
};
// use rhai_wrapper::wrap_vec_return; // Not currently used for flow, but keep for potential future use.
use super::flow::Flow;
use super::flow_step::FlowStep;
use super::signature_requirement::SignatureRequirement;
type RhaiFlow = Flow;
type RhaiFlowStep = FlowStep;
type RhaiSignatureRequirement = SignatureRequirement;
use crate::db::hero::OurDB;
use crate::db::Collection;
use crate::db::Db;
use heromodels_core::Model;
// Helper function to convert Rhai's i64 to u32 for IDs
fn i64_to_u32(val: i64, context_pos: Position, field_name: &str, object_name: &str) -> Result<u32, Box<EvalAltResult>> {
val.try_into().map_err(|_e| {
// 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!("Conversion error for {} in {} from i64 to u32", field_name, object_name),
context_pos,
format!("Failed to convert ID '{}' to u32", id_i64).into(),
Position::NONE
))
})
)
}
// Helper to convert i64 from Rhai to u64 for timestamps or other large numbers
fn val_from_i64_to_u64(val_i64: i64) -> Result<u64, Box<EvalAltResult>> {
u64::try_from(val_i64).map_err(|_|
Box::new(EvalAltResult::ErrorArithmetic(
format!("Failed to convert value '{}' to u64", val_i64).into(),
Position::NONE
))
)
}
#[export_module]
mod rhai_flow_module {
// --- Flow Functions ---
#[rhai_fn(name = "new_flow")]
pub fn new_flow(flow_uuid: String) -> RhaiFlow {
Flow::new(flow_uuid)
}
/// Sets the flow name
#[rhai_fn(name = "name", return_raw, global, pure)]
pub fn flow_name(flow: &mut RhaiFlow, name: String) -> Result<RhaiFlow, Box<EvalAltResult>> {
let owned_flow = mem::replace(flow, Flow::new("")); // Dummy for replacement
*flow = owned_flow.name(name);
Ok(flow.clone())
}
/// Sets the flow status
#[rhai_fn(name = "status", return_raw, global, pure)]
pub fn flow_status(flow: &mut RhaiFlow, status: String) -> Result<RhaiFlow, Box<EvalAltResult>> {
let owned_flow = mem::replace(flow, Flow::new("")); // Dummy for replacement
*flow = owned_flow.status(status);
Ok(flow.clone())
}
/// Adds a step to the flow
#[rhai_fn(name = "add_step", return_raw, global, pure)]
pub fn flow_add_step(flow: &mut RhaiFlow, step: RhaiFlowStep) -> Result<RhaiFlow, Box<EvalAltResult>> {
let owned_flow = mem::replace(flow, Flow::new("")); // Dummy for replacement
*flow = owned_flow.add_step(step);
Ok(flow.clone())
}
// Flow Getters
#[rhai_fn(get = "id", pure)]
pub fn get_id(flow: &mut RhaiFlow) -> i64 { flow.base_data.id as i64 }
#[rhai_fn(get = "created_at", pure)]
pub fn get_created_at(flow: &mut RhaiFlow) -> i64 { flow.base_data.created_at }
#[rhai_fn(get = "modified_at", pure)]
pub fn get_modified_at(flow: &mut RhaiFlow) -> i64 { flow.base_data.modified_at }
#[rhai_fn(get = "flow_uuid", pure)]
pub fn get_flow_uuid(flow: &mut RhaiFlow) -> String { flow.flow_uuid.clone() }
#[rhai_fn(get = "name", pure)]
pub fn get_name(flow: &mut RhaiFlow) -> String { flow.name.clone() }
#[rhai_fn(get = "status", pure)]
pub fn get_status(flow: &mut RhaiFlow) -> String { flow.status.clone() }
#[rhai_fn(get = "steps", pure)]
pub fn get_steps(flow: &mut RhaiFlow) -> Array {
flow.steps.iter().cloned().map(Dynamic::from).collect::<Array>()
}
// --- FlowStep Functions ---
#[rhai_fn(global)]
pub fn new_flow_step(step_order_i64: i64) -> Dynamic {
match id_from_i64_to_u32(step_order_i64) {
Ok(step_order) => {
let mut flow_step = FlowStep::default();
flow_step.step_order = step_order;
Dynamic::from(flow_step)
},
Err(err) => Dynamic::from(err.to_string())
}
}
/// Sets the flow step description
#[rhai_fn(name = "description", return_raw, global, pure)]
pub fn flow_step_description(step: &mut RhaiFlowStep, description: String) -> Result<RhaiFlowStep, Box<EvalAltResult>> {
let owned_step = mem::replace(step, FlowStep::default()); // Use Default trait
*step = owned_step.description(description);
Ok(step.clone())
}
/// Sets the flow step status
#[rhai_fn(name = "status", return_raw, global, pure)]
pub fn flow_step_status(step: &mut RhaiFlowStep, status: String) -> Result<RhaiFlowStep, Box<EvalAltResult>> {
let owned_step = mem::replace(step, FlowStep::default()); // Use Default trait
*step = owned_step.status(status);
Ok(step.clone())
}
// FlowStep Getters
#[rhai_fn(get = "id", pure)]
pub fn get_step_id(step: &mut RhaiFlowStep) -> i64 { step.base_data.id as i64 }
#[rhai_fn(get = "created_at", pure)]
pub fn get_step_created_at(step: &mut RhaiFlowStep) -> i64 { step.base_data.created_at }
#[rhai_fn(get = "modified_at", pure)]
pub fn get_step_modified_at(step: &mut RhaiFlowStep) -> i64 { step.base_data.modified_at }
#[rhai_fn(get = "description", pure)]
pub fn get_step_description(step: &mut RhaiFlowStep) -> Dynamic {
match &step.description {
Some(desc) => Dynamic::from(desc.clone()),
None => Dynamic::UNIT,
}
}
#[rhai_fn(get = "step_order", pure)]
pub fn get_step_order(step: &mut RhaiFlowStep) -> i64 { step.step_order as i64 }
#[rhai_fn(get = "status", pure)]
pub fn get_step_status(step: &mut RhaiFlowStep) -> String { step.status.clone() }
// --- SignatureRequirement Functions ---
/// Create a new signature requirement
#[rhai_fn(global)]
pub fn new_signature_requirement(flow_step_id_i64: i64, public_key: String, message: String) -> Dynamic {
match id_from_i64_to_u32(flow_step_id_i64) {
Ok(flow_step_id) => {
let mut signature_requirement = SignatureRequirement::default();
signature_requirement.flow_step_id = flow_step_id;
signature_requirement.public_key = public_key;
signature_requirement.message = message;
Dynamic::from(signature_requirement)
},
Err(err) => Dynamic::from(err.to_string())
}
}
/// Sets the signed_by field
#[rhai_fn(name = "signed_by", return_raw, global, pure)]
pub fn signature_requirement_signed_by(sr: &mut RhaiSignatureRequirement, signed_by: String) -> Result<RhaiSignatureRequirement, Box<EvalAltResult>> {
let owned_sr = mem::replace(sr, SignatureRequirement::default()); // Use Default trait
*sr = owned_sr.signed_by(signed_by);
Ok(sr.clone())
}
/// Sets the signature field
#[rhai_fn(name = "signature", return_raw, global, pure)]
pub fn signature_requirement_signature(sr: &mut RhaiSignatureRequirement, signature: String) -> Result<RhaiSignatureRequirement, Box<EvalAltResult>> {
let owned_sr = mem::replace(sr, SignatureRequirement::default()); // Use Default trait
*sr = owned_sr.signature(signature);
Ok(sr.clone())
}
/// Sets the status field
#[rhai_fn(name = "status", return_raw, global, pure)]
pub fn signature_requirement_status(sr: &mut RhaiSignatureRequirement, status: String) -> Result<RhaiSignatureRequirement, Box<EvalAltResult>> {
let owned_sr = mem::replace(sr, SignatureRequirement::default()); // Use Default trait
*sr = owned_sr.status(status);
Ok(sr.clone())
}
// SignatureRequirement Getters
#[rhai_fn(get = "id", pure)]
pub fn get_sr_id(sr: &mut RhaiSignatureRequirement) -> i64 { sr.base_data.id as i64 }
#[rhai_fn(get = "created_at", pure)]
pub fn get_sr_created_at(sr: &mut RhaiSignatureRequirement) -> i64 { sr.base_data.created_at }
#[rhai_fn(get = "modified_at", pure)]
pub fn get_sr_modified_at(sr: &mut RhaiSignatureRequirement) -> i64 { sr.base_data.modified_at }
#[rhai_fn(get = "flow_step_id", pure)]
pub fn get_sr_flow_step_id(sr: &mut RhaiSignatureRequirement) -> i64 { sr.flow_step_id as i64 }
#[rhai_fn(get = "public_key", pure)]
pub fn get_sr_public_key(sr: &mut RhaiSignatureRequirement) -> String { sr.public_key.clone() }
#[rhai_fn(get = "message", pure)]
pub fn get_sr_message(sr: &mut RhaiSignatureRequirement) -> String { sr.message.clone() }
#[rhai_fn(get = "signed_by", pure)]
pub fn get_sr_signed_by(sr: &mut RhaiSignatureRequirement) -> Dynamic {
match &sr.signed_by {
Some(signed_by) => Dynamic::from(signed_by.clone()),
None => Dynamic::UNIT,
}
}
#[rhai_fn(get = "signature", pure)]
pub fn get_sr_signature(sr: &mut RhaiSignatureRequirement) -> Dynamic {
match &sr.signature {
Some(signature) => Dynamic::from(signature.clone()),
None => Dynamic::UNIT,
}
}
#[rhai_fn(get = "status", pure)]
pub fn get_sr_status(sr: &mut RhaiSignatureRequirement) -> String { sr.status.clone() }
}
/// Register the flow module with the Rhai engine
pub fn register_flow_rhai_module(engine: &mut Engine, db: Arc<OurDB>) {
// --- Flow Model ---
// Constructor: new_flow(id: u32, flow_uuid: String)
engine.register_fn("new_flow", move |context: NativeCallContext, id_i64: i64, flow_uuid: String| -> Result<Flow, Box<EvalAltResult>> {
let id_u32 = i64_to_u32(id_i64, context.position(), "id", "new_flow")?;
Ok(Flow::new(id_u32, flow_uuid))
// Create a module for database functions
let mut db_module = Module::new();
// Flow database functions
let db_clone = Arc::clone(&db);
db_module.set_native_fn("save_flow", move |flow: Flow| -> Result<Flow, Box<EvalAltResult>> {
// Use the Collection trait method directly
let result = db_clone.set(&flow)
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("DB Error save_flow: {:?}", e).into(), Position::NONE)))?;
// Return the updated flow with the correct ID
Ok(result.1)
});
// Builder methods for Flow
engine.register_fn("name", |flow: Flow, name_val: String| -> Flow { flow.name(name_val) });
engine.register_fn("status", |flow: Flow, status_val: String| -> Flow { flow.status(status_val) });
engine.register_fn("add_step", |flow: Flow, step: FlowStep| -> Flow { flow.add_step(step) });
// Getters for Flow fields
engine.register_get("id", |flow: &mut Flow| -> Result<i64, Box<EvalAltResult>> { Ok(flow.base_data.id as i64) });
engine.register_get("base_data", |flow: &mut Flow| -> Result<BaseModelData, Box<EvalAltResult>> { Ok(flow.base_data.clone()) });
engine.register_get("flow_uuid", |flow: &mut Flow| -> Result<String, Box<EvalAltResult>> { Ok(flow.flow_uuid.clone()) });
engine.register_get("name", |flow: &mut Flow| -> Result<String, Box<EvalAltResult>> { Ok(flow.name.clone()) });
engine.register_get("status", |flow: &mut Flow| -> Result<String, Box<EvalAltResult>> { Ok(flow.status.clone()) });
engine.register_get("steps", |flow: &mut Flow| -> Result<rhai::Array, Box<EvalAltResult>> {
let rhai_array = flow.steps.iter().cloned().map(Dynamic::from).collect::<rhai::Array>();
Ok(rhai_array)
});
// --- FlowStep Model ---
// Constructor: new_flow_step(id: u32, step_order: u32)
engine.register_fn("new_flow_step", move |context: NativeCallContext, id_i64: i64, step_order_i64: i64| -> Result<FlowStep, Box<EvalAltResult>> {
let id_u32 = i64_to_u32(id_i64, context.position(), "id", "new_flow_step")?;
let step_order_u32 = i64_to_u32(step_order_i64, context.position(), "step_order", "new_flow_step")?;
Ok(FlowStep::new(id_u32, step_order_u32))
});
// Builder methods for FlowStep
engine.register_fn("description", |fs: FlowStep, desc_val: String| -> FlowStep { fs.description(desc_val) }); // Assuming FlowStep::description takes impl ToString
engine.register_fn("status", |fs: FlowStep, status_val: String| -> FlowStep { fs.status(status_val) });
// Getters for FlowStep fields
engine.register_get("id", |step: &mut FlowStep| -> Result<i64, Box<EvalAltResult>> { Ok(step.base_data.id as i64) });
engine.register_get("base_data", |step: &mut FlowStep| -> Result<BaseModelData, Box<EvalAltResult>> { Ok(step.base_data.clone()) });
engine.register_get("description", |step: &mut FlowStep| -> Result<Dynamic, Box<EvalAltResult>> { Ok(match step.description.clone() { Some(s) => Dynamic::from(s), None => Dynamic::from(()) }) });
engine.register_get("step_order", |step: &mut FlowStep| -> Result<i64, Box<EvalAltResult>> { Ok(step.step_order as i64) });
engine.register_get("status", |step: &mut FlowStep| -> Result<String, Box<EvalAltResult>> { Ok(step.status.clone()) });
// --- SignatureRequirement Model ---
// Constructor: new_signature_requirement(id: u32, flow_step_id: u32, public_key: String, message: String)
engine.register_fn("new_signature_requirement",
move |context: NativeCallContext, id_i64: i64, flow_step_id_i64: i64, public_key: String, message: String|
-> Result<SignatureRequirement, Box<EvalAltResult>> {
let id_u32 = i64_to_u32(id_i64, context.position(), "id", "new_signature_requirement")?;
let flow_step_id_u32 = i64_to_u32(flow_step_id_i64, context.position(), "flow_step_id", "new_signature_requirement")?;
Ok(SignatureRequirement::new(id_u32, flow_step_id_u32, public_key, message))
});
// Builder methods for SignatureRequirement
engine.register_fn("signed_by", |sr: SignatureRequirement, signed_by_val: String| -> SignatureRequirement { sr.signed_by(signed_by_val) }); // Assuming SR::signed_by takes impl ToString
engine.register_fn("signature", |sr: SignatureRequirement, sig_val: String| -> SignatureRequirement { sr.signature(sig_val) }); // Assuming SR::signature takes impl ToString
engine.register_fn("status", |sr: SignatureRequirement, status_val: String| -> SignatureRequirement { sr.status(status_val) });
// Getters for SignatureRequirement fields
engine.register_get("id", |sr: &mut SignatureRequirement| -> Result<i64, Box<EvalAltResult>> { Ok(sr.base_data.id as i64) });
engine.register_get("base_data", |sr: &mut SignatureRequirement| -> Result<BaseModelData, Box<EvalAltResult>> { Ok(sr.base_data.clone()) });
engine.register_get("flow_step_id", |sr: &mut SignatureRequirement| -> Result<i64, Box<EvalAltResult>> { Ok(sr.flow_step_id as i64) });
engine.register_get("public_key", |sr: &mut SignatureRequirement| -> Result<String, Box<EvalAltResult>> { Ok(sr.public_key.clone()) });
engine.register_get("message", |sr: &mut SignatureRequirement| -> Result<String, Box<EvalAltResult>> { Ok(sr.message.clone()) });
engine.register_get("signed_by", |sr: &mut SignatureRequirement| -> Result<Dynamic, Box<EvalAltResult>> { Ok(match sr.signed_by.clone() { Some(s) => Dynamic::from(s), None => Dynamic::from(()) }) });
engine.register_get("signature", |sr: &mut SignatureRequirement| -> Result<Dynamic, Box<EvalAltResult>> { Ok(match sr.signature.clone() { Some(s) => Dynamic::from(s), None => Dynamic::from(()) }) });
engine.register_get("status", |sr: &mut SignatureRequirement| -> Result<String, Box<EvalAltResult>> { Ok(sr.status.clone()) });
// --- BaseModelData Getters (if not already globally registered) ---
// Assuming these might be specific to the context or shadowed, explicit registration is safer.
engine.register_get("id", |bmd: &mut BaseModelData| -> Result<i64, Box<EvalAltResult>> { Ok(bmd.id as i64) });
engine.register_get("created_at", |bmd: &mut BaseModelData| -> Result<i64, Box<EvalAltResult>> { Ok(bmd.created_at) });
engine.register_get("modified_at", |bmd: &mut BaseModelData| -> Result<i64, Box<EvalAltResult>> { Ok(bmd.modified_at) });
// engine.register_get("comments", |bmd: &mut BaseModelData| Ok(bmd.comments.clone())); // Rhai might need specific handling for Vec<String>
// --- Database Interaction Functions ---
let captured_db_for_set_flow = Arc::clone(&db);
engine.register_fn("set_flow", move |flow: Flow| -> Result<(), Box<EvalAltResult>> {
captured_db_for_set_flow.set(&flow).map(|_| ()).map_err(|e| {
Box::new(EvalAltResult::ErrorRuntime(format!("Failed to set Flow (ID: {}): {}", flow.base_data.id, e).into(), Position::NONE))
})
});
let captured_db_for_get_flow = Arc::clone(&db);
engine.register_fn("get_flow_by_id", move |context: NativeCallContext, id_i64: i64| -> Result<Flow, Box<EvalAltResult>> {
let id_u32 = i64_to_u32(id_i64, context.position(), "id", "get_flow_by_id")?;
captured_db_for_get_flow.get_by_id(id_u32)
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("Error getting Flow (ID: {}): {}", id_u32, e).into(), Position::NONE)))?
let db_clone = Arc::clone(&db);
db_module.set_native_fn("get_flow_by_id", move |id_i64: INT| -> Result<Flow, Box<EvalAltResult>> {
let id_u32 = id_from_i64_to_u32(id_i64)?;
// Use the Collection trait method directly
db_clone.get_by_id(id_u32)
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("DB Error get_flow_by_id: {:?}", e).into(), Position::NONE)))?
.ok_or_else(|| Box::new(EvalAltResult::ErrorRuntime(format!("Flow with ID {} not found", id_u32).into(), Position::NONE)))
});
// Add get_flows_by_uuid, flow_exists etc. as needed, using wrap_vec_return for Vec results.
// FlowStep DB functions are removed as FlowSteps are now part of Flow.
let captured_db_for_set_sig_req = Arc::clone(&db);
engine.register_fn("set_signature_requirement", move |sr: SignatureRequirement| -> Result<(), Box<EvalAltResult>> {
captured_db_for_set_sig_req.set(&sr).map(|_| ()).map_err(|e| {
Box::new(EvalAltResult::ErrorRuntime(format!("Failed to set SignatureRequirement (ID: {}): {}", sr.base_data.id, e).into(), Position::NONE))
})
let db_clone = Arc::clone(&db);
db_module.set_native_fn("delete_flow", move |id_i64: INT| -> Result<(), Box<EvalAltResult>> {
let id_u32 = id_from_i64_to_u32(id_i64)?;
// Use the Collection trait method directly
let collection = db_clone.collection::<Flow>()
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to get flow collection: {:?}", e).into(),
Position::NONE
)))?;
collection.delete_by_id(id_u32)
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to delete Flow (ID: {}): {:?}", id_u32, e).into(),
Position::NONE
)))
});
let captured_db_for_get_sig_req = Arc::clone(&db);
engine.register_fn("get_signature_requirement_by_id",
move |context: NativeCallContext, id_i64: i64|
-> Result<SignatureRequirement, Box<EvalAltResult>> {
let id_u32 = i64_to_u32(id_i64, context.position(), "id", "get_signature_requirement_by_id")?;
captured_db_for_get_sig_req.get_by_id(id_u32)
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("Error getting SignatureRequirement (ID: {}): {}", id_u32, e).into(), Position::NONE)))?
.ok_or_else(|| Box::new(EvalAltResult::ErrorRuntime(format!("SignatureRequirement with ID {} not found", id_u32).into(), Position::NONE)))
let db_clone = Arc::clone(&db);
db_module.set_native_fn("list_flows", move || -> Result<Dynamic, Box<EvalAltResult>> {
let collection = db_clone.collection::<Flow>()
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to get flow collection: {:?}", e).into(),
Position::NONE
)))?;
let flows = collection.get_all()
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to get all flows: {:?}", e).into(),
Position::NONE
)))?;
let mut array = Array::new();
for flow in flows {
array.push(Dynamic::from(flow));
}
Ok(Dynamic::from(array))
});
// FlowStep database functions
let db_clone = Arc::clone(&db);
db_module.set_native_fn("save_flow_step", move |step: FlowStep| -> Result<FlowStep, Box<EvalAltResult>> {
// Use the Collection trait method directly
let result = db_clone.set(&step)
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("DB Error save_flow_step: {:?}", e).into(), Position::NONE)))?;
// Return the updated flow step with the correct ID
Ok(result.1)
});
let db_clone = Arc::clone(&db);
db_module.set_native_fn("get_flow_step_by_id", move |id_i64: INT| -> Result<FlowStep, Box<EvalAltResult>> {
let id_u32 = id_from_i64_to_u32(id_i64)?;
// Use the Collection trait method directly
db_clone.get_by_id(id_u32)
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("DB Error get_flow_step_by_id: {:?}", e).into(), Position::NONE)))?
.ok_or_else(|| Box::new(EvalAltResult::ErrorRuntime(format!("FlowStep with ID {} not found", id_u32).into(), Position::NONE)))
});
let db_clone = Arc::clone(&db);
db_module.set_native_fn("delete_flow_step", move |id_i64: INT| -> Result<(), Box<EvalAltResult>> {
let id_u32 = id_from_i64_to_u32(id_i64)?;
// Use the Collection trait method directly
let collection = db_clone.collection::<FlowStep>()
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to get flow step collection: {:?}", e).into(),
Position::NONE
)))?;
collection.delete_by_id(id_u32)
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to delete FlowStep (ID: {}): {:?}", id_u32, e).into(),
Position::NONE
)))
});
let db_clone = Arc::clone(&db);
db_module.set_native_fn("list_flow_steps", move || -> Result<Dynamic, Box<EvalAltResult>> {
let collection = db_clone.collection::<FlowStep>()
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to get flow step collection: {:?}", e).into(),
Position::NONE
)))?;
let steps = collection.get_all()
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to get all flow steps: {:?}", e).into(),
Position::NONE
)))?;
let mut array = Array::new();
for step in steps {
array.push(Dynamic::from(step));
}
Ok(Dynamic::from(array))
});
// SignatureRequirement database functions
let db_clone = Arc::clone(&db);
db_module.set_native_fn("save_signature_requirement", move |sr: SignatureRequirement| -> Result<SignatureRequirement, Box<EvalAltResult>> {
// Use the Collection trait method directly
let result = db_clone.set(&sr)
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("DB Error save_signature_requirement: {:?}", e).into(), Position::NONE)))?;
// Return the updated signature requirement with the correct ID
Ok(result.1)
});
let db_clone = Arc::clone(&db);
db_module.set_native_fn("get_signature_requirement_by_id", move |id_i64: INT| -> Result<SignatureRequirement, Box<EvalAltResult>> {
let id_u32 = id_from_i64_to_u32(id_i64)?;
// Use the Collection trait method directly
db_clone.get_by_id(id_u32)
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("DB Error get_signature_requirement_by_id: {:?}", e).into(), Position::NONE)))?
.ok_or_else(|| Box::new(EvalAltResult::ErrorRuntime(format!("SignatureRequirement with ID {} not found", id_u32).into(), Position::NONE)))
});
let db_clone = Arc::clone(&db);
db_module.set_native_fn("delete_signature_requirement", move |id_i64: INT| -> Result<(), Box<EvalAltResult>> {
let id_u32 = id_from_i64_to_u32(id_i64)?;
// Use the Collection trait method directly
let collection = db_clone.collection::<SignatureRequirement>()
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to get signature requirement collection: {:?}", e).into(),
Position::NONE
)))?;
collection.delete_by_id(id_u32)
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to delete SignatureRequirement (ID: {}): {:?}", id_u32, e).into(),
Position::NONE
)))
});
let db_clone = Arc::clone(&db);
db_module.set_native_fn("list_signature_requirements", move || -> Result<Dynamic, Box<EvalAltResult>> {
let collection = db_clone.collection::<SignatureRequirement>()
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to get signature requirement collection: {:?}", e).into(),
Position::NONE
)))?;
let srs = collection.get_all()
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(
format!("Failed to get all signature requirements: {:?}", e).into(),
Position::NONE
)))?;
let mut array = Array::new();
for sr in srs {
array.push(Dynamic::from(sr));
}
Ok(Dynamic::from(array))
});
// Register the database module globally
engine.register_static_module("db", db_module.into());
// Register the flow module using exported_module! macro
let module = exported_module!(rhai_flow_module);
engine.register_global_module(module.into());
println!("Flow Rhai module registered.");
}

View File

@@ -1,9 +1,10 @@
use heromodels_core::BaseModelData;
use heromodels_derive::model;
use serde::{Deserialize, Serialize};
use std::default::Default;
/// Represents a signature requirement for a flow step.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[model]
pub struct SignatureRequirement {
/// Base model data.