mod builder;
pub use builder::{AuthenticatedBuilder, ForceClientBuilder, HasAuth, NoAuth};
use crate::config::ClientConfig;
use crate::session::Session;
use std::sync::Arc;
#[derive(Debug)]
pub struct ForceClient<A: crate::auth::authenticator::Authenticator> {
inner: Arc<Session<A>>,
#[cfg(feature = "data_cloud")]
dc_session: Option<Arc<Session<crate::auth::DataCloudAuthenticator<A>>>>,
}
impl<A: crate::auth::authenticator::Authenticator> Clone for ForceClient<A> {
fn clone(&self) -> Self {
Self {
inner: Arc::clone(&self.inner),
#[cfg(feature = "data_cloud")]
dc_session: self.dc_session.clone(),
}
}
}
#[must_use]
pub fn builder() -> ForceClientBuilder<NoAuth> {
ForceClientBuilder::new()
}
macro_rules! handler_accessor {
(
$(#[$meta:meta])*
pub fn $name:ident -> $Handler:ty
) => {
$(#[$meta])*
#[must_use]
pub fn $name(&self) -> $Handler {
<$Handler>::new(Arc::clone(&self.inner))
}
};
}
impl<A: crate::auth::authenticator::Authenticator> ForceClient<A> {
#[must_use]
pub fn config(&self) -> &ClientConfig {
&self.inner.config
}
pub async fn token(&self) -> crate::error::Result<crate::auth::token::AccessToken> {
self.inner.token_manager.token().await
}
#[must_use]
pub fn session(&self) -> Arc<Session<A>> {
Arc::clone(&self.inner)
}
handler_accessor! {
#[cfg(feature = "rest")]
pub fn rest -> crate::api::rest::RestHandler<A>
}
handler_accessor! {
#[cfg(feature = "bulk")]
pub fn bulk -> crate::api::bulk::BulkHandler<A>
}
handler_accessor! {
#[cfg(feature = "tooling")]
pub fn tooling -> crate::api::tooling::ToolingHandler<A>
}
handler_accessor! {
#[cfg(feature = "composite")]
pub fn composite -> crate::api::composite::CompositeHandler<A>
}
handler_accessor! {
#[cfg(feature = "ui")]
pub fn ui -> crate::api::ui::UiHandler<A>
}
handler_accessor! {
#[cfg(feature = "graphql")]
pub fn graphql -> crate::api::graphql::GraphqlHandler<A>
}
handler_accessor! {
#[cfg(feature = "apex_rest")]
pub fn apex_rest -> crate::api::apex_rest::ApexRestHandler<A>
}
handler_accessor! {
#[cfg(feature = "cpq")]
pub fn cpq -> crate::api::cpq::CpqHandler<A>
}
handler_accessor! {
#[cfg(feature = "consent")]
pub fn consent -> crate::api::consent::ConsentHandler<A>
}
#[cfg(feature = "data_cloud")]
pub fn data_cloud(&self) -> crate::error::Result<crate::api::data_cloud::DataCloudHandler<A>> {
let dc = self.dc_session.as_ref().ok_or_else(|| {
crate::error::ForceError::Config(crate::error::ConfigError::MissingValue(
"Data Cloud not configured — call .with_data_cloud() on the builder".into(),
))
})?;
Ok(crate::api::data_cloud::DataCloudHandler::new(Arc::clone(
dc,
)))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_support::MockAuthenticator;
use crate::test_support::Must;
#[test]
fn test_builder_creates_noauth_state() {
let _builder = builder();
}
#[tokio::test]
async fn test_force_client_clone() {
let auth = MockAuthenticator::new("test_token", "https://test.salesforce.com");
let client = builder().authenticate(auth).build().await.must();
let cloned_client = client.clone();
let s1 = client.session();
let s2 = cloned_client.session();
assert!(Arc::ptr_eq(&s1, &s2));
}
}