1use busbar_sf_client::{ClientConfig, SalesforceClient};
8
9use crate::error::Result;
10
11mod binary;
12mod collections;
13mod composite;
14mod consent;
15mod crud;
16mod describe;
17mod embedded_service;
18mod invocable_actions;
19mod knowledge;
20mod layout;
21mod limits;
22mod list_views;
23mod process;
24mod query;
25mod quick_actions;
26mod scheduler;
27mod search;
28mod standalone;
29mod sync;
30mod user_password;
31
32#[derive(Debug, Clone)]
65pub struct SalesforceRestClient {
66 client: SalesforceClient,
67}
68
69impl SalesforceRestClient {
70 pub fn new(instance_url: impl Into<String>, access_token: impl Into<String>) -> Result<Self> {
72 let client = SalesforceClient::new(instance_url, access_token)?;
73 Ok(Self { client })
74 }
75
76 pub fn with_config(
78 instance_url: impl Into<String>,
79 access_token: impl Into<String>,
80 config: ClientConfig,
81 ) -> Result<Self> {
82 let client = SalesforceClient::with_config(instance_url, access_token, config)?;
83 Ok(Self { client })
84 }
85
86 pub fn from_client(client: SalesforceClient) -> Self {
88 Self { client }
89 }
90
91 pub fn inner(&self) -> &SalesforceClient {
93 &self.client
94 }
95
96 pub fn instance_url(&self) -> &str {
98 self.client.instance_url()
99 }
100
101 pub fn api_version(&self) -> &str {
103 self.client.api_version()
104 }
105
106 pub fn with_api_version(mut self, version: impl Into<String>) -> Self {
108 self.client = self.client.with_api_version(version);
109 self
110 }
111}
112
113#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
115pub struct SearchResult<T> {
116 #[serde(rename = "searchRecords")]
117 pub search_records: Vec<T>,
118}
119
120#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
122pub struct ApiVersion {
123 pub version: String,
124 pub label: String,
125 pub url: String,
126}
127
128#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
130pub struct GetDeletedResult {
131 #[serde(rename = "deletedRecords")]
132 pub deleted_records: Vec<DeletedRecord>,
133 #[serde(rename = "earliestDateAvailable")]
134 pub earliest_date_available: String,
135 #[serde(rename = "latestDateCovered")]
136 pub latest_date_covered: String,
137}
138
139#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
141pub struct DeletedRecord {
142 pub id: String,
143 #[serde(rename = "deletedDate")]
144 pub deleted_date: String,
145}
146
147#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
149pub struct GetUpdatedResult {
150 pub ids: Vec<String>,
151 #[serde(rename = "latestDateCovered")]
152 pub latest_date_covered: String,
153}
154
155#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
157pub struct SObjectInfo {
158 #[serde(rename = "objectDescribe")]
159 pub object_describe: SObjectInfoDescribe,
160 #[serde(rename = "recentItems")]
161 pub recent_items: Vec<serde_json::Value>,
162}
163
164#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
166pub struct SObjectInfoDescribe {
167 pub name: String,
168 pub label: String,
169 #[serde(rename = "keyPrefix")]
170 pub key_prefix: Option<String>,
171 pub urls: std::collections::HashMap<String, String>,
172 pub custom: bool,
173 pub createable: bool,
174 pub updateable: bool,
175 pub deletable: bool,
176 pub queryable: bool,
177 pub searchable: bool,
178}
179
180#[cfg(test)]
181mod tests {
182 use super::*;
183
184 #[test]
185 fn test_client_creation() {
186 let client = SalesforceRestClient::new("https://na1.salesforce.com", "token123").unwrap();
187
188 assert_eq!(client.instance_url(), "https://na1.salesforce.com");
189 assert_eq!(client.api_version(), "62.0");
190 }
191
192 #[test]
193 fn test_api_version_override() {
194 let client = SalesforceRestClient::new("https://na1.salesforce.com", "token")
195 .unwrap()
196 .with_api_version("60.0");
197
198 assert_eq!(client.api_version(), "60.0");
199 }
200
201 #[test]
202 fn test_get_deleted_result_deserialize() {
203 let json = serde_json::json!({
204 "deletedRecords": [
205 {"id": "001xx000003DgAAAS", "deletedDate": "2024-01-15T10:30:00.000Z"}
206 ],
207 "earliestDateAvailable": "2024-01-01T00:00:00.000Z",
208 "latestDateCovered": "2024-01-15T23:59:59.000Z"
209 });
210 let result: GetDeletedResult = serde_json::from_value(json).unwrap();
211 assert_eq!(result.deleted_records.len(), 1);
212 assert_eq!(result.deleted_records[0].id, "001xx000003DgAAAS");
213 assert_eq!(result.earliest_date_available, "2024-01-01T00:00:00.000Z");
214 }
215
216 #[test]
217 fn test_get_updated_result_deserialize() {
218 let json = serde_json::json!({
219 "ids": ["001xx000003DgAAAS", "001xx000003DgBBAS"],
220 "latestDateCovered": "2024-01-15T23:59:59.000Z"
221 });
222 let result: GetUpdatedResult = serde_json::from_value(json).unwrap();
223 assert_eq!(result.ids.len(), 2);
224 assert_eq!(result.latest_date_covered, "2024-01-15T23:59:59.000Z");
225 }
226
227 #[test]
228 fn test_sobject_info_deserialize() {
229 let json = serde_json::json!({
230 "objectDescribe": {
231 "name": "Account",
232 "label": "Account",
233 "keyPrefix": "001",
234 "urls": {
235 "sobject": "/services/data/v62.0/sobjects/Account",
236 "describe": "/services/data/v62.0/sobjects/Account/describe"
237 },
238 "custom": false,
239 "createable": true,
240 "updateable": true,
241 "deletable": true,
242 "queryable": true,
243 "searchable": true
244 },
245 "recentItems": [
246 {"Id": "001xx000003DgAAAS", "Name": "Acme Corp"}
247 ]
248 });
249 let info: SObjectInfo = serde_json::from_value(json).unwrap();
250 assert_eq!(info.object_describe.name, "Account");
251 assert_eq!(info.object_describe.key_prefix, Some("001".to_string()));
252 assert!(!info.object_describe.custom);
253 assert!(info.object_describe.createable);
254 assert_eq!(info.recent_items.len(), 1);
255 }
256
257 #[test]
258 fn test_sobject_info_describe_custom() {
259 let json = serde_json::json!({
260 "objectDescribe": {
261 "name": "MyObject__c",
262 "label": "My Object",
263 "keyPrefix": "a00",
264 "urls": {},
265 "custom": true,
266 "createable": true,
267 "updateable": true,
268 "deletable": true,
269 "queryable": true,
270 "searchable": false
271 },
272 "recentItems": []
273 });
274 let info: SObjectInfo = serde_json::from_value(json).unwrap();
275 assert!(info.object_describe.custom);
276 assert!(!info.object_describe.searchable);
277 assert!(info.recent_items.is_empty());
278 }
279}