mod common;
use salesforce_core::restapi::{
ClientBuilder, CompositeCollectionCreateRequest, CompositeCollectionRetrieveRequest,
CompositeCollectionUpdateRequest, CompositeRecordRequest, CompositeTreeRequest,
};
use serde_json::json;
type Result<T = ()> = std::result::Result<T, Box<dyn std::error::Error>>;
fn extract_ids(
results: &salesforce_core::restapi::CompositeCollectionCreateResponse,
) -> Vec<String> {
results
.iter()
.filter(|r| r.success)
.filter_map(|r| r.id.clone())
.collect()
}
async fn cleanup(client: &salesforce_core::restapi::Client, ids: &[String]) -> Result {
if ids.is_empty() {
return Ok(());
}
let id_str = ids.join(",");
client.delete_records(&id_str, Some(false)).await?;
Ok(())
}
#[tokio::test]
async fn test_composite_create_and_delete() -> Result {
skip_if_no_credentials!();
let auth = common::auth_client().await?;
let client = ClientBuilder::new(auth).build()?;
let records: Vec<CompositeRecordRequest> = (0..3)
.map(|i| {
serde_json::from_value(json!({
"attributes": {"type": "Account"},
"Name": format!("Composite Test {}", i)
}))
})
.collect::<std::result::Result<_, _>>()?;
let create_request = CompositeCollectionCreateRequest {
all_or_none: true,
records,
};
let results = client.create_records(&create_request).await?;
assert_eq!(results.len(), 3);
let ids = extract_ids(&results);
assert_eq!(ids.len(), 3);
let delete_results = client.delete_records(&ids.join(","), Some(false)).await?;
assert_eq!(delete_results.len(), 3);
for r in delete_results.iter() {
assert!(r.success);
}
Ok(())
}
#[tokio::test]
async fn test_composite_update() -> Result {
skip_if_no_credentials!();
let auth = common::auth_client().await?;
let client = ClientBuilder::new(auth).build()?;
let records: Vec<CompositeRecordRequest> = (0..2)
.map(|i| {
serde_json::from_value(json!({
"attributes": {"type": "Account"},
"Name": format!("Update Test {}", i),
"Industry": "Technology"
}))
})
.collect::<std::result::Result<_, _>>()?;
let create_request = CompositeCollectionCreateRequest {
all_or_none: true,
records,
};
let created = client.create_records(&create_request).await?;
let ids = extract_ids(&created);
assert_eq!(ids.len(), 2);
let id0 = ids.first().ok_or("missing first created record id")?;
let id1 = ids.get(1).ok_or("missing second created record id")?;
let update_request: CompositeCollectionUpdateRequest = serde_json::from_value(json!({
"allOrNone": true,
"records": [
{"attributes": {"type": "Account"}, "id": id0, "Industry": "Finance"},
{"attributes": {"type": "Account"}, "id": id1, "Industry": "Healthcare"}
]
}))?;
let update_results = client.update_records(&update_request).await?;
assert_eq!(update_results.len(), 2);
for r in update_results.iter() {
assert!(r.success);
}
let acc0 = client.get("Account", id0, Some("Industry")).await?;
assert_eq!(
acc0.get("Industry").and_then(|v| v.as_str()),
Some("Finance")
);
let acc1 = client.get("Account", id1, Some("Industry")).await?;
assert_eq!(
acc1.get("Industry").and_then(|v| v.as_str()),
Some("Healthcare")
);
cleanup(&client, &ids).await?;
Ok(())
}
#[tokio::test]
async fn test_composite_retrieve() -> Result {
skip_if_no_credentials!();
let auth = common::auth_client().await?;
let client = ClientBuilder::new(auth).build()?;
let records: Vec<CompositeRecordRequest> = (0..2)
.map(|i| {
serde_json::from_value(json!({
"attributes": {"type": "Account"},
"Name": format!("Retrieve Test {}", i)
}))
})
.collect::<std::result::Result<_, _>>()?;
let create_request = CompositeCollectionCreateRequest {
all_or_none: true,
records,
};
let created = client.create_records(&create_request).await?;
let ids = extract_ids(&created);
let retrieve_request = CompositeCollectionRetrieveRequest {
ids: ids.clone(),
fields: vec!["Id".to_string(), "Name".to_string()],
};
let retrieved = client.get_records("Account", &retrieve_request).await?;
assert_eq!(retrieved.len(), 2);
cleanup(&client, &ids).await?;
Ok(())
}
#[tokio::test]
async fn test_composite_tree_create() -> Result {
skip_if_no_credentials!();
let auth = common::auth_client().await?;
let client = ClientBuilder::new(auth).build()?;
let tree_request: CompositeTreeRequest = serde_json::from_value(json!({
"records": [{
"attributes": {"type": "Account", "referenceId": "ref1"},
"Name": "Tree Test Account",
"Contacts": {
"records": [{
"attributes": {"type": "Contact", "referenceId": "ref2"},
"LastName": "TreeContact"
}]
}
}]
}))?;
let result = client.create_record_tree("Account", &tree_request).await?;
assert!(!result.has_errors);
assert!(result.results.len() >= 2);
let contact_id = result
.results
.iter()
.find(|r| r.reference_id == "ref2")
.map(|r| r.id.clone())
.ok_or("missing contact reference in tree response")?;
let account_id = result
.results
.iter()
.find(|r| r.reference_id == "ref1")
.map(|r| r.id.clone())
.ok_or("missing account reference in tree response")?;
client.delete("Contact", &contact_id).await?;
client.delete("Account", &account_id).await?;
Ok(())
}