#![allow(warnings)]
use injectable_rs::*;
#[injectable]
#[derive(Default, Debug)]
pub struct AppConfig;
#[tokio::main]
async fn main() {
println!("=== External Type Injection Example ===\n");
println!("1. Sync DynProvider (no dependencies):");
let container = Container::builder()
.register(
"",
DynProvider::sync(|| {
println!(" Creating reqwest::Client via DynProvider::sync");
Ok(reqwest::Client::new())
}),
)
.build()
.await
.expect("container should build");
let client = container
.resolve_external::<reqwest::Client>()
.await
.expect("should resolve reqwest::Client");
println!(" Resolved reqwest::Client successfully!\n");
println!("2. Async DynProvider with real sqlx::SqlitePool:");
println!(" (Using DATABASE_URL env var if set, otherwise a default)");
let db_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| "sqlite:./test.db".to_string());
let container = Container::builder()
.register(
"",
DynProvider::new(move || {
let url = db_url.clone();
async move {
println!(" Connecting to SqlitePool at {}...", url);
let pool = sqlx::SqlitePool::connect(&url).await.map_err(|e| {
injectable_rs_runtime::InjectableError::ConstructionFailed {
type_name: "SqlitePool",
reason: format!("Failed to connect to SQLite: {e}"),
}
})?;
println!(" SqlitePool connected successfully!");
Ok(pool)
}
}),
)
.build()
.await
.expect("container should build");
match container.resolve_external::<sqlx::SqlitePool>().await {
Ok(pool) => {
println!(" Resolved SqlitePool successfully!");
println!(" Pool size: {}", pool.size());
}
Err(e) => {
println!(" Could not resolve SqlitePool (is the database accessible?): {e}");
println!(" This is expected if no database is available.");
}
}
println!();
println!("3. Context-aware DynProvider (depends on Injectable types):");
let db_url2 = std::env::var("DATABASE_URL").unwrap_or_else(|_| "sqlite:./test.db".to_string());
let container = Container::builder()
.register(
"",
DynProvider::with_ctx(move |ctx| {
let url = db_url2.clone();
async move {
let _config = ctx.extract::<Inject<AppConfig>>().await?;
println!(" Creating SqlitePool using AppConfig from context");
let pool = sqlx::SqlitePool::connect(&url).await.map_err(|e| {
injectable_rs_runtime::InjectableError::ConstructionFailed {
type_name: "SqlitePool",
reason: format!("Failed to connect: {e}"),
}
})?;
Ok(pool)
}
}),
)
.build()
.await
.expect("container should build");
match container.resolve_external::<sqlx::SqlitePool>().await {
Ok(pool) => {
println!(
" Resolved SqlitePool with config: pool size = {}",
pool.size()
);
}
Err(e) => {
println!(" Could not resolve SqlitePool: {e}");
}
}
println!();
println!("4. External type depending on another external type:");
let container = Container::builder()
.register(
"",
DynProvider::sync(|| {
println!(" Creating reqwest::Client");
Ok(reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(30))
.build()
.expect("failed to build reqwest client"))
}),
)
.register(
"",
DynProvider::with_ctx(|ctx| async move {
let _client = ctx.resolve_external::<reqwest::Client>().await?;
println!(" Creating a service that uses the HTTP client");
Ok("service-created".to_string())
}),
)
.build()
.await
.expect("container should build");
let service = container
.resolve_external::<String>()
.await
.expect("should resolve dependent service");
println!(" Resolved dependent service: {service}\n");
println!("5. Mixing Injectable types and external types:");
let container = Container::builder()
.register("", DynProvider::sync(|| Ok(reqwest::Client::new())))
.build()
.await
.expect("container should build");
let config = container
.resolve::<AppConfig>()
.await
.expect("resolve AppConfig");
println!(" Owned type: {config:?}");
let client = container
.resolve_external::<reqwest::Client>()
.await
.expect("resolve HttpClient");
println!(" External type: reqwest::Client resolved successfully");
println!("\n6. Error handling for unregistered types:");
let container = Container::builder()
.build()
.await
.expect("container should build");
let result = container.resolve_external::<reqwest::Client>().await;
match result {
Err(InjectableError::MissingDependency { type_name }) => {
println!(" Expected error: MissingDependency for '{type_name}'");
}
other => panic!("Unexpected result: {other:?}"),
}
println!("\n=== Example Complete ===");
}