diff --git a/README.md b/README.md index 057485c32..49ec5bd42 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Crate | Docs | Crates.io | Downloads | Downloads@Latest | -- | -- | -- | -- | -- | [azure_sdk_auth_aad](https://github.com/MindFlavor/AzureSDKForRust/tree/master/azure_sdk_auth_aad) | [![docs](https://docs.rs/azure_sdk_auth_aad/badge.svg)](https://docs.rs/azure_sdk_auth_aad/0.42.2/azure_sdk_auth_aad) | [![Crate](https://img.shields.io/crates/v/azure_sdk_auth_aad.svg)](https://crates.io/crates/azure_sdk_auth_aad) | [![cratedown](https://img.shields.io/crates/d/azure_sdk_auth_aad.svg)](https://crates.io/crates/azure_sdk_auth_aad) | [![cratelastdown](https://img.shields.io/crates/dv/azure_sdk_auth_aad.svg)](https://crates.io/crates/azure_sdk_auth_aad) [azure_sdk_core](https://github.com/MindFlavor/AzureSDKForRust/tree/master/azure_sdk_core) | [![docs](https://docs.rs/azure_sdk_core/badge.svg)](https://docs.rs/azure_sdk_core/0.43.2/azure_sdk_core) | [![Crate](https://img.shields.io/crates/v/azure_sdk_core.svg)](https://crates.io/crates/azure_sdk_core) | [![cratedown](https://img.shields.io/crates/d/azure_sdk_core.svg)](https://crates.io/crates/azure_sdk_core) | [![cratelastdown](https://img.shields.io/crates/dv/azure_sdk_core.svg)](https://crates.io/crates/azure_sdk_core) -[azure_sdk_cosmos](https://github.com/MindFlavor/AzureSDKForRust/tree/master/azure_sdk_cosmos) | [![docs](https://docs.rs/azure_sdk_cosmos/badge.svg)](https://docs.rs/azure_sdk_cosmos/0.42.4/azure_sdk_cosmos) | [![Crate](https://img.shields.io/crates/v/azure_sdk_cosmos.svg)](https://crates.io/crates/azure_sdk_cosmos) | [![cratedown](https://img.shields.io/crates/d/azure_sdk_cosmos.svg)](https://crates.io/crates/azure_sdk_cosmos) | [![cratelastdown](https://img.shields.io/crates/dv/azure_sdk_cosmos.svg)](https://crates.io/crates/azure_sdk_cosmos) +[azure_sdk_cosmos](https://github.com/MindFlavor/AzureSDKForRust/tree/master/azure_sdk_cosmos) | [![docs](https://docs.rs/azure_sdk_cosmos/badge.svg)](https://docs.rs/azure_sdk_cosmos/0.43.0/azure_sdk_cosmos) | [![Crate](https://img.shields.io/crates/v/azure_sdk_cosmos.svg)](https://crates.io/crates/azure_sdk_cosmos) | [![cratedown](https://img.shields.io/crates/d/azure_sdk_cosmos.svg)](https://crates.io/crates/azure_sdk_cosmos) | [![cratelastdown](https://img.shields.io/crates/dv/azure_sdk_cosmos.svg)](https://crates.io/crates/azure_sdk_cosmos) [azure_sdk_service_bus](https://github.com/MindFlavor/AzureSDKForRust/tree/master/azure_sdk_service_bus) | [![docs](https://docs.rs/azure_sdk_service_bus/badge.svg)](https://docs.rs/azure_sdk_service_bus/0.44.0/azure_sdk_service_bus) | [![Crate](https://img.shields.io/crates/v/azure_sdk_service_bus.svg)](https://crates.io/crates/azure_sdk_service_bus) | [![cratedown](https://img.shields.io/crates/d/azure_sdk_service_bus.svg)](https://crates.io/crates/azure_sdk_service_bus) | [![cratelastdown](https://img.shields.io/crates/dv/azure_sdk_service_bus.svg)](https://crates.io/crates/azure_sdk_service_bus) [azure_sdk_storage_account](https://github.com/MindFlavor/AzureSDKForRust/tree/master/azure_sdk_storage_account) | [![docs](https://docs.rs/azure_sdk_storage_account/badge.svg)](https://docs.rs/azure_sdk_storage_account/0.40.4/azure_sdk_storage_account) | [![Crate](https://img.shields.io/crates/v/azure_sdk_storage_account.svg)](https://crates.io/crates/azure_sdk_storage_account) | [![cratedown](https://img.shields.io/crates/d/azure_sdk_storage_account.svg)](https://crates.io/crates/azure_sdk_storage_account) | [![cratelastdown](https://img.shields.io/crates/dv/azure_sdk_storage_account.svg)](https://crates.io/crates/azure_sdk_storage_account) [azure_sdk_storage_blob](https://github.com/MindFlavor/AzureSDKForRust/tree/master/azure_sdk_storage_blob) | [![docs](https://docs.rs/azure_sdk_storage_blob/badge.svg)](https://docs.rs/azure_sdk_storage_blob/0.43.2/azure_sdk_storage_blob) | [![Crate](https://img.shields.io/crates/v/azure_sdk_storage_blob.svg)](https://crates.io/crates/azure_sdk_storage_blob) | [![cratedown](https://img.shields.io/crates/d/azure_sdk_storage_blob.svg)](https://crates.io/crates/azure_sdk_storage_blob) | [![cratelastdown](https://img.shields.io/crates/dv/azure_sdk_storage_blob.svg)](https://crates.io/crates/azure_sdk_storage_blob) @@ -42,7 +42,7 @@ You can find examples in the [```examples```](https://github.com/MindFlavor/Azur ```rust #[macro_use] extern crate serde_derive; -// Using the prelude module of the Cosmos crate makes easier to use the Rust Azure SDK for Cosmos +// Using the prelude module of the CosmosDB crate makes easier to use the Rust Azure SDK for Cosmos // DB. use azure_sdk_core::prelude::*; use azure_sdk_cosmos::prelude::*; @@ -55,6 +55,7 @@ use std::error::Error; // work (you can create with this SDK too, check the examples folder for that task). #[derive(Serialize, Deserialize, Debug)] struct MySampleStruct<'a> { + id: Cow<'a, str>, a_string: Cow<'a, str>, a_number: u64, a_timestamp: i64, @@ -98,14 +99,12 @@ async fn main() -> Result<(), Box> { println!("Inserting 10 documents..."); for i in 0..10 { // define the document. - let document_to_insert = Document::new( - format!("unique_id{}", i), // this is the primary key, AKA "/id". - MySampleStruct { - a_string: Cow::Borrowed("Something here"), - a_number: i * 100, // this is the partition key - a_timestamp: chrono::Utc::now().timestamp(), - }, - ); + let document_to_insert = Document::new(MySampleStruct { + id: Cow::Owned(format!("unique_id{}", i)), + a_string: Cow::Borrowed("Something here"), + a_number: i * 100, // this is the partition key + a_timestamp: chrono::Utc::now().timestamp(), + }); // insert it! collection_client @@ -138,10 +137,12 @@ async fn main() -> Result<(), Box> { println!("\nQuerying documents"); let query_documents_response = collection_client .query_documents() - .with_query(&("SELECT * FROM A WHERE A.a_number < 600".into())) + .with_query(&("SELECT * FROM A WHERE A.a_number < 600".into())) // there are other ways to construct a query, this is the simplest. .with_query_cross_partition(true) // this will perform a cross partition query! notice how simple it is! - .execute::() - .await?; + .execute::() // This will make sure the result is our custom struct! + .await? + .into_documents() // queries can return Documents or Raw json (ie without etag, _rid, etc...). Since our query return docs we convert with this function. + .unwrap(); // we know in advance that the conversion to Document will not fail since we SELECT'ed * FROM table println!( "Received {} documents!", @@ -151,19 +152,22 @@ async fn main() -> Result<(), Box> { query_documents_response .results .iter() - .for_each(|document| println!("number ==> {}", document.result.a_number)); + .for_each(|document| { + println!("number ==> {}", document.result.a_number); + }); // TASK 4 for ref document in query_documents_response.results { + // From our query above we are sure to receive a Document. println!( "deleting id == {}, a_number == {}.", - document.document_attributes.id, document.result.a_number + document.result.id, document.result.a_number ); // to spice the delete a little we use optimistic concurreny collection_client .with_document( - &document.document_attributes.id, + &document.result.id, PartitionKeys::new().push(&document.result.a_number)?, ) .delete_document() diff --git a/azure_sdk_cosmos/Cargo.toml b/azure_sdk_cosmos/Cargo.toml index 68b97cb6a..dc860e9b4 100644 --- a/azure_sdk_cosmos/Cargo.toml +++ b/azure_sdk_cosmos/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "azure_sdk_cosmos" -version = "0.42.4" +version = "0.43.0" description = "Rust wrappers around Microsoft Azure REST APIs - Azure Cosmos DB crate" readme = "README.md" authors = ["Francesco Cogno ", "Max Gortman "] diff --git a/azure_sdk_cosmos/examples/attachments00.rs b/azure_sdk_cosmos/examples/attachments00.rs index ca1857cb7..22e20f7b0 100644 --- a/azure_sdk_cosmos/examples/attachments00.rs +++ b/azure_sdk_cosmos/examples/attachments00.rs @@ -13,6 +13,7 @@ extern crate serde_derive; // specified in the Document struct below. #[derive(Serialize, Deserialize, Clone, Debug)] struct MySampleStruct<'a> { + id: Cow<'a, str>, a_string: Cow<'a, str>, a_number: u64, a_timestamp: i64, @@ -41,20 +42,18 @@ async fn main() -> Result<(), Box> { let id = format!("unique_id{}", 100); - let doc = Document::new( - id.clone(), - MySampleStruct { - a_string: Cow::Borrowed("Something here"), - a_number: 100, - a_timestamp: chrono::Utc::now().timestamp(), - }, - ); + let doc = Document::new(MySampleStruct { + id: Cow::Borrowed(&id), + a_string: Cow::Borrowed("Something here"), + a_number: 100, + a_timestamp: chrono::Utc::now().timestamp(), + }); // let's add an entity. match client .create_document() .with_document(&doc) - .with_partition_keys(PartitionKeys::new().push(doc.document_attributes.id())?) + .with_partition_keys(PartitionKeys::new().push(&doc.document.id)?) .execute() .await { @@ -67,7 +66,7 @@ async fn main() -> Result<(), Box> { }; let mut partition_keys = PartitionKeys::new(); - partition_keys.push(doc.document_attributes.id())?; + partition_keys.push(&doc.document.id)?; let document_client = client.with_document(&id, &partition_keys); // list attachments @@ -79,6 +78,7 @@ async fn main() -> Result<(), Box> { let attachment_client = document_client.with_attachment(&"myref03"); let resp = attachment_client .create_reference() + .with_consistency_level((&ret).into()) .with_content_type("image/jpeg") .with_media( "https://cdn.pixabay.com/photo/2020/01/11/09/30/abstract-background-4756987__340.jpg", @@ -95,7 +95,7 @@ async fn main() -> Result<(), Box> { let attachment_client = document_client.with_attachment(&"myref03"); let resp = attachment_client .replace_reference() - .with_consistency_level(session_token.clone()) + .with_consistency_level(session_token) .with_content_type("image/jpeg") .with_media( "https://Adn.pixabay.com/photo/2020/01/11/09/30/abstract-background-4756987__340.jpg", @@ -107,7 +107,7 @@ async fn main() -> Result<(), Box> { println!("deleting"); let resp_delete = attachment_client .delete() - .with_consistency_level(session_token.clone()) + .with_consistency_level((&resp).into()) .execute() .await?; println!("delete attachment == {:#?}", resp_delete); @@ -117,6 +117,7 @@ async fn main() -> Result<(), Box> { let attachment_client = document_client.with_attachment(&"slug00"); let resp = attachment_client .create_slug() + .with_consistency_level((&resp_delete).into()) .with_content_type("text/plain") .with_body(b"FFFFF") .execute() @@ -127,7 +128,7 @@ async fn main() -> Result<(), Box> { println!("deleting"); let resp_delete = attachment_client .delete() - .with_consistency_level(session_token) + .with_consistency_level((&resp).into()) .execute() .await?; println!("delete attachment == {:#?}", resp_delete); diff --git a/azure_sdk_cosmos/examples/database00.rs b/azure_sdk_cosmos/examples/database00.rs index a5e835c98..d2e4b303d 100644 --- a/azure_sdk_cosmos/examples/database00.rs +++ b/azure_sdk_cosmos/examples/database00.rs @@ -40,6 +40,7 @@ async fn main() -> Result<(), Box> { let data = r#" { + "id": "my_id", "name": "John Tonno7", "age": 43, "phones": [ @@ -49,7 +50,7 @@ async fn main() -> Result<(), Box> { }"#; let v: Value = serde_json::from_str(data)?; - let document = Document::new("my_id".to_owned(), v); + let document = Document::new(v); let resp = collection_client .create_document() .with_document(&document) diff --git a/azure_sdk_cosmos/examples/document00.rs b/azure_sdk_cosmos/examples/document00.rs index 74dd4ea1e..574f289b7 100644 --- a/azure_sdk_cosmos/examples/document00.rs +++ b/azure_sdk_cosmos/examples/document00.rs @@ -10,6 +10,7 @@ use std::error::Error; #[derive(Serialize, Deserialize, Debug)] struct MySampleStruct<'a> { + id: Cow<'a, str>, a_string: Cow<'a, str>, a_number: u64, a_timestamp: i64, @@ -126,14 +127,12 @@ async fn main() -> Result<(), Box> { // Now that we have a database and a collection we can insert // data in them. Let's create a Document. The only constraint // is that we need an id and an arbitrary, Serializable type. - let doc = Document::new( - "unique_id100".to_owned(), - MySampleStruct { - a_string: Cow::Borrowed("Something here"), - a_number: 100, - a_timestamp: chrono::Utc::now().timestamp(), - }, - ); + let doc = Document::new(MySampleStruct { + id: Cow::Owned("unique_id100".to_owned()), + a_string: Cow::Borrowed("Something here"), + a_number: 100, + a_timestamp: chrono::Utc::now().timestamp(), + }); // Now we store the struct in Azure Cosmos DB. // Notice how easy it is! :) @@ -147,7 +146,7 @@ async fn main() -> Result<(), Box> { let create_document_response = collection_client .create_document() .with_document(&doc) - .with_partition_keys(&(&doc.document_attributes.id).into()) + .with_partition_keys(&(&doc.document.id).into()) .execute() .await?; println!( @@ -169,7 +168,7 @@ async fn main() -> Result<(), Box> { // Now we get the same document by id. let get_document_response = collection_client - .with_document(&doc, &(&doc.document_attributes.id).into()) + .with_document(&doc.document.id, &(&doc.document.id).into()) .get_document() .execute::() .await?; @@ -188,7 +187,8 @@ async fn main() -> Result<(), Box> { let replace_document_response = collection_client .replace_document() .with_document(&doc) - .with_partition_keys(&(&doc.document_attributes.id).into()) + .with_document_id(&doc.document.id) + .with_partition_keys(&(&doc.document.id).into()) .with_if_match_condition(IfMatchCondition::Match(&document.etag)) .execute() .await?; diff --git a/azure_sdk_cosmos/examples/document_entries00.rs b/azure_sdk_cosmos/examples/document_entries00.rs index 2e19525be..98506f8d8 100644 --- a/azure_sdk_cosmos/examples/document_entries00.rs +++ b/azure_sdk_cosmos/examples/document_entries00.rs @@ -16,6 +16,7 @@ extern crate serde_derive; // specified in the Document struct below. #[derive(Serialize, Deserialize, Clone, Debug)] struct MySampleStruct<'a> { + id: Cow<'a, str>, a_string: Cow<'a, str>, a_number: u64, a_timestamp: i64, @@ -43,20 +44,18 @@ async fn main() -> Result<(), Box> { let client = client.with_collection(&collection_name); for i in 0u64..5 { - let doc = Document::new( - format!("unique_id{}", i), - MySampleStruct { - a_string: Cow::Borrowed("Something here"), - a_number: i, - a_timestamp: chrono::Utc::now().timestamp(), - }, - ); + let doc = Document::new(MySampleStruct { + id: Cow::Owned(format!("unique_id{}", i)), + a_string: Cow::Borrowed("Something here"), + a_number: i, + a_timestamp: chrono::Utc::now().timestamp(), + }); // let's add an entity. client .create_document() .with_document(&doc) - .with_partition_keys(PartitionKeys::new().push(doc.document_attributes.id())?) + .with_partition_keys(PartitionKeys::new().push(&doc.document.id)?) .execute() .await?; } @@ -136,6 +135,7 @@ async fn main() -> Result<(), Box> { .replace_document() .with_document(&doc.document) .with_partition_keys(PartitionKeys::new().push(&id)?) + .with_document_id(&id) .with_consistency_level(ConsistencyLevel::from(&response)) .with_if_match_condition(IfMatchCondition::Match(&etag)) // use optimistic concurrency check .execute() diff --git a/azure_sdk_cosmos/examples/document_entries01.rs b/azure_sdk_cosmos/examples/document_entries01.rs index 86e6db15c..50abce1d8 100644 --- a/azure_sdk_cosmos/examples/document_entries01.rs +++ b/azure_sdk_cosmos/examples/document_entries01.rs @@ -6,6 +6,7 @@ extern crate serde_derive; #[derive(Serialize, Deserialize, Clone, Debug)] struct MySampleStruct<'a> { + id: Cow<'a, str>, a_string: Cow<'a, str>, a_number: u64, a_timestamp: i64, @@ -32,17 +33,15 @@ async fn main() -> Result<(), Box> { let client = client.with_database(&database_name); let client = client.with_collection(&collection_name); - let mut doc = Document::new( - format!("unique_id{}", 500), - MySampleStruct { - a_string: Cow::Borrowed("Something here"), - a_number: 600, - a_timestamp: chrono::Utc::now().timestamp(), - }, - ); + let mut doc = Document::new(MySampleStruct { + id: Cow::Owned(format!("unique_id{}", 500)), + a_string: Cow::Borrowed("Something here"), + a_number: 600, + a_timestamp: chrono::Utc::now().timestamp(), + }); let mut partition_keys = PartitionKeys::new(); - partition_keys.push(doc.document_attributes.id())?; + partition_keys.push(&doc.document.id)?; // let's add an entity. let create_document_response = client @@ -58,7 +57,7 @@ async fn main() -> Result<(), Box> { create_document_response ); - let document_client = client.with_document(&doc, &partition_keys); + let document_client = client.with_document(&doc.document.id, &partition_keys); let get_document_response = document_client .get_document() @@ -99,6 +98,7 @@ async fn main() -> Result<(), Box> { let replace_document_response = client .replace_document() .with_document(&doc) + .with_document_id(&doc.document.id) .with_partition_keys(&partition_keys) .execute() .await?; diff --git a/azure_sdk_cosmos/examples/query_document00.rs b/azure_sdk_cosmos/examples/query_document00.rs index 015513f66..db669346c 100644 --- a/azure_sdk_cosmos/examples/query_document00.rs +++ b/azure_sdk_cosmos/examples/query_document00.rs @@ -44,24 +44,25 @@ async fn main() -> Result<(), Box> { let client = client.with_collection(&collection_name); let query_obj = Query::new(&query); - let respo: QueryDocumentsResponse = client + + let respo: QueryDocumentsResponse = client .query_documents() .with_query(&query_obj) .with_query_cross_partition(true) - .with_parallelize_cross_partition_query(true) - .with_max_item_count(2) + .with_max_item_count(3) .execute() .await?; - println!("as items == {:?}", respo); + println!("as json == {:?}", respo); - let respo: QueryDocumentsResponse = client + let respo: QueryDocumentsResponse = client .query_documents() .with_query(&query_obj) .with_query_cross_partition(true) - .with_max_item_count(3) + .with_parallelize_cross_partition_query(true) + .with_max_item_count(2) .execute() .await?; - println!("as json == {:?}", respo); + println!("as items == {:?}", respo); //let ret = client // .query_documents( diff --git a/azure_sdk_cosmos/examples/readme.rs b/azure_sdk_cosmos/examples/readme.rs index c2f729442..8bd61d832 100644 --- a/azure_sdk_cosmos/examples/readme.rs +++ b/azure_sdk_cosmos/examples/readme.rs @@ -13,6 +13,7 @@ use std::error::Error; // work (you can create with this SDK too, check the examples folder for that task). #[derive(Serialize, Deserialize, Debug)] struct MySampleStruct<'a> { + id: Cow<'a, str>, a_string: Cow<'a, str>, a_number: u64, a_timestamp: i64, @@ -56,14 +57,12 @@ async fn main() -> Result<(), Box> { println!("Inserting 10 documents..."); for i in 0..10 { // define the document. - let document_to_insert = Document::new( - format!("unique_id{}", i), // this is the primary key, AKA "/id". - MySampleStruct { - a_string: Cow::Borrowed("Something here"), - a_number: i * 100, // this is the partition key - a_timestamp: chrono::Utc::now().timestamp(), - }, - ); + let document_to_insert = Document::new(MySampleStruct { + id: Cow::Owned(format!("unique_id{}", i)), + a_string: Cow::Borrowed("Something here"), + a_number: i * 100, // this is the partition key + a_timestamp: chrono::Utc::now().timestamp(), + }); // insert it! collection_client @@ -96,10 +95,12 @@ async fn main() -> Result<(), Box> { println!("\nQuerying documents"); let query_documents_response = collection_client .query_documents() - .with_query(&("SELECT * FROM A WHERE A.a_number < 600".into())) + .with_query(&("SELECT * FROM A WHERE A.a_number < 600".into())) // there are other ways to construct a query, this is the simplest. .with_query_cross_partition(true) // this will perform a cross partition query! notice how simple it is! - .execute::() - .await?; + .execute::() // This will make sure the result is our custom struct! + .await? + .into_documents() // queries can return Documents or Raw json (ie without etag, _rid, etc...). Since our query return docs we convert with this function. + .unwrap(); // we know in advance that the conversion to Document will not fail since we SELECT'ed * FROM table println!( "Received {} documents!", @@ -109,19 +110,22 @@ async fn main() -> Result<(), Box> { query_documents_response .results .iter() - .for_each(|document| println!("number ==> {}", document.result.a_number)); + .for_each(|document| { + println!("number ==> {}", document.result.a_number); + }); // TASK 4 for ref document in query_documents_response.results { + // From our query above we are sure to receive a Document. println!( "deleting id == {}, a_number == {}.", - document.document_attributes.id, document.result.a_number + document.result.id, document.result.a_number ); // to spice the delete a little we use optimistic concurreny collection_client .with_document( - &document.document_attributes.id, + &document.result.id, PartitionKeys::new().push(&document.result.a_number)?, ) .delete_document() diff --git a/azure_sdk_cosmos/examples/user_defined_function_00.rs b/azure_sdk_cosmos/examples/user_defined_function_00.rs new file mode 100644 index 000000000..934377182 --- /dev/null +++ b/azure_sdk_cosmos/examples/user_defined_function_00.rs @@ -0,0 +1,98 @@ +use azure_sdk_cosmos::prelude::*; +use futures::stream::StreamExt; +use std::error::Error; + +const FN_BODY: &str = r#" +function tax(income) { + if (income == undefined) + throw 'no input'; + if (income < 1000) + return income * 0.1; + else if (income < 10000) + return income * 0.2; + else + return income * 0.4; +}"#; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let database = std::env::args() + .nth(1) + .expect("please specify database name as first command line parameter"); + let collection = std::env::args() + .nth(2) + .expect("please specify collection name as second command line parameter"); + + let account = std::env::var("COSMOS_ACCOUNT").expect("Set env variable COSMOS_ACCOUNT first!"); + let master_key = + std::env::var("COSMOS_MASTER_KEY").expect("Set env variable COSMOS_MASTER_KEY first!"); + + let authorization_token = AuthorizationToken::new_master(&master_key)?; + + let client = ClientBuilder::new(account, authorization_token)?; + let database_client = client.with_database(&database); + let collection_client = database_client.with_collection(&collection); + let user_defined_function_client = collection_client.with_user_defined_function(&"test15"); + + let ret = user_defined_function_client + .create_user_defined_function() + .with_body("body") + .execute() + .await?; + println!("Creeate response object:\n{:#?}", ret); + + let stream = collection_client + .list_user_defined_functions() + .with_max_item_count(3) + .with_consistency_level((&ret).into()); + let mut stream = Box::pin(stream.stream()); + while let Some(ret) = stream.next().await { + let ret = ret.unwrap(); + println!( + "List loop received {} items. Object:\n{:#?}", + ret.item_count, ret + ); + } + + let ret = user_defined_function_client + .replace_user_defined_function() + .with_consistency_level((&ret).into()) + .with_body(FN_BODY) + .execute() + .await?; + println!("Replace response object:\n{:#?}", ret); + + let ret = collection_client + .query_documents() + .with_query(&"SELECT udf.test15(100)".into()) + .with_consistency_level((&ret).into()) + .with_max_item_count(2) + .execute::() + .await? + .into_raw(); + println!("Query response object:\n{:#?}", ret); + + // this code extracts the first object + let fn_return = &ret.results[0].as_object().unwrap(); + println!("fn_return == {:?}", fn_return); + // and from the first object get the first value as f64 + let value = fn_return + .into_iter() + .take(1) + .next() + .unwrap() + .1 + .as_f64() + .unwrap(); + println!("value == {:?}", value); + + let ret = user_defined_function_client + .delete_user_defined_function() + .with_consistency_level((&ret).into()) + .execute() + .await?; + + println!("Delete response object:\n{:#?}", ret); + + Ok(()) +} diff --git a/azure_sdk_cosmos/examples/user_permission_token.rs b/azure_sdk_cosmos/examples/user_permission_token.rs index 5a7057273..4de20bfde 100644 --- a/azure_sdk_cosmos/examples/user_permission_token.rs +++ b/azure_sdk_cosmos/examples/user_permission_token.rs @@ -92,16 +92,14 @@ async fn main() -> Result<(), Box> { // for this example to work. let data = r#" { + "id": "Gianluigi Bombatomica", "age": 43, "phones": [ "+39 1234567", "+39 2345678" ] }"#; - let document = Document::new( - "Gianluigi Bombatomica".to_owned(), - serde_json::from_str::(data)?, - ); + let document = Document::new(serde_json::from_str::(data)?); println!( "Trying to insert {:#?} into the collection with a read-only authorization_token.", document @@ -113,7 +111,7 @@ async fn main() -> Result<(), Box> { .create_document() .with_document(&document) .with_is_upsert(true) - .with_partition_keys(PartitionKeys::new().push(document.document_attributes.id())?) + .with_partition_keys(PartitionKeys::new().push("Gianluigi Bombatomica")?) .execute() .await { @@ -155,7 +153,7 @@ async fn main() -> Result<(), Box> { .create_document() .with_document(&document) .with_is_upsert(true) - .with_partition_keys(PartitionKeys::new().push(document.document_attributes.id())?) + .with_partition_keys(PartitionKeys::new().push("Gianluigi Bombatomica")?) .execute() .await?; println!( diff --git a/azure_sdk_cosmos/src/clients/client.rs b/azure_sdk_cosmos/src/clients/client.rs index 9d7e8599d..79b0ed145 100644 --- a/azure_sdk_cosmos/src/clients/client.rs +++ b/azure_sdk_cosmos/src/clients/client.rs @@ -32,6 +32,7 @@ pub(crate) enum ResourceType { Permissions, Attachments, PartitionKeyRanges, + UserDefinedFunctions, } pub trait CosmosUriBuilder { @@ -334,6 +335,7 @@ fn string_to_sign( ResourceType::Permissions => "permissions", ResourceType::Attachments => "attachments", ResourceType::PartitionKeyRanges => "pkranges", + ResourceType::UserDefinedFunctions => "udfs", }, resource_link, time.to_lowercase() @@ -350,6 +352,7 @@ fn generate_resource_link(u: &str) -> &str { "permissions", "attachments", "pkranges", + "udfs", ]; // store the element only if it does not end with dbs, colls or docs diff --git a/azure_sdk_cosmos/src/clients/collection_client.rs b/azure_sdk_cosmos/src/clients/collection_client.rs index f122b1803..361dd7812 100644 --- a/azure_sdk_cosmos/src/clients/collection_client.rs +++ b/azure_sdk_cosmos/src/clients/collection_client.rs @@ -1,11 +1,13 @@ use crate::clients::{ Client, CosmosUriBuilder, DatabaseClient, DocumentClient, ResourceType, StoredProcedureClient, + UserDefinedFunctionClient, }; use crate::collection::CollectionName; use crate::database::DatabaseName; use crate::document::DocumentName; use crate::requests; use crate::stored_procedure::StoredProcedureName; +use crate::user_defined_function::UserDefinedFunctionName; use crate::{CollectionBuilderTrait, CollectionTrait, DatabaseTrait, PartitionKeys}; use azure_sdk_core::No; use serde::Serialize; @@ -79,7 +81,7 @@ where requests::CreateDocumentBuilder::new(self) } - fn replace_document(&self) -> requests::ReplaceDocumentBuilder<'_, '_, T, CUB, No, No> + fn replace_document(&self) -> requests::ReplaceDocumentBuilder<'_, '_, T, CUB, No, No, No> where T: Serialize, { @@ -97,10 +99,23 @@ where StoredProcedureClient::new(&self, stored_procedure_name) } + fn with_user_defined_function<'c>( + &'c self, + user_defined_function_name: &'c dyn UserDefinedFunctionName, + ) -> UserDefinedFunctionClient<'c, CUB> { + UserDefinedFunctionClient::new(&self, user_defined_function_name) + } + fn list_stored_procedures(&self) -> requests::ListStoredProceduresBuilder<'_, CUB> { requests::ListStoredProceduresBuilder::new(self) } + fn list_user_defined_functions( + &self, + ) -> requests::ListUserDefinedFunctionsBuilder<'_, '_, CUB> { + requests::ListUserDefinedFunctionsBuilder::new(self) + } + fn get_partition_key_ranges(&self) -> requests::GetPartitionKeyRangesBuilder<'_, '_, CUB> { requests::GetPartitionKeyRangesBuilder::new(self) } diff --git a/azure_sdk_cosmos/src/clients/mod.rs b/azure_sdk_cosmos/src/clients/mod.rs index bd6c15911..2b3f6650e 100644 --- a/azure_sdk_cosmos/src/clients/mod.rs +++ b/azure_sdk_cosmos/src/clients/mod.rs @@ -6,6 +6,7 @@ mod document_client; mod permission_client; mod stored_procedure_client; mod user_client; +mod user_defined_function_client; pub use attachment_client::AttachmentClient; pub use client::*; pub use collection_client::CollectionClient; @@ -14,3 +15,4 @@ pub use document_client::DocumentClient; pub use permission_client::PermissionClient; pub use stored_procedure_client::StoredProcedureClient; pub use user_client::UserClient; +pub use user_defined_function_client::UserDefinedFunctionClient; diff --git a/azure_sdk_cosmos/src/clients/user_defined_function_client.rs b/azure_sdk_cosmos/src/clients/user_defined_function_client.rs new file mode 100644 index 000000000..acd2a9ec4 --- /dev/null +++ b/azure_sdk_cosmos/src/clients/user_defined_function_client.rs @@ -0,0 +1,108 @@ +use crate::clients::{Client, CollectionClient, CosmosUriBuilder, ResourceType}; +use crate::collection::CollectionName; +use crate::database::DatabaseName; +use crate::requests; +use crate::user_defined_function::UserDefinedFunctionName; +use crate::{CollectionTrait, UserDefinedFunctionBuilderTrait, UserDefinedFunctionTrait}; +use azure_sdk_core::No; + +#[derive(Debug, Clone)] +pub struct UserDefinedFunctionClient<'a, CUB> +where + CUB: CosmosUriBuilder, +{ + collection_client: &'a CollectionClient<'a, CUB>, + user_defined_function_name: &'a dyn UserDefinedFunctionName, +} + +impl<'a, CUB> UserDefinedFunctionClient<'a, CUB> +where + CUB: CosmosUriBuilder, +{ + pub(crate) fn new( + collection_client: &'a CollectionClient<'a, CUB>, + user_defined_function_name: &'a dyn UserDefinedFunctionName, + ) -> Self { + UserDefinedFunctionClient { + collection_client, + user_defined_function_name, + } + } + + pub(crate) fn main_client(&self) -> &Client { + self.collection_client.main_client() + } + + pub(crate) fn hyper_client( + &self, + ) -> &hyper::Client> { + self.main_client().hyper_client() + } +} + +impl<'a, CUB> UserDefinedFunctionTrait<'a, CUB> for UserDefinedFunctionClient<'a, CUB> +where + CUB: CosmosUriBuilder, +{ + fn database_name(&self) -> &'a dyn DatabaseName { + self.collection_client.database_name() + } + + fn collection_name(&self) -> &'a dyn CollectionName { + self.collection_client.collection_name() + } + + fn user_defined_function_name(&self) -> &'a dyn UserDefinedFunctionName { + self.user_defined_function_name + } + + fn create_user_defined_function( + &self, + ) -> requests::CreateOrReplaceUserDefinedFunctionBuilder<'_, CUB, No> { + requests::CreateOrReplaceUserDefinedFunctionBuilder::new(self, true) + } + + fn replace_user_defined_function( + &self, + ) -> requests::CreateOrReplaceUserDefinedFunctionBuilder<'_, CUB, No> { + requests::CreateOrReplaceUserDefinedFunctionBuilder::new(self, false) + } + + fn delete_user_defined_function(&self) -> requests::DeleteUserDefinedFunctionBuilder<'_, CUB> { + requests::DeleteUserDefinedFunctionBuilder::new(self) + } +} + +impl<'a, CUB> UserDefinedFunctionBuilderTrait<'a, CUB> for UserDefinedFunctionClient<'a, CUB> +where + CUB: CosmosUriBuilder, +{ + fn prepare_request( + &self, + method: hyper::Method, + specify_user_defined_function_name: bool, + ) -> http::request::Builder { + if specify_user_defined_function_name { + self.main_client().prepare_request( + &format!( + "dbs/{}/colls/{}/udfs/{}", + self.database_name().name(), + self.collection_name().name(), + self.user_defined_function_name().name() + ), + method, + ResourceType::UserDefinedFunctions, + ) + } else { + self.main_client().prepare_request( + &format!( + "dbs/{}/colls/{}/udfs", + self.database_name().name(), + self.collection_name().name(), + ), + method, + ResourceType::UserDefinedFunctions, + ) + } + } +} diff --git a/azure_sdk_cosmos/src/consistency_level.rs b/azure_sdk_cosmos/src/consistency_level.rs index 3050c63aa..0e2babad5 100644 --- a/azure_sdk_cosmos/src/consistency_level.rs +++ b/azure_sdk_cosmos/src/consistency_level.rs @@ -1,7 +1,10 @@ use crate::responses::{ CreateDocumentResponse, CreateReferenceAttachmentResponse, CreateSlugAttachmentResponse, - DeleteDocumentResponse, ExecuteStoredProcedureResponse, GetDocumentResponse, - ListDocumentsResponse, QueryDocumentsResponse, ReplaceDocumentResponse, + CreateUserDefinedFunctionResponse, DeleteAttachmentResponse, DeleteDocumentResponse, + DeleteUserDefinedFunctionResponse, ExecuteStoredProcedureResponse, GetAttachmentResponse, + GetDocumentResponse, ListAttachmentsResponse, ListDocumentsResponse, + ListUserDefinedFunctionsResponse, QueryDocumentsResponse, QueryDocumentsResponseDocuments, + QueryDocumentsResponseRaw, ReplaceDocumentResponse, ReplaceReferenceAttachmentResponse, }; use serde::de::DeserializeOwned; use std::borrow::Cow; @@ -28,41 +31,51 @@ impl<'a> ConsistencyLevel<'a> { } } -impl<'a> From<&'a CreateSlugAttachmentResponse> for ConsistencyLevel<'a> { - fn from(a: &'a CreateSlugAttachmentResponse) -> Self { - ConsistencyLevel::Session(Cow::from(&a.session_token)) - } -} - -impl<'a> From for ConsistencyLevel<'a> { - fn from(a: CreateSlugAttachmentResponse) -> Self { - ConsistencyLevel::Session(Cow::from(a.session_token)) - } -} - -impl<'a> From<&'a CreateReferenceAttachmentResponse> for ConsistencyLevel<'a> { - fn from(a: &'a CreateReferenceAttachmentResponse) -> Self { - ConsistencyLevel::Session(Cow::from(&a.session_token)) - } -} +macro_rules! implement_from { + ($response_type:ident) => { + impl<'a> From<&'a $response_type> for ConsistencyLevel<'a> { + fn from(a: &'a $response_type) -> Self { + ConsistencyLevel::Session(Cow::from(&a.session_token)) + } + } -impl<'a> From for ConsistencyLevel<'a> { - fn from(a: CreateReferenceAttachmentResponse) -> Self { - ConsistencyLevel::Session(Cow::from(a.session_token)) - } -} + impl<'a> From<$response_type> for ConsistencyLevel<'a> { + fn from(a: $response_type) -> Self { + ConsistencyLevel::Session(Cow::from(a.session_token)) + } + } + }; + ($response_type:ident, $generic:tt) => { + impl<'a, $generic> From<&'a $response_type<$generic>> for ConsistencyLevel<'a> { + fn from(a: &'a $response_type<$generic>) -> Self { + ConsistencyLevel::Session(Cow::from(&a.session_token)) + } + } -impl<'a, T> From<&'a ListDocumentsResponse> for ConsistencyLevel<'a> { - fn from(list_documents_response: &'a ListDocumentsResponse) -> Self { - ConsistencyLevel::Session(Cow::from(&list_documents_response.session_token)) - } + impl<'a, $generic> From<$response_type<$generic>> for ConsistencyLevel<'a> { + fn from(a: $response_type<$generic>) -> Self { + ConsistencyLevel::Session(Cow::from(a.session_token)) + } + } + }; } -impl<'a, T> From<&'a QueryDocumentsResponse> for ConsistencyLevel<'a> { - fn from(query_documents_response: &'a QueryDocumentsResponse) -> Self { - ConsistencyLevel::Session(Cow::from(&query_documents_response.session_token)) - } -} +implement_from!(CreateSlugAttachmentResponse); +implement_from!(DeleteAttachmentResponse); +implement_from!(ReplaceReferenceAttachmentResponse); +implement_from!(CreateReferenceAttachmentResponse); +implement_from!(ListAttachmentsResponse); +implement_from!(GetAttachmentResponse); +implement_from!(CreateDocumentResponse); +implement_from!(ReplaceDocumentResponse); +implement_from!(DeleteDocumentResponse); +implement_from!(CreateUserDefinedFunctionResponse); +implement_from!(DeleteUserDefinedFunctionResponse); +implement_from!(ListUserDefinedFunctionsResponse); +implement_from!(ListDocumentsResponse, T); +implement_from!(QueryDocumentsResponse, T); +implement_from!(QueryDocumentsResponseRaw, T); +implement_from!(QueryDocumentsResponseDocuments, T); impl<'a, T> From<&'a GetDocumentResponse> for ConsistencyLevel<'a> { fn from(get_document_response: &'a GetDocumentResponse) -> Self { @@ -77,30 +90,6 @@ impl<'a, T> From<&'a GetDocumentResponse> for ConsistencyLevel<'a> { } } -impl<'a> From<&'a CreateDocumentResponse> for ConsistencyLevel<'a> { - fn from(create_document_response: &'a CreateDocumentResponse) -> Self { - ConsistencyLevel::Session(Cow::from(&create_document_response.session_token)) - } -} - -impl<'a> From for ConsistencyLevel<'a> { - fn from(create_document_response: CreateDocumentResponse) -> Self { - ConsistencyLevel::Session(Cow::from(create_document_response.session_token)) - } -} - -impl<'a> From<&'a ReplaceDocumentResponse> for ConsistencyLevel<'a> { - fn from(replace_document_response: &'a ReplaceDocumentResponse) -> Self { - ConsistencyLevel::Session(Cow::from(&replace_document_response.session_token)) - } -} - -impl<'a> From<&'a DeleteDocumentResponse> for ConsistencyLevel<'a> { - fn from(delete_document_response: &'a DeleteDocumentResponse) -> Self { - ConsistencyLevel::Session(Cow::from(&delete_document_response.session_token)) - } -} - impl<'a, T> From<&'a ExecuteStoredProcedureResponse> for ConsistencyLevel<'a> where T: DeserializeOwned, diff --git a/azure_sdk_cosmos/src/document.rs b/azure_sdk_cosmos/src/document.rs index 5780c1036..7fd187405 100644 --- a/azure_sdk_cosmos/src/document.rs +++ b/azure_sdk_cosmos/src/document.rs @@ -16,14 +16,8 @@ pub struct Document { } impl Document { - #[inline] - pub fn id(&self) -> &str { - self.document_attributes.id() - } - - pub fn new(id: String, t: T) -> Self { - let mut document_attributes = DocumentAttributes::default(); - document_attributes.id = id; + pub fn new(t: T) -> Self { + let document_attributes = DocumentAttributes::default(); Self { document_attributes, @@ -32,22 +26,19 @@ impl Document { } } -impl DocumentName for Document -where - T: std::fmt::Debug, -{ +impl DocumentName for &str { fn name(&self) -> &str { - self.id() + self } } -impl DocumentName for &str { +impl DocumentName for String { fn name(&self) -> &str { - self + self.as_ref() } } -impl DocumentName for String { +impl DocumentName for std::borrow::Cow<'_, str> { fn name(&self) -> &str { self.as_ref() } diff --git a/azure_sdk_cosmos/src/document_attributes.rs b/azure_sdk_cosmos/src/document_attributes.rs index f3172f583..92efd6158 100644 --- a/azure_sdk_cosmos/src/document_attributes.rs +++ b/azure_sdk_cosmos/src/document_attributes.rs @@ -4,7 +4,6 @@ use http::HeaderMap; #[derive(Default, Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct DocumentAttributes { - pub id: String, #[serde(rename = "_rid")] pub rid: String, #[serde(rename = "_ts")] @@ -18,10 +17,6 @@ pub struct DocumentAttributes { } impl DocumentAttributes { - pub fn id(&self) -> &str { - &self.id - } - pub fn rid(&self) -> &str { &self.rid } @@ -42,13 +37,6 @@ impl DocumentAttributes { &self.attachments } - pub fn set_id(&mut self, value: T) - where - T: Into, - { - self.id = value.into(); - } - pub fn set_rid(&mut self, value: T) where T: Into, @@ -103,7 +91,6 @@ mod tests { use super::*; let mut a = DocumentAttributes { - id: "id".to_owned(), rid: "rid".to_owned(), ts: 100, _self: "_self".to_owned(), @@ -111,7 +98,6 @@ mod tests { attachments: "attachments".to_owned(), }; - a.set_id("new_id"); a.set_attachments("new_attachments".to_owned()); } } diff --git a/azure_sdk_cosmos/src/errors.rs b/azure_sdk_cosmos/src/errors.rs index cf207eca2..e92be3a93 100644 --- a/azure_sdk_cosmos/src/errors.rs +++ b/azure_sdk_cosmos/src/errors.rs @@ -32,6 +32,12 @@ pub enum TokenParsingError { }, } +#[derive(Debug, Fail)] +pub enum ConversionToDocumentError { + #[fail(display = "Conversion to document failed because at lease one element is raw.")] + RawElementFound {}, +} + #[inline] pub(crate) fn item_or_error<'a>( s: &'a str, diff --git a/azure_sdk_cosmos/src/from_headers.rs b/azure_sdk_cosmos/src/from_headers.rs index df5488d36..8fd8a1cdc 100644 --- a/azure_sdk_cosmos/src/from_headers.rs +++ b/azure_sdk_cosmos/src/from_headers.rs @@ -150,14 +150,23 @@ pub(crate) fn collection_partition_index_from_headers( .parse()?) } -pub(crate) fn indexing_directive_from_headers( +//pub(crate) fn indexing_directive_from_headers( +// headers: &HeaderMap, +//) -> Result { +// Ok(headers +// .get(HEADER_INDEXING_DIRECTIVE) +// .ok_or_else(|| AzureError::HeaderNotFound(HEADER_INDEXING_DIRECTIVE.to_owned()))? +// .to_str()? +// .parse()?) +//} + +pub(crate) fn indexing_directive_from_headers_optional( headers: &HeaderMap, -) -> Result { - Ok(headers - .get(HEADER_INDEXING_DIRECTIVE) - .ok_or_else(|| AzureError::HeaderNotFound(HEADER_INDEXING_DIRECTIVE.to_owned()))? - .to_str()? - .parse()?) +) -> Result, AzureError> { + match headers.get(HEADER_INDEXING_DIRECTIVE) { + Some(header) => Ok(Some(header.to_str()?.parse()?)), + None => Ok(None), + } } pub(crate) fn collection_service_index_from_headers( diff --git a/azure_sdk_cosmos/src/lib.rs b/azure_sdk_cosmos/src/lib.rs index 0217c1bbd..87ebb91a0 100644 --- a/azure_sdk_cosmos/src/lib.rs +++ b/azure_sdk_cosmos/src/lib.rs @@ -34,6 +34,7 @@ pub mod responses; pub mod stored_procedure; mod to_json_vector; mod user; +mod user_defined_function; pub use self::attachment::Attachment; pub use self::authorization_token::*; @@ -54,7 +55,7 @@ pub use self::resource::Resource; pub use self::resource_quota::ResourceQuota; use crate::clients::{ AttachmentClient, Client, CollectionClient, CosmosUriBuilder, DatabaseClient, DocumentClient, - PermissionClient, StoredProcedureClient, UserClient, + PermissionClient, StoredProcedureClient, UserClient, UserDefinedFunctionClient, }; use crate::collection::Collection; use crate::collection::CollectionName; @@ -62,6 +63,7 @@ use crate::headers::*; pub use crate::partition_keys::PartitionKeys; use crate::stored_procedure::{Parameters, StoredProcedureName}; pub use crate::user::{User, UserName}; +pub use crate::user_defined_function::UserDefinedFunctionName; use attachment::AttachmentName; use azure_sdk_core::No; use http::request::Builder; @@ -346,7 +348,16 @@ pub trait StoredProcedureBodyRequired<'a> { pub trait StoredProcedureBodySupport<'a> { type O; - fn with_body(self, partition_keys: &'a str) -> Self::O; + fn with_body(self, body: &'a str) -> Self::O; +} + +pub trait UserDefinedFunctionBodyRequired<'a> { + fn body(&self) -> &'a str; +} + +pub trait UserDefinedFunctionBodySupport<'a> { + type O; + fn with_body(self, body: &'a str) -> Self::O; } pub trait ExpirySecondsOption { @@ -400,6 +411,13 @@ where fn stored_procedure_client(&self) -> &'a StoredProcedureClient<'a, CUB>; } +pub trait UserDefinedFunctionClientRequired<'a, CUB> +where + CUB: CosmosUriBuilder, +{ + fn user_defined_function_client(&self) -> &'a UserDefinedFunctionClient<'a, CUB>; +} + pub trait UserClientRequired<'a, CUB> where CUB: CosmosUriBuilder, @@ -602,7 +620,7 @@ where fn create_document(&self) -> requests::CreateDocumentBuilder<'_, '_, T, CUB, No, No> where T: Serialize; - fn replace_document(&self) -> requests::ReplaceDocumentBuilder<'_, '_, T, CUB, No, No> + fn replace_document(&self) -> requests::ReplaceDocumentBuilder<'_, '_, T, CUB, No, No, No> where T: Serialize; fn query_documents(&self) -> requests::QueryDocumentsBuilder<'_, '_, CUB, No>; @@ -610,7 +628,13 @@ where &'c self, stored_procedure_name: &'c dyn StoredProcedureName, ) -> StoredProcedureClient<'c, CUB>; + fn with_user_defined_function<'c>( + &'c self, + user_defined_function_name: &'c dyn UserDefinedFunctionName, + ) -> UserDefinedFunctionClient<'c, CUB>; fn list_stored_procedures(&self) -> requests::ListStoredProceduresBuilder<'_, CUB>; + fn list_user_defined_functions(&self) + -> requests::ListUserDefinedFunctionsBuilder<'_, '_, CUB>; fn get_partition_key_ranges(&self) -> requests::GetPartitionKeyRangesBuilder<'_, '_, CUB>; fn with_document<'c>( &'c self, @@ -671,6 +695,34 @@ where fn prepare_request(&self, method: hyper::Method) -> http::request::Builder; } +pub trait UserDefinedFunctionTrait<'a, CUB> +where + CUB: CosmosUriBuilder, +{ + fn database_name(&self) -> &'a dyn DatabaseName; + fn collection_name(&self) -> &'a dyn CollectionName; + fn user_defined_function_name(&self) -> &'a dyn UserDefinedFunctionName; + fn create_user_defined_function( + &self, + ) -> requests::CreateOrReplaceUserDefinedFunctionBuilder<'_, CUB, No>; + fn replace_user_defined_function( + &self, + ) -> requests::CreateOrReplaceUserDefinedFunctionBuilder<'_, CUB, No>; + fn delete_user_defined_function(&self) -> requests::DeleteUserDefinedFunctionBuilder<'_, CUB>; +} + +pub(crate) trait UserDefinedFunctionBuilderTrait<'a, CUB>: + UserDefinedFunctionTrait<'a, CUB> +where + CUB: CosmosUriBuilder, +{ + fn prepare_request( + &self, + method: hyper::Method, + specify_user_defined_function_name: bool, + ) -> http::request::Builder; +} + pub trait AttachmentTrait<'a, CUB> where CUB: CosmosUriBuilder, diff --git a/azure_sdk_cosmos/src/prelude.rs b/azure_sdk_cosmos/src/prelude.rs index bf5b5f34a..9bf960f67 100644 --- a/azure_sdk_cosmos/src/prelude.rs +++ b/azure_sdk_cosmos/src/prelude.rs @@ -5,6 +5,7 @@ pub use crate::collection::{ pub use crate::database::DatabaseName; pub use crate::document::Document; pub use crate::query::Query; +pub use crate::responses::{QueryDocumentsResponse, QueryDocumentsResponseRaw, QueryResult}; pub use crate::{ AIMOption, AIMSupport, AllowTentativeWritesOption, AllowTentativeWritesSupport, AttachmentTrait, AuthorizationToken, ClientRequired, CollectionClientRequired, @@ -23,6 +24,7 @@ pub use crate::{ PermissionClientRequired, PermissionModeRequired, PermissionModeSupport, PermissionTrait, QueryCrossPartitionOption, QueryCrossPartitionSupport, QueryRequired, QuerySupport, StoredProcedureBodyRequired, StoredProcedureBodySupport, StoredProcedureNameRequired, - StoredProcedureNameSupport, StoredProcedureTrait, UserClientRequired, UserName, - UserNameRequired, UserNameSupport, UserTrait, + StoredProcedureNameSupport, StoredProcedureTrait, UserClientRequired, + UserDefinedFunctionBodyRequired, UserDefinedFunctionBodySupport, UserDefinedFunctionTrait, + UserName, UserNameRequired, UserNameSupport, UserTrait, }; diff --git a/azure_sdk_cosmos/src/requests/create_or_replace_user_defined_function_builder.json b/azure_sdk_cosmos/src/requests/create_or_replace_user_defined_function_builder.json new file mode 100644 index 000000000..30a9dc86d --- /dev/null +++ b/azure_sdk_cosmos/src/requests/create_or_replace_user_defined_function_builder.json @@ -0,0 +1,64 @@ +{ + "name": "CreateOrReplaceUserDefinedFunctionBuilder", + "derive": "Debug, Clone", + "uses": [ + "crate::clients::{CosmosUriBuilder}", + "crate::prelude::*", + "crate::UserDefinedFunctionClient", + "crate::UserDefinedFunctionClientRequired", + "crate::{UserDefinedFunctionBuilderTrait, UserDefinedFunctionTrait}", + "azure_sdk_core::errors::{check_status_extract_headers_and_body, AzureError}", + "azure_sdk_core::prelude::*", + "azure_sdk_core::{Yes,No,ToAssign}", + "std::marker::PhantomData", + "hyper::StatusCode", + "crate::responses::CreateUserDefinedFunctionResponse", + "std::convert::TryInto" + ], + "inline": true, + "extra_types": [ "'a", "CUB" ], + "extra_wheres": ["CUB: CosmosUriBuilder" ], + "constructor_fields": [ + { + "name": "user_defined_function_client", + "field_type": "&'a UserDefinedFunctionClient<'a, CUB>", + "trait_get": "UserDefinedFunctionClientRequired<'a, CUB>" + }, + { + "name": "is_create", + "field_type": "bool" + } + ], + "fields": [ + { + "name": "body", + "field_type": "&'a str", + "builder_type": "BodySet", + "optional": false, + "trait_get": "UserDefinedFunctionBodyRequired<'a>", + "trait_set": "UserDefinedFunctionBodySupport<'a>" + }, + { + "name": "user_agent", + "field_type": "&'a str", + "optional": true, + "trait_get": "UserAgentOption<'a>", + "trait_set": "UserAgentSupport<'a>" + }, + { + "name": "activity_id", + "field_type": "&'a str", + "optional": true, + "trait_get": "ActivityIdOption<'a>", + "trait_set": "ActivityIdSupport<'a>" + }, + { + "name": "consistency_level", + "field_type": "ConsistencyLevel<'a>", + "optional": true, + "trait_get": "ConsistencyLevelOption<'a>", + "trait_set": "ConsistencyLevelSupport<'a>", + "get_via_clone": true + } + ] +} diff --git a/azure_sdk_cosmos/src/requests/create_or_replace_user_defined_function_builder.rs b/azure_sdk_cosmos/src/requests/create_or_replace_user_defined_function_builder.rs new file mode 100644 index 000000000..562f32480 --- /dev/null +++ b/azure_sdk_cosmos/src/requests/create_or_replace_user_defined_function_builder.rs @@ -0,0 +1,266 @@ +use crate::clients::CosmosUriBuilder; +use crate::prelude::*; +use crate::responses::CreateUserDefinedFunctionResponse; +use crate::UserDefinedFunctionClient; +use crate::UserDefinedFunctionClientRequired; +use crate::{UserDefinedFunctionBuilderTrait, UserDefinedFunctionTrait}; +use azure_sdk_core::errors::{check_status_extract_headers_and_body, AzureError}; +use azure_sdk_core::prelude::*; +use azure_sdk_core::{No, ToAssign, Yes}; +use hyper::StatusCode; +use std::convert::TryInto; +use std::marker::PhantomData; + +#[derive(Debug, Clone)] +pub struct CreateOrReplaceUserDefinedFunctionBuilder<'a, CUB, BodySet> +where + BodySet: ToAssign, + CUB: CosmosUriBuilder, +{ + user_defined_function_client: &'a UserDefinedFunctionClient<'a, CUB>, + is_create: bool, + p_body: PhantomData, + body: Option<&'a str>, + user_agent: Option<&'a str>, + activity_id: Option<&'a str>, + consistency_level: Option>, +} + +impl<'a, CUB> CreateOrReplaceUserDefinedFunctionBuilder<'a, CUB, No> +where + CUB: CosmosUriBuilder, +{ + #[inline] + pub(crate) fn new( + user_defined_function_client: &'a UserDefinedFunctionClient<'a, CUB>, + is_create: bool, + ) -> CreateOrReplaceUserDefinedFunctionBuilder<'a, CUB, No> { + CreateOrReplaceUserDefinedFunctionBuilder { + user_defined_function_client, + is_create, + p_body: PhantomData {}, + body: None, + user_agent: None, + activity_id: None, + consistency_level: None, + } + } +} + +impl<'a, CUB, BodySet> UserDefinedFunctionClientRequired<'a, CUB> + for CreateOrReplaceUserDefinedFunctionBuilder<'a, CUB, BodySet> +where + BodySet: ToAssign, + CUB: CosmosUriBuilder, +{ + #[inline] + fn user_defined_function_client(&self) -> &'a UserDefinedFunctionClient<'a, CUB> { + self.user_defined_function_client + } +} + +//set mandatory no traits methods +impl<'a, CUB> UserDefinedFunctionBodyRequired<'a> + for CreateOrReplaceUserDefinedFunctionBuilder<'a, CUB, Yes> +where + CUB: CosmosUriBuilder, +{ + #[inline] + fn body(&self) -> &'a str { + self.body.unwrap() + } +} + +impl<'a, CUB, BodySet> UserAgentOption<'a> + for CreateOrReplaceUserDefinedFunctionBuilder<'a, CUB, BodySet> +where + BodySet: ToAssign, + CUB: CosmosUriBuilder, +{ + #[inline] + fn user_agent(&self) -> Option<&'a str> { + self.user_agent + } +} + +impl<'a, CUB, BodySet> ActivityIdOption<'a> + for CreateOrReplaceUserDefinedFunctionBuilder<'a, CUB, BodySet> +where + BodySet: ToAssign, + CUB: CosmosUriBuilder, +{ + #[inline] + fn activity_id(&self) -> Option<&'a str> { + self.activity_id + } +} + +impl<'a, CUB, BodySet> ConsistencyLevelOption<'a> + for CreateOrReplaceUserDefinedFunctionBuilder<'a, CUB, BodySet> +where + BodySet: ToAssign, + CUB: CosmosUriBuilder, +{ + #[inline] + fn consistency_level(&self) -> Option> { + self.consistency_level.clone() + } +} + +impl<'a, CUB> UserDefinedFunctionBodySupport<'a> + for CreateOrReplaceUserDefinedFunctionBuilder<'a, CUB, No> +where + CUB: CosmosUriBuilder, +{ + type O = CreateOrReplaceUserDefinedFunctionBuilder<'a, CUB, Yes>; + + #[inline] + fn with_body(self, body: &'a str) -> Self::O { + CreateOrReplaceUserDefinedFunctionBuilder { + user_defined_function_client: self.user_defined_function_client, + is_create: self.is_create, + p_body: PhantomData {}, + body: Some(body), + user_agent: self.user_agent, + activity_id: self.activity_id, + consistency_level: self.consistency_level, + } + } +} + +impl<'a, CUB, BodySet> UserAgentSupport<'a> + for CreateOrReplaceUserDefinedFunctionBuilder<'a, CUB, BodySet> +where + BodySet: ToAssign, + CUB: CosmosUriBuilder, +{ + type O = CreateOrReplaceUserDefinedFunctionBuilder<'a, CUB, BodySet>; + + #[inline] + fn with_user_agent(self, user_agent: &'a str) -> Self::O { + CreateOrReplaceUserDefinedFunctionBuilder { + user_defined_function_client: self.user_defined_function_client, + is_create: self.is_create, + p_body: PhantomData {}, + body: self.body, + user_agent: Some(user_agent), + activity_id: self.activity_id, + consistency_level: self.consistency_level, + } + } +} + +impl<'a, CUB, BodySet> ActivityIdSupport<'a> + for CreateOrReplaceUserDefinedFunctionBuilder<'a, CUB, BodySet> +where + BodySet: ToAssign, + CUB: CosmosUriBuilder, +{ + type O = CreateOrReplaceUserDefinedFunctionBuilder<'a, CUB, BodySet>; + + #[inline] + fn with_activity_id(self, activity_id: &'a str) -> Self::O { + CreateOrReplaceUserDefinedFunctionBuilder { + user_defined_function_client: self.user_defined_function_client, + is_create: self.is_create, + p_body: PhantomData {}, + body: self.body, + user_agent: self.user_agent, + activity_id: Some(activity_id), + consistency_level: self.consistency_level, + } + } +} + +impl<'a, CUB, BodySet> ConsistencyLevelSupport<'a> + for CreateOrReplaceUserDefinedFunctionBuilder<'a, CUB, BodySet> +where + BodySet: ToAssign, + CUB: CosmosUriBuilder, +{ + type O = CreateOrReplaceUserDefinedFunctionBuilder<'a, CUB, BodySet>; + + #[inline] + fn with_consistency_level(self, consistency_level: ConsistencyLevel<'a>) -> Self::O { + CreateOrReplaceUserDefinedFunctionBuilder { + user_defined_function_client: self.user_defined_function_client, + is_create: self.is_create, + p_body: PhantomData {}, + body: self.body, + user_agent: self.user_agent, + activity_id: self.activity_id, + consistency_level: Some(consistency_level), + } + } +} + +// methods callable regardless +impl<'a, CUB, BodySet> CreateOrReplaceUserDefinedFunctionBuilder<'a, CUB, BodySet> +where + BodySet: ToAssign, + CUB: CosmosUriBuilder, +{ + #[inline] + pub fn is_create(&self) -> bool { + self.is_create + } +} + +// methods callable only when every mandatory field has been filled +impl<'a, CUB> CreateOrReplaceUserDefinedFunctionBuilder<'a, CUB, Yes> +where + CUB: CosmosUriBuilder, +{ + pub async fn execute(&self) -> Result { + trace!("CreateOrReplaceUserDefinedFunctionBuilder::execute called"); + + // Create is POST with no name in the URL. Expected return is CREATED. + // See https://docs.microsoft.com/en-us/rest/api/cosmos-db/create-a-user-defined-function + // Replace is PUT with name appended to the URL. Expected return is OK. + // See: https://docs.microsoft.com/en-us/rest/api/cosmos-db/replace-a-user-defined-function + let req = match self.is_create { + true => self + .user_defined_function_client + .prepare_request(hyper::Method::POST, false), + false => self + .user_defined_function_client + .prepare_request(hyper::Method::PUT, true), + }; + + // add trait headers + let req = UserAgentOption::add_header(self, req); + let req = ActivityIdOption::add_header(self, req); + let req = ConsistencyLevelOption::add_header(self, req); + + let req = req.header(http::header::CONTENT_TYPE, "application/json"); + + #[derive(Debug, Serialize)] + struct Request<'a> { + body: &'a str, + id: &'a str, + } + let request = Request { + body: self.body(), + id: self + .user_defined_function_client + .user_defined_function_name() + .name(), + }; + + let request = serde_json::to_string(&request)?; + let request = req.body(hyper::Body::from(request))?; + + let (headers, body) = check_status_extract_headers_and_body( + self.user_defined_function_client() + .hyper_client() + .request(request), + match self.is_create { + true => StatusCode::CREATED, + false => StatusCode::OK, + }, + ) + .await?; + + Ok((&headers, &body as &[u8]).try_into()?) + } +} diff --git a/azure_sdk_cosmos/src/requests/delete_user_defined_function_builder.json b/azure_sdk_cosmos/src/requests/delete_user_defined_function_builder.json new file mode 100644 index 000000000..116f5be70 --- /dev/null +++ b/azure_sdk_cosmos/src/requests/delete_user_defined_function_builder.json @@ -0,0 +1,50 @@ +{ + "name": "DeleteUserDefinedFunctionBuilder", + "derive": "Debug, Clone", + "uses": [ + "crate::clients::{CosmosUriBuilder}", + "crate::prelude::*", + "crate::UserDefinedFunctionClient", + "crate::UserDefinedFunctionClientRequired", + "crate::{UserDefinedFunctionBuilderTrait}", + "azure_sdk_core::errors::{check_status_extract_headers_and_body, AzureError}", + "azure_sdk_core::prelude::*", + "hyper::StatusCode", + "crate::responses::DeleteUserDefinedFunctionResponse", + "std::convert::TryInto" + ], + "inline": true, + "extra_types": [ "'a", "CUB" ], + "extra_wheres": ["CUB: CosmosUriBuilder" ], + "constructor_fields": [ + { + "name": "user_defined_function_client", + "field_type": "&'a UserDefinedFunctionClient<'a, CUB>", + "trait_get": "UserDefinedFunctionClientRequired<'a, CUB>" + } + ], + "fields": [ + { + "name": "user_agent", + "field_type": "&'a str", + "optional": true, + "trait_get": "UserAgentOption<'a>", + "trait_set": "UserAgentSupport<'a>" + }, + { + "name": "activity_id", + "field_type": "&'a str", + "optional": true, + "trait_get": "ActivityIdOption<'a>", + "trait_set": "ActivityIdSupport<'a>" + }, + { + "name": "consistency_level", + "field_type": "ConsistencyLevel<'a>", + "optional": true, + "trait_get": "ConsistencyLevelOption<'a>", + "trait_set": "ConsistencyLevelSupport<'a>", + "get_via_clone": true + } + ] +} diff --git a/azure_sdk_cosmos/src/requests/delete_user_defined_function_builder.rs b/azure_sdk_cosmos/src/requests/delete_user_defined_function_builder.rs new file mode 100644 index 000000000..57d74c97e --- /dev/null +++ b/azure_sdk_cosmos/src/requests/delete_user_defined_function_builder.rs @@ -0,0 +1,164 @@ +use crate::clients::CosmosUriBuilder; +use crate::prelude::*; +use crate::responses::DeleteUserDefinedFunctionResponse; +use crate::UserDefinedFunctionBuilderTrait; +use crate::UserDefinedFunctionClient; +use crate::UserDefinedFunctionClientRequired; +use azure_sdk_core::errors::{check_status_extract_headers_and_body, AzureError}; +use azure_sdk_core::prelude::*; +use hyper::StatusCode; +use std::convert::TryInto; + +#[derive(Debug, Clone)] +pub struct DeleteUserDefinedFunctionBuilder<'a, CUB> +where + CUB: CosmosUriBuilder, +{ + user_defined_function_client: &'a UserDefinedFunctionClient<'a, CUB>, + user_agent: Option<&'a str>, + activity_id: Option<&'a str>, + consistency_level: Option>, +} + +impl<'a, CUB> DeleteUserDefinedFunctionBuilder<'a, CUB> +where + CUB: CosmosUriBuilder, +{ + #[inline] + pub(crate) fn new( + user_defined_function_client: &'a UserDefinedFunctionClient<'a, CUB>, + ) -> DeleteUserDefinedFunctionBuilder<'a, CUB> { + DeleteUserDefinedFunctionBuilder { + user_defined_function_client, + user_agent: None, + activity_id: None, + consistency_level: None, + } + } +} + +impl<'a, CUB> UserDefinedFunctionClientRequired<'a, CUB> + for DeleteUserDefinedFunctionBuilder<'a, CUB> +where + CUB: CosmosUriBuilder, +{ + #[inline] + fn user_defined_function_client(&self) -> &'a UserDefinedFunctionClient<'a, CUB> { + self.user_defined_function_client + } +} + +//get mandatory no traits methods + +//set mandatory no traits methods +impl<'a, CUB> UserAgentOption<'a> for DeleteUserDefinedFunctionBuilder<'a, CUB> +where + CUB: CosmosUriBuilder, +{ + #[inline] + fn user_agent(&self) -> Option<&'a str> { + self.user_agent + } +} + +impl<'a, CUB> ActivityIdOption<'a> for DeleteUserDefinedFunctionBuilder<'a, CUB> +where + CUB: CosmosUriBuilder, +{ + #[inline] + fn activity_id(&self) -> Option<&'a str> { + self.activity_id + } +} + +impl<'a, CUB> ConsistencyLevelOption<'a> for DeleteUserDefinedFunctionBuilder<'a, CUB> +where + CUB: CosmosUriBuilder, +{ + #[inline] + fn consistency_level(&self) -> Option> { + self.consistency_level.clone() + } +} + +impl<'a, CUB> UserAgentSupport<'a> for DeleteUserDefinedFunctionBuilder<'a, CUB> +where + CUB: CosmosUriBuilder, +{ + type O = DeleteUserDefinedFunctionBuilder<'a, CUB>; + + #[inline] + fn with_user_agent(self, user_agent: &'a str) -> Self::O { + DeleteUserDefinedFunctionBuilder { + user_defined_function_client: self.user_defined_function_client, + user_agent: Some(user_agent), + activity_id: self.activity_id, + consistency_level: self.consistency_level, + } + } +} + +impl<'a, CUB> ActivityIdSupport<'a> for DeleteUserDefinedFunctionBuilder<'a, CUB> +where + CUB: CosmosUriBuilder, +{ + type O = DeleteUserDefinedFunctionBuilder<'a, CUB>; + + #[inline] + fn with_activity_id(self, activity_id: &'a str) -> Self::O { + DeleteUserDefinedFunctionBuilder { + user_defined_function_client: self.user_defined_function_client, + user_agent: self.user_agent, + activity_id: Some(activity_id), + consistency_level: self.consistency_level, + } + } +} + +impl<'a, CUB> ConsistencyLevelSupport<'a> for DeleteUserDefinedFunctionBuilder<'a, CUB> +where + CUB: CosmosUriBuilder, +{ + type O = DeleteUserDefinedFunctionBuilder<'a, CUB>; + + #[inline] + fn with_consistency_level(self, consistency_level: ConsistencyLevel<'a>) -> Self::O { + DeleteUserDefinedFunctionBuilder { + user_defined_function_client: self.user_defined_function_client, + user_agent: self.user_agent, + activity_id: self.activity_id, + consistency_level: Some(consistency_level), + } + } +} + +// methods callable only when every mandatory field has been filled +impl<'a, CUB> DeleteUserDefinedFunctionBuilder<'a, CUB> +where + CUB: CosmosUriBuilder, +{ + pub async fn execute(&self) -> Result { + trace!("DeleteUserDefinedFunctionBuilder::execute called"); + + let req = self + .user_defined_function_client + .prepare_request(hyper::Method::DELETE, true); + + // add trait headers + let req = UserAgentOption::add_header(self, req); + let req = ActivityIdOption::add_header(self, req); + let req = ConsistencyLevelOption::add_header(self, req); + + let request = req.body(hyper::Body::empty())?; + + let (headers, body) = check_status_extract_headers_and_body( + self.user_defined_function_client() + .hyper_client() + .request(request), + StatusCode::NO_CONTENT, + ) + .await?; + + Ok((&headers, &body as &[u8]).try_into()?) + } +} diff --git a/azure_sdk_cosmos/src/requests/list_user_defined_functions_builder.json b/azure_sdk_cosmos/src/requests/list_user_defined_functions_builder.json new file mode 100644 index 000000000..dd39bf2b5 --- /dev/null +++ b/azure_sdk_cosmos/src/requests/list_user_defined_functions_builder.json @@ -0,0 +1,73 @@ +{ + "name": "ListUserDefinedFunctionsBuilder", + "derive": "Debug, Clone", + "uses": [ + "crate::clients::{CollectionClient, CosmosUriBuilder, ResourceType}", + "crate::prelude::*", + "crate::responses::ListUserDefinedFunctionsResponse", + "crate::CollectionClientRequired", + "azure_sdk_core::errors::{check_status_extract_headers_and_body, AzureError}", + "azure_sdk_core::modify_conditions::IfMatchCondition", + "azure_sdk_core::prelude::*", + "azure_sdk_core::{IfMatchConditionOption, IfMatchConditionSupport}", + "futures::stream::{unfold, Stream}", + "hyper::StatusCode", + "std::convert::TryInto" + ], + "inline": true, + "extra_types": [ "'a", "'b", "CUB" ], + "extra_wheres": ["CUB: CosmosUriBuilder" ], + "constructor_fields": [ + { + "name": "collection_client", + "field_type": "&'a CollectionClient<'a, CUB>", + "trait_get": "CollectionClientRequired<'a, CUB>" + } + ], + "fields": [ + { + "name": "if_match_condition", + "field_type": "IfMatchCondition<'b>", + "optional": true, + "trait_get": "IfMatchConditionOption<'b>", + "trait_set": "IfMatchConditionSupport<'b>" + }, + { + "name": "user_agent", + "field_type": "&'b str", + "optional": true, + "trait_get": "UserAgentOption<'b>", + "trait_set": "UserAgentSupport<'b>" + }, + { + "name": "activity_id", + "field_type": "&'b str", + "optional": true, + "trait_get": "ActivityIdOption<'b>", + "trait_set": "ActivityIdSupport<'b>" + }, + { + "name": "consistency_level", + "field_type": "ConsistencyLevel<'b>", + "optional": true, + "trait_get": "ConsistencyLevelOption<'b>", + "trait_set": "ConsistencyLevelSupport<'b>", + "get_via_clone": true + }, + { + "name": "continuation", + "field_type": "&'b str", + "optional": true, + "trait_get": "ContinuationOption<'b>", + "trait_set": "ContinuationSupport<'b>" + }, + { + "name": "max_item_count", + "field_type": "i32", + "optional": true, + "initializer": "-1", + "trait_get": "MaxItemCountOption", + "trait_set": "MaxItemCountSupport" + } + ] +} diff --git a/azure_sdk_cosmos/src/requests/list_user_defined_functions_builder.rs b/azure_sdk_cosmos/src/requests/list_user_defined_functions_builder.rs new file mode 100644 index 000000000..52fee6ea6 --- /dev/null +++ b/azure_sdk_cosmos/src/requests/list_user_defined_functions_builder.rs @@ -0,0 +1,336 @@ +use crate::clients::{CollectionClient, CosmosUriBuilder, ResourceType}; +use crate::prelude::*; +use crate::responses::ListUserDefinedFunctionsResponse; +use crate::CollectionClientRequired; +use azure_sdk_core::errors::{check_status_extract_headers_and_body, AzureError}; +use azure_sdk_core::modify_conditions::IfMatchCondition; +use azure_sdk_core::prelude::*; +use azure_sdk_core::{IfMatchConditionOption, IfMatchConditionSupport}; +use futures::stream::{unfold, Stream}; +use hyper::StatusCode; +use std::convert::TryInto; + +#[derive(Debug)] +pub struct ListUserDefinedFunctionsBuilder<'a, 'b, CUB> +where + CUB: CosmosUriBuilder, +{ + collection_client: &'a CollectionClient<'a, CUB>, + if_match_condition: Option>, + user_agent: Option<&'b str>, + activity_id: Option<&'b str>, + consistency_level: Option>, + continuation: Option<&'b str>, + max_item_count: i32, +} + +impl<'a, 'b, CUB> Clone for ListUserDefinedFunctionsBuilder<'a, 'b, CUB> +where + CUB: CosmosUriBuilder, +{ + fn clone(&self) -> Self { + Self { + collection_client: self.collection_client, + if_match_condition: self.if_match_condition, + user_agent: self.user_agent, + activity_id: self.activity_id, + consistency_level: self.consistency_level.clone(), + continuation: self.continuation, + max_item_count: self.max_item_count, + } + } +} + +impl<'a, 'b, CUB> ListUserDefinedFunctionsBuilder<'a, 'b, CUB> +where + CUB: CosmosUriBuilder, +{ + #[inline] + pub(crate) fn new( + collection_client: &'a CollectionClient<'a, CUB>, + ) -> ListUserDefinedFunctionsBuilder<'a, 'b, CUB> { + ListUserDefinedFunctionsBuilder { + collection_client, + if_match_condition: None, + user_agent: None, + activity_id: None, + consistency_level: None, + continuation: None, + max_item_count: -1, + } + } +} + +impl<'a, 'b, CUB> CollectionClientRequired<'a, CUB> for ListUserDefinedFunctionsBuilder<'a, 'b, CUB> +where + CUB: CosmosUriBuilder, +{ + #[inline] + fn collection_client(&self) -> &'a CollectionClient<'a, CUB> { + self.collection_client + } +} + +//get mandatory no traits methods + +//set mandatory no traits methods +impl<'a, 'b, CUB> IfMatchConditionOption<'b> for ListUserDefinedFunctionsBuilder<'a, 'b, CUB> +where + CUB: CosmosUriBuilder, +{ + #[inline] + fn if_match_condition(&self) -> Option> { + self.if_match_condition + } +} + +impl<'a, 'b, CUB> UserAgentOption<'b> for ListUserDefinedFunctionsBuilder<'a, 'b, CUB> +where + CUB: CosmosUriBuilder, +{ + #[inline] + fn user_agent(&self) -> Option<&'b str> { + self.user_agent + } +} + +impl<'a, 'b, CUB> ActivityIdOption<'b> for ListUserDefinedFunctionsBuilder<'a, 'b, CUB> +where + CUB: CosmosUriBuilder, +{ + #[inline] + fn activity_id(&self) -> Option<&'b str> { + self.activity_id + } +} + +impl<'a, 'b, CUB> ConsistencyLevelOption<'b> for ListUserDefinedFunctionsBuilder<'a, 'b, CUB> +where + CUB: CosmosUriBuilder, +{ + #[inline] + fn consistency_level(&self) -> Option> { + self.consistency_level.clone() + } +} + +impl<'a, 'b, CUB> ContinuationOption<'b> for ListUserDefinedFunctionsBuilder<'a, 'b, CUB> +where + CUB: CosmosUriBuilder, +{ + #[inline] + fn continuation(&self) -> Option<&'b str> { + self.continuation + } +} + +impl<'a, 'b, CUB> MaxItemCountOption for ListUserDefinedFunctionsBuilder<'a, 'b, CUB> +where + CUB: CosmosUriBuilder, +{ + #[inline] + fn max_item_count(&self) -> i32 { + self.max_item_count + } +} + +impl<'a, 'b, CUB> IfMatchConditionSupport<'b> for ListUserDefinedFunctionsBuilder<'a, 'b, CUB> +where + CUB: CosmosUriBuilder, +{ + type O = ListUserDefinedFunctionsBuilder<'a, 'b, CUB>; + + #[inline] + fn with_if_match_condition(self, if_match_condition: IfMatchCondition<'b>) -> Self::O { + ListUserDefinedFunctionsBuilder { + collection_client: self.collection_client, + if_match_condition: Some(if_match_condition), + user_agent: self.user_agent, + activity_id: self.activity_id, + consistency_level: self.consistency_level, + continuation: self.continuation, + max_item_count: self.max_item_count, + } + } +} + +impl<'a, 'b, CUB> UserAgentSupport<'b> for ListUserDefinedFunctionsBuilder<'a, 'b, CUB> +where + CUB: CosmosUriBuilder, +{ + type O = ListUserDefinedFunctionsBuilder<'a, 'b, CUB>; + + #[inline] + fn with_user_agent(self, user_agent: &'b str) -> Self::O { + ListUserDefinedFunctionsBuilder { + collection_client: self.collection_client, + if_match_condition: self.if_match_condition, + user_agent: Some(user_agent), + activity_id: self.activity_id, + consistency_level: self.consistency_level, + continuation: self.continuation, + max_item_count: self.max_item_count, + } + } +} + +impl<'a, 'b, CUB> ActivityIdSupport<'b> for ListUserDefinedFunctionsBuilder<'a, 'b, CUB> +where + CUB: CosmosUriBuilder, +{ + type O = ListUserDefinedFunctionsBuilder<'a, 'b, CUB>; + + #[inline] + fn with_activity_id(self, activity_id: &'b str) -> Self::O { + ListUserDefinedFunctionsBuilder { + collection_client: self.collection_client, + if_match_condition: self.if_match_condition, + user_agent: self.user_agent, + activity_id: Some(activity_id), + consistency_level: self.consistency_level, + continuation: self.continuation, + max_item_count: self.max_item_count, + } + } +} + +impl<'a, 'b, CUB> ConsistencyLevelSupport<'b> for ListUserDefinedFunctionsBuilder<'a, 'b, CUB> +where + CUB: CosmosUriBuilder, +{ + type O = ListUserDefinedFunctionsBuilder<'a, 'b, CUB>; + + #[inline] + fn with_consistency_level(self, consistency_level: ConsistencyLevel<'b>) -> Self::O { + ListUserDefinedFunctionsBuilder { + collection_client: self.collection_client, + if_match_condition: self.if_match_condition, + user_agent: self.user_agent, + activity_id: self.activity_id, + consistency_level: Some(consistency_level), + continuation: self.continuation, + max_item_count: self.max_item_count, + } + } +} + +impl<'a, 'b, CUB> ContinuationSupport<'b> for ListUserDefinedFunctionsBuilder<'a, 'b, CUB> +where + CUB: CosmosUriBuilder, +{ + type O = ListUserDefinedFunctionsBuilder<'a, 'b, CUB>; + + #[inline] + fn with_continuation(self, continuation: &'b str) -> Self::O { + ListUserDefinedFunctionsBuilder { + collection_client: self.collection_client, + if_match_condition: self.if_match_condition, + user_agent: self.user_agent, + activity_id: self.activity_id, + consistency_level: self.consistency_level, + continuation: Some(continuation), + max_item_count: self.max_item_count, + } + } +} + +impl<'a, 'b, CUB> MaxItemCountSupport for ListUserDefinedFunctionsBuilder<'a, 'b, CUB> +where + CUB: CosmosUriBuilder, +{ + type O = ListUserDefinedFunctionsBuilder<'a, 'b, CUB>; + + #[inline] + fn with_max_item_count(self, max_item_count: i32) -> Self::O { + ListUserDefinedFunctionsBuilder { + collection_client: self.collection_client, + if_match_condition: self.if_match_condition, + user_agent: self.user_agent, + activity_id: self.activity_id, + consistency_level: self.consistency_level, + continuation: self.continuation, + max_item_count, + } + } +} + +// methods callable only when every mandatory field has been filled +impl<'a, 'b, CUB> ListUserDefinedFunctionsBuilder<'a, 'b, CUB> +where + CUB: CosmosUriBuilder, +{ + pub async fn execute(&self) -> Result { + trace!("ListUserDefinedFunctionsBuilder::execute called"); + + let req = self.collection_client.main_client().prepare_request( + &format!( + "dbs/{}/colls/{}/udfs", + self.collection_client.database_name().name(), + self.collection_client.collection_name().name() + ), + hyper::Method::GET, + ResourceType::UserDefinedFunctions, + ); + + // add trait headers + let req = IfMatchConditionOption::add_header(self, req); + let req = UserAgentOption::add_header(self, req); + let req = ActivityIdOption::add_header(self, req); + let req = ConsistencyLevelOption::add_header(self, req); + let req = ContinuationOption::add_header(self, req); + let req = MaxItemCountOption::add_header(self, req); + + let request = req.body(hyper::Body::empty())?; + + let (headers, body) = check_status_extract_headers_and_body( + self.collection_client().hyper_client().request(request), + StatusCode::OK, + ) + .await?; + + Ok((&headers, &body as &[u8]).try_into()?) + } + + pub fn stream( + &self, + ) -> impl Stream> + '_ { + #[derive(Debug, Clone, PartialEq)] + enum States { + Init, + Continuation(String), + }; + + unfold( + Some(States::Init), + move |continuation_token: Option| { + async move { + debug!("continuation_token == {:?}", &continuation_token); + let response = match continuation_token { + Some(States::Init) => self.execute().await, + Some(States::Continuation(continuation_token)) => { + self.clone() + .with_continuation(&continuation_token) + .execute() + .await + } + None => return None, + }; + + // the ? operator does not work in async move (yet?) + // so we have to resort to this boilerplate + let response = match response { + Ok(response) => response, + Err(err) => return Some((Err(err), None)), + }; + + let continuation_token = match &response.continuation_token { + Some(ct) => Some(States::Continuation(ct.to_owned())), + None => None, + }; + + Some((Ok(response), continuation_token)) + } + }, + ) + } +} diff --git a/azure_sdk_cosmos/src/requests/mod.rs b/azure_sdk_cosmos/src/requests/mod.rs index b91128cf5..1ea025bee 100644 --- a/azure_sdk_cosmos/src/requests/mod.rs +++ b/azure_sdk_cosmos/src/requests/mod.rs @@ -1,6 +1,7 @@ mod create_collection_builder; mod create_database_builder; mod create_document_builder; +mod create_or_replace_user_defined_function_builder; mod create_permission_builder; mod create_reference_attachment_builder; mod create_slug_attachment_builder; @@ -13,6 +14,7 @@ mod delete_document_builder; mod delete_permission_builder; mod delete_stored_procedure_builder; mod delete_user_builder; +mod delete_user_defined_function_builder; mod execute_stored_procedure_builder; mod get_attachment_builder; mod get_collection_builder; @@ -27,6 +29,7 @@ mod list_databases_builder; mod list_documents_builder; mod list_permissions_builder; mod list_stored_procedures_builder; +mod list_user_defined_functions_builder; mod list_users_builder; mod query_documents_builder; mod replace_collection_builder; @@ -39,6 +42,7 @@ mod replace_user_builder; pub use self::create_collection_builder::CreateCollectionBuilder; pub use self::create_database_builder::CreateDatabaseBuilder; pub use self::create_document_builder::CreateDocumentBuilder; +pub use self::create_or_replace_user_defined_function_builder::CreateOrReplaceUserDefinedFunctionBuilder; pub use self::create_permission_builder::CreatePermissionBuilder; pub use self::create_reference_attachment_builder::CreateReferenceAttachmentBuilder; pub use self::create_slug_attachment_builder::CreateSlugAttachmentBuilder; @@ -51,6 +55,7 @@ pub use self::delete_document_builder::DeleteDocumentBuilder; pub use self::delete_permission_builder::DeletePermissionsBuilder; pub use self::delete_stored_procedure_builder::DeleteStoredProcedureBuilder; pub use self::delete_user_builder::DeleteUserBuilder; +pub use self::delete_user_defined_function_builder::DeleteUserDefinedFunctionBuilder; pub use self::execute_stored_procedure_builder::ExecuteStoredProcedureBuilder; pub use self::get_attachment_builder::GetAttachmentBuilder; pub use self::get_collection_builder::GetCollectionBuilder; @@ -65,6 +70,7 @@ pub use self::list_databases_builder::ListDatabasesBuilder; pub use self::list_documents_builder::ListDocumentsBuilder; pub use self::list_permissions_builder::ListPermissionsBuilder; pub use self::list_stored_procedures_builder::ListStoredProceduresBuilder; +pub use self::list_user_defined_functions_builder::ListUserDefinedFunctionsBuilder; pub use self::list_users_builder::ListUsersBuilder; pub use self::query_documents_builder::QueryDocumentsBuilder; pub use self::replace_collection_builder::ReplaceCollectionBuilder; diff --git a/azure_sdk_cosmos/src/requests/replace_document_builder.json b/azure_sdk_cosmos/src/requests/replace_document_builder.json index 4fa4167d3..dfbc8bef4 100644 --- a/azure_sdk_cosmos/src/requests/replace_document_builder.json +++ b/azure_sdk_cosmos/src/requests/replace_document_builder.json @@ -45,6 +45,14 @@ "trait_get": "PartitionKeysRequired<'b>", "trait_set": "PartitionKeysSupport<'b>" }, + { + "name": "document_id", + "field_type": "&'b str", + "optional": false, + "builder_type": "DocumentIdSet", + "trait_get": "DocumentIdRequired<'b>", + "trait_set": "DocumentIdSupport<'b>" + }, { "name": "indexing_directive", "field_type": "IndexingDirective", @@ -86,7 +94,8 @@ "field_type": "ConsistencyLevel<'b>", "optional": true, "trait_get": "ConsistencyLevelOption<'b>", - "trait_set": "ConsistencyLevelSupport<'b>" + "trait_set": "ConsistencyLevelSupport<'b>", + "get_via_clone": true }, { "name": "allow_tentative_writes", diff --git a/azure_sdk_cosmos/src/requests/replace_document_builder.rs b/azure_sdk_cosmos/src/requests/replace_document_builder.rs index 38c5e79bf..b842f65c5 100644 --- a/azure_sdk_cosmos/src/requests/replace_document_builder.rs +++ b/azure_sdk_cosmos/src/requests/replace_document_builder.rs @@ -15,18 +15,21 @@ use std::convert::TryInto; use std::marker::PhantomData; #[derive(Debug, Clone)] -pub struct ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> +pub struct ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> where DocumentSet: ToAssign, PartitionKeysSet: ToAssign, + DocumentIdSet: ToAssign, T: Serialize, CUB: CosmosUriBuilder, { collection_client: &'a CollectionClient<'a, CUB>, p_document: PhantomData, p_partition_keys: PhantomData, + p_document_id: PhantomData, document: Option<&'b Document>, partition_keys: Option<&'b PartitionKeys>, + document_id: Option<&'b str>, indexing_directive: IndexingDirective, if_match_condition: Option>, if_modified_since: Option<&'b DateTime>, @@ -36,7 +39,7 @@ where allow_tentative_writes: bool, } -impl<'a, 'b, T, CUB> ReplaceDocumentBuilder<'a, 'b, T, CUB, No, No> +impl<'a, 'b, T, CUB> ReplaceDocumentBuilder<'a, 'b, T, CUB, No, No, No> where T: Serialize, CUB: CosmosUriBuilder, @@ -44,13 +47,15 @@ where #[inline] pub(crate) fn new( collection_client: &'a CollectionClient<'a, CUB>, - ) -> ReplaceDocumentBuilder<'a, 'b, T, CUB, No, No> { + ) -> ReplaceDocumentBuilder<'a, 'b, T, CUB, No, No, No> { ReplaceDocumentBuilder { collection_client, p_document: PhantomData {}, document: None, p_partition_keys: PhantomData {}, partition_keys: None, + p_document_id: PhantomData {}, + document_id: None, indexing_directive: IndexingDirective::Default, if_match_condition: None, if_modified_since: None, @@ -62,11 +67,12 @@ where } } -impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> CollectionClientRequired<'a, CUB> - for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> +impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> CollectionClientRequired<'a, CUB> + for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> where DocumentSet: ToAssign, PartitionKeysSet: ToAssign, + DocumentIdSet: ToAssign, T: Serialize, CUB: CosmosUriBuilder, { @@ -79,10 +85,11 @@ where //get mandatory no traits methods //set mandatory no traits methods -impl<'a, 'b, T, CUB, PartitionKeysSet> DocumentRequired<'b, T> - for ReplaceDocumentBuilder<'a, 'b, T, CUB, Yes, PartitionKeysSet> +impl<'a, 'b, T, CUB, PartitionKeysSet, DocumentIdSet> DocumentRequired<'b, T> + for ReplaceDocumentBuilder<'a, 'b, T, CUB, Yes, PartitionKeysSet, DocumentIdSet> where PartitionKeysSet: ToAssign, + DocumentIdSet: ToAssign, T: Serialize, CUB: CosmosUriBuilder, { @@ -92,10 +99,11 @@ where } } -impl<'a, 'b, T, CUB, DocumentSet> PartitionKeysRequired<'b> - for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, Yes> +impl<'a, 'b, T, CUB, DocumentSet, DocumentIdSet> PartitionKeysRequired<'b> + for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, Yes, DocumentIdSet> where DocumentSet: ToAssign, + DocumentIdSet: ToAssign, T: Serialize, CUB: CosmosUriBuilder, { @@ -105,13 +113,28 @@ where } } -impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> IndexingDirectiveOption - for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> +impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> DocumentIdRequired<'b> + for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, Yes> where DocumentSet: ToAssign, PartitionKeysSet: ToAssign, T: Serialize, CUB: CosmosUriBuilder, +{ + #[inline] + fn document_id(&self) -> &'b str { + self.document_id.unwrap() + } +} + +impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> IndexingDirectiveOption + for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> +where + DocumentSet: ToAssign, + PartitionKeysSet: ToAssign, + DocumentIdSet: ToAssign, + T: Serialize, + CUB: CosmosUriBuilder, { #[inline] fn indexing_directive(&self) -> IndexingDirective { @@ -119,11 +142,12 @@ where } } -impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> IfMatchConditionOption<'b> - for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> +impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> IfMatchConditionOption<'b> + for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> where DocumentSet: ToAssign, PartitionKeysSet: ToAssign, + DocumentIdSet: ToAssign, T: Serialize, CUB: CosmosUriBuilder, { @@ -133,11 +157,12 @@ where } } -impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> IfModifiedSinceOption<'b> - for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> +impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> IfModifiedSinceOption<'b> + for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> where DocumentSet: ToAssign, PartitionKeysSet: ToAssign, + DocumentIdSet: ToAssign, T: Serialize, CUB: CosmosUriBuilder, { @@ -147,11 +172,12 @@ where } } -impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> UserAgentOption<'b> - for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> +impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> UserAgentOption<'b> + for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> where DocumentSet: ToAssign, PartitionKeysSet: ToAssign, + DocumentIdSet: ToAssign, T: Serialize, CUB: CosmosUriBuilder, { @@ -161,11 +187,12 @@ where } } -impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> ActivityIdOption<'b> - for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> +impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> ActivityIdOption<'b> + for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> where DocumentSet: ToAssign, PartitionKeysSet: ToAssign, + DocumentIdSet: ToAssign, T: Serialize, CUB: CosmosUriBuilder, { @@ -175,11 +202,12 @@ where } } -impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> ConsistencyLevelOption<'b> - for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> +impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> ConsistencyLevelOption<'b> + for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> where DocumentSet: ToAssign, PartitionKeysSet: ToAssign, + DocumentIdSet: ToAssign, T: Serialize, CUB: CosmosUriBuilder, { @@ -189,11 +217,12 @@ where } } -impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> AllowTentativeWritesOption - for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> +impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> AllowTentativeWritesOption + for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> where DocumentSet: ToAssign, PartitionKeysSet: ToAssign, + DocumentIdSet: ToAssign, T: Serialize, CUB: CosmosUriBuilder, { @@ -203,14 +232,15 @@ where } } -impl<'a, 'b, T, CUB, PartitionKeysSet> DocumentSupport<'b, T> - for ReplaceDocumentBuilder<'a, 'b, T, CUB, No, PartitionKeysSet> +impl<'a, 'b, T, CUB, PartitionKeysSet, DocumentIdSet> DocumentSupport<'b, T> + for ReplaceDocumentBuilder<'a, 'b, T, CUB, No, PartitionKeysSet, DocumentIdSet> where PartitionKeysSet: ToAssign, + DocumentIdSet: ToAssign, T: Serialize, CUB: CosmosUriBuilder, { - type O = ReplaceDocumentBuilder<'a, 'b, T, CUB, Yes, PartitionKeysSet>; + type O = ReplaceDocumentBuilder<'a, 'b, T, CUB, Yes, PartitionKeysSet, DocumentIdSet>; #[inline] fn with_document(self, document: &'b Document) -> Self::O { @@ -218,8 +248,10 @@ where collection_client: self.collection_client, p_document: PhantomData {}, p_partition_keys: PhantomData {}, + p_document_id: PhantomData {}, document: Some(document), partition_keys: self.partition_keys, + document_id: self.document_id, indexing_directive: self.indexing_directive, if_match_condition: self.if_match_condition, if_modified_since: self.if_modified_since, @@ -231,14 +263,15 @@ where } } -impl<'a, 'b, T, CUB, DocumentSet> PartitionKeysSupport<'b> - for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, No> +impl<'a, 'b, T, CUB, DocumentSet, DocumentIdSet> PartitionKeysSupport<'b> + for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, No, DocumentIdSet> where DocumentSet: ToAssign, + DocumentIdSet: ToAssign, T: Serialize, CUB: CosmosUriBuilder, { - type O = ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, Yes>; + type O = ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, Yes, DocumentIdSet>; #[inline] fn with_partition_keys(self, partition_keys: &'b PartitionKeys) -> Self::O { @@ -246,8 +279,41 @@ where collection_client: self.collection_client, p_document: PhantomData {}, p_partition_keys: PhantomData {}, + p_document_id: PhantomData {}, document: self.document, partition_keys: Some(partition_keys), + document_id: self.document_id, + indexing_directive: self.indexing_directive, + if_match_condition: self.if_match_condition, + if_modified_since: self.if_modified_since, + user_agent: self.user_agent, + activity_id: self.activity_id, + consistency_level: self.consistency_level, + allow_tentative_writes: self.allow_tentative_writes, + } + } +} + +impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> DocumentIdSupport<'b> + for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, No> +where + DocumentSet: ToAssign, + PartitionKeysSet: ToAssign, + T: Serialize, + CUB: CosmosUriBuilder, +{ + type O = ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, Yes>; + + #[inline] + fn with_document_id(self, document_id: &'b str) -> Self::O { + ReplaceDocumentBuilder { + collection_client: self.collection_client, + p_document: PhantomData {}, + p_partition_keys: PhantomData {}, + p_document_id: PhantomData {}, + document: self.document, + partition_keys: self.partition_keys, + document_id: Some(document_id), indexing_directive: self.indexing_directive, if_match_condition: self.if_match_condition, if_modified_since: self.if_modified_since, @@ -259,15 +325,16 @@ where } } -impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> IndexingDirectiveSupport - for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> +impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> IndexingDirectiveSupport + for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> where DocumentSet: ToAssign, PartitionKeysSet: ToAssign, + DocumentIdSet: ToAssign, T: Serialize, CUB: CosmosUriBuilder, { - type O = ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet>; + type O = ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet>; #[inline] fn with_indexing_directive(self, indexing_directive: IndexingDirective) -> Self::O { @@ -275,8 +342,10 @@ where collection_client: self.collection_client, p_document: PhantomData {}, p_partition_keys: PhantomData {}, + p_document_id: PhantomData {}, document: self.document, partition_keys: self.partition_keys, + document_id: self.document_id, indexing_directive, if_match_condition: self.if_match_condition, if_modified_since: self.if_modified_since, @@ -288,15 +357,16 @@ where } } -impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> IfMatchConditionSupport<'b> - for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> +impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> IfMatchConditionSupport<'b> + for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> where DocumentSet: ToAssign, PartitionKeysSet: ToAssign, + DocumentIdSet: ToAssign, T: Serialize, CUB: CosmosUriBuilder, { - type O = ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet>; + type O = ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet>; #[inline] fn with_if_match_condition(self, if_match_condition: IfMatchCondition<'b>) -> Self::O { @@ -304,8 +374,10 @@ where collection_client: self.collection_client, p_document: PhantomData {}, p_partition_keys: PhantomData {}, + p_document_id: PhantomData {}, document: self.document, partition_keys: self.partition_keys, + document_id: self.document_id, indexing_directive: self.indexing_directive, if_match_condition: Some(if_match_condition), if_modified_since: self.if_modified_since, @@ -317,15 +389,16 @@ where } } -impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> IfModifiedSinceSupport<'b> - for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> +impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> IfModifiedSinceSupport<'b> + for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> where DocumentSet: ToAssign, PartitionKeysSet: ToAssign, + DocumentIdSet: ToAssign, T: Serialize, CUB: CosmosUriBuilder, { - type O = ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet>; + type O = ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet>; #[inline] fn with_if_modified_since(self, if_modified_since: &'b DateTime) -> Self::O { @@ -333,8 +406,10 @@ where collection_client: self.collection_client, p_document: PhantomData {}, p_partition_keys: PhantomData {}, + p_document_id: PhantomData {}, document: self.document, partition_keys: self.partition_keys, + document_id: self.document_id, indexing_directive: self.indexing_directive, if_match_condition: self.if_match_condition, if_modified_since: Some(if_modified_since), @@ -346,15 +421,16 @@ where } } -impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> UserAgentSupport<'b> - for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> +impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> UserAgentSupport<'b> + for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> where DocumentSet: ToAssign, PartitionKeysSet: ToAssign, + DocumentIdSet: ToAssign, T: Serialize, CUB: CosmosUriBuilder, { - type O = ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet>; + type O = ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet>; #[inline] fn with_user_agent(self, user_agent: &'b str) -> Self::O { @@ -362,8 +438,10 @@ where collection_client: self.collection_client, p_document: PhantomData {}, p_partition_keys: PhantomData {}, + p_document_id: PhantomData {}, document: self.document, partition_keys: self.partition_keys, + document_id: self.document_id, indexing_directive: self.indexing_directive, if_match_condition: self.if_match_condition, if_modified_since: self.if_modified_since, @@ -375,15 +453,16 @@ where } } -impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> ActivityIdSupport<'b> - for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> +impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> ActivityIdSupport<'b> + for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> where DocumentSet: ToAssign, PartitionKeysSet: ToAssign, + DocumentIdSet: ToAssign, T: Serialize, CUB: CosmosUriBuilder, { - type O = ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet>; + type O = ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet>; #[inline] fn with_activity_id(self, activity_id: &'b str) -> Self::O { @@ -391,8 +470,10 @@ where collection_client: self.collection_client, p_document: PhantomData {}, p_partition_keys: PhantomData {}, + p_document_id: PhantomData {}, document: self.document, partition_keys: self.partition_keys, + document_id: self.document_id, indexing_directive: self.indexing_directive, if_match_condition: self.if_match_condition, if_modified_since: self.if_modified_since, @@ -404,15 +485,16 @@ where } } -impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> ConsistencyLevelSupport<'b> - for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> +impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> ConsistencyLevelSupport<'b> + for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> where DocumentSet: ToAssign, PartitionKeysSet: ToAssign, + DocumentIdSet: ToAssign, T: Serialize, CUB: CosmosUriBuilder, { - type O = ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet>; + type O = ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet>; #[inline] fn with_consistency_level(self, consistency_level: ConsistencyLevel<'b>) -> Self::O { @@ -420,8 +502,10 @@ where collection_client: self.collection_client, p_document: PhantomData {}, p_partition_keys: PhantomData {}, + p_document_id: PhantomData {}, document: self.document, partition_keys: self.partition_keys, + document_id: self.document_id, indexing_directive: self.indexing_directive, if_match_condition: self.if_match_condition, if_modified_since: self.if_modified_since, @@ -433,15 +517,16 @@ where } } -impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> AllowTentativeWritesSupport - for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet> +impl<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> AllowTentativeWritesSupport + for ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet> where DocumentSet: ToAssign, PartitionKeysSet: ToAssign, + DocumentIdSet: ToAssign, T: Serialize, CUB: CosmosUriBuilder, { - type O = ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet>; + type O = ReplaceDocumentBuilder<'a, 'b, T, CUB, DocumentSet, PartitionKeysSet, DocumentIdSet>; #[inline] fn with_allow_tentative_writes(self, allow_tentative_writes: bool) -> Self::O { @@ -449,8 +534,10 @@ where collection_client: self.collection_client, p_document: PhantomData {}, p_partition_keys: PhantomData {}, + p_document_id: PhantomData {}, document: self.document, partition_keys: self.partition_keys, + document_id: self.document_id, indexing_directive: self.indexing_directive, if_match_condition: self.if_match_condition, if_modified_since: self.if_modified_since, @@ -463,7 +550,7 @@ where } // methods callable only when every mandatory field has been filled -impl<'a, 'b, T, CUB> ReplaceDocumentBuilder<'a, 'b, T, CUB, Yes, Yes> +impl<'a, 'b, T, CUB> ReplaceDocumentBuilder<'a, 'b, T, CUB, Yes, Yes, Yes> where T: Serialize, CUB: CosmosUriBuilder, @@ -476,7 +563,7 @@ where "dbs/{}/colls/{}/docs/{}", self.collection_client.database_name().name(), self.collection_client.collection_name().name(), - self.document().id() + self.document_id() ), hyper::Method::PUT, ResourceType::Documents, diff --git a/azure_sdk_cosmos/src/responses/create_user_defined_function_response.rs b/azure_sdk_cosmos/src/responses/create_user_defined_function_response.rs new file mode 100644 index 000000000..b431c922c --- /dev/null +++ b/azure_sdk_cosmos/src/responses/create_user_defined_function_response.rs @@ -0,0 +1,76 @@ +use crate::from_headers::*; +use crate::user_defined_function::UserDefinedFunction; +use crate::ResourceQuota; +use azure_sdk_core::errors::AzureError; +use azure_sdk_core::etag_from_headers; +use azure_sdk_core::session_token_from_headers; +use chrono::{DateTime, Utc}; +use http::HeaderMap; + +#[derive(Debug, Clone, PartialEq)] +pub struct CreateUserDefinedFunctionResponse { + pub user_defined_function: UserDefinedFunction, + pub server: String, + pub last_state_change: DateTime, + pub etag: String, + pub resource_quota: Vec, + pub resource_usage: Vec, + pub lsn: u64, + pub schema_version: String, + pub alt_content_path: String, + pub content_path: String, + pub quorum_acked_lsn: u64, + pub current_write_quorum: u64, + pub current_replica_set_size: u64, + pub role: u32, + pub global_committed_lsn: u64, + pub number_of_read_regions: u32, + pub transport_request_id: u64, + pub cosmos_llsn: u64, + pub cosmos_quorum_acked_llsn: u64, + pub session_token: String, + pub charge: f64, + pub service_version: String, + pub activity_id: uuid::Uuid, + pub gateway_version: String, + pub date: DateTime, +} + +impl std::convert::TryFrom<(&HeaderMap, &[u8])> for CreateUserDefinedFunctionResponse { + type Error = AzureError; + fn try_from(value: (&HeaderMap, &[u8])) -> Result { + let headers = value.0; + let body = value.1; + + debug!("{:#?}", headers); + debug!("{:#?}", std::str::from_utf8(body)); + + Ok(Self { + user_defined_function: serde_json::from_slice(body)?, + server: server_from_headers(headers)?.to_owned(), + last_state_change: last_state_change_from_headers(headers)?, + etag: etag_from_headers(headers)?, + resource_quota: resource_quota_from_headers(headers)?, + resource_usage: resource_usage_from_headers(headers)?, + lsn: lsn_from_headers(headers)?, + schema_version: schema_version_from_headers(headers)?.to_owned(), + alt_content_path: alt_content_path_from_headers(headers)?.to_owned(), + content_path: content_path_from_headers(headers)?.to_owned(), + quorum_acked_lsn: quorum_acked_lsn_from_headers(headers)?, + current_write_quorum: current_write_quorum_from_headers(headers)?, + current_replica_set_size: current_replica_set_size_from_headers(headers)?, + role: role_from_headers(headers)?, + global_committed_lsn: global_committed_lsn_from_headers(headers)?, + number_of_read_regions: number_of_read_regions_from_headers(headers)?, + transport_request_id: transport_request_id_from_headers(headers)?, + cosmos_llsn: cosmos_llsn_from_headers(headers)?, + cosmos_quorum_acked_llsn: cosmos_quorum_acked_llsn_from_headers(headers)?, + session_token: session_token_from_headers(headers)?, + charge: request_charge_from_headers(headers)?, + service_version: service_version_from_headers(headers)?.to_owned(), + activity_id: activity_id_from_headers(headers)?, + gateway_version: gateway_version_from_headers(headers)?.to_owned(), + date: date_from_headers(headers)?, + }) + } +} diff --git a/azure_sdk_cosmos/src/responses/delete_user_defined_function_response.rs b/azure_sdk_cosmos/src/responses/delete_user_defined_function_response.rs new file mode 100644 index 000000000..733ac35f4 --- /dev/null +++ b/azure_sdk_cosmos/src/responses/delete_user_defined_function_response.rs @@ -0,0 +1,72 @@ +use crate::from_headers::*; +use crate::ResourceQuota; +use azure_sdk_core::errors::AzureError; +use azure_sdk_core::session_token_from_headers; +use chrono::{DateTime, Utc}; +use http::HeaderMap; + +#[derive(Debug, Clone, PartialEq)] +pub struct DeleteUserDefinedFunctionResponse { + pub content_location: String, + pub server: String, + pub last_state_change: DateTime, + pub resource_quota: Vec, + pub resource_usage: Vec, + pub lsn: u64, + pub schema_version: String, + pub alt_content_path: String, + pub content_path: String, + pub quorum_acked_lsn: u64, + pub current_write_quorum: u64, + pub current_replica_set_size: u64, + pub role: u32, + pub global_committed_lsn: u64, + pub number_of_read_regions: u32, + pub transport_request_id: u64, + pub cosmos_llsn: u64, + pub cosmos_quorum_acked_llsn: u64, + pub session_token: String, + pub charge: f64, + pub service_version: String, + pub activity_id: uuid::Uuid, + pub gateway_version: String, + pub date: DateTime, +} + +impl std::convert::TryFrom<(&HeaderMap, &[u8])> for DeleteUserDefinedFunctionResponse { + type Error = AzureError; + fn try_from(value: (&HeaderMap, &[u8])) -> Result { + let headers = value.0; + let _body = value.1; + + debug!("{:#?}", headers); + debug!("{:#?}", std::str::from_utf8(_body)); + + Ok(Self { + content_location: content_location_from_headers(headers)?.to_owned(), + server: server_from_headers(headers)?.to_owned(), + last_state_change: last_state_change_from_headers(headers)?, + resource_quota: resource_quota_from_headers(headers)?, + resource_usage: resource_usage_from_headers(headers)?, + lsn: lsn_from_headers(headers)?, + schema_version: schema_version_from_headers(headers)?.to_owned(), + alt_content_path: alt_content_path_from_headers(headers)?.to_owned(), + content_path: content_path_from_headers(headers)?.to_owned(), + quorum_acked_lsn: quorum_acked_lsn_from_headers(headers)?, + current_write_quorum: current_write_quorum_from_headers(headers)?, + current_replica_set_size: current_replica_set_size_from_headers(headers)?, + role: role_from_headers(headers)?, + global_committed_lsn: global_committed_lsn_from_headers(headers)?, + number_of_read_regions: number_of_read_regions_from_headers(headers)?, + transport_request_id: transport_request_id_from_headers(headers)?, + cosmos_llsn: cosmos_llsn_from_headers(headers)?, + cosmos_quorum_acked_llsn: cosmos_quorum_acked_llsn_from_headers(headers)?, + session_token: session_token_from_headers(headers)?, + charge: request_charge_from_headers(headers)?, + service_version: service_version_from_headers(headers)?.to_owned(), + activity_id: activity_id_from_headers(headers)?, + gateway_version: gateway_version_from_headers(headers)?.to_owned(), + date: date_from_headers(headers)?, + }) + } +} diff --git a/azure_sdk_cosmos/src/responses/get_attachment_response.rs b/azure_sdk_cosmos/src/responses/get_attachment_response.rs index e4c4366fd..120809f9f 100644 --- a/azure_sdk_cosmos/src/responses/get_attachment_response.rs +++ b/azure_sdk_cosmos/src/responses/get_attachment_response.rs @@ -26,7 +26,7 @@ pub struct GetAttachmentResponse { pub cosmos_item_llsn: u64, pub session_token: SessionToken, pub request_charge: f64, - pub indexing_directive: IndexingDirective, + pub indexing_directive: Option, pub service_version: String, pub activity_id: uuid::Uuid, pub gateway_version: String, @@ -61,7 +61,7 @@ impl std::convert::TryFrom<(&HeaderMap, &[u8])> for GetAttachmentResponse { cosmos_item_llsn: cosmos_item_llsn_from_headers(headers)?, session_token: session_token_from_headers(headers)?, request_charge: request_charge_from_headers(headers)?, - indexing_directive: indexing_directive_from_headers(headers)?, + indexing_directive: indexing_directive_from_headers_optional(headers)?, service_version: service_version_from_headers(headers)?.to_owned(), activity_id: activity_id_from_headers(headers)?, gateway_version: gateway_version_from_headers(headers)?.to_owned(), diff --git a/azure_sdk_cosmos/src/responses/list_user_defined_functions_response.rs b/azure_sdk_cosmos/src/responses/list_user_defined_functions_response.rs new file mode 100644 index 000000000..ab62c276f --- /dev/null +++ b/azure_sdk_cosmos/src/responses/list_user_defined_functions_response.rs @@ -0,0 +1,84 @@ +use crate::from_headers::*; +use crate::user_defined_function::UserDefinedFunction; +use crate::ResourceQuota; +use azure_sdk_core::errors::AzureError; +use azure_sdk_core::{continuation_token_from_headers_optional, session_token_from_headers}; +use chrono::{DateTime, Utc}; +use http::HeaderMap; + +#[derive(Debug, Clone, PartialEq)] +pub struct ListUserDefinedFunctionsResponse { + pub rid: String, + pub user_defined_functions: Vec, + pub content_location: String, + pub server: String, + pub last_state_change: DateTime, + pub continuation_token: Option, + pub resource_quota: Vec, + pub resource_usage: Vec, + pub lsn: u64, + pub item_count: u32, + pub schema_version: String, + pub alt_content_path: String, + pub content_path: String, + pub role: u32, + pub global_committed_lsn: u64, + pub number_of_read_regions: u32, + pub transport_request_id: u64, + pub cosmos_llsn: u64, + pub session_token: String, + pub charge: f64, + pub service_version: String, + pub activity_id: uuid::Uuid, + pub gateway_version: String, + pub date: DateTime, +} + +impl std::convert::TryFrom<(&HeaderMap, &[u8])> for ListUserDefinedFunctionsResponse { + type Error = AzureError; + fn try_from(value: (&HeaderMap, &[u8])) -> Result { + let headers = value.0; + let body = value.1; + + debug!("{:#?}", headers); + debug!("{:#?}", std::str::from_utf8(&body)?); + + #[derive(Debug, Deserialize)] + struct Response<'a> { + #[serde(rename = "_rid")] + rid: &'a str, + #[serde(rename = "UserDefinedFunctions")] + user_defined_functions: Vec, + #[serde(rename = "_count")] + count: u32, + } + let response: Response = serde_json::from_slice(body)?; + + Ok(Self { + rid: response.rid.to_owned(), + user_defined_functions: response.user_defined_functions, + content_location: content_location_from_headers(headers)?.to_owned(), + server: server_from_headers(headers)?.to_owned(), + last_state_change: last_state_change_from_headers(headers)?, + continuation_token: continuation_token_from_headers_optional(headers)?, + resource_quota: resource_quota_from_headers(headers)?, + resource_usage: resource_usage_from_headers(headers)?, + lsn: lsn_from_headers(headers)?, + item_count: item_count_from_headers(headers)?, + schema_version: schema_version_from_headers(headers)?.to_owned(), + alt_content_path: alt_content_path_from_headers(headers)?.to_owned(), + content_path: content_path_from_headers(headers)?.to_owned(), + role: role_from_headers(headers)?, + global_committed_lsn: global_committed_lsn_from_headers(headers)?, + number_of_read_regions: number_of_read_regions_from_headers(headers)?, + transport_request_id: transport_request_id_from_headers(headers)?, + cosmos_llsn: cosmos_llsn_from_headers(headers)?, + session_token: session_token_from_headers(headers)?, + charge: request_charge_from_headers(headers)?, + service_version: service_version_from_headers(headers)?.to_owned(), + activity_id: activity_id_from_headers(headers)?, + gateway_version: gateway_version_from_headers(headers)?.to_owned(), + date: date_from_headers(headers)?, + }) + } +} diff --git a/azure_sdk_cosmos/src/responses/mod.rs b/azure_sdk_cosmos/src/responses/mod.rs index 6a12f593d..8d34d156f 100644 --- a/azure_sdk_cosmos/src/responses/mod.rs +++ b/azure_sdk_cosmos/src/responses/mod.rs @@ -5,6 +5,7 @@ mod create_permission_response; mod create_reference_attachment_response; mod create_slug_attachment_response; mod create_stored_procedure_response; +mod create_user_defined_function_response; mod create_user_response; mod delete_attachment_response; mod delete_collection_response; @@ -12,6 +13,7 @@ mod delete_database_response; mod delete_document_response; mod delete_permission_response; mod delete_stored_procedure_response; +mod delete_user_defined_function_response; mod delete_user_response; mod execute_stored_procedure_response; mod get_attachment_response; @@ -26,6 +28,7 @@ mod list_databases_response; mod list_documents_response; mod list_permissions_response; mod list_stored_procedures_response; +mod list_user_defined_functions_response; mod list_users_response; mod query_documents_response; mod replace_document_response; @@ -39,6 +42,7 @@ pub use self::create_permission_response::CreatePermissionResponse; pub use self::create_reference_attachment_response::CreateReferenceAttachmentResponse; pub use self::create_slug_attachment_response::CreateSlugAttachmentResponse; pub use self::create_stored_procedure_response::CreateStoredProcedureResponse; +pub use self::create_user_defined_function_response::CreateUserDefinedFunctionResponse; pub use self::create_user_response::CreateUserResponse; pub use self::delete_attachment_response::DeleteAttachmentResponse; pub use self::delete_collection_response::DeleteCollectionResponse; @@ -46,6 +50,7 @@ pub use self::delete_database_response::DeleteDatabaseResponse; pub use self::delete_document_response::DeleteDocumentResponse; pub use self::delete_permission_response::DeletePermissionResponse; pub use self::delete_stored_procedure_response::DeleteStoredProcedureResponse; +pub use self::delete_user_defined_function_response::DeleteUserDefinedFunctionResponse; pub use self::delete_user_response::DeleteUserResponse; pub use self::execute_stored_procedure_response::ExecuteStoredProcedureResponse; pub use self::get_attachment_response::GetAttachmentResponse; @@ -62,8 +67,12 @@ pub use self::list_documents_response::{ }; pub use self::list_permissions_response::ListPermissionsResponse; pub use self::list_stored_procedures_response::ListStoredProceduresResponse; +pub use self::list_user_defined_functions_response::ListUserDefinedFunctionsResponse; pub use self::list_users_response::ListUsersResponse; -pub use self::query_documents_response::{QueryDocumentsResponse, QueryResponseMeta, QueryResult}; +pub use self::query_documents_response::{ + QueryDocumentsResponse, QueryDocumentsResponseDocuments, QueryDocumentsResponseRaw, + QueryResponseMeta, QueryResult, +}; pub use self::replace_document_response::ReplaceDocumentResponse; pub use self::replace_permission_response::ReplacePermissionResponse; pub use self::replace_reference_attachment_response::ReplaceReferenceAttachmentResponse; diff --git a/azure_sdk_cosmos/src/responses/query_documents_response.rs b/azure_sdk_cosmos/src/responses/query_documents_response.rs index 533b6aef0..aa8d49260 100644 --- a/azure_sdk_cosmos/src/responses/query_documents_response.rs +++ b/azure_sdk_cosmos/src/responses/query_documents_response.rs @@ -1,4 +1,5 @@ use crate::document_attributes::DocumentAttributes; +use crate::errors::ConversionToDocumentError; use crate::from_headers::*; use crate::ResourceQuota; use azure_sdk_core::errors::AzureError; @@ -12,14 +13,14 @@ use serde_json::Value; use std::convert::TryInto; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct QueryResult { +pub struct DocumentQueryResult { #[serde(flatten)] pub document_attributes: DocumentAttributes, #[serde(flatten)] pub result: T, } -impl std::convert::TryFrom<(&HeaderMap, &[u8])> for QueryResult +impl std::convert::TryFrom<(&HeaderMap, &[u8])> for DocumentQueryResult where T: DeserializeOwned, { @@ -50,6 +51,12 @@ impl std::convert::TryFrom<(&HeaderMap, &[u8])> for QueryResponseMeta { } } +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub enum QueryResult { + Document(DocumentQueryResult), + Raw(T), +} + #[derive(Debug, Clone, PartialEq)] pub struct QueryDocumentsResponse { pub query_response_meta: QueryResponseMeta, @@ -81,6 +88,18 @@ pub struct QueryDocumentsResponse { pub continuation_token: Option, } +impl QueryDocumentsResponse { + pub fn into_raw(self) -> QueryDocumentsResponseRaw { + self.into() + } + + pub fn into_documents( + self, + ) -> Result, ConversionToDocumentError> { + self.try_into() + } +} + impl std::convert::TryFrom<(&HeaderMap, &[u8])> for QueryDocumentsResponse where T: DeserializeOwned, @@ -97,13 +116,26 @@ where let mut results = Vec::new(); if let Value::Array(documents) = &inner["Documents"] { for doc in documents { - let document_attributes: DocumentAttributes = - serde_json::from_value(doc.to_owned())?; let result: T = serde_json::from_value(doc.to_owned())?; - results.push(QueryResult { - document_attributes, - result, - }); + // If we have all the necessary fields to construct a + // DocumentQueryResult we use it, otherwise we just add a raw + // struct. + // If I can ascertain that we receive *either* QueryResults + // or a raw documents - but not a mix of the two - + // we might want to avoid a discriminated union + // to be handled at runtime. + match serde_json::from_value(doc.to_owned()) { + Ok(document_attributes) => { + results.push(QueryResult::Document(DocumentQueryResult { + document_attributes, + result, + })) + } + Err(error) => { + warn!("{:#?}", error); + results.push(QueryResult::Raw(result)); + } + } } } @@ -137,3 +169,159 @@ where }) } } + +#[derive(Debug, Clone, PartialEq)] +pub struct QueryDocumentsResponseRaw { + pub query_response_meta: QueryResponseMeta, + pub results: Vec, + + pub last_state_change: DateTime, + pub resource_quota: Vec, + pub resource_usage: Vec, + pub lsn: u64, + pub item_count: u32, + pub schema_version: String, + pub alt_content_path: String, + pub content_path: String, + pub quorum_acked_lsn: Option, + pub current_write_quorum: Option, + pub current_replica_set_size: Option, + pub role: u32, + pub global_committed_lsn: u64, + pub number_of_read_regions: u32, + pub transport_request_id: u64, + pub cosmos_llsn: u64, + pub cosmos_quorum_acked_llsn: Option, + pub session_token: SessionToken, + pub charge: f64, + pub service_version: String, + pub activity_id: uuid::Uuid, + pub gateway_version: String, + pub date: DateTime, + pub continuation_token: Option, +} + +impl std::convert::From> for QueryDocumentsResponseRaw { + #[inline] + fn from(q: QueryDocumentsResponse) -> Self { + Self { + query_response_meta: q.query_response_meta, + results: q + .results + .into_iter() + .map(|r| match r { + QueryResult::Document(document) => document.result, + QueryResult::Raw(raw) => raw, + }) + .collect(), + last_state_change: q.last_state_change, + resource_quota: q.resource_quota, + resource_usage: q.resource_usage, + lsn: q.lsn, + item_count: q.item_count, + schema_version: q.schema_version, + alt_content_path: q.alt_content_path, + content_path: q.content_path, + quorum_acked_lsn: q.quorum_acked_lsn, + current_write_quorum: q.current_write_quorum, + current_replica_set_size: q.current_replica_set_size, + role: q.role, + global_committed_lsn: q.global_committed_lsn, + number_of_read_regions: q.number_of_read_regions, + transport_request_id: q.transport_request_id, + cosmos_llsn: q.cosmos_llsn, + cosmos_quorum_acked_llsn: q.cosmos_quorum_acked_llsn, + session_token: q.session_token, + charge: q.charge, + service_version: q.service_version, + activity_id: q.activity_id, + gateway_version: q.gateway_version, + continuation_token: q.continuation_token, + date: q.date, + } + } +} + +#[derive(Debug, Clone, PartialEq)] +pub struct QueryDocumentsResponseDocuments { + pub query_response_meta: QueryResponseMeta, + pub results: Vec>, + + pub last_state_change: DateTime, + pub resource_quota: Vec, + pub resource_usage: Vec, + pub lsn: u64, + pub item_count: u32, + pub schema_version: String, + pub alt_content_path: String, + pub content_path: String, + pub quorum_acked_lsn: Option, + pub current_write_quorum: Option, + pub current_replica_set_size: Option, + pub role: u32, + pub global_committed_lsn: u64, + pub number_of_read_regions: u32, + pub transport_request_id: u64, + pub cosmos_llsn: u64, + pub cosmos_quorum_acked_llsn: Option, + pub session_token: SessionToken, + pub charge: f64, + pub service_version: String, + pub activity_id: uuid::Uuid, + pub gateway_version: String, + pub date: DateTime, + pub continuation_token: Option, +} + +impl std::convert::TryFrom> for QueryDocumentsResponseDocuments { + type Error = ConversionToDocumentError; + + #[inline] + fn try_from(q: QueryDocumentsResponse) -> Result { + // first check if there is a Raw document. In case we bail out + if let Some(_) = q.results.iter().find(|r| match r { + QueryResult::Document(_) => false, + QueryResult::Raw(_) => true, + }) { + return Err(ConversionToDocumentError::RawElementFound {}); + } + + Ok(Self { + query_response_meta: q.query_response_meta, + results: q + .results + .into_iter() + .map(|r| match r { + QueryResult::Document(document) => document, + QueryResult::Raw(_) => { + panic!("this should have been caugth by the previous check") + } + }) + .collect(), + last_state_change: q.last_state_change, + resource_quota: q.resource_quota, + resource_usage: q.resource_usage, + lsn: q.lsn, + item_count: q.item_count, + schema_version: q.schema_version, + alt_content_path: q.alt_content_path, + content_path: q.content_path, + quorum_acked_lsn: q.quorum_acked_lsn, + current_write_quorum: q.current_write_quorum, + current_replica_set_size: q.current_replica_set_size, + role: q.role, + global_committed_lsn: q.global_committed_lsn, + number_of_read_regions: q.number_of_read_regions, + transport_request_id: q.transport_request_id, + cosmos_llsn: q.cosmos_llsn, + cosmos_quorum_acked_llsn: q.cosmos_quorum_acked_llsn, + session_token: q.session_token, + charge: q.charge, + service_version: q.service_version, + activity_id: q.activity_id, + gateway_version: q.gateway_version, + continuation_token: q.continuation_token, + date: q.date, + }) + } +} diff --git a/azure_sdk_cosmos/src/to_json_vector.rs b/azure_sdk_cosmos/src/to_json_vector.rs index a12a11b62..d9cc25ac3 100644 --- a/azure_sdk_cosmos/src/to_json_vector.rs +++ b/azure_sdk_cosmos/src/to_json_vector.rs @@ -1,5 +1,6 @@ use azure_sdk_core::errors::AzureError; use serde::ser::Serialize; +use std::borrow::Cow; #[derive(Debug, Clone, PartialEq, PartialOrd)] pub struct ToJsonVector { @@ -91,6 +92,22 @@ impl std::convert::From<&str> for ToJsonVector { } } +impl std::convert::From> for ToJsonVector { + fn from(t: Cow<'_, str>) -> Self { + let mut pk = Self::new(); + let _ = pk.push(t).unwrap(); + pk + } +} + +impl std::convert::From<&Cow<'_, str>> for ToJsonVector { + fn from(t: &Cow<'_, str>) -> Self { + let mut pk = Self::new(); + let _ = pk.push(t).unwrap(); + pk + } +} + impl std::convert::From<&String> for ToJsonVector { fn from(t: &String) -> Self { let mut pk = Self::new(); diff --git a/azure_sdk_cosmos/src/user_defined_function/mod.rs b/azure_sdk_cosmos/src/user_defined_function/mod.rs new file mode 100644 index 000000000..5dfff5975 --- /dev/null +++ b/azure_sdk_cosmos/src/user_defined_function/mod.rs @@ -0,0 +1,23 @@ +mod user_defined_function_name; + +pub use self::user_defined_function_name::UserDefinedFunctionName; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct UserDefinedFunction { + pub id: String, + #[serde(rename = "_rid")] + pub rid: String, + #[serde(rename = "_ts")] + pub ts: u64, + #[serde(rename = "_self")] + pub _self: String, + #[serde(rename = "_etag")] + pub etag: String, + pub body: String, +} + +impl UserDefinedFunctionName for UserDefinedFunction { + fn name(&self) -> &str { + &self.id + } +} diff --git a/azure_sdk_cosmos/src/user_defined_function/user_defined_function_name.rs b/azure_sdk_cosmos/src/user_defined_function/user_defined_function_name.rs new file mode 100644 index 000000000..748ab6545 --- /dev/null +++ b/azure_sdk_cosmos/src/user_defined_function/user_defined_function_name.rs @@ -0,0 +1,15 @@ +pub trait UserDefinedFunctionName: std::fmt::Debug { + fn name(&self) -> &str; +} + +impl UserDefinedFunctionName for &str { + fn name(&self) -> &str { + self + } +} + +impl UserDefinedFunctionName for String { + fn name(&self) -> &str { + self.as_ref() + } +} diff --git a/azure_sdk_cosmos/tests/attachment00.rs b/azure_sdk_cosmos/tests/attachment00.rs index 5189ea1a3..b1dc40f99 100644 --- a/azure_sdk_cosmos/tests/attachment00.rs +++ b/azure_sdk_cosmos/tests/attachment00.rs @@ -16,6 +16,7 @@ mod setup; // specified in the Document struct below. #[derive(Serialize, Deserialize, Clone, Debug)] struct MySampleStruct<'a> { + id: Cow<'a, str>, a_string: Cow<'a, str>, a_number: u64, a_timestamp: i64, @@ -73,26 +74,24 @@ async fn attachment() -> Result<(), Box> { let id = format!("unique_id{}", 100); - let doc = Document::new( - id.clone(), - MySampleStruct { - a_string: Cow::Borrowed("Something here"), - a_number: 100, - a_timestamp: chrono::Utc::now().timestamp(), - }, - ); + let doc = Document::new(MySampleStruct { + id: Cow::Borrowed(&id), + a_string: Cow::Borrowed("Something here"), + a_number: 100, + a_timestamp: chrono::Utc::now().timestamp(), + }); // let's add an entity. let session_token: ConsistencyLevel = collection_client .create_document() .with_document(&doc) - .with_partition_keys(PartitionKeys::new().push(doc.document_attributes.id())?) + .with_partition_keys(PartitionKeys::new().push(&doc.document.id)?) .execute() .await? .into(); let mut partition_keys = PartitionKeys::new(); - partition_keys.push(doc.document_attributes.id())?; + partition_keys.push(doc.document.id)?; let document_client = collection_client.with_document(&id, &partition_keys); // list attachments, there must be none. @@ -105,9 +104,9 @@ async fn attachment() -> Result<(), Box> { // create reference attachment let attachment_client = document_client.with_attachment(&"reference"); - let _resp = attachment_client + let resp = attachment_client .create_reference() - .with_consistency_level(session_token.clone()) + .with_consistency_level((&ret).into()) .with_content_type("image/jpeg") .with_media("https://www.bing.com") .execute() @@ -115,9 +114,9 @@ async fn attachment() -> Result<(), Box> { // replace reference attachment let attachment_client = document_client.with_attachment(&"reference"); - let _resp = attachment_client + let resp = attachment_client .replace_reference() - .with_consistency_level(session_token.clone()) + .with_consistency_level((&resp).into()) .with_content_type("image/jpeg") .with_media("https://www.microsoft.com") .execute() @@ -125,9 +124,9 @@ async fn attachment() -> Result<(), Box> { // create slug attachment let attachment_client = document_client.with_attachment(&"slug"); - let _resp = attachment_client + let resp = attachment_client .create_slug() - .with_consistency_level(session_token.clone()) + .with_consistency_level((&resp).into()) .with_content_type("text/plain") .with_body(b"something cool here") .execute() @@ -136,7 +135,7 @@ async fn attachment() -> Result<(), Box> { // list attachments, there must be two. let ret = document_client .list_attachments() - .with_consistency_level(session_token.clone()) + .with_consistency_level((&resp).into()) .execute() .await?; assert_eq!(2, ret.attachments.len()); @@ -145,7 +144,7 @@ async fn attachment() -> Result<(), Box> { let reference_attachment = document_client .with_attachment(&"reference") .get() - .with_consistency_level(session_token.clone()) + .with_consistency_level((&ret).into()) .execute() .await?; assert_eq!( @@ -158,23 +157,23 @@ async fn attachment() -> Result<(), Box> { let slug_attachment = document_client .with_attachment(&"slug") .get() - .with_consistency_level(session_token.clone()) + .with_consistency_level((&reference_attachment).into()) .execute() .await .unwrap(); assert_eq!("text/plain", slug_attachment.attachment.content_type); // delete slug attachment - let _resp_delete = attachment_client + let resp_delete = attachment_client .delete() - .with_consistency_level(session_token.clone()) + .with_consistency_level((&slug_attachment).into()) .execute() .await?; // list attachments, there must be one. let ret = document_client .list_attachments() - .with_consistency_level(session_token.clone()) + .with_consistency_level((&resp_delete).into()) .execute() .await?; assert_eq!(1, ret.attachments.len()); diff --git a/azure_sdk_cosmos/tests/cosmos_document.rs b/azure_sdk_cosmos/tests/cosmos_document.rs index 10b2f2371..54a519f96 100644 --- a/azure_sdk_cosmos/tests/cosmos_document.rs +++ b/azure_sdk_cosmos/tests/cosmos_document.rs @@ -9,10 +9,9 @@ use azure_sdk_cosmos::Offer; use azure_sdk_cosmos::Query; mod setup; -// the id will be specified in the azure_sdk_cosmos::Document struct -// ctor. #[derive(Serialize, Deserialize, Debug, PartialEq)] struct MyDocument { + id: String, hello: u32, } @@ -54,11 +53,14 @@ async fn create_and_delete_document() { let collection_client = database_client.with_collection(&COLLECTION_NAME); // create a new document - let document_data = Document::new(DOCUMENT_NAME.to_string(), MyDocument { hello: 42 }); + let document_data = Document::new(MyDocument { + id: DOCUMENT_NAME.to_owned(), + hello: 42, + }); collection_client .create_document() .with_document(&document_data) - .with_partition_keys(&(&document_data.document_attributes.id as &str).into()) + .with_partition_keys(&DOCUMENT_NAME.into()) .execute() .await .unwrap(); @@ -138,10 +140,13 @@ async fn query_documents() { let collection_client = database_client.with_collection(&COLLECTION_NAME); // create a new document - let document_data = Document::new(DOCUMENT_NAME.to_string(), MyDocument { hello: 42 }); + let document_data = Document::new(MyDocument { + id: DOCUMENT_NAME.to_owned(), + hello: 42, + }); collection_client .create_document() - .with_partition_keys(&(&document_data.document_attributes.id as &str).into()) + .with_partition_keys(&(&document_data.document.id).into()) .with_document(&document_data) .execute() .await @@ -163,6 +168,8 @@ async fn query_documents() { .execute::() .await .unwrap() + .into_documents() + .unwrap() .results; assert!(query_result.len() == 1); @@ -209,11 +216,14 @@ async fn replace_document() { let collection_client = database_client.with_collection(&COLLECTION_NAME); // create a new document - let mut document_data = Document::new(DOCUMENT_NAME.to_string(), MyDocument { hello: 42 }); + let mut document_data = Document::new(MyDocument { + id: DOCUMENT_NAME.to_owned(), + hello: 42, + }); collection_client .create_document() .with_document(&document_data) - .with_partition_keys(&(&document_data.document_attributes.id as &str).into()) + .with_partition_keys(&(&document_data.document.id).into()) .execute() .await .unwrap(); @@ -230,7 +240,8 @@ async fn replace_document() { collection_client .replace_document() .with_document(&document_data) - .with_partition_keys(&(&document_data.document_attributes.id as &str).into()) + .with_document_id(&document_data.document.id) + .with_partition_keys(&(&document_data.document.id).into()) .with_consistency_level(ConsistencyLevel::from(&documents)) .with_if_match_condition(IfMatchCondition::Match( &documents.documents[0].document_attributes.etag, diff --git a/azure_sdk_cosmos/tests/permission_token_usage.rs b/azure_sdk_cosmos/tests/permission_token_usage.rs index dc13af179..5bfd1147b 100644 --- a/azure_sdk_cosmos/tests/permission_token_usage.rs +++ b/azure_sdk_cosmos/tests/permission_token_usage.rs @@ -79,25 +79,19 @@ async fn permissions() { // authorization_token just created. It must fail. let data = r#" { + "id": "Gianluigi Bombatomica", "age": 43, "phones": [ "+39 1234567", "+39 2345678" ] }"#; - let document = Document::new( - "Gianluigi Bombatomica".to_owned(), - serde_json::from_str::(data).unwrap(), - ); + let document = Document::new(serde_json::from_str::(data).unwrap()); new_collection_client .create_document() .with_document(&document) .with_is_upsert(true) - .with_partition_keys( - PartitionKeys::new() - .push(document.document_attributes.id()) - .unwrap(), - ) + .with_partition_keys(PartitionKeys::new().push(&"Gianluigi Bombatomica").unwrap()) .execute() .await .unwrap_err(); @@ -132,11 +126,7 @@ async fn permissions() { .create_document() .with_document(&document) .with_is_upsert(true) - .with_partition_keys( - PartitionKeys::new() - .push(document.document_attributes.id()) - .unwrap(), - ) + .with_partition_keys(PartitionKeys::new().push(&"Gianluigi Bombatomica").unwrap()) .execute() .await .unwrap(); diff --git a/azure_sdk_cosmos/tests/user_defined_function00.rs b/azure_sdk_cosmos/tests/user_defined_function00.rs new file mode 100644 index 000000000..68466b665 --- /dev/null +++ b/azure_sdk_cosmos/tests/user_defined_function00.rs @@ -0,0 +1,145 @@ +#![cfg(all(test, feature = "test_e2e"))] +use azure_sdk_cosmos::prelude::*; +use futures::stream::StreamExt; +use std::error::Error; + +mod setup; + +const FN_BODY: &str = r#" +function tax(income) { + if (income == undefined) + throw 'no input'; + if (income < 1000) + return income * 0.1; + else if (income < 10000) + return income * 0.2; + else + return income * 0.4; +}"#; + +#[tokio::test] +async fn user_defined_function00() -> Result<(), Box> { + const DATABASE_NAME: &str = "test-cosmos-db-udf"; + const COLLECTION_NAME: &str = "test-udf"; + const USER_DEFINED_FUNCTION_NAME: &str = "test"; + + let client = setup::initialize().unwrap(); + + // create a temp database + let _create_database_response = client + .create_database() + .with_database_name(&DATABASE_NAME) + .execute() + .await + .unwrap(); + + let database_client = client.with_database(&DATABASE_NAME); + + // create a temp collection + let _create_collection_response = { + let indexes = IncludedPathIndex { + kind: KeyKind::Hash, + data_type: DataType::String, + precision: Some(3), + }; + + let ip = IncludedPath { + path: "/*".to_owned(), + indexes: Some(vec![indexes]), + }; + + let ip = IndexingPolicy { + automatic: true, + indexing_mode: IndexingMode::Consistent, + included_paths: vec![ip], + excluded_paths: vec![], + }; + + database_client + .create_collection() + .with_collection_name(&COLLECTION_NAME) + .with_partition_key(&("/id".into())) + .with_offer(Offer::Throughput(400)) + .with_indexing_policy(&ip) + .execute() + .await + .unwrap() + }; + + let collection_client = database_client.with_collection(&COLLECTION_NAME); + let user_defined_function_client = + collection_client.with_user_defined_function(&USER_DEFINED_FUNCTION_NAME); + + let ret = user_defined_function_client + .create_user_defined_function() + .with_body("body") + .execute() + .await?; + + let stream = collection_client + .list_user_defined_functions() + .with_max_item_count(3) + .with_consistency_level((&ret).into()); + let mut stream = Box::pin(stream.stream()); + while let Some(ret) = stream.next().await { + let ret = ret.unwrap(); + assert_eq!(ret.item_count, 1); + } + + let ret = user_defined_function_client + .replace_user_defined_function() + .with_consistency_level((&ret).into()) + .with_body(FN_BODY) + .execute() + .await?; + + let query_stmt = format!("SELECT udf.{}(100)", USER_DEFINED_FUNCTION_NAME); + let ret: QueryDocumentsResponseRaw = collection_client + .query_documents() + .with_query(&(&query_stmt as &str).into()) + .with_consistency_level((&ret).into()) + .with_max_item_count(2) + .execute() + .await? + .into_raw(); + + assert_eq!(ret.item_count, 1); + + let fn_return = ret.results[0].as_object().unwrap(); + let value = fn_return.iter().take(1).next().unwrap().1.as_f64().unwrap(); + assert_eq!(value, 10.0); + + let query_stmt = format!("SELECT udf.{}(10000)", USER_DEFINED_FUNCTION_NAME); + let ret: QueryDocumentsResponseRaw = collection_client + .query_documents() + .with_query(&(&query_stmt as &str).into()) + .with_consistency_level((&ret).into()) + .with_max_item_count(2) + .execute() + .await? + .into_raw(); + + assert_eq!(ret.item_count, 1); + + let fn_return = ret.results[0].as_object().unwrap(); + let value = fn_return + .into_iter() + .take(1) + .next() + .unwrap() + .1 + .as_f64() + .unwrap(); + assert_eq!(value, 4000.0); + + let _ret = user_defined_function_client + .delete_user_defined_function() + .with_consistency_level((&ret).into()) + .execute() + .await?; + + // delete the database + database_client.delete_database().execute().await?; + + Ok(()) +}