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
2.7 KiB
2.7 KiB
OSIRIS Type Registry Design
Problem
We need applications (like ZDFZ API) to register custom types with OSIRIS so that:
- The
save()method can use the correct struct type instead of hardcodingNote - Each collection name maps to a specific Rust type
- 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:
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:
// 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:
- ✅ Create
TypeRegistrywith callback-based savers - ✅ Add
set_registry()toGenericStore - ✅ Update
OsirisContext::save()to use registry if available - ✅ Fall back to
Noteif no registry or collection not registered - Document usage for ZDFZ API
Next Steps:
The type registry infrastructure is in place. Now ZDFZ API can:
- Create a
TypeRegistry - Register all SDK model types
- Pass registry when creating OSIRIS contexts
- Use generic
save()method with proper types!
Status: Design complete, ready for implementation with callback approach.