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