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 { async fn insert_now(&self, value: &T) -> Result; 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 InsertOrUpdate for FlightclasMethods<'_, S> where S: tower_service::Service + 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>, { async fn insert_now(&self, value: &FlightClass) -> Result { 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 InsertOrUpdate for FlightobjectMethods<'_, S> where S: tower_service::Service + 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>, { async fn insert_now(&self, value: &FlightObject) -> Result { 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(into: &dyn InsertOrUpdate, 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( into: Arc<&dyn InsertOrUpdate>, value: &T, ) -> Result<()> { insert_or_update_now(*into.as_ref(), value).await?; Ok(()) } pub async fn insert_or_update_many( into: &dyn InsertOrUpdate, values: Vec, ) -> Result<()> { let i = Arc::new(into); try_join_all( values .iter() .map(|c| insert_or_update_now_arc(i.clone(), c)), ) .await?; Ok(()) }