Files
google_bigquery/src/data/big_data_table_base_convenience.rs
2023-02-19 02:39:19 +01:00

214 lines
8.9 KiB
Rust

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<google_bigquery2::api::QueryResponse, Box<dyn Error>>;
async fn run_get_query_with_params(&self,
query: &str,
parameters: Vec<google_bigquery2::api::QueryParameter>,
project_id: &str)
-> Result<google_bigquery2::api::QueryResponse, Box<dyn Error>>;
async fn run_get_query_with_params_on_client(client: &'a BigqueryClient,
query: &str,
parameters: Vec<google_bigquery2::api::QueryParameter>,
project_id: &str)
-> Result<google_bigquery2::api::QueryResponse, Box<dyn Error>>;
// async fn get_identifier_and_base_where(&self) -> Result<(String, String), Box<dyn Error>>;
async fn get_identifier(&self) -> Result<String, Box<dyn Error>>;
async fn get_identifier_from_client(client: &'a BigqueryClient) -> Result<String, Box<dyn Error>>;
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<dyn Error>>;
fn get_query_param<TField: BigDataValueType>(field_name: &str, field_value: &Option<TField>)
-> google_bigquery2::api::QueryParameter;
fn parse_value_to_parameter<TValue>(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<String, usize>)
// -> Result<Self, Box<dyn Error>>
// where
// Self: Sized;
}
impl<'a, TABLE, TPK> BigDataTableBaseConvenience<'a, TABLE, TPK> for TABLE
where
TABLE: BigDataTableBase<'a, TABLE, TPK>,
TPK: BigDataValueType + FromStr + Debug,
<TPK as FromStr>::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::<Vec<String>>()
.join(", ")
}
fn get_query_fields_insert_str() -> String {
Self::get_query_fields()
.values()
.into_iter()
.map(|v| format!("@__{}", v))
.collect::<Vec<String>>()
.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<google_bigquery2::api::QueryResponse, Box<dyn Error>> {
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<google_bigquery2::api::QueryParameter>,
project_id: &str)
-> Result<google_bigquery2::api::QueryResponse, Box<dyn Error>> {
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<google_bigquery2::api::QueryParameter>,
project_id: &str)
-> Result<google_bigquery2::api::QueryResponse, Box<dyn Error>> {
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<dyn Error>> {
// 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<String, Box<dyn Error>> {
let client = self.get_client();
Self::get_identifier_from_client(&client).await
}
async fn get_identifier_from_client(client: &'a BigqueryClient) -> Result<String, Box<dyn Error>> {
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<TField: BigDataValueType>(field_name: &str, field_value: &Option<TField>) -> google_bigquery2::api::QueryParameter
{
let type_to_string: String = TField::to_bigquery_type();
let value: Option<google_bigquery2::api::QueryParameterValue> = 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<TValue>(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<String, usize>)
// -> Result<Self, Box<dyn Error>>
// 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::<TPK>()
// .unwrap();
// let mut res = Self::create_with_pk(client, pk);
// res.write_from_table_row(row, index_to_name_mapping)?;
// Ok(res)
// }
}