Skip to content

Commit 3f9148d

Browse files
authored
Pager rename and refactor (#1836)
1 parent cf8e183 commit 3f9148d

File tree

8 files changed

+329
-197
lines changed

8 files changed

+329
-197
lines changed

sdk/core/azure_core/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ pub use typespec_client_core::xml;
5151
pub use typespec_client_core::{
5252
base64, date,
5353
http::{
54-
headers::Header, new_http_client, AppendToUrlQuery, Body, Context, Continuable, HttpClient,
55-
Method, Pageable, Request, RequestContent, StatusCode, Url,
54+
headers::Header, new_http_client, AppendToUrlQuery, Body, Context, HttpClient, Method,
55+
Pager, Request, RequestContent, StatusCode, Url,
5656
},
5757
json, parsing,
5858
sleep::{self, sleep},

sdk/cosmos/azure_data_cosmos/examples/cosmos/query.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,8 @@ impl QueryCommand {
3434
container_client.query_items::<serde_json::Value>(&self.query, pk, None)?;
3535

3636
while let Some(page) = items_pager.next().await {
37-
let response = page?;
37+
let response = page?.deserialize_body().await?;
3838
println!("Results Page");
39-
println!(" Query Metrics: {:?}", response.query_metrics);
40-
println!(" Index Metrics: {:?}", response.index_metrics);
4139
println!(" Items:");
4240
for item in response.items {
4341
println!(" * {:#?}", item);

sdk/cosmos/azure_data_cosmos/src/clients/container_client.rs

Lines changed: 28 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ use crate::{
1010
ItemOptions, PartitionKey, Query, QueryPartitionStrategy,
1111
};
1212

13-
use azure_core::{Context, Request, Response};
14-
use serde::{de::DeserializeOwned, Deserialize, Serialize};
13+
use azure_core::{Context, Pager, Request, Response};
14+
use serde::{de::DeserializeOwned, Serialize};
15+
use typespec_client_core::http::PagerResult;
1516
use url::Url;
1617

1718
#[cfg(doc)]
@@ -44,13 +45,13 @@ pub trait ContainerClientMethods {
4445
async fn read(
4546
&self,
4647
options: Option<ReadContainerOptions>,
47-
) -> azure_core::Result<azure_core::Response<ContainerProperties>>;
48+
) -> azure_core::Result<Response<ContainerProperties>>;
4849

4950
/// Creates a new item in the container.
5051
///
5152
/// # Arguments
5253
/// * `partition_key` - The partition key of the new item.
53-
/// * `item` - The item to create. The type must implement [`Serialize`] and [`Deserialize`]
54+
/// * `item` - The item to create. The type must implement [`Serialize`] and [`Deserialize`](serde::Deserialize)
5455
/// * `options` - Optional parameters for the request
5556
///
5657
/// # Examples
@@ -87,14 +88,14 @@ pub trait ContainerClientMethods {
8788
partition_key: impl Into<PartitionKey>,
8889
item: T,
8990
options: Option<ItemOptions>,
90-
) -> azure_core::Result<azure_core::Response<Item<T>>>;
91+
) -> azure_core::Result<Response<Item<T>>>;
9192

9293
/// Replaces an existing item in the container.
9394
///
9495
/// # Arguments
9596
/// * `partition_key` - The partition key of the item to replace.
9697
/// * `item_id` - The id of the item to replace.
97-
/// * `item` - The item to create. The type must implement [`Serialize`] and [`Deserialize`]
98+
/// * `item` - The item to create. The type must implement [`Serialize`] and [`Deserialize`](serde::Deserialize)
9899
/// * `options` - Optional parameters for the request
99100
///
100101
/// # Examples
@@ -132,7 +133,7 @@ pub trait ContainerClientMethods {
132133
item_id: impl AsRef<str>,
133134
item: T,
134135
options: Option<ItemOptions>,
135-
) -> azure_core::Result<azure_core::Response<Item<T>>>;
136+
) -> azure_core::Result<Response<Item<T>>>;
136137

137138
/// Creates or replaces an item in the container.
138139
///
@@ -141,7 +142,7 @@ pub trait ContainerClientMethods {
141142
///
142143
/// # Arguments
143144
/// * `partition_key` - The partition key of the item to create or replace.
144-
/// * `item` - The item to create. The type must implement [`Serialize`] and [`Deserialize`]
145+
/// * `item` - The item to create. The type must implement [`Serialize`] and [`Deserialize`](serde::Deserialize)
145146
/// * `options` - Optional parameters for the request
146147
///
147148
/// # Examples
@@ -178,7 +179,7 @@ pub trait ContainerClientMethods {
178179
partition_key: impl Into<PartitionKey>,
179180
item: T,
180181
options: Option<ItemOptions>,
181-
) -> azure_core::Result<azure_core::Response<Item<T>>>;
182+
) -> azure_core::Result<Response<Item<T>>>;
182183

183184
/// Reads a specific item from the container.
184185
///
@@ -216,7 +217,7 @@ pub trait ContainerClientMethods {
216217
partition_key: impl Into<PartitionKey>,
217218
item_id: impl AsRef<str>,
218219
options: Option<ItemOptions>,
219-
) -> azure_core::Result<azure_core::Response<Item<T>>>;
220+
) -> azure_core::Result<Response<Item<T>>>;
220221

221222
/// Deletes an item from the container.
222223
///
@@ -243,7 +244,7 @@ pub trait ContainerClientMethods {
243244
partition_key: impl Into<PartitionKey>,
244245
item_id: impl AsRef<str>,
245246
options: Option<ItemOptions>,
246-
) -> azure_core::Result<azure_core::Response>;
247+
) -> azure_core::Result<Response>;
247248

248249
/// Executes a single-partition query against items in the container.
249250
///
@@ -304,7 +305,7 @@ pub trait ContainerClientMethods {
304305
query: impl Into<Query>,
305306
partition_key: impl Into<QueryPartitionStrategy>,
306307
options: Option<QueryOptions>,
307-
) -> azure_core::Result<azure_core::Pageable<QueryResults<T>, azure_core::Error>>;
308+
) -> azure_core::Result<Pager<QueryResults<T>>>;
308309
}
309310

310311
/// A client for working with a specific container in a Cosmos DB account.
@@ -333,7 +334,7 @@ impl ContainerClientMethods for ContainerClient {
333334
#[allow(unused_variables)]
334335
// REASON: This is a documented public API so prefixing with '_' is undesirable.
335336
options: Option<ReadContainerOptions>,
336-
) -> azure_core::Result<azure_core::Response<ContainerProperties>> {
337+
) -> azure_core::Result<Response<ContainerProperties>> {
337338
let mut req = Request::new(self.container_url.clone(), azure_core::Method::Get);
338339
self.pipeline
339340
.send(Context::new(), &mut req, ResourceType::Containers)
@@ -348,7 +349,7 @@ impl ContainerClientMethods for ContainerClient {
348349
#[allow(unused_variables)]
349350
// REASON: This is a documented public API so prefixing with '_' is undesirable.
350351
options: Option<ItemOptions>,
351-
) -> azure_core::Result<azure_core::Response<Item<T>>> {
352+
) -> azure_core::Result<Response<Item<T>>> {
352353
let url = self.container_url.with_path_segments(["docs"]);
353354
let mut req = Request::new(url, azure_core::Method::Post);
354355
req.insert_headers(&partition_key.into())?;
@@ -367,7 +368,7 @@ impl ContainerClientMethods for ContainerClient {
367368
#[allow(unused_variables)]
368369
// REASON: This is a documented public API so prefixing with '_' is undesirable.
369370
options: Option<ItemOptions>,
370-
) -> azure_core::Result<azure_core::Response<Item<T>>> {
371+
) -> azure_core::Result<Response<Item<T>>> {
371372
let url = self
372373
.container_url
373374
.with_path_segments(["docs", item_id.as_ref()]);
@@ -387,7 +388,7 @@ impl ContainerClientMethods for ContainerClient {
387388
#[allow(unused_variables)]
388389
// REASON: This is a documented public API so prefixing with '_' is undesirable.
389390
options: Option<ItemOptions>,
390-
) -> azure_core::Result<azure_core::Response<Item<T>>> {
391+
) -> azure_core::Result<Response<Item<T>>> {
391392
let url = self.container_url.with_path_segments(["docs"]);
392393
let mut req = Request::new(url, azure_core::Method::Post);
393394
req.insert_header(constants::IS_UPSERT, "true");
@@ -406,7 +407,7 @@ impl ContainerClientMethods for ContainerClient {
406407
#[allow(unused_variables)]
407408
// REASON: This is a documented public API so prefixing with '_' is undesirable.
408409
options: Option<ItemOptions>,
409-
) -> azure_core::Result<azure_core::Response<Item<T>>> {
410+
) -> azure_core::Result<Response<Item<T>>> {
410411
let url = self
411412
.container_url
412413
.with_path_segments(["docs", item_id.as_ref()]);
@@ -425,7 +426,7 @@ impl ContainerClientMethods for ContainerClient {
425426
#[allow(unused_variables)]
426427
// REASON: This is a documented public API so prefixing with '_' is undesirable.
427428
options: Option<ItemOptions>,
428-
) -> azure_core::Result<azure_core::Response> {
429+
) -> azure_core::Result<Response> {
429430
let url = self
430431
.container_url
431432
.with_path_segments(["docs", item_id.as_ref()]);
@@ -444,26 +445,9 @@ impl ContainerClientMethods for ContainerClient {
444445
#[allow(unused_variables)]
445446
// REASON: This is a documented public API so prefixing with '_' is undesirable.
446447
options: Option<QueryOptions>,
447-
) -> azure_core::Result<azure_core::Pageable<QueryResults<T>, azure_core::Error>> {
448-
// Represents the raw response model from the server.
449-
// We'll use this to deserialize the response body and then convert it to a more user-friendly model.
450-
#[derive(Deserialize)]
451-
struct QueryResponseModel<M> {
452-
#[serde(rename = "Documents")]
453-
documents: Vec<M>,
454-
}
455-
456-
// We have to manually implement Model, because the derive macro doesn't support auto-inferring type and lifetime bounds.
457-
// See https://github.com/Azure/azure-sdk-for-rust/issues/1803
458-
impl<M: DeserializeOwned> azure_core::Model for QueryResponseModel<M> {
459-
async fn from_response_body(
460-
body: azure_core::ResponseBody,
461-
) -> typespec_client_core::Result<Self> {
462-
body.json().await
463-
}
464-
}
465-
466-
let url = self.container_url.with_path_segments(["docs"]);
448+
) -> azure_core::Result<Pager<QueryResults<T>>> {
449+
let mut url = self.container_url.clone();
450+
url.append_path_segments(["docs"]);
467451
let mut base_req = Request::new(url, azure_core::Method::Post);
468452

469453
base_req.insert_header(constants::QUERY, "True");
@@ -477,7 +461,7 @@ impl ContainerClientMethods for ContainerClient {
477461
// We have to double-clone here.
478462
// First we clone the pipeline to pass it in to the closure
479463
let pipeline = self.pipeline.clone();
480-
Ok(azure_core::Pageable::new(move |continuation| {
464+
Ok(Pager::from_callback(move |continuation| {
481465
// Then we have to clone it again to pass it in to the async block.
482466
// This is because Pageable can't borrow any data, it has to own it all.
483467
// That's probably good, because it means a Pageable can outlive the client that produced it, but it requires some extra cloning.
@@ -488,29 +472,13 @@ impl ContainerClientMethods for ContainerClient {
488472
req.insert_header(constants::CONTINUATION, continuation);
489473
}
490474

491-
let resp: Response<QueryResponseModel<T>> = pipeline
475+
let response = pipeline
492476
.send(Context::new(), &mut req, ResourceType::Items)
493477
.await?;
494-
495-
let query_metrics = resp
496-
.headers()
497-
.get_optional_string(&constants::QUERY_METRICS);
498-
let index_metrics = resp
499-
.headers()
500-
.get_optional_string(&constants::INDEX_METRICS);
501-
let continuation_token =
502-
resp.headers().get_optional_string(&constants::CONTINUATION);
503-
504-
let query_response: QueryResponseModel<T> = resp.deserialize_body().await?;
505-
506-
let query_results = QueryResults {
507-
items: query_response.documents,
508-
query_metrics,
509-
index_metrics,
510-
continuation_token,
511-
};
512-
513-
Ok(query_results)
478+
Ok(PagerResult::from_response_header(
479+
response,
480+
&constants::CONTINUATION,
481+
))
514482
}
515483
}))
516484
}

sdk/cosmos/azure_data_cosmos/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#![cfg_attr(docsrs, feature(doc_cfg_hide))]
1212

1313
pub mod clients;
14-
pub(crate) mod constants;
14+
pub mod constants;
1515
mod options;
1616
mod partition_key;
1717
pub(crate) mod pipeline;

sdk/cosmos/azure_data_cosmos/src/models/mod.rs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
//! Model types sent to and received from the Cosmos DB API.
55
6-
use azure_core::{date::OffsetDateTime, Continuable, Model};
7-
use serde::{Deserialize, Deserializer};
6+
use azure_core::{date::OffsetDateTime, Model};
7+
use serde::{de::DeserializeOwned, Deserialize, Deserializer};
88

99
#[cfg(doc)]
1010
use crate::{
@@ -37,19 +37,17 @@ where
3737

3838
/// A page of query results, where each item is a document of type `T`.
3939
#[non_exhaustive]
40-
#[derive(Clone, Default, Debug)]
40+
#[derive(Clone, Default, Debug, Deserialize)]
4141
pub struct QueryResults<T> {
42+
#[serde(rename = "Documents")]
4243
pub items: Vec<T>,
43-
pub query_metrics: Option<String>,
44-
pub index_metrics: Option<String>,
45-
pub continuation_token: Option<String>,
4644
}
4745

48-
impl<T> Continuable for QueryResults<T> {
49-
type Continuation = String;
50-
51-
fn continuation(&self) -> Option<Self::Continuation> {
52-
self.continuation_token.clone()
46+
impl<T: DeserializeOwned> azure_core::Model for QueryResults<T> {
47+
async fn from_response_body(
48+
body: azure_core::ResponseBody,
49+
) -> typespec_client_core::Result<Self> {
50+
body.json().await
5351
}
5452
}
5553

sdk/typespec/typespec_client_core/src/http/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ mod context;
88
pub mod headers;
99
mod models;
1010
mod options;
11-
mod pageable;
11+
mod pager;
1212
mod pipeline;
1313
pub mod policies;
1414
pub mod request;
@@ -19,7 +19,7 @@ pub use context::*;
1919
pub use headers::Header;
2020
pub use models::*;
2121
pub use options::*;
22-
pub use pageable::*;
22+
pub use pager::*;
2323
pub use pipeline::*;
2424
pub use request::{Body, Request, RequestContent};
2525
pub use response::{Model, Response};

0 commit comments

Comments
 (0)