implement delete

This commit is contained in:
OMGeeky
2023-04-15 15:00:37 +02:00
parent 9d6c719cbc
commit 535a5896b8
3 changed files with 145 additions and 81 deletions

View File

@@ -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<String, Value>,
) -> Result<Self>
where
Self: Sized;
where
Self: Sized;
//region update
@@ -68,26 +66,32 @@ pub trait BigQueryTableBase {
#[async_trait]
pub trait BigQueryTable: BigQueryTableBase {
fn select() -> QueryBuilder<Self, QueryTypeSelect, NoClient, QueryWasNotBuilt, NoStartingData>
where
Self: Sized,
where
Self: Sized,
{
QueryBuilder::<Self, QueryTypeNoType, NoClient, QueryWasNotBuilt, NoStartingData>::select()
}
fn insert() -> QueryBuilder<Self, QueryTypeInsert, NoClient, QueryWasNotBuilt, NoStartingData>
where
Self: Sized,
where
Self: Sized,
{
QueryBuilder::<Self, QueryTypeNoType, NoClient, QueryWasNotBuilt, NoStartingData>::insert()
}
fn update() -> QueryBuilder<Self, QueryTypeUpdate, NoClient, QueryWasNotBuilt, NoStartingData>
where
Self: Sized,
where
Self: Sized,
{
QueryBuilder::<Self, QueryTypeNoType, NoClient, QueryWasNotBuilt, NoStartingData>::update()
}
fn delete() -> QueryBuilder<Self, QueryTypeDelete, NoClient, QueryWasNotBuilt, NoStartingData>
where
Self: Sized,
{
QueryBuilder::<Self, QueryTypeNoType, NoClient, QueryWasNotBuilt, NoStartingData>::delete()
}
fn get_parameter<T>(value: &T, param_name: &String) -> Option<QueryParameter>
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<PK>(client: BigqueryClient, pk_value: &PK) -> Result<Self>
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())
}
}

View File

@@ -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<Table, QueryType, Client, QueryBuilt, StartingData> {
//region default implementation for QueryBuilder
impl<Table, QueryType, Client: Default, QueryBuilt, StartingData: Default> Default
for QueryBuilder<Table, QueryType, Client, QueryBuilt, StartingData>
for QueryBuilder<Table, QueryType, Client, QueryBuilt, StartingData>
{
fn default() -> Self {
Self {
@@ -189,7 +196,7 @@ for QueryBuilder<Table, QueryType, Client, QueryBuilt, StartingData>
//region general QueryBuilder
//region functions for all queries
impl<Table: BigQueryTable, UnknownQueryType, Client, QueryBuilt, StartingData>
QueryBuilder<Table, UnknownQueryType, Client, QueryBuilt, StartingData>
QueryBuilder<Table, UnknownQueryType, Client, QueryBuilt, StartingData>
{
fn get_sorted_selected_fields(&self) -> Vec<(String, String)> {
trace!("get_sorted_selected_fields()");
@@ -214,7 +221,7 @@ QueryBuilder<Table, UnknownQueryType, Client, QueryBuilt, StartingData>
//region functions for not built queries
//region with Starting data
impl<Table: BigQueryTable + Default, UnknownQueryType, Client>
QueryBuilder<Table, UnknownQueryType, Client, QueryWasNotBuilt, HasStartingData<Table>>
QueryBuilder<Table, UnknownQueryType, Client, QueryWasNotBuilt, HasStartingData<Table>>
{
pub fn add_field_where(self, field: &str) -> Result<Self> {
trace!("add_field_where(field: {})", field);
@@ -268,12 +275,12 @@ QueryBuilder<Table, UnknownQueryType, Client, QueryWasNotBuilt, HasStartingData<
//endregion
impl<Table: BigQueryTable + Debug, UnknownQueryType: Debug, Client: Debug, StartingData: Debug>
QueryBuilder<Table, UnknownQueryType, Client, QueryWasNotBuilt, StartingData>
QueryBuilder<Table, UnknownQueryType, Client, QueryWasNotBuilt, StartingData>
{
//region set query content
pub fn add_where_eq<T>(self, column: &str, value: Option<&T>) -> Result<Self>
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<Table, UnknownQueryType, Client, QueryWasNotBuilt, StartingData>
//endregion
//region set_data
impl<Table: BigQueryTable + Default + Debug, QueryType: HasQueryType, Client: Default>
QueryBuilder<Table, QueryType, Client, QueryWasNotBuilt, NoStartingData>
QueryBuilder<Table, QueryType, Client, QueryWasNotBuilt, NoStartingData>
{
pub fn set_data(
self,
@@ -378,13 +385,12 @@ QueryBuilder<Table, QueryType, Client, QueryWasNotBuilt, NoStartingData>
//endregion
//region QueryTypeNoType
impl<Table: BigQueryTable, Client: Default, StartingData: Default>
QueryBuilder<Table, QueryTypeNoType, Client, QueryWasNotBuilt, StartingData>
QueryBuilder<Table, QueryTypeNoType, Client, QueryWasNotBuilt, StartingData>
{
pub fn select() -> QueryBuilder<Table, QueryTypeSelect, NoClient, QueryWasNotBuilt, StartingData>
{
trace!("select()");
QueryBuilder {
query: String::from("SELECT "),
..Default::default()
}
}
@@ -392,7 +398,6 @@ QueryBuilder<Table, QueryTypeNoType, Client, QueryWasNotBuilt, StartingData>
{
trace!("insert()");
QueryBuilder {
query: String::from("INSERT INTO "),
..Default::default()
}
}
@@ -400,7 +405,13 @@ QueryBuilder<Table, QueryTypeNoType, Client, QueryWasNotBuilt, StartingData>
{
trace!("update()");
QueryBuilder {
query: String::from("INSERT INTO "),
..Default::default()
}
}
pub fn delete() -> QueryBuilder<Table, QueryTypeDelete, NoClient, QueryWasNotBuilt, StartingData>
{
trace!("delete()");
QueryBuilder {
..Default::default()
}
}
@@ -409,7 +420,37 @@ QueryBuilder<Table, QueryTypeNoType, Client, QueryWasNotBuilt, StartingData>
//endregion
//region QueryTypeInsert
impl<Table: BigQueryTable + Default + Debug>
QueryBuilder<Table, QueryTypeInsert, HasClient, QueryWasNotBuilt, HasStartingData<Table>>
QueryBuilder<Table, QueryTypeDelete, HasClient, QueryWasNotBuilt, HasStartingData<Table>>
{
pub fn build_query(
mut self,
) -> Result<
QueryBuilder<Table, QueryTypeDelete, HasClient, QueryWasBuilt, HasStartingData<Table>>,
> {
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<Table: BigQueryTable + Default + Debug>
QueryBuilder<Table, QueryTypeInsert, HasClient, QueryWasNotBuilt, HasStartingData<Table>>
{
pub fn build_query(
mut self,
@@ -461,9 +502,21 @@ QueryBuilder<Table, QueryTypeInsert, HasClient, QueryWasNotBuilt, HasStartingDat
fn get_value_parameter_names(&self) -> Result<Vec<Option<String>>> {
trace!("get_value_parameter_names\tself: {:?}", self);
let mut values = self.get_sorted_selected_fields();
let existing_params: Vec<String> = 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<String> = 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<Table, QueryTypeInsert, HasClient, QueryWasNotBuilt, HasStartingDat
//endregion
//region QueryTypeUpdate
impl<Table: BigQueryTable + Default + Debug>
QueryBuilder<Table, QueryTypeUpdate, HasClient, QueryWasNotBuilt, HasStartingData<Table>>
QueryBuilder<Table, QueryTypeUpdate, HasClient, QueryWasNotBuilt, HasStartingData<Table>>
{
pub fn build_query(
mut self,
@@ -527,10 +580,9 @@ QueryBuilder<Table, QueryTypeUpdate, HasClient, QueryWasNotBuilt, HasStartingDat
.get_value_parameter_names()?
.into_iter()
.map(|(f, p)| match p {
Some(p) => format!("{} = @{}", f, p),
None => format!("{} = NULL", f),
}
)
Some(p) => format!("{} = @{}", f, p),
None => format!("{} = NULL", f),
})
.collect::<Vec<String>>()
.join(", ");
trace!("build_update_fields_string: result: {}", result);
@@ -539,7 +591,11 @@ QueryBuilder<Table, QueryTypeUpdate, HasClient, QueryWasNotBuilt, HasStartingDat
fn get_value_parameter_names(&self) -> Result<Vec<(String, Option<String>)>> {
let mut values = self.get_sorted_selected_fields();
let existing_params: Vec<String> = self.params.iter().map(|p| p.name.clone().unwrap()).collect();
let existing_params: Vec<String> = 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<Table, QueryTypeUpdate, HasClient, QueryWasNotBuilt, HasStartingDat
//region QueryTypeSelect
//region client not needed
impl<Table: BigQueryTable + Debug, Client: Debug, StartingData: Debug>
QueryBuilder<Table, QueryTypeSelect, Client, QueryWasNotBuilt, StartingData>
QueryBuilder<Table, QueryTypeSelect, Client, QueryWasNotBuilt, StartingData>
{
pub fn add_order_by(
mut self,
@@ -573,7 +629,7 @@ QueryBuilder<Table, QueryTypeSelect, Client, QueryWasNotBuilt, StartingData>
//endregion
//region client needed
impl<Table: BigQueryTable + Debug, StartingData: Debug>
QueryBuilder<Table, QueryTypeSelect, HasClient, QueryWasNotBuilt, StartingData>
QueryBuilder<Table, QueryTypeSelect, HasClient, QueryWasNotBuilt, StartingData>
{
pub fn build_query(
self,
@@ -608,7 +664,7 @@ QueryBuilder<Table, QueryTypeSelect, HasClient, QueryWasNotBuilt, StartingData>
//endregion
//region with_client
impl<Table: BigQueryTable, QueryType, StartingData>
QueryBuilder<Table, QueryType, NoClient, QueryWasNotBuilt, StartingData>
QueryBuilder<Table, QueryType, NoClient, QueryWasNotBuilt, StartingData>
{
pub fn with_client(
self,
@@ -632,7 +688,7 @@ QueryBuilder<Table, QueryType, NoClient, QueryWasNotBuilt, StartingData>
//endregion
//region un_build & get query string
impl<Table: BigQueryTable, QueryType, Client, StartingData>
QueryBuilder<Table, QueryType, Client, QueryWasBuilt, StartingData>
QueryBuilder<Table, QueryType, Client, QueryWasBuilt, StartingData>
{
pub fn un_build(
self,
@@ -658,7 +714,7 @@ QueryBuilder<Table, QueryType, Client, QueryWasBuilt, StartingData>
//endregion
//region run
impl<Table: BigQueryTable, QueryType: HasQueryType, StartingData>
QueryBuilder<Table, QueryType, HasClient, QueryWasBuilt, StartingData>
QueryBuilder<Table, QueryType, HasClient, QueryWasBuilt, StartingData>
{
pub async fn run(self) -> Result<QueryResultType<Table>> {
trace!("run query: {}", self.query);

View File

@@ -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::<bool>,
}
pub struct DbInfos2 {
client: BigqueryClient,
row_id: i64,
info1: Option<String>,
info2: Option<String>,
info3: Option<String>,
info4i: Option<i32>,
info4b: Option<bool>,
}
#[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 {