Skip to content

Commit

Permalink
rebase and store copies of commonly-used feed links on clients
Browse files Browse the repository at this point in the history
  • Loading branch information
analogrelay authored Oct 24, 2024
1 parent 46e6184 commit e0dec46
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 88 deletions.
68 changes: 34 additions & 34 deletions sdk/cosmos/azure_data_cosmos/src/clients/container_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,30 @@ use crate::{

use azure_core::{Context, Method, Pager, Request, Response};
use serde::{de::DeserializeOwned, Serialize};
use url::Url;

/// A client for working with a specific container in a Cosmos DB account.
///
/// You can get a `Container` by calling [`DatabaseClient::container_client()`](crate::clients::DatabaseClient::container_client()).
pub struct ContainerClient {
container_url: Url,
link: ResourceLink,
items_link: ResourceLink,
pipeline: CosmosPipeline,
}

impl ContainerClient {
pub(crate) fn new(pipeline: CosmosPipeline, database_url: &Url, container_name: &str) -> Self {
let container_url = database_url.with_path_segments(["colls", container_name]);
pub(crate) fn new(
pipeline: CosmosPipeline,
database_link: &ResourceLink,
container_id: &str,
) -> Self {
let link = database_link
.feed(ResourceType::Containers)
.item(container_id);
let items_link = link.feed(ResourceType::Items);

Self {
container_url,
link,
items_link,
pipeline,
}
}
Expand Down Expand Up @@ -57,9 +65,10 @@ impl ContainerClient {
// REASON: This is a documented public API so prefixing with '_' is undesirable.
options: Option<ReadContainerOptions>,
) -> azure_core::Result<Response<ContainerProperties>> {
let mut req = Request::new(self.container_url.clone(), Method::Get);
let url = self.pipeline.url(&self.link);
let mut req = Request::new(url, Method::Get);
self.pipeline
.send(Context::new(), &mut req, ResourceType::Containers)
.send(Context::new(), &mut req, self.link.clone())
.await
}

Expand All @@ -75,9 +84,10 @@ impl ContainerClient {
// REASON: This is a documented public API so prefixing with '_' is undesirable.
options: Option<DeleteContainerOptions>,
) -> azure_core::Result<Response> {
let mut req = Request::new(self.container_url.clone(), Method::Delete);
let url = self.pipeline.url(&self.link);
let mut req = Request::new(url, Method::Delete);
self.pipeline
.send(Context::new(), &mut req, ResourceType::Containers)
.send(Context::new(), &mut req, self.link.clone())
.await
}

Expand Down Expand Up @@ -125,12 +135,12 @@ impl ContainerClient {
// REASON: This is a documented public API so prefixing with '_' is undesirable.
options: Option<ItemOptions>,
) -> azure_core::Result<Response<Item<T>>> {
let url = self.container_url.with_path_segments(["docs"]);
let url = self.pipeline.url(&self.items_link);
let mut req = Request::new(url, Method::Post);
req.insert_headers(&partition_key.into())?;
req.set_json(&item)?;
self.pipeline
.send(Context::new(), &mut req, ResourceType::Items)
.send(Context::new(), &mut req, self.items_link.clone())
.await
}

Expand Down Expand Up @@ -180,15 +190,12 @@ impl ContainerClient {
// REASON: This is a documented public API so prefixing with '_' is undesirable.
options: Option<ItemOptions>,
) -> azure_core::Result<Response<Item<T>>> {
let url = self
.container_url
.with_path_segments(["docs", item_id.as_ref()]);
let link = self.items_link.item(item_id);
let url = self.pipeline.url(&link);
let mut req = Request::new(url, Method::Put);
req.insert_headers(&partition_key.into())?;
req.set_json(&item)?;
self.pipeline
.send(Context::new(), &mut req, ResourceType::Items)
.await
self.pipeline.send(Context::new(), &mut req, link).await
}

/// Creates or replaces an item in the container.
Expand Down Expand Up @@ -238,13 +245,13 @@ impl ContainerClient {
// REASON: This is a documented public API so prefixing with '_' is undesirable.
options: Option<ItemOptions>,
) -> azure_core::Result<Response<Item<T>>> {
let url = self.container_url.with_path_segments(["docs"]);
let url = self.pipeline.url(&self.items_link);
let mut req = Request::new(url, Method::Post);
req.insert_header(constants::IS_UPSERT, "true");
req.insert_headers(&partition_key.into())?;
req.set_json(&item)?;
self.pipeline
.send(Context::new(), &mut req, ResourceType::Items)
.send(Context::new(), &mut req, self.items_link.clone())
.await
}

Expand Down Expand Up @@ -287,14 +294,11 @@ impl ContainerClient {
// REASON: This is a documented public API so prefixing with '_' is undesirable.
options: Option<ItemOptions>,
) -> azure_core::Result<Response<Item<T>>> {
let url = self
.container_url
.with_path_segments(["docs", item_id.as_ref()]);
let link = self.items_link.item(item_id);
let url = self.pipeline.url(&link);
let mut req = Request::new(url, Method::Get);
req.insert_headers(&partition_key.into())?;
self.pipeline
.send(Context::new(), &mut req, ResourceType::Items)
.await
self.pipeline.send(Context::new(), &mut req, link).await
}

/// Deletes an item from the container.
Expand Down Expand Up @@ -325,14 +329,11 @@ impl ContainerClient {
// REASON: This is a documented public API so prefixing with '_' is undesirable.
options: Option<ItemOptions>,
) -> azure_core::Result<Response> {
let url = self
.container_url
.with_path_segments(["docs", item_id.as_ref()]);
let link = self.items_link.item(item_id);
let url = self.pipeline.url(&link);
let mut req = Request::new(url, Method::Delete);
req.insert_headers(&partition_key.into())?;
self.pipeline
.send(Context::new(), &mut req, ResourceType::Items)
.await
self.pipeline.send(Context::new(), &mut req, link).await
}

/// Executes a single-partition query against items in the container.
Expand Down Expand Up @@ -398,13 +399,12 @@ impl ContainerClient {
// REASON: This is a documented public API so prefixing with '_' is undesirable.
options: Option<QueryOptions>,
) -> azure_core::Result<Pager<QueryResults<T>>> {
let link = self.link.feed(ResourceType::Items);
let url = link.url(&self.endpoint);
let url = self.pipeline.url(&self.items_link);
let mut base_request = Request::new(url, Method::Post);
let QueryPartitionStrategy::SinglePartition(partition_key) = partition_key.into();
base_request.insert_headers(&partition_key)?;

self.pipeline
.send_query_request(query.into(), base_request, link)
.send_query_request(query.into(), base_request, self.items_link.clone())
}
}
32 changes: 15 additions & 17 deletions sdk/cosmos/azure_data_cosmos/src/clients/cosmos_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ use azure_core::credentials::Secret;
/// Client for Azure Cosmos DB.
#[derive(Debug, Clone)]
pub struct CosmosClient {
endpoint: Url,
pub(crate) pipeline: CosmosPipeline,
databases_link: ResourceLink,
pipeline: CosmosPipeline,

#[allow(dead_code)]
options: CosmosClientOptions,
Expand Down Expand Up @@ -50,8 +50,9 @@ impl CosmosClient {
) -> azure_core::Result<Self> {
let options = options.unwrap_or_default();
Ok(Self {
endpoint: endpoint.as_ref().parse()?,
databases_link: ResourceLink::root(ResourceType::Databases),
pipeline: CosmosPipeline::new(
endpoint.as_ref().parse()?,
AuthorizationPolicy::from_token_credential(credential),
options.client_options.clone(),
),
Expand Down Expand Up @@ -82,8 +83,9 @@ impl CosmosClient {
) -> azure_core::Result<Self> {
let options = options.unwrap_or_default();
Ok(Self {
endpoint: endpoint.as_ref().parse()?,
databases_link: ResourceLink::root(ResourceType::Databases),
pipeline: CosmosPipeline::new(
endpoint.as_ref().parse()?,
AuthorizationPolicy::from_shared_key(key.into()),
options.client_options.clone(),
),
Expand All @@ -96,12 +98,12 @@ impl CosmosClient {
/// # Arguments
/// * `id` - The ID of the database.
pub fn database_client(&self, id: impl AsRef<str>) -> DatabaseClient {
DatabaseClient::new(self.pipeline.clone(), &self.endpoint, id.as_ref())
DatabaseClient::new(self.pipeline.clone(), id.as_ref())
}

/// Gets the endpoint of the database account this client is connected to.
pub fn endpoint(&self) -> &Url {
&self.endpoint
&self.pipeline.endpoint
}

/// Executes a query against databases in the account.
Expand Down Expand Up @@ -135,16 +137,11 @@ impl CosmosClient {
// REASON: This is a documented public API so prefixing with '_' is undesirable.
options: Option<QueryDatabasesOptions>,
) -> azure_core::Result<azure_core::Pager<DatabaseQueryResults>> {
let link = ResourceLink::root(ResourceType::Databases);
let url = link.url(&self.endpoint);
let url = self.pipeline.url(&self.databases_link);
let base_request = Request::new(url, azure_core::Method::Post);

self.pipeline.send_query_request(
query.into(),
base_request,
// Databases have no parent resource, so we use an empty resource link
link,
)
self.pipeline
.send_query_request(query.into(), base_request, self.databases_link.clone())
}

/// Creates a new database.
Expand All @@ -167,11 +164,12 @@ impl CosmosClient {
id: String,
}

let link = ResourceLink::root(ResourceType::Databases);
let url = link.url(&self.endpoint);
let url = self.pipeline.url(&self.databases_link);
let mut req = Request::new(url, Method::Post);
req.set_json(&RequestBody { id })?;

self.pipeline.send(Context::new(), &mut req, link).await
self.pipeline
.send(Context::new(), &mut req, self.databases_link.clone())
.await
}
}
31 changes: 18 additions & 13 deletions sdk/cosmos/azure_data_cosmos/src/clients/database_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,26 @@ use crate::{
};

use azure_core::{Context, Method, Pager, Request, Response};
use url::Url;

/// A client for working with a specific database in a Cosmos DB account.
///
/// You can get a `DatabaseClient` by calling [`CosmosClient::database_client()`](crate::CosmosClient::database_client()).
pub struct DatabaseClient {
endpoint: Url,
link: ResourceLink,
containers_link: ResourceLink,
database_id: String,
pipeline: CosmosPipeline,
}

impl DatabaseClient {
pub(crate) fn new(pipeline: CosmosPipeline, endpoint: Url, database_id: String) -> Self {
pub(crate) fn new(pipeline: CosmosPipeline, database_id: &str) -> Self {
let database_id = database_id.to_string();
let link = ResourceLink::root(ResourceType::Databases).item(&database_id);
let containers_link = link.feed(ResourceType::Containers);

Self {
endpoint,
link,
containers_link,
database_id,
pipeline,
}
Expand All @@ -40,7 +41,7 @@ impl DatabaseClient {
/// # Arguments
/// * `name` - The name of the container.
pub fn container_client(&self, name: impl AsRef<str>) -> ContainerClient {
ContainerClient::new(self.pipeline.clone(), &self.database_url, name.as_ref())
ContainerClient::new(self.pipeline.clone(), &self.link, name.as_ref())
}

/// Returns the identifier of the Cosmos database.
Expand Down Expand Up @@ -73,7 +74,8 @@ impl DatabaseClient {
// REASON: This is a documented public API so prefixing with '_' is undesirable.
options: Option<ReadDatabaseOptions>,
) -> azure_core::Result<Response<DatabaseProperties>> {
let mut req = Request::new(self.link.url(&self.endpoint), Method::Get);
let url = self.pipeline.url(&self.link);
let mut req = Request::new(url, Method::Get);
self.pipeline
.send(Context::new(), &mut req, self.link.clone())
.await
Expand Down Expand Up @@ -110,11 +112,11 @@ impl DatabaseClient {
// REASON: This is a documented public API so prefixing with '_' is undesirable.
options: Option<QueryContainersOptions>,
) -> azure_core::Result<Pager<ContainerQueryResults>> {
let link = self.link.feed(ResourceType::Containers);
let base_request = Request::new(link.url(&self.endpoint), Method::Post);
let url = self.pipeline.url(&self.containers_link);
let base_request = Request::new(url, Method::Post);

self.pipeline
.send_query_request(query.into(), base_request, link)
.send_query_request(query.into(), base_request, self.containers_link.clone())
}

/// Creates a new container.
Expand All @@ -132,11 +134,13 @@ impl DatabaseClient {
// REASON: This is a documented public API so prefixing with '_' is undesirable.
options: Option<CreateContainerOptions>,
) -> azure_core::Result<Response<Item<ContainerProperties>>> {
let link = self.link.feed(ResourceType::Containers);
let mut req = Request::new(link.url(&self.endpoint), Method::Post);
let url = self.pipeline.url(&self.containers_link);
let mut req = Request::new(url, Method::Post);
req.set_json(&properties)?;

self.pipeline.send(Context::new(), &mut req, link).await
self.pipeline
.send(Context::new(), &mut req, self.containers_link.clone())
.await
}

/// Deletes this database.
Expand All @@ -151,7 +155,8 @@ impl DatabaseClient {
// REASON: This is a documented public API so prefixing with '_' is undesirable.
options: Option<DeleteDatabaseOptions>,
) -> azure_core::Result<Response> {
let mut req = Request::new(self.link.url(&self.endpoint), Method::Delete);
let url = self.pipeline.url(&self.link);
let mut req = Request::new(url, Method::Delete);
self.pipeline
.send(Context::new(), &mut req, self.link.clone())
.await
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ impl Policy for AuthorizationPolicy {
"Authorization policies cannot be the last policy of a pipeline"
);

let time_nonce = OffsetDateTime::now_utc();
// x-ms-date and the string used in the signature must be exactly the same, so just generate it here once.
let date_string = date::to_rfc1123(&OffsetDateTime::now_utc()).to_lowercase();

let resource_link: &ResourceLink = ctx
.value()
Expand All @@ -78,11 +79,11 @@ impl Policy for AuthorizationPolicy {
let auth = generate_authorization(
&self.credential,
request.url(),
SignatureTarget::new(*request.method(), resource_link, time_nonce),
SignatureTarget::new(*request.method(), resource_link, &date_string),
)
.await?;

request.insert_header(MS_DATE, HeaderValue::from(date::to_rfc1123(&time_nonce)));
request.insert_header(MS_DATE, HeaderValue::from(date_string));
request.insert_header(VERSION, HeaderValue::from_static(AZURE_VERSION));
request.insert_header(AUTHORIZATION, HeaderValue::from(auth));

Expand Down
Loading

0 comments on commit e0dec46

Please sign in to comment.