use crate::sequence::Sequence;
pub struct FactoryContext {
pub sequences: Sequence,
#[cfg(feature = "postgres")]
pub pool: Option<sqlx::PgPool>,
pub http_client: Option<reqwest::Client>,
pub base_url: Option<String>,
pub test_key: String,
pub overrides: std::collections::HashMap<String, serde_json::Value>,
}
impl FactoryContext {
pub fn http(base_url: &str) -> Self {
Self {
sequences: Sequence::new(),
#[cfg(feature = "postgres")]
pool: None,
http_client: Some(reqwest::Client::new()),
base_url: Some(base_url.to_string()),
test_key: "test-key".to_string(),
overrides: std::collections::HashMap::new(),
}
}
#[cfg(feature = "postgres")]
pub fn database(pool: sqlx::PgPool) -> Self {
Self {
sequences: Sequence::new(),
pool: Some(pool),
http_client: None,
base_url: None,
test_key: "test-key".to_string(),
overrides: std::collections::HashMap::new(),
}
}
pub fn with_test_key(mut self, key: &str) -> Self {
self.test_key = key.to_string();
self
}
pub fn sequence(&mut self, name: &str) -> u64 {
self.sequences.next(name)
}
pub fn email(&mut self, prefix: &str) -> String {
self.sequences.email(prefix)
}
pub fn phone(&mut self) -> String {
self.sequences.phone()
}
pub fn full_name(&mut self) -> String {
self.sequences.full_name()
}
pub fn set_override(&mut self, field: &str, value: serde_json::Value) {
self.overrides.insert(field.to_string(), value);
}
pub fn get_override(&self, field: &str) -> Option<&serde_json::Value> {
self.overrides.get(field)
}
pub fn clear_overrides(&mut self) {
self.overrides.clear();
}
pub fn reset(&mut self) {
self.sequences.reset();
self.overrides.clear();
}
pub async fn health_check(&self) -> crate::Result<bool> {
let client = self
.http_client
.as_ref()
.ok_or_else(|| crate::Error::Build("No HTTP client configured".into()))?;
let base = self
.base_url
.as_ref()
.ok_or_else(|| crate::Error::Build("No base URL configured".into()))?;
let url = format!("{base}/api/v1/health");
let resp = client
.get(&url)
.header("X-Test-Key", &self.test_key)
.send()
.await?;
Ok(resp.status().is_success())
}
pub async fn test_post<T: serde::Serialize>(
&self,
path: &str,
body: &T,
) -> crate::Result<serde_json::Value> {
let client = self
.http_client
.as_ref()
.ok_or_else(|| crate::Error::Build("No HTTP client configured".into()))?;
let base = self
.base_url
.as_ref()
.ok_or_else(|| crate::Error::Build("No base URL configured".into()))?;
let url = format!("{base}/api/v1/test{path}");
let resp = client
.post(&url)
.header("X-Test-Key", &self.test_key)
.header("Content-Type", "application/json")
.json(body)
.send()
.await?;
if !resp.status().is_success() {
let status = resp.status();
let text = resp.text().await.unwrap_or_default();
return Err(crate::Error::Build(format!(
"API error {status}: {text}"
)));
}
let json: serde_json::Value = resp.json().await?;
Ok(json)
}
pub async fn test_delete(&self, path: &str) -> crate::Result<()> {
let client = self
.http_client
.as_ref()
.ok_or_else(|| crate::Error::Build("No HTTP client configured".into()))?;
let base = self
.base_url
.as_ref()
.ok_or_else(|| crate::Error::Build("No base URL configured".into()))?;
let url = format!("{base}/api/v1/test{path}");
let resp = client
.post(&url)
.header("X-Test-Key", &self.test_key)
.header("Content-Type", "application/json")
.json(&serde_json::json!({}))
.send()
.await?;
if !resp.status().is_success() {
let status = resp.status();
let text = resp.text().await.unwrap_or_default();
return Err(crate::Error::Build(format!(
"API error {status}: {text}"
)));
}
Ok(())
}
}