Skip to content

Commit 1901782

Browse files
authored
[Cosmos] "Enable Content Response on Write" option and integration tests for items and query (#1963)
* format-specific deserializers for Response<T> * add enable_content_response_on_write option * stash not content on write * remove changes outside cosmos for now * don't try to start test proxy on live tests * [Cosmos] add integration tests for items * [Cosmos] add integration tests for query * spelling fix * show 'use' statements in examples * switch clap attributes to arg/command
1 parent 7684225 commit 1901782

File tree

23 files changed

+880
-287
lines changed

23 files changed

+880
-287
lines changed

sdk/core/azure_core_test/src/recorded.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,14 @@ static TEST_PROXY: OnceCell<Result<Arc<Proxy>>> = OnceCell::const_new();
1919
///
2020
/// The [Test Proxy](https://github.com/Azure/azure-sdk-tools/blob/main/tools/test-proxy/Azure.Sdk.Tools.TestProxy/README.md) service will be started as needed.
2121
/// Every `#[recorded::test]` will call this automatically, but it can also be called manually by any other test e.g., those attributed with `#[tokio::test]`.
22-
pub async fn start(ctx: &TestContext, options: Option<ProxyOptions>) -> Result<Recording> {
22+
///
23+
/// This function will return `Ok(None)` if the test is running in live mode and should not use the test proxy at all.
24+
pub async fn start(ctx: &TestContext, options: Option<ProxyOptions>) -> Result<Option<Recording>> {
25+
// Live tests don't use test-proxy.
26+
if ctx.test_mode() == azure_core::test::TestMode::Live {
27+
return Ok(None);
28+
}
29+
2330
let proxy = TEST_PROXY
2431
.get_or_init(|| async move {
2532
proxy::start(ctx.test_data_dir(), options)
@@ -31,9 +38,9 @@ pub async fn start(ctx: &TestContext, options: Option<ProxyOptions>) -> Result<R
3138
.map_err(|err| azure_core::Error::new(err.kind().clone(), err))?;
3239

3340
let span = debug_span!(target: crate::SPAN_TARGET, "recording", mode = ?ctx.test_mode(), test = ?ctx.test_name());
34-
Ok(Recording {
41+
Ok(Some(Recording {
3542
proxy: proxy.clone(),
3643
span,
3744
mode: ctx.test_mode(),
38-
})
45+
}))
3946
}

sdk/cosmos/azure_data_cosmos/examples/cosmos/create.rs

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::error::Error;
22

33
use azure_data_cosmos::{
44
models::{ContainerProperties, PartitionKeyDefinition, ThroughputProperties},
5-
CosmosClient, CreateContainerOptions, CreateDatabaseOptions, PartitionKey,
5+
CosmosClient, CreateContainerOptions, CreateDatabaseOptions, ItemOptions, PartitionKey,
66
};
77
use clap::{Args, Subcommand};
88

@@ -26,20 +26,24 @@ pub enum Subcommands {
2626
container: String,
2727

2828
/// The partition key of the new item.
29-
#[clap(long, short)]
29+
#[arg(long, short)]
3030
partition_key: String,
3131

3232
/// The JSON of the new item.
33-
#[clap(long, short)]
33+
#[arg(long, short)]
3434
json: String,
35+
36+
/// If set, the updated item will be included in the response.
37+
#[arg(long)]
38+
show_updated: bool,
3539
},
3640

3741
/// Create a database (does not support Entra ID).
3842
Database {
3943
/// The ID of the new database to create.
4044
id: String,
4145

42-
#[clap(flatten)]
46+
#[command(flatten)]
4347
throughput_options: ThroughputOptions,
4448
},
4549

@@ -48,19 +52,19 @@ pub enum Subcommands {
4852
/// The ID of the database to create the container in.
4953
database: String,
5054

51-
#[clap(flatten)]
55+
#[command(flatten)]
5256
throughput_options: ThroughputOptions,
5357

5458
/// The ID of the new container to create.
55-
#[clap(long, short)]
59+
#[arg(long, short)]
5660
id: Option<String>,
5761

5862
/// The path to the partition key properties (supports up to 3).
59-
#[clap(long, short)]
63+
#[arg(long, short)]
6064
partition_key: Vec<String>,
6165

6266
/// The JSON for a ContainerProperties value. The 'id' and 'partition key' options are ignored if this is set.
63-
#[clap(long)]
67+
#[arg(long)]
6468
json: Option<String>,
6569
},
6670
}
@@ -73,21 +77,30 @@ impl CreateCommand {
7377
container,
7478
partition_key,
7579
json,
80+
show_updated,
7681
} => {
7782
let db_client = client.database_client(&database);
7883
let container_client = db_client.container_client(&container);
7984

8085
let pk = PartitionKey::from(&partition_key);
8186
let item: serde_json::Value = serde_json::from_str(&json)?;
8287

83-
let created = container_client
84-
.create_item(pk, item, None)
85-
.await?
86-
.into_body()
87-
.await?
88-
.unwrap();
89-
println!("Created item:");
90-
println!("{:#?}", created);
88+
let options = ItemOptions {
89+
enable_content_response_on_write: show_updated,
90+
..Default::default()
91+
};
92+
93+
let response = container_client
94+
.create_item(pk, item, Some(options))
95+
.await?;
96+
97+
println!("Created item successfully");
98+
99+
if show_updated {
100+
let created = response.into_json_body::<serde_json::Value>().await?;
101+
println!("Newly created item:");
102+
println!("{:#?}", created);
103+
}
91104
Ok(())
92105
}
93106

@@ -106,8 +119,7 @@ impl CreateCommand {
106119
.create_database(&id, options)
107120
.await?
108121
.into_body()
109-
.await?
110-
.unwrap();
122+
.await?;
111123
println!("Created database:");
112124
println!("{:#?}", db);
113125
Ok(())
@@ -152,8 +164,7 @@ impl CreateCommand {
152164
.create_container(properties, options)
153165
.await?
154166
.into_body()
155-
.await?
156-
.unwrap();
167+
.await?;
157168
println!("Created container:");
158169
println!("{:#?}", container);
159170
Ok(())

sdk/cosmos/azure_data_cosmos/examples/cosmos/delete.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ pub enum Subcommands {
2222
container: String,
2323

2424
/// The ID of the item.
25-
#[clap(long, short)]
25+
#[arg(long, short)]
2626
item_id: String,
2727

2828
/// The partition key of the item.
29-
#[clap(long, short)]
29+
#[arg(long, short)]
3030
partition_key: String,
3131
},
3232

sdk/cosmos/azure_data_cosmos/examples/cosmos/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ mod utils;
2222
/// It exists for illustrative purposes and to simplify ad-hoc end-to-end testing.
2323
#[derive(Clone, Parser)]
2424
struct ProgramArgs {
25-
#[clap(flatten)]
25+
#[command(flatten)]
2626
shared_args: SharedArgs,
2727

2828
#[command(subcommand)]
@@ -35,7 +35,7 @@ struct SharedArgs {
3535
endpoint: String,
3636

3737
/// An authentication key to use when connecting to the Cosmos DB account. If omitted, the connection will use Entra ID.
38-
#[clap(long)]
38+
#[arg(long)]
3939
key: Option<String>,
4040
}
4141

sdk/cosmos/azure_data_cosmos/examples/cosmos/metadata.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub struct MetadataCommand {
1313
database: String,
1414

1515
/// Optionally, the container to fetch information for.
16-
#[clap(long, short)]
16+
#[arg(long, short)]
1717
container: Option<String>,
1818
}
1919

sdk/cosmos/azure_data_cosmos/examples/cosmos/patch.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@ pub struct PatchCommand {
1717
container: String,
1818

1919
/// The ID of the item.
20-
#[clap(long, short)]
20+
#[arg(long, short)]
2121
item_id: String,
2222

2323
/// The partition key of the new item.
24-
#[clap(long, short)]
24+
#[arg(long, short)]
2525
partition_key: String,
2626

2727
/// A JSON patch operation to apply to the item, can be specified multiple times. See https://learn.microsoft.com/en-us/azure/cosmos-db/partial-document-update
28-
#[clap(long, short)]
28+
#[arg(long, short)]
2929
operation: Vec<String>,
3030
}
3131

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ enum Subcommands {
2424
query: String,
2525

2626
/// The partition key to use when querying the container. Currently this only supports a single string partition key.
27-
#[clap(long, short)]
27+
#[arg(long, short)]
2828
partition_key: String,
2929
},
3030
Databases {

sdk/cosmos/azure_data_cosmos/examples/cosmos/read.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ enum Subcommands {
3232
container: String,
3333

3434
/// The ID of the item.
35-
#[clap(long, short)]
35+
#[arg(long, short)]
3636
item_id: String,
3737

3838
/// The partition key of the item.
39-
#[clap(long, short)]
39+
#[arg(long, short)]
4040
partition_key: String,
4141
},
4242
}
@@ -61,7 +61,7 @@ impl ReadCommand {
6161
println!("Item not found!")
6262
}
6363
Ok(r) => {
64-
let item: serde_json::Value = r.into_body().await?.unwrap();
64+
let item: serde_json::Value = r.into_json_body().await?;
6565
println!("Found item:");
6666
println!("{:#?}", item);
6767
}

sdk/cosmos/azure_data_cosmos/examples/cosmos/replace.rs

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::error::Error;
22

33
use azure_core::StatusCode;
4-
use azure_data_cosmos::{CosmosClient, PartitionKey};
4+
use azure_data_cosmos::{CosmosClient, ItemOptions, PartitionKey};
55
use clap::{Args, Subcommand};
66

77
use crate::utils::ThroughputOptions;
@@ -23,22 +23,26 @@ pub enum Subcommands {
2323
container: String,
2424

2525
/// The ID of the item.
26-
#[clap(long, short)]
26+
#[arg(long, short)]
2727
item_id: String,
2828

2929
/// The partition key of the new item.
30-
#[clap(long, short)]
30+
#[arg(long, short)]
3131
partition_key: String,
3232

3333
/// The JSON of the new item.
34-
#[clap(long, short)]
34+
#[arg(long, short)]
3535
json: String,
36+
37+
/// If set, the updated item will be included in the response.
38+
#[arg(long)]
39+
show_updated: bool,
3640
},
3741
DatabaseThroughput {
3842
/// The database to update throughput for.
3943
database: String,
4044

41-
#[clap(flatten)]
45+
#[command(flatten)]
4246
throughput_options: ThroughputOptions,
4347
},
4448
ContainerThroughput {
@@ -48,7 +52,7 @@ pub enum Subcommands {
4852
/// The container to update throughput for.
4953
container: String,
5054

51-
#[clap(flatten)]
55+
#[command(flatten)]
5256
throughput_options: ThroughputOptions,
5357
},
5458
}
@@ -62,24 +66,34 @@ impl ReplaceCommand {
6266
item_id,
6367
partition_key,
6468
json,
69+
show_updated,
6570
} => {
6671
let db_client = client.database_client(&database);
6772
let container_client = db_client.container_client(&container);
6873

6974
let pk = PartitionKey::from(&partition_key);
7075
let item: serde_json::Value = serde_json::from_str(&json)?;
7176

77+
let options = ItemOptions {
78+
enable_content_response_on_write: show_updated,
79+
..Default::default()
80+
};
81+
7282
let response = container_client
73-
.replace_item(pk, &item_id, item, None)
83+
.replace_item(pk, &item_id, item, Some(options))
7484
.await;
7585
match response {
7686
Err(e) if e.http_status() == Some(StatusCode::NotFound) => {
7787
println!("Item not found!")
7888
}
7989
Ok(r) => {
80-
let item: serde_json::Value = r.into_body().await?.unwrap();
81-
println!("Replaced item:");
82-
println!("{:#?}", item);
90+
println!("Replaced item successfully");
91+
92+
if show_updated {
93+
let created: serde_json::Value = r.into_json_body().await?;
94+
println!("Newly replaced item:");
95+
println!("{:#?}", created);
96+
}
8397
}
8498
Err(e) => return Err(e.into()),
8599
};
Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::error::Error;
22

3-
use azure_data_cosmos::{CosmosClient, PartitionKey};
3+
use azure_data_cosmos::{CosmosClient, ItemOptions, PartitionKey};
44
use clap::Args;
55

66
/// Creates a new item or replaces an existing item, if a matching item already exists.
@@ -13,12 +13,16 @@ pub struct UpsertCommand {
1313
container: String,
1414

1515
/// The partition key of the new item.
16-
#[clap(long, short)]
16+
#[arg(long, short)]
1717
partition_key: String,
1818

1919
/// The JSON of the new item.
20-
#[clap(long, short)]
20+
#[arg(long, short)]
2121
json: String,
22+
23+
/// If set, the updated item will be included in the response.
24+
#[arg(long)]
25+
show_updated: bool,
2226
}
2327

2428
impl UpsertCommand {
@@ -29,14 +33,21 @@ impl UpsertCommand {
2933
let pk = PartitionKey::from(&self.partition_key);
3034
let item: serde_json::Value = serde_json::from_str(&self.json)?;
3135

32-
let created = container_client
33-
.upsert_item(pk, item, None)
34-
.await?
35-
.into_body()
36-
.await?
37-
.unwrap();
38-
println!("Created item:");
39-
println!("{:#?}", created);
36+
let options = ItemOptions {
37+
enable_content_response_on_write: self.show_updated,
38+
..Default::default()
39+
};
40+
41+
let response = container_client
42+
.upsert_item(pk, item, Some(options))
43+
.await?;
44+
println!("Item updated successfully");
45+
46+
if self.show_updated {
47+
let created: serde_json::Value = response.into_json_body().await?;
48+
println!("Updated item:");
49+
println!("{:#?}", created);
50+
}
4051
Ok(())
4152
}
4253
}

0 commit comments

Comments
 (0)