pub struct Client<A: Authenticate> {
pub url: &'static str,
/* private fields */
}Expand description
A client capable of connecting to a dataverse environment
A client should be created once and then reused to take advantage of its connection-pooling.
Examples
let client_id = String::from("<clientid>");
let client_secret = String::from("<clientsecret>");
let client = Client::with_client_secret_auth(
"https://instance.crm.dynamics.com/",
"12345678-1234-1234-1234-123456789012",
client_id,
client_secret,
);Fields
url: &'static strImplementations
sourceimpl Client<ClientSecretAuth>
impl Client<ClientSecretAuth>
sourcepub fn with_client_secret_auth(
url: &'static str,
tenant_id: &'static str,
client_id: String,
client_secret: String
) -> Self
pub fn with_client_secret_auth(
url: &'static str,
tenant_id: &'static str,
client_id: String,
client_secret: String
) -> Self
Creates a dataverse client that uses client/secret authentication
Please note that this function will not fail right away even when the provided credentials are invalid. This is because the authentication is handled lazily and a token is only acquired on the first call or when an acquired token is no longer valid and needs to be refreshed
Examples
let client_id = String::from("<clientid>");
let client_secret = String::from("<clientsecret>");
let client = Client::with_client_secret_auth(
"https://instance.crm.dynamics.com/",
"12345678-1234-1234-1234-123456789012",
client_id,
client_secret,
);sourceimpl<A: Authenticate> Client<A>
impl<A: Authenticate> Client<A>
sourcepub fn new(url: &'static str, backend: Client, auth: A) -> Self
pub fn new(url: &'static str, backend: Client, auth: A) -> Self
Creates a dataverse client with a custom authentication handler and backend
This function may not panic so the custom authentication should follow these rules:
- tokens should be acquired lazily
- tokens should be cached and reused where possible
- each call to the
get_valid_token()function should give a token that is valid for at least the next 2 minutes
Examples
let client = reqwest::Client::builder()
.https_only(true)
.connect_timeout(Duration::from_secs(120))
.timeout(Duration::from_secs(120))
.build()
.unwrap();
let auth = ClientSecretAuth::new(
client.clone(),
format!(
"https://login.microsoftonline.com/{}/oauth2/v2.0/token",
tenant_id
),
format!("{}.default", url),
client_id,
client_secret,
);
Client::new(url, client, auth)sourcepub async fn create(&self, entity: &impl WriteEntity) -> Result<Uuid>
pub async fn create(&self, entity: &impl WriteEntity) -> Result<Uuid>
Writes the given entity into the current dataverse instance and returns its generated Uuid
This may fail for any of these reasons
- An authentication failure
- A serde serialization error
- Any http client or server error
- there is already a record with this Uuid in the table
Examples
let contact = Contact {
contactid: Uuid::parse_str("12345678-1234-1234-1234-123456789012").unwrap(),
firstname: String::from("Testy"),
lastname: String::from("McTestface"),
};
client.create(&contact).await.unwrap();
#[derive(Serialize)]
struct Contact {
contactid: Uuid,
firstname: String,
lastname: String,
}
impl WriteEntity for Contact {}
impl Reference for Contact {
fn get_reference(&self) -> ReferenceStruct {
ReferenceStruct::new(
"contacts",
self.contactid,
)
}
}sourcepub async fn update(&self, entity: &impl WriteEntity) -> Result<()>
pub async fn update(&self, entity: &impl WriteEntity) -> Result<()>
Updates the attributes of the gven entity in the current dataverse instance
Please note that only those attributes are updated that are present in the serialization payload. Other attributes are untouched
This may fail for any of these reasons
- An authentication failure
- A serde serialization error
- Any http client or server error
- there is no record with this Uuid in the table
Examples
let contact = Contact {
contactid: Uuid::parse_str("12345678-1234-1234-1234-123456789012").unwrap(),
firstname: String::from("Testy"),
lastname: String::from("McTestface"),
};
client.update(&contact).await.unwrap();
#[derive(Serialize)]
struct Contact {
contactid: Uuid,
firstname: String,
lastname: String,
}
impl WriteEntity for Contact {}
impl Reference for Contact {
fn get_reference(&self) -> ReferenceStruct {
ReferenceStruct::new(
"contacts",
self.contactid,
)
}
}
sourcepub async fn upsert(&self, entity: &impl WriteEntity) -> Result<()>
pub async fn upsert(&self, entity: &impl WriteEntity) -> Result<()>
Updates or creates the given entity in the current dataverse instance
Please note that only those attributes are updated that are present in the serialization payload. Other attributes are untouched
This may fail for any of these reasons
- An authentication failure
- A serde serialization error
- Any http client or server error
Examples
let contact = Contact {
contactid: Uuid::parse_str("12345678-1234-1234-1234-123456789012").unwrap(),
firstname: String::from("Testy"),
lastname: String::from("McTestface"),
};
client.upsert(&contact).await.unwrap();
#[derive(Serialize)]
struct Contact {
contactid: Uuid,
firstname: String,
lastname: String,
}
impl WriteEntity for Contact {}
impl Reference for Contact {
fn get_reference(&self) -> ReferenceStruct {
ReferenceStruct::new(
"contacts",
self.contactid,
)
}
}
sourcepub async fn delete(&self, reference: &impl Reference) -> Result<()>
pub async fn delete(&self, reference: &impl Reference) -> Result<()>
Deletes the entity record this reference points to
Please note that each structs that implements WriteEntity also implements
Reference so you can use it as input here, but there is a sensible default implementation
called ReferenceStruct for those cases where you only have access to the raw
reference data
This may fail for any of these reasons
- An authentication failure
- Any http client or server error
- The referenced entity record doesn’t exist
Examples
let reference = ReferenceStruct::new(
"contacts",
Uuid::parse_str("12345678-1234-1234-1234-123456789012").unwrap()
);
client.delete(&reference).unwrap();sourcepub async fn retrieve<E: ReadEntity>(
&self,
reference: &impl Reference
) -> Result<E>
pub async fn retrieve<E: ReadEntity>(
&self,
reference: &impl Reference
) -> Result<E>
retrieves the entity record that the reference points to from dataverse
This function uses the implementation of the Select trait to only retrieve
those attributes relevant to the struct defined. It is an Anti-Pattern to
retrieve all attributes when they are not needed, so this library does not
give the option to do that
This may fail for any of these reasons
- An authentication failure
- A serde deserialization error
- Any http client or server error
- The entity record referenced doesn’t exist
Examples
let contact: Contact = client
.retrieve(
&ReferenceStruct::new(
"contacts",
Uuid::parse_str("12345678-1234-1234-1234-123456789012").unwrap()
)
)
.await
.unwrap();
#[derive(Deserialize)]
struct Contact {
contactid: Uuid,
firstname: String,
lastname: String,
}
impl ReadEntity for Contact {}
impl Select for Contact {
fn get_columns() -> &'static [&'static str] {
&["contactid", "firstname", "lastname"]
}
}sourcepub async fn retrieve_multiple<E: ReadEntity>(
&self,
query: &Query
) -> Result<Vec<E>>
pub async fn retrieve_multiple<E: ReadEntity>(
&self,
query: &Query
) -> Result<Vec<E>>
Executes the query and retrieves the entities from dataverse
This function uses the implementation of the Select trait to only retrieve
those attributes relevant to the struct defined. It is an Anti-Pattern to
retrieve all attributes when they are not needed, so this library does not
give the option to do that
Please note that if you don’t specify a limit then the client will try to retrieve all matching records. This can take a lot of time.
This may fail for any of these reasons
- An authentication failure
- A serde deserialization error
- Any http client or server error
Examples
// this query retrieves the first 3 contacts
let query = Query::new("contacts").limit(3);
let contacts = client.retrieve_multiple(&query).unwrap();
#[derive(Deserialize)]
struct Contact {
contactid: Uuid,
firstname: String,
lastname: String,
}
impl ReadEntity for Contact {}
impl Select for Contact {
fn get_columns() -> &'static [&'static str] {
&["contactid", "firstname", "lastname"]
}
}sourcepub async fn execute(&self, batch: &Batch) -> Result<()>
pub async fn execute(&self, batch: &Batch) -> Result<()>
executes the batch against the dataverse environment
This function will fail if:
- the batch size exceeds 1000 calls
- the batch execution time exceeds 2 minutes
the second restriction is especially tricky to handle because the execution time depends on the complexity of the entity in dataverse. So it is possible to create 300 records of an entity with low complexity but only 50 records of an entity with high complexity in that timeframe.
Based on experience a batch size of 50 should be safe for all entities though
Examples
let testy_contact = Contact {
contactid: Uuid::parse_str("12345678-1234-1234-1234-123456789012").unwrap(),
firstname: String::from("Testy"),
lastname: String::from("McTestface"),
};
let marianne_contact = Contact {
contactid: Uuid::parse_str("12345678-1234-1234-1234-123456789abc").unwrap(),
firstname: String::from("Marianne"),
lastname: String::from("McTestface"),
};
// this batch creates both contacts in one call
let mut batch = Batch::new("https://instance.crm.dynamics.com/");
batch.create(&testy_contact).unwrap();
batch.create(&marianne_contact).unwrap();
client.execute(&batch).unwrap();
#[derive(Serialize)]
struct Contact {
contactid: Uuid,
firstname: String,
lastname: String,
}
impl WriteEntity for Contact {}
impl Reference for Contact {
fn get_reference(&self) -> ReferenceStruct {
ReferenceStruct::new(
"contacts",
self.contactid,
)
}
}Auto Trait Implementations
impl<A> !RefUnwindSafe for Client<A>
impl<A> Send for Client<A> where
A: Send,
impl<A> Sync for Client<A> where
A: Sync,
impl<A> Unpin for Client<A> where
A: Unpin,
impl<A> !UnwindSafe for Client<A>
Blanket Implementations
sourceimpl<T> BorrowMut<T> for T where
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
const: unstable · sourcefn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
sourceimpl<T> Instrument for T
impl<T> Instrument for T
sourcefn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
sourcefn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
impl<V, T> VZip<V> for T where
V: MultiLane<T>,
impl<V, T> VZip<V> for T where
V: MultiLane<T>,
fn vzip(self) -> V
sourceimpl<T> WithSubscriber for T
impl<T> WithSubscriber for T
sourcefn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> where
S: Into<Dispatch>,
fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> where
S: Into<Dispatch>,
Attaches the provided Subscriber to this type, returning a
WithDispatch wrapper. Read more
sourcefn with_current_subscriber(self) -> WithDispatch<Self>
fn with_current_subscriber(self) -> WithDispatch<Self>
Attaches the current default Subscriber to this type, returning a
WithDispatch wrapper. Read more