use std::collections::HashMap; use std::error::Error; use std::fmt::Debug; use std::str::FromStr; use google_bigquery2::api::{QueryParameter, QueryParameterType, QueryParameterValue}; use crate::client::BigqueryClient; use crate::data::BigDataTableBase; use crate::utils::BigDataValueType; pub trait BigDataTableBaseConvenience<'a, TABLE, TPK> : BigDataTableBase<'a, TABLE, TPK> where TPK: BigDataValueType + FromStr + Debug { fn get_pk_param(&self) -> google_bigquery2::api::QueryParameter; fn get_query_fields_str() -> String; fn get_query_fields_insert_str() -> String; fn get_where_part(field_name: &str, is_comparing_to_null: bool) -> String; async fn run_get_query(&self, query: &str, project_id: &str) -> Result>; async fn run_get_query_with_params(&self, query: &str, parameters: Vec, project_id: &str) -> Result>; async fn run_get_query_with_params_on_client(client: &'a BigqueryClient, query: &str, parameters: Vec, project_id: &str) -> Result>; // async fn get_identifier_and_base_where(&self) -> Result<(String, String), Box>; async fn get_identifier(&self) -> Result>; async fn get_identifier_from_client(client: &'a BigqueryClient) -> Result>; fn get_base_where() -> String; // async fn get_identifier_and_base_where_from_client(client: &'a BigqueryClient, pk_name: &str, table_name: &str) -> Result<(String, String), Box>; fn get_query_param(field_name: &str, field_value: &Option) -> google_bigquery2::api::QueryParameter; fn parse_value_to_parameter(value: &TValue) -> String where TValue: std::fmt::Display + BigDataValueType; // fn create_from_table_row(client: &'a BigqueryClient, // row: &google_bigquery2::api::TableRow, // index_to_name_mapping: &HashMap) // -> Result> // where // Self: Sized; } impl<'a, TABLE, TPK> BigDataTableBaseConvenience<'a, TABLE, TPK> for TABLE where TABLE: BigDataTableBase<'a, TABLE, TPK>, TPK: BigDataValueType + FromStr + Debug, ::Err: Debug, { fn get_pk_param(&self) -> QueryParameter { Self::get_query_param(&Self::get_pk_name(), &Some(self.get_pk_value())) // QueryParameter { // name: Some(format!("__{}",Self::get_pk_name())), // parameter_type: Some(QueryParameterType { // array_type: None, // struct_types: None, // type_: Some(TPK::to_bigquery_type()), // }), // parameter_value: Some(QueryParameterValue { // value: Some(self.get_pk_value().to_bigquery_param_value()), // ..Default::default() // }), // } } fn get_query_fields_str() -> String { Self::get_query_fields().values().into_iter() .map(|v| format!("{}", v)) .collect::>() .join(", ") } fn get_query_fields_insert_str() -> String { Self::get_query_fields() .values() .into_iter() .map(|v| format!("@__{}", v)) .collect::>() .join(", ") } fn get_where_part(field_name: &str, is_comparing_to_null: bool) -> String { if is_comparing_to_null { format!("{} IS NULL", field_name) } else { format!("{} = @__{}", field_name, field_name) } } async fn run_get_query(&self, query: &str, project_id: &str) -> Result> { let parameters = vec![self.get_pk_param()];//default parameters (pk) self.run_get_query_with_params(query, parameters, project_id).await } async fn run_get_query_with_params(&self, query: &str, parameters: Vec, project_id: &str) -> Result> { let client = self.get_client(); Self::run_get_query_with_params_on_client(client, query, parameters, project_id).await } async fn run_get_query_with_params_on_client(client: &'a BigqueryClient, query: &str, parameters: Vec, project_id: &str) -> Result> { println!("Query: {}", query); println!("Parameters: {}", parameters.len()); for (i, param) in parameters.iter().enumerate() { println!("{:2}: {:?}", i, param); } println!(); let req = google_bigquery2::api::QueryRequest { query: Some(query.to_string()), query_parameters: Some(parameters), use_legacy_sql: Some(false), ..Default::default() }; let (res, query_res) = client.get_client().jobs().query(req, project_id) .doit().await?; if res.status() != 200 { return Err(format!("Wrong status code returned! ({})", res.status()).into()); } Ok(query_res) } // async fn get_identifier_and_base_where(&self) // -> Result<(String, String), Box> { // let pk_name = Self::get_pk_name(); // let table_name = Self::get_table_name(); // Ok(Self::get_identifier_and_base_where_from_client(&self.get_client(), &pk_name, &table_name).await?) // } async fn get_identifier(&self) -> Result> { let client = self.get_client(); Self::get_identifier_from_client(&client).await } async fn get_identifier_from_client(client: &'a BigqueryClient) -> Result> { let dataset_id = client.get_dataset_id(); let table_name = Self::get_table_name(); let table_identifier = format!("{}.{}", dataset_id, table_name); Ok(table_identifier) } fn get_base_where() -> String { let pk_name = Self::get_pk_name(); Self::get_where_part(&pk_name, false) } default fn get_query_param(field_name: &str, field_value: &Option) -> google_bigquery2::api::QueryParameter { let type_to_string: String = TField::to_bigquery_type(); let value: Option = match field_value { Some(value) => Some(google_bigquery2::api::QueryParameterValue { value: Some(value.to_bigquery_param_value()),//TODO: maybe add a way to use array types ..Default::default() }), None => None, }; google_bigquery2::api::QueryParameter { name: Some(format!("__{}", field_name.clone())), parameter_type: Some(google_bigquery2::api::QueryParameterType { type_: Some(type_to_string), ..Default::default() }), parameter_value: value, ..Default::default() } } fn parse_value_to_parameter(value: &TValue) -> String where TValue: std::fmt::Display + BigDataValueType { return value.to_bigquery_param_value(); } // // fn create_from_table_row(client: &'a BigqueryClient, // row: &google_bigquery2::api::TableRow, // index_to_name_mapping: &HashMap) // -> Result> // where // Self: Sized // { // let pk_index = *index_to_name_mapping.get(&Self::get_pk_name()).unwrap(); // let pk = row // .f.as_ref() // .unwrap()[pk_index] // .v.as_ref() // .unwrap() // .parse::() // .unwrap(); // let mut res = Self::create_with_pk(client, pk); // res.write_from_table_row(row, index_to_name_mapping)?; // Ok(res) // } }