add zdfz models and macros for auto client generation

This commit is contained in:
Timur Gordon
2025-11-20 08:52:11 +01:00
parent 5d8189a653
commit 9f6032e2e1
4 changed files with 242 additions and 0 deletions

View File

@@ -5,13 +5,19 @@ edition.workspace = true
description = "Osiris client library" description = "Osiris client library"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
[features]
default = []
zdfz = ["dep:zdfz-models"]
[dependencies] [dependencies]
zdfz-models = { path = "../../../../../zdfz/sdk/models", optional = true }
# Core dependencies # Core dependencies
serde.workspace = true serde.workspace = true
serde_json.workspace = true serde_json.workspace = true
anyhow.workspace = true anyhow.workspace = true
thiserror.workspace = true thiserror.workspace = true
chrono.workspace = true chrono.workspace = true
paste = "1.0"
# HTTP client # HTTP client
reqwest = { version = "0.12", default-features = false, features = ["json"] } reqwest = { version = "0.12", default-features = false, features = ["json"] }

View File

@@ -13,10 +13,15 @@ use thiserror::Error;
pub mod kyc; pub mod kyc;
pub mod payment; pub mod payment;
pub mod communication; pub mod communication;
pub mod macros;
#[cfg(feature = "zdfz")]
pub mod zdfz_extensions;
pub use kyc::*; pub use kyc::*;
pub use payment::*; pub use payment::*;
pub use communication::*; pub use communication::*;
pub use macros::*;
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum OsirisClientError { pub enum OsirisClientError {
@@ -34,6 +39,9 @@ pub enum OsirisClientError {
#[error("Command execution failed: {0}")] #[error("Command execution failed: {0}")]
CommandFailed(String), CommandFailed(String),
#[error("Serialization failed: {0}")]
SerializationFailed(String),
} }
/// Osiris client with CQRS support /// Osiris client with CQRS support

View File

@@ -0,0 +1,204 @@
//! Macros for generating CRUD methods on OsirisClient
//!
//! These macros allow you to quickly generate standard CRUD operations
//! and custom methods for your models.
/// Generate CRUD methods for a model on OsirisClient
///
/// This macro generates 5 standard methods:
/// - create_{collection}
/// - get_{collection}
/// - update_{collection}
/// - delete_{collection}
/// - list_{collection}
///
/// # Example
///
/// ```rust
/// use osiris_client::{OsirisClient, impl_osiris_crud};
///
/// #[derive(serde::Serialize, serde::Deserialize)]
/// struct User {
/// id: String,
/// name: String,
/// }
///
/// impl_osiris_crud!(User, "users", "id");
///
/// // Now you can use:
/// // client.create_users(&user).await?;
/// // client.get_users("123").await?;
/// // client.update_users("123", &user).await?;
/// // client.delete_users("123").await?;
/// // client.list_users().await?;
/// ```
#[macro_export]
macro_rules! impl_osiris_crud {
($model:ty, $collection:expr, $id_field:expr) => {
paste::paste! {
impl $crate::OsirisClient {
/// Create a new instance
#[doc = "Create a new " $collection " instance"]
pub async fn [<$collection:snake _create>](&self, model: &$model) -> Result<$model, $crate::OsirisClientError> {
let json = serde_json::to_string(model)
.map_err(|e| $crate::OsirisClientError::SerializationFailed(e.to_string()))?;
// Create Rhai script that uses Osiris context API
// Note: The actual object creation depends on the model type
// For now, we serialize the data and would need model-specific constructors
let script = format!(
r#"
let ctx = get_context(["system"]);
let data = {};
// TODO: Model-specific object creation
// For now, this is a placeholder
data
"#,
json
);
let response = self.execute_script(&script).await?;
// TODO: Parse response from job result
Err($crate::OsirisClientError::CommandFailed("Not yet implemented".to_string()))
}
/// Get an instance by ID
#[doc = "Get a " $collection " instance by ID"]
pub async fn [<$collection:snake _get>](&self, id: &str) -> Result<$model, $crate::OsirisClientError> {
let script = format!(
r#"
let ctx = get_context(["system"]);
ctx.get("{}", "{}")
"#,
$collection, id
);
let response = self.execute_script(&script).await?;
// TODO: Parse response from job result
Err($crate::OsirisClientError::CommandFailed("Not yet implemented".to_string()))
}
/// Update an existing instance
#[doc = "Update an existing " $collection " instance"]
pub async fn [<$collection:snake _update>](&self, id: &str, model: &$model) -> Result<$model, $crate::OsirisClientError> {
let json = serde_json::to_string(model)
.map_err(|e| $crate::OsirisClientError::SerializationFailed(e.to_string()))?;
let script = format!(
r#"
let ctx = get_context(["system"]);
let obj = ctx.get("{}", "{}");
let data = {};
// TODO: Update object fields from data
ctx.save(obj);
obj
"#,
$collection, id, json
);
let response = self.execute_script(&script).await?;
// TODO: Parse response from job result
Err($crate::OsirisClientError::CommandFailed("Not yet implemented".to_string()))
}
/// Delete an instance
#[doc = "Delete a " $collection " instance"]
pub async fn [<$collection:snake _delete>](&self, id: &str) -> Result<(), $crate::OsirisClientError> {
let script = format!(
r#"
let ctx = get_context(["system"]);
ctx.delete("{}", "{}")
"#,
$collection, id
);
self.execute_script(&script).await?;
Ok(())
}
/// List all instances
#[doc = "List all " $collection " instances"]
pub async fn [<$collection:snake _list>](&self) -> Result<Vec<$model>, $crate::OsirisClientError> {
let script = format!(
r#"
let ctx = get_context(["system"]);
ctx.list("{}")
"#,
$collection
);
let response = self.execute_script(&script).await?;
// TODO: Parse response from job result
Err($crate::OsirisClientError::CommandFailed("Not yet implemented".to_string()))
}
}
}
};
}
/// Generate a custom method on a model
///
/// This macro generates a method that calls a custom Rhai function on the model.
///
/// # Example
///
/// ```rust
/// use osiris_client::{OsirisClient, impl_osiris_method};
///
/// #[derive(serde::Serialize, serde::Deserialize)]
/// struct CalendarEvent {
/// id: String,
/// start_time: i64,
/// }
///
/// impl_osiris_method!(CalendarEvent, "calendar_events", reschedule, new_start: i64, new_end: i64);
///
/// // Now you can use:
/// // client.reschedule_calendar_events("123", 1234567890, 1234567900).await?;
/// ```
#[macro_export]
macro_rules! impl_osiris_method {
($model:ty, $collection:expr, $method_name:ident $(, $param:ident: $param_type:ty)*) => {
paste::paste! {
impl $crate::OsirisClient {
#[doc = "Call " $method_name " on a " $collection " instance"]
pub async fn [<$collection:snake _ $method_name>](&self, id: &str $(, $param: $param_type)*) -> Result<$model, $crate::OsirisClientError> {
let params = serde_json::json!({
$(stringify!($param): $param),*
});
let script = format!(
r#"
let ctx = get_context(["system"]);
let obj = ctx.get("{}", "{}");
// TODO: Call custom method on object
// obj.{}({});
ctx.save(obj);
obj
"#,
$collection, id, stringify!($method_name), params
);
let response = self.execute_script(&script).await?;
// TODO: Parse response from job result
Err($crate::OsirisClientError::CommandFailed("Not yet implemented".to_string()))
}
}
}
};
}
#[cfg(test)]
mod tests {
use super::*;
// Example model for testing
#[derive(serde::Serialize, serde::Deserialize)]
struct TestModel {
id: String,
name: String,
}
// This would generate the methods (can't actually test async in doc tests easily)
// impl_osiris_crud!(TestModel, "test_models", "id");
}

View File

@@ -0,0 +1,24 @@
//! ZDFZ model extensions for OsirisClient
//!
//! This module generates CRUD and custom methods for ZDFZ models.
//! It must be in the osiris-client crate to satisfy Rust's orphan rules.
use crate::{impl_osiris_crud, impl_osiris_method};
// Import ZDFZ models - these will be available when zdfz-models is a dependency
#[cfg(feature = "zdfz")]
use zdfz_models::*;
// ========== Core Business Models ==========
// Digital Residents - Individual users of the freezone
#[cfg(feature = "zdfz")]
impl_osiris_crud!(ApiDigitalResident, "digital_residents", "resident_id");
// Free Zone Companies - Companies registered in the freezone
#[cfg(feature = "zdfz")]
impl_osiris_crud!(FreeZoneCompany, "free_zone_companies", "fzc_id");
// Invoices - Financial documents for companies
#[cfg(feature = "zdfz")]
impl_osiris_crud!(FreeZoneInvoice, "invoices", "fz_invoice_id");