depot/rust/passgen/src/insert_or_update.rs

133 lines
3.5 KiB
Rust

use anyhow::{anyhow, Result};
use async_trait::async_trait;
use futures_util::future::try_join_all;
use google_walletobjects1::api::{
FlightClass, FlightObject, FlightclasMethods, FlightobjectMethods,
};
use std::sync::Arc;
#[async_trait]
pub trait InsertOrUpdate<T: Clone> {
async fn insert_now(&self, value: &T) -> Result<bool>;
async fn update_now(&self, value: &T) -> Result<()>;
}
fn is_already_exists(err: &google_walletobjects1::Error) -> bool {
match err {
google_walletobjects1::Error::BadRequest(v) => match v.pointer("/error/code") {
Some(num) => num == 409,
None => false,
},
_ => false,
}
}
#[async_trait]
impl<S> InsertOrUpdate<FlightClass> for FlightclasMethods<'_, S>
where
S: tower_service::Service<http::Uri> + Clone + Send + Sync + 'static,
S::Response: hyper::client::connect::Connection
+ tokio::io::AsyncRead
+ tokio::io::AsyncWrite
+ Send
+ Unpin
+ 'static,
S::Future: Send + Unpin + 'static,
S::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
{
async fn insert_now(&self, value: &FlightClass) -> Result<bool> {
self.insert(value.clone())
.doit()
.await
.and(Ok(true))
.or_else(|e| {
if is_already_exists(&e) {
Ok(false)
} else {
Err(anyhow!(e))
}
})
}
async fn update_now(&self, value: &FlightClass) -> Result<()> {
self.update(
value.clone(),
&value
.id
.clone()
.ok_or_else(|| anyhow!("no id on FlightClass"))?,
)
.doit()
.await?;
Ok(())
}
}
#[async_trait]
impl<S> InsertOrUpdate<FlightObject> for FlightobjectMethods<'_, S>
where
S: tower_service::Service<http::Uri> + Clone + Send + Sync + 'static,
S::Response: hyper::client::connect::Connection
+ tokio::io::AsyncRead
+ tokio::io::AsyncWrite
+ Send
+ Unpin
+ 'static,
S::Future: Send + Unpin + 'static,
S::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
{
async fn insert_now(&self, value: &FlightObject) -> Result<bool> {
self.insert(value.clone())
.doit()
.await
.and(Ok(true))
.or_else(|e| {
if is_already_exists(&e) {
Ok(false)
} else {
Err(anyhow!(e))
}
})
}
async fn update_now(&self, value: &FlightObject) -> Result<()> {
self.update(
value.clone(),
&value
.id
.clone()
.ok_or_else(|| anyhow!("no id on FlightObject"))?,
)
.doit()
.await?;
Ok(())
}
}
pub async fn insert_or_update_now<T: Clone>(into: &dyn InsertOrUpdate<T>, value: &T) -> Result<()> {
let created: bool = into.insert_now(value).await?;
if !created {
into.update_now(value).await?;
}
Ok(())
}
pub async fn insert_or_update_now_arc<T: Clone>(
into: Arc<&dyn InsertOrUpdate<T>>,
value: &T,
) -> Result<()> {
insert_or_update_now(*into.as_ref(), value).await?;
Ok(())
}
pub async fn insert_or_update_many<T: Clone>(
into: &dyn InsertOrUpdate<T>,
values: &Vec<T>,
) -> Result<()> {
let i = Arc::new(into);
try_join_all(
values
.iter()
.map(|c| insert_or_update_now_arc(i.clone(), c)),
)
.await?;
Ok(())
}