final db models wip
This commit is contained in:
151
prompts/new_rhai_rs_gen.md
Normal file
151
prompts/new_rhai_rs_gen.md
Normal file
@@ -0,0 +1,151 @@
|
||||
# AI Prompt: Generate Rhai Module Integration for Rust Models
|
||||
|
||||
## Context
|
||||
You are tasked with creating a Rhai scripting integration for Rust models in the heromodels crate. The integration should follow the builder pattern and provide a comprehensive set of functions for interacting with the models through Rhai scripts.
|
||||
|
||||
## Key Concepts to Understand
|
||||
1. **Builder Pattern vs. Rhai Mutation**: Rust models use builder pattern (methods consume self and return Self), but Rhai requires functions that mutate in place (&mut self).
|
||||
2. **Database Access**: Database functions are exposed as global functions in a 'db' module namespace (e.g., `db::save_flow`, not `db.save_flow`).
|
||||
3. **ID Handling**: New objects should use ID 0 to allow database assignment of real IDs.
|
||||
4. **Function vs. Method Calls**: Rhai scripts must use function calls (e.g., `status(flow, STATUS_DRAFT)`) not method chaining (e.g., `flow.status(STATUS_DRAFT)`).
|
||||
|
||||
## Requirements
|
||||
|
||||
1. **Module Structure and Imports**:
|
||||
- Create a `rhai.rs` file that exports a function named `register_[model]_rhai_module` which takes an Engine and an Arc<OurDB>
|
||||
- **IMPORTANT**: Import `heromodels_core::Model` trait for access to methods like `get_id`
|
||||
- Use the `#[export_module]` macro to define the Rhai module
|
||||
- Register the module globally with the engine using the correct module registration syntax
|
||||
- Create separate database functions that capture the database reference
|
||||
|
||||
2. **Builder Pattern Integration**:
|
||||
- For each model struct marked with `#[model]`, create constructor functions (e.g., `new_[model]`) that accept ID 0 for new objects
|
||||
- For each builder method in the model, create a corresponding Rhai function that:
|
||||
- Takes a mutable reference to the model as first parameter
|
||||
- Uses `std::mem::take` to get ownership (if the model implements Default) or `std::mem::replace` (if it doesn't)
|
||||
- Calls the builder method on the owned object
|
||||
- Assigns the result back to the mutable reference
|
||||
- Returns a clone of the modified object
|
||||
|
||||
3. **Field Access**:
|
||||
- **IMPORTANT**: Do NOT create getter methods for fields that can be accessed directly
|
||||
- Use direct field access in example code (e.g., `flow.name`, not `flow.get_name()`)
|
||||
- Only create getter functions for computed properties or when special conversion is needed
|
||||
- Handle special types appropriately (e.g., convert timestamps, IDs, etc.)
|
||||
|
||||
4. **Database Functions**:
|
||||
- For each model, implement the following database functions in the `db` module namespace:
|
||||
- `db::save_[model]`: Save the model to the database and return the saved model with assigned ID
|
||||
- `db::get_[model]_by_id`: Retrieve a model by ID
|
||||
- `db::delete_[model]`: Delete a model from the database
|
||||
- `db::list_[model]s`: List all models of this type
|
||||
- **IMPORTANT**: Use `db::function_name` syntax in scripts, not `db.function_name`
|
||||
- Handle errors properly with detailed error messages using debug format `{:?}` for error objects
|
||||
- Convert between Rhai's i64 and Rust's u32/u64 types for IDs and timestamps
|
||||
- Return saved objects from save functions to ensure proper ID handling
|
||||
|
||||
5. **Error Handling**:
|
||||
- Use `Box<EvalAltResult>` for error returns
|
||||
- Provide detailed error messages with proper position information
|
||||
- **IMPORTANT**: Use `context.call_position()` not the deprecated `context.position()`
|
||||
- Handle type conversions safely
|
||||
- Format error messages with debug format for error objects: `format!("Error: {:?}", err)`
|
||||
|
||||
6. **Type Conversions**:
|
||||
- Create helper functions for converting between Rhai and Rust types
|
||||
- Handle special cases like enums with string representations
|
||||
|
||||
## Implementation Pattern
|
||||
|
||||
```rust
|
||||
// Helper functions for type conversion
|
||||
fn i64_to_u32(val: i64, position: Position, param_name: &str, function_name: &str) -> Result<u32, Box<EvalAltResult>> {
|
||||
u32::try_from(val).map_err(|_| {
|
||||
Box::new(EvalAltResult::ErrorArithmetic(
|
||||
format!("{} must be a positive integer less than 2^32 in {}", param_name, function_name).into(),
|
||||
position
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
// Model constructor
|
||||
#[rhai_fn(name = "new_[model]")]
|
||||
pub fn new_model() -> Model {
|
||||
Model::new()
|
||||
}
|
||||
|
||||
// Builder method integration
|
||||
#[rhai_fn(name = "[method_name]", return_raw, global, pure)]
|
||||
pub fn model_method(model: &mut Model, param: Type) -> Result<Model, Box<EvalAltResult>> {
|
||||
let owned_model = std::mem::take(model); // or replace if Default not implemented
|
||||
*model = owned_model.method_name(param);
|
||||
Ok(model.clone())
|
||||
}
|
||||
|
||||
// Getter method
|
||||
#[rhai_fn(name = "[field]", global)]
|
||||
pub fn get_model_field(model: &mut Model) -> Type {
|
||||
model.field.clone()
|
||||
}
|
||||
|
||||
// Database function
|
||||
db_module.set_native_fn("save_[model]", move |model: Model| -> Result<Model, Box<EvalAltResult>> {
|
||||
db_clone.set(&model)
|
||||
.map_err(|e| Box::new(EvalAltResult::ErrorRuntime(format!("DB Error: {}", e).into(), Position::NONE)))
|
||||
.map(|(_, model)| model)
|
||||
});
|
||||
```
|
||||
|
||||
## Important Notes
|
||||
|
||||
1. All models must follow the builder pattern where methods take ownership of `self` and return `Self`
|
||||
2. If a model doesn't implement `Default`, use `std::mem::replace` instead of `std::mem::take`
|
||||
3. Ensure proper error handling for all operations
|
||||
4. Register all functions with appropriate Rhai names
|
||||
5. Follow the naming conventions established in existing modules
|
||||
6. Ensure all database operations are properly wrapped with error handling
|
||||
7. **CRITICAL**: When creating example scripts, use function calls not method chaining
|
||||
8. **CRITICAL**: Always use ID 0 for new objects in scripts to allow database assignment
|
||||
9. **CRITICAL**: After saving objects, use the returned objects with assigned IDs for further operations
|
||||
10. **CRITICAL**: In Rust examples, include the Model trait import and use direct field access
|
||||
|
||||
## Example Rhai Script
|
||||
|
||||
```rhai
|
||||
// Create a new flow with ID 0 (database will assign real ID)
|
||||
let flow = new_flow(0, "12345678-1234-1234-1234-123456789012");
|
||||
name(flow, "Document Approval Flow");
|
||||
status(flow, STATUS_DRAFT);
|
||||
|
||||
// Save flow to database and get saved object with assigned ID
|
||||
let saved_flow = db::save_flow(flow);
|
||||
print(`Flow saved to database with ID: ${get_flow_id(saved_flow)}`);
|
||||
|
||||
// Retrieve flow from database using assigned ID
|
||||
let retrieved_flow = db::get_flow_by_id(get_flow_id(saved_flow));
|
||||
```
|
||||
|
||||
## Example Rust Code
|
||||
|
||||
```rust
|
||||
use heromodels_core::Model; // Import Model trait for get_id()
|
||||
|
||||
// Create flow using Rhai
|
||||
let flow: Flow = engine.eval("new_flow(0, \"12345678-1234-1234-1234-123456789012\")").unwrap();
|
||||
|
||||
// Access fields directly
|
||||
println!("Flow name: {}", flow.name);
|
||||
|
||||
// Save to database using Rhai function
|
||||
let save_script = "fn save_it(f) { return db::save_flow(f); }";
|
||||
let save_ast = engine.compile(save_script).unwrap();
|
||||
let saved_flow: Flow = engine.call_fn(&mut scope, &save_ast, "save_it", (flow,)).unwrap();
|
||||
println!("Saved flow ID: {}", saved_flow.get_id());
|
||||
```
|
||||
|
||||
## Reference Implementations
|
||||
See the existing implementations for examples:
|
||||
1. `heromodels/src/models/calendar/rhai.rs` - Calendar module Rhai bindings
|
||||
2. `heromodels/src/models/flow/rhai.rs` - Flow module Rhai bindings
|
||||
3. `heromodels_rhai/examples/flow/flow_script.rhai` - Example Rhai script
|
||||
4. `heromodels_rhai/examples/flow/example.rs` - Example Rust code
|
Reference in New Issue
Block a user