-
Notifications
You must be signed in to change notification settings - Fork 298
Convert get database operation to pipeline architecture #286
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
use azure_core::prelude::*; | ||
use azure_cosmos::prelude::*; | ||
use std::error::Error; | ||
|
||
|
@@ -20,7 +21,9 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync>> { | |
|
||
let database_client = client.into_database_client(database_name.clone()); | ||
|
||
let response = database_client.get_database().execute().await?; | ||
let response = database_client | ||
.get_database(Context::new(), GetDatabaseOptions::new()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For client and method options, do we want to standardize on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some options won't be able to have default implementations because they have required arguments. If we opt for Unfortunately since Rust doesn't have default params, this is fairly verbose and There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Generally, if a parameter is required (hence making it required to create options) it's its own parameter. Eventually we'll want to be consistent with the other SDKs when not idiomatic e.g. which parameters are parameters and which are in some sort of options bag. |
||
.await?; | ||
println!("response == {:?}", response); | ||
|
||
Ok(()) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,10 @@ | ||
use super::*; | ||
use crate::operations::*; | ||
use crate::requests; | ||
use crate::resources::ResourceType; | ||
use crate::ReadonlyString; | ||
use crate::{requests, ReadonlyString}; | ||
|
||
use azure_core::pipeline::Pipeline; | ||
use azure_core::{Context, HttpClient, Request}; | ||
use azure_core::{Context, HttpClient}; | ||
|
||
/// A client for Cosmos database resources. | ||
#[derive(Debug, Clone)] | ||
|
@@ -35,8 +35,26 @@ impl DatabaseClient { | |
} | ||
|
||
/// Get the database | ||
pub fn get_database(&self) -> requests::GetDatabaseBuilder<'_, '_> { | ||
requests::GetDatabaseBuilder::new(self) | ||
pub async fn get_database( | ||
&self, | ||
mut ctx: Context, | ||
options: GetDatabaseOptions, | ||
) -> Result<GetDatabaseResponse, crate::Error> { | ||
let mut request = self | ||
.prepare_request_with_database_name(http::Method::GET) | ||
.body(bytes::Bytes::new()) | ||
.unwrap() | ||
.into(); | ||
options.decorate_request(&mut request)?; | ||
let response = self | ||
.pipeline() | ||
.send(&mut ctx, &mut request) | ||
.await | ||
.map_err(crate::Error::PolicyError)? | ||
.validate(http::StatusCode::OK) | ||
.await?; | ||
Comment on lines
+43
to
+55
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is something the pipeline should actually do, and the types of errors, which can be retried, etc. is typically handled by the pipeline. Again, we can do this in a separate PR, but I bring it up as a design point. Having every single method repeat this is burdensome and exactly what the pipeline was meant to handle. For an example reference, see .NETs: https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/core/Azure.Core/src/Pipeline/HttpPipeline.cs. Our other language SDKs use something similar. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you talking about the validation? This something that depends on the specific operation being performed, so I don't think we can move this into the pipeline. I agree it's currently fairly verbose, but I'm not sure the right way to solve that is moving it into pipelines rather than moving some of this into a function somewhere. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some of our SDKs use a response classifier they can pass in when building the pipeline. We don't necessarily have to be the same, but - even if |
||
|
||
Ok(GetDatabaseResponse::try_from(response).await?) | ||
} | ||
|
||
/// List collections in the database | ||
|
@@ -52,24 +70,23 @@ impl DatabaseClient { | |
/// Create a collection | ||
pub async fn create_collection<S: AsRef<str>>( | ||
&self, | ||
ctx: Context, | ||
mut ctx: Context, | ||
collection_name: S, | ||
options: CreateCollectionOptions, | ||
) -> Result<CreateCollectionResponse, crate::Error> { | ||
let request = self.cosmos_client().prepare_request( | ||
let mut request = self.cosmos_client().prepare_request2( | ||
&format!("dbs/{}/colls", self.database_name()), | ||
http::Method::POST, | ||
ResourceType::Collections, | ||
); | ||
let mut request: Request = request.body(bytes::Bytes::new()).unwrap().into(); | ||
|
||
let mut ctx = ctx.clone(); | ||
options.decorate_request(&mut request, collection_name.as_ref())?; | ||
let response = self | ||
.pipeline() | ||
.send(&mut ctx, &mut request) | ||
.await | ||
.map_err(crate::Error::PolicyError)?; | ||
.map_err(crate::Error::PolicyError)? | ||
.validate(http::StatusCode::CREATED) | ||
.await?; | ||
|
||
Ok(CreateCollectionResponse::try_from(response).await?) | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
use crate::headers::from_headers::*; | ||
use crate::prelude::*; | ||
use crate::ResourceQuota; | ||
|
||
use azure_core::headers::{etag_from_headers, session_token_from_headers}; | ||
use azure_core::{collect_pinned_stream, Request as HttpRequest, Response as HttpResponse}; | ||
use chrono::{DateTime, Utc}; | ||
|
||
#[derive(Debug, Clone, Default)] | ||
pub struct GetDatabaseOptions { | ||
consistency_level: Option<ConsistencyLevel>, | ||
} | ||
|
||
impl GetDatabaseOptions { | ||
pub fn new() -> Self { | ||
rylev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Self { | ||
consistency_level: None, | ||
} | ||
} | ||
|
||
setters! { | ||
consistency_level: ConsistencyLevel => Some(consistency_level), | ||
} | ||
|
||
pub(crate) fn decorate_request(&self, request: &mut HttpRequest) -> Result<(), crate::Error> { | ||
azure_core::headers::add_optional_header2(&self.consistency_level, request); | ||
request.set_body(bytes::Bytes::from_static(&[]).into()); | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
#[derive(Debug, Clone)] | ||
pub struct GetDatabaseResponse { | ||
pub database: Database, | ||
pub charge: f64, | ||
pub activity_id: uuid::Uuid, | ||
pub session_token: String, | ||
pub etag: String, | ||
pub last_state_change: DateTime<Utc>, | ||
pub resource_quota: Vec<ResourceQuota>, | ||
pub resource_usage: Vec<ResourceQuota>, | ||
pub schema_version: String, | ||
pub service_version: String, | ||
pub gateway_version: String, | ||
} | ||
|
||
impl GetDatabaseResponse { | ||
pub async fn try_from(response: HttpResponse) -> Result<Self, crate::Error> { | ||
let (_status_code, headers, pinned_stream) = response.deconstruct(); | ||
let body = collect_pinned_stream(pinned_stream).await?; | ||
|
||
Ok(Self { | ||
database: serde_json::from_slice(&body)?, | ||
charge: request_charge_from_headers(&headers)?, | ||
activity_id: activity_id_from_headers(&headers)?, | ||
session_token: session_token_from_headers(&headers)?, | ||
etag: etag_from_headers(&headers)?, | ||
last_state_change: last_state_change_from_headers(&headers)?, | ||
resource_quota: resource_quota_from_headers(&headers)?, | ||
resource_usage: resource_usage_from_headers(&headers)?, | ||
schema_version: schema_version_from_headers(&headers)?.to_owned(), | ||
service_version: service_version_from_headers(&headers)?.to_owned(), | ||
gateway_version: gateway_version_from_headers(&headers)?.to_owned(), | ||
}) | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.