busbar_sf_rest/client/composite.rs
1use tracing::instrument;
2
3use busbar_sf_client::security::soql;
4
5use crate::composite::{
6 CompositeBatchRequest, CompositeBatchResponse, CompositeGraphRequest, CompositeGraphResponse,
7 CompositeRequest, CompositeResponse, CompositeTreeRequest, CompositeTreeResponse,
8};
9use crate::error::{Error, ErrorKind, Result};
10
11impl super::SalesforceRestClient {
12 /// Execute a composite request with multiple subrequests.
13 ///
14 /// The composite API allows up to 25 subrequests in a single API call.
15 /// Subrequests can reference results from earlier subrequests using `@{referenceId}`.
16 ///
17 /// Available since API v34.0.
18 #[instrument(skip(self, request))]
19 pub async fn composite(&self, request: &CompositeRequest) -> Result<CompositeResponse> {
20 self.client
21 .rest_post("composite", request)
22 .await
23 .map_err(Into::into)
24 }
25
26 /// Execute a composite batch request with multiple independent subrequests.
27 ///
28 /// The composite batch API executes up to 25 subrequests independently.
29 /// Unlike the standard composite API, subrequests cannot reference each other's results.
30 ///
31 /// Available since API v34.0.
32 #[instrument(skip(self, request))]
33 pub async fn composite_batch(
34 &self,
35 request: &CompositeBatchRequest,
36 ) -> Result<CompositeBatchResponse> {
37 self.client
38 .rest_post("composite/batch", request)
39 .await
40 .map_err(Into::into)
41 }
42
43 /// Execute a composite tree request to create record hierarchies.
44 ///
45 /// Creates parent records with nested child records in a single request.
46 /// Supports up to 200 records total across all levels of the hierarchy.
47 ///
48 /// Available since API v42.0.
49 ///
50 /// # Arguments
51 /// * `sobject` - The parent SObject type (e.g., "Account")
52 /// * `request` - The tree request containing parent records and nested children
53 #[instrument(skip(self, request))]
54 pub async fn composite_tree(
55 &self,
56 sobject: &str,
57 request: &CompositeTreeRequest,
58 ) -> Result<CompositeTreeResponse> {
59 if !soql::is_safe_sobject_name(sobject) {
60 return Err(Error::new(ErrorKind::Salesforce {
61 error_code: "INVALID_SOBJECT".to_string(),
62 message: "Invalid SObject name".to_string(),
63 }));
64 }
65 let path = format!("composite/tree/{}", sobject);
66 self.client
67 .rest_post(&path, request)
68 .await
69 .map_err(Into::into)
70 }
71
72 /// Execute a composite graph request with multiple independent graphs.
73 ///
74 /// Each graph contains a set of composite subrequests that can reference
75 /// each other within the same graph. Different graphs are independent.
76 ///
77 /// Available since API v50.0.
78 #[instrument(skip(self, request))]
79 pub async fn composite_graph(
80 &self,
81 request: &CompositeGraphRequest,
82 ) -> Result<CompositeGraphResponse> {
83 self.client
84 .rest_post("composite/graph", request)
85 .await
86 .map_err(Into::into)
87 }
88}