diff --git a/src/data/bigquery_table.rs b/src/data/bigquery_table.rs index 503d163..4f6592d 100644 --- a/src/data/bigquery_table.rs +++ b/src/data/bigquery_table.rs @@ -1,20 +1,18 @@ use std::collections::HashMap; -use std::fmt::{Debug, Display, Formatter}; -use std::marker::PhantomData; +use std::fmt::Debug; use async_trait::async_trait; -pub use google_bigquery2::api::{QueryParameterType, QueryParameterValue}; pub use google_bigquery2::api::QueryParameter; -use google_bigquery2::api::QueryRequest; +pub use google_bigquery2::api::{QueryParameterType, QueryParameterValue}; use log::debug; use log::trace; use serde_json::Value; use crate::client::BigqueryClient; -use crate::data::param_conversion::{BigDataValueType, convert_value_to_string}; +use crate::data::param_conversion::{convert_value_to_string, BigDataValueType}; use crate::data::query_builder::{ - NoClient, NoStartingData, QueryBuilder, QueryResultType, QueryTypeInsert, QueryTypeNoType, - QueryTypeSelect, QueryTypeUpdate, QueryWasNotBuilt, + NoClient, NoStartingData, QueryBuilder, QueryResultType, QueryTypeDelete, QueryTypeInsert, + QueryTypeNoType, QueryTypeSelect, QueryTypeUpdate, QueryWasNotBuilt, }; use crate::prelude::*; @@ -53,8 +51,8 @@ pub trait BigQueryTableBase { client: BigqueryClient, row: &HashMap, ) -> Result - where - Self: Sized; + where + Self: Sized; //region update @@ -68,26 +66,32 @@ pub trait BigQueryTableBase { #[async_trait] pub trait BigQueryTable: BigQueryTableBase { fn select() -> QueryBuilder - where - Self: Sized, + where + Self: Sized, { QueryBuilder::::select() } fn insert() -> QueryBuilder - where - Self: Sized, + where + Self: Sized, { QueryBuilder::::insert() } fn update() -> QueryBuilder - where - Self: Sized, + where + Self: Sized, { QueryBuilder::::update() } + fn delete() -> QueryBuilder + where + Self: Sized, + { + QueryBuilder::::delete() + } fn get_parameter(value: &T, param_name: &String) -> Option - where - T: BigDataValueType + Debug, + where + T: BigDataValueType + Debug, { trace!("get_parameter({:?}, {})", value, param_name); let value = value.to_param(); @@ -147,9 +151,9 @@ pub trait BigQueryTable: BigQueryTableBase { } async fn get_by_pk(client: BigqueryClient, pk_value: &PK) -> Result - where - PK: BigDataValueType + Send + Sync + 'static, - Self: Sized + Debug, + where + PK: BigDataValueType + Send + Sync + 'static, + Self: Sized + Debug, { trace!("get_by_pk({:?}, {:?})", client, pk_value); let pk_field_name = Self::get_pk_field_name(); @@ -167,7 +171,7 @@ pub trait BigQueryTable: BigQueryTableBase { "something went wrong when getting for {} = {:?};\tresult: {:?}", pk_field_name, pk_value, success ) - .into()); + .into()); } }; @@ -178,15 +182,15 @@ pub trait BigQueryTable: BigQueryTableBase { "More than one entry found for {} = {:?}", pk_db_name, pk_value ) - .into()) + .into()) } else { Ok(rows.remove(0)) } } async fn upsert(&mut self) -> Result<()> - where - Self: Sized + Clone + Send + Sync + Debug + Default, + where + Self: Sized + Clone + Send + Sync + Debug + Default, { trace!("upsert()"); @@ -211,8 +215,8 @@ pub trait BigQueryTable: BigQueryTableBase { /// proxy for update async fn save(&mut self) -> Result<()> - where - Self: Sized + Clone + Send + Sync + Debug + Default, + where + Self: Sized + Clone + Send + Sync + Debug + Default, { trace!("save(): {:?}", self); let result = Self::update() @@ -232,7 +236,7 @@ pub trait BigQueryTable: BigQueryTableBase { "save should return empty data, but returned {} rows.", count ) - .into()) + .into()) } } diff --git a/src/data/query_builder.rs b/src/data/query_builder.rs index 82155a9..37150c5 100644 --- a/src/data/query_builder.rs +++ b/src/data/query_builder.rs @@ -139,6 +139,13 @@ pub struct QueryTypeUpdate; impl HasQueryType for QueryTypeUpdate {} +//endregion +//region update +#[derive(Debug, Clone)] +pub struct QueryTypeDelete; + +impl HasQueryType for QueryTypeDelete {} + //endregion //endregion @@ -167,7 +174,7 @@ pub struct QueryBuilder { //region default implementation for QueryBuilder impl Default -for QueryBuilder + for QueryBuilder { fn default() -> Self { Self { @@ -189,7 +196,7 @@ for QueryBuilder //region general QueryBuilder //region functions for all queries impl -QueryBuilder + QueryBuilder { fn get_sorted_selected_fields(&self) -> Vec<(String, String)> { trace!("get_sorted_selected_fields()"); @@ -214,7 +221,7 @@ QueryBuilder //region functions for not built queries //region with Starting data impl -QueryBuilder> + QueryBuilder> { pub fn add_field_where(self, field: &str) -> Result { trace!("add_field_where(field: {})", field); @@ -268,12 +275,12 @@ QueryBuilder -QueryBuilder + QueryBuilder { //region set query content pub fn add_where_eq(self, column: &str, value: Option<&T>) -> Result - where - T: BigDataValueType + Debug, + where + T: BigDataValueType + Debug, { trace!("add_where_eq({:?}, {:?})", column, value); let column = Table::get_field_db_name(column)?; @@ -353,7 +360,7 @@ QueryBuilder //endregion //region set_data impl -QueryBuilder + QueryBuilder { pub fn set_data( self, @@ -378,13 +385,12 @@ QueryBuilder //endregion //region QueryTypeNoType impl -QueryBuilder + QueryBuilder { pub fn select() -> QueryBuilder { trace!("select()"); QueryBuilder { - query: String::from("SELECT "), ..Default::default() } } @@ -392,7 +398,6 @@ QueryBuilder { trace!("insert()"); QueryBuilder { - query: String::from("INSERT INTO "), ..Default::default() } } @@ -400,7 +405,13 @@ QueryBuilder { trace!("update()"); QueryBuilder { - query: String::from("INSERT INTO "), + ..Default::default() + } + } + pub fn delete() -> QueryBuilder + { + trace!("delete()"); + QueryBuilder { ..Default::default() } } @@ -409,7 +420,37 @@ QueryBuilder //endregion //region QueryTypeInsert impl -QueryBuilder> + QueryBuilder> +{ + pub fn build_query( + mut self, + ) -> Result< + QueryBuilder>, + > { + trace!("build_query: delete: {:?}", self); + let table_identifier = Table::get_table_identifier_from_client(&self.client.0); + self = self.add_field_where(&Table::get_pk_field_name())?; + let where_clause = &self.build_where_string(); + + let query = format!("DELETE FROM {} {}", table_identifier, where_clause); + Ok(QueryBuilder { + query, + params: self.params, + where_clauses: self.where_clauses, + order_by: self.order_by, + limit: self.limit, + client: self.client, + table: self.table, + starting_data: self.starting_data, + query_type: self.query_type, + query_built: PhantomData, + }) + } +} + +//region QueryTypeInsert +impl + QueryBuilder> { pub fn build_query( mut self, @@ -461,9 +502,21 @@ QueryBuilder Result>> { trace!("get_value_parameter_names\tself: {:?}", self); let mut values = self.get_sorted_selected_fields(); - let existing_params: Vec = self.params.iter().map(|p| p.name.clone().unwrap()).collect(); - debug!("existing_params: len: {} params: {:?}", existing_params.len(), existing_params); - debug!("selected_fields: len: {} fields: {:?}", values.len(), values); + let existing_params: Vec = self + .params + .iter() + .map(|p| p.name.clone().unwrap()) + .collect(); + debug!( + "existing_params: len: {} params: {:?}", + existing_params.len(), + existing_params + ); + debug!( + "selected_fields: len: {} fields: {:?}", + values.len(), + values + ); let res = values .iter_mut() .map(|(field, _)| match Table::get_field_param_name(field) { @@ -484,7 +537,7 @@ QueryBuilder -QueryBuilder> + QueryBuilder> { pub fn build_query( mut self, @@ -527,10 +580,9 @@ QueryBuilder format!("{} = @{}", f, p), - None => format!("{} = NULL", f), - } - ) + Some(p) => format!("{} = @{}", f, p), + None => format!("{} = NULL", f), + }) .collect::>() .join(", "); trace!("build_update_fields_string: result: {}", result); @@ -539,7 +591,11 @@ QueryBuilder Result)>> { let mut values = self.get_sorted_selected_fields(); - let existing_params: Vec = self.params.iter().map(|p| p.name.clone().unwrap()).collect(); + let existing_params: Vec = self + .params + .iter() + .map(|p| p.name.clone().unwrap()) + .collect(); let mut res = vec![]; for (field, _) in values.iter_mut() { res.push(( @@ -558,7 +614,7 @@ QueryBuilder -QueryBuilder + QueryBuilder { pub fn add_order_by( mut self, @@ -573,7 +629,7 @@ QueryBuilder //endregion //region client needed impl -QueryBuilder + QueryBuilder { pub fn build_query( self, @@ -608,7 +664,7 @@ QueryBuilder //endregion //region with_client impl -QueryBuilder + QueryBuilder { pub fn with_client( self, @@ -632,7 +688,7 @@ QueryBuilder //endregion //region un_build & get query string impl -QueryBuilder + QueryBuilder { pub fn un_build( self, @@ -658,7 +714,7 @@ QueryBuilder //endregion //region run impl -QueryBuilder + QueryBuilder { pub async fn run(self) -> Result> { trace!("run query: {}", self.query); diff --git a/tests/tests.rs b/tests/tests.rs index fa7b90d..79bffed 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1,10 +1,7 @@ use log::{debug, info, LevelFilter}; use nameof::name_of; -use google_bigquery_v2::data::query_builder::{ - HasStartingData, NoClient, NoStartingData, QueryBuilder, QueryResultType, QueryTypeInsert, - QueryTypeNoType, QueryTypeSelect, QueryTypeUpdate, QueryWasNotBuilt, -}; +use google_bigquery_v2::data::query_builder::QueryResultType; use google_bigquery_v2::prelude::*; #[derive(BigDataTableDerive, Debug, Default, Clone)] @@ -24,16 +21,6 @@ pub struct DbInfos { info4b: Option::, } -pub struct DbInfos2 { - client: BigqueryClient, - row_id: i64, - info1: Option, - info2: Option, - info3: Option, - info4i: Option, - info4b: Option, -} - #[tokio::test] async fn test1() { init_logger(); @@ -56,14 +43,24 @@ async fn test1() { }; let query_builder = DbInfos::insert(); - println!("{:?}", query_builder); - let query_builder = query_builder.with_client(client); - let query_builder = query_builder.set_data(sample_data); + debug!("{:?}", query_builder); + let query_builder = query_builder.with_client(client.clone()); + let query_builder = query_builder.set_data(sample_data.clone()); let query_builder = query_builder.build_query().expect("query builder failed"); - println!("query: {:?}", query_builder); + debug!("query: {:?}", query_builder); let result = query_builder.clone().run().await; - println!("query: {:?}", query_builder); - println!("result: {:?}", result); + debug!("query: {:?}", query_builder); + debug!("result: {:?}", result); + + let query_builder = DbInfos::delete() + .with_client(client.clone()) + .set_data(sample_data); + let query_builder = query_builder.build_query().expect("query builder failed"); + debug!("query: {:?}", query_builder); + let result = query_builder.clone().run().await; + debug!("query: {:?}", query_builder); + debug!("result: {:?}", result); + result.expect("result is not ok"); } #[tokio::test] @@ -76,8 +73,8 @@ async fn test_save() { entry.info1 = Some("test1".to_string()); entry.info2 = Some("test2".to_string()); entry.info3 = None; - entry.info4i = Some(1); entry.info4b = Some(true); + let info4i = entry.info4i; debug!("entry: {:?}", entry); debug!("========================================================================"); debug!("starting save"); @@ -97,14 +94,21 @@ async fn test_save() { debug!("reload done"); debug!("========================================================================"); assert_eq!(info1, entry.info1.unwrap(), "reload failed"); - assert_eq!(None, entry.info3, "Info 3 should be set to None before the save happened"); + assert_eq!( + None, entry.info3, + "Info 3 should be set to None before the save happened" + ); + assert_eq!( + info4i, entry.info4i, + "Info 4i should not have changed between the load from pk and the reload" + ); } #[tokio::test] async fn test_get_table_name() { init_logger(); let pk = DbInfos::get_table_name(); - log::debug!("table name: {}", pk); + debug!("table name: {}", pk); assert_eq!("Infos", pk, "table name is not correct") } @@ -112,7 +116,7 @@ async fn test_get_table_name() { async fn test_get_query_fields() { init_logger(); let fields = DbInfos::get_query_fields(true); - log::debug!("fields: {:?}", fields); + debug!("fields: {:?}", fields); assert_eq!(6, fields.len(), "fields length is not correct"); assert_eq!("Id", fields.get("row_id").unwrap(),); assert_eq!("info1", fields.get("info1").unwrap(),); @@ -142,9 +146,9 @@ async fn test_query_builder_1() { let expected_query_string = "SELECT info1, info, info3, yes, info4i, Id FROM `testrustproject-372221.test1.Infos` WHERE info1 is NULL AND info3 = @__PARAM_0 ORDER BY info ASC".to_string() ; - log::debug!("query : {}", query_string); - log::debug!("expected: {}", expected_query_string); - log::debug!("request: {:?}", query_builder.clone().build_query()); + debug!("query : {}", query_string); + debug!("expected: {}", expected_query_string); + debug!("request: {:?}", query_builder.clone().build_query()); assert_eq!(query_string, expected_query_string); // assert_eq!( @@ -163,7 +167,7 @@ async fn test_query_builder_1() { .run() .await .unwrap(); - log::debug!("res: {:?}", res); + debug!("res: {:?}", res); } async fn get_test_client() -> BigqueryClient {