Refactor Rhai integration with context-based execution and type registry

Major Changes:
- Moved Rhai support from rhai_support/ to rhai/ module
- Implemented context-based execution with signatory access control
- Added TypeRegistry for dynamic type registration and object creation
- Refactored engine to use context (Vec<String>) instead of instance
- Removed old runner binary (moved to runner_rust crate)

Rhai Module:
- engine.rs: Core Rhai engine with context-based get_context()
- functions.rs: Rhai function bindings (create_note, create_event, etc.)
- mod.rs: Module exports and organization

Store Improvements:
- TypeRegistry for registering object types and creators
- Generic store uses type registry for dynamic object creation
- Improved error handling and type safety

Documentation:
- RHAI_REFACTOR_COMPLETE.md: Refactoring details
- SIGNATORY_ACCESS_CONTROL.md: Context-based access control
- TYPE_REGISTRY_DESIGN.md: Type registry architecture
- REFACTORING_COMPLETE.md: Overall refactoring summary
- TESTS_COMPLETE.md: Testing documentation

Build Status:  Compiles successfully with minor warnings
This commit is contained in:
Timur Gordon
2025-10-28 03:33:39 +01:00
parent 097360ad12
commit e04012c8c0
24 changed files with 1810 additions and 249 deletions

93
TYPE_REGISTRY_DESIGN.md Normal file
View File

@@ -0,0 +1,93 @@
# OSIRIS Type Registry Design
## Problem
We need applications (like ZDFZ API) to register custom types with OSIRIS so that:
1. The `save()` method can use the correct struct type instead of hardcoding `Note`
2. Each collection name maps to a specific Rust type
3. The type system properly deserializes, indexes, and stores data
## Challenge
The `Object` trait is not "dyn compatible" (object-safe) because it has:
- Associated functions (`object_type()`, `from_json()`)
- Generic methods
- Serialize/Deserialize bounds
This means we **cannot** use `Box<dyn Object>` for dynamic dispatch.
## Solution: Type Registry with Callbacks
Instead of trying to return `Box<dyn Object>`, we use a callback-based approach:
```rust
pub struct TypeRegistry {
// For each collection, store a function that:
// 1. Takes JSON string
// 2. Deserializes to the correct type
// 3. Stores it using GenericStore
// 4. Returns the ID
savers: HashMap<String, Box<dyn Fn(&GenericStore, &str, &str) -> Result<()>>>,
}
```
### Usage in ZDFZ API:
```rust
// Create registry
let registry = TypeRegistry::new();
// Register Resident type
registry.register_saver("residents", |store, id, json| {
let mut resident: Resident = serde_json::from_str(json)?;
resident.set_id(id);
store.put(&resident).await
});
// Register Company type
registry.register_saver("companies", |store, id, json| {
let mut company: Company = serde_json::from_str(json)?;
company.set_id(id);
store.put(&company).await
});
// Create OSIRIS context with registry
let ctx = OsirisContext::new_with_registry(
"my_context",
"owner_id",
herodb_url,
db_id,
Some(Arc::new(registry))
);
// Now save() uses the registered type!
ctx.save("residents", "id123", resident_json)?;
```
### Benefits:
**Type-safe** - Each collection uses its proper Rust type
**Flexible** - Applications register their own types
**No trait object issues** - Uses closures instead of `Box<dyn Object>`
**Proper indexing** - Each type's `index_keys()` method is called
**Clean API** - Simple registration interface
## Implementation Plan:
1. ✅ Create `TypeRegistry` with callback-based savers
2. ✅ Add `set_registry()` to `GenericStore`
3. ✅ Update `OsirisContext::save()` to use registry if available
4. ✅ Fall back to `Note` if no registry or collection not registered
5. Document usage for ZDFZ API
## Next Steps:
The type registry infrastructure is in place. Now ZDFZ API can:
1. Create a `TypeRegistry`
2. Register all SDK model types
3. Pass registry when creating OSIRIS contexts
4. Use generic `save()` method with proper types!
---
**Status:** Design complete, ready for implementation with callback approach.