#[cfg(feature="sea-orm")]
use sea_orm::{prelude::*, ActiveValue, DatabaseConnection, EntityTrait};
#[cfg_attr(feature="serde",derive(serde::Serialize,serde::Deserialize))]
#[derive(Clone, Debug, PartialEq)]
pub struct NaiveDate(pub chrono::NaiveDate);
impl std::convert::From<chrono::NaiveDate> for NaiveDate {
fn from(value: chrono::NaiveDate) -> Self {
Self(value)
}
}
#[cfg(feature="rocket")]
impl rocket::http::uri::fmt::UriDisplay<rocket::http::uri::fmt::Query> for NaiveDate {
fn fmt(&self, f: &mut rocket::http::uri::fmt::Formatter<'_, rocket::http::uri::fmt::Query>) -> std::fmt::Result {
f.write_value(
rocket::http::RawStr::new(self.0.to_string().as_str())
.percent_encode()
.to_string(),
)
}
}
#[cfg(feature="rocket")]
impl rocket::http::uri::fmt::FromUriParam<rocket::http::uri::fmt::Query, NaiveDate> for NaiveDate {
type Target = String;
fn from_uri_param(param: NaiveDate) -> Self::Target {
rocket::http::RawStr::new(param.0.to_string().as_str())
.percent_encode()
.to_string()
}
}
#[cfg_attr(feature="rocket",rocket::async_trait)]
#[cfg(feature="rocket")]
impl<'v> rocket::form::FromFormField<'v> for NaiveDate {
fn from_value(field: rocket::form::ValueField<'v>) -> rocket::form::Result<'v, Self> {
use std::str::FromStr;
let mut errors = rocket::form::Errors::new();
match chrono::NaiveDate::from_str(field.value) {
Ok(naive_date) => Ok(Self(naive_date)),
Err(e) => {
let error = rocket::form::Error::validation(e.to_string());
errors.push(error);
Err(errors)
}
}
}
async fn from_data(_field: rocket::form::DataField<'v, '_>) -> rocket::form::Result<'v, Self> {
unimplemented!()
}
}
#[cfg_attr(feature="serde",derive(serde::Serialize,serde::Deserialize))]
#[derive(Clone, Debug, PartialEq)]
pub struct NaiveTime(pub chrono::NaiveTime);
impl std::convert::From<chrono::NaiveTime> for NaiveTime {
fn from(value: chrono::NaiveTime) -> Self {
Self(value)
}
}
#[cfg_attr(feature="rocket",rocket::async_trait)]
#[cfg(feature="rocket")]
impl<'v> rocket::form::FromFormField<'v> for NaiveTime {
fn from_value(field: rocket::form::ValueField<'v>) -> rocket::form::Result<'v, Self> {
use std::str::FromStr;
let mut errors = rocket::form::Errors::new();
match chrono::NaiveTime::from_str(field.value) {
Ok(naive_time) => Ok(Self(naive_time)),
Err(e) => {
let error = rocket::form::Error::validation(e.to_string());
errors.push(error);
Err(errors)
}
}
}
async fn from_data(_field: rocket::form::DataField<'v, '_>) -> rocket::form::Result<'v, Self> {
unimplemented!()
}
}
#[cfg_attr(feature="serde",derive(serde::Serialize,serde::Deserialize))]
#[derive(Clone, Debug, PartialEq)]
pub struct Decimal(pub rust_decimal::Decimal);
impl std::convert::From<rust_decimal::Decimal> for Decimal {
fn from(value: rust_decimal::Decimal) -> Self {
Self(value)
}
}
#[cfg_attr(feature="rocket",rocket::async_trait)]
#[cfg(feature="rocket")]
impl<'v> rocket::form::FromFormField<'v> for Decimal {
fn from_value(field: rocket::form::ValueField<'v>) -> rocket::form::Result<'v, Self> {
let mut errors = rocket::form::Errors::new();
match rust_decimal::Decimal::from_str_exact(field.value) {
Ok(decimal) => Ok(Self(decimal)),
Err(e) => {
let error = rocket::form::Error::validation(e.to_string());
errors.push(error);
Err(errors)
}
}
}
async fn from_data(_field: rocket::form::DataField<'v, '_>) -> rocket::form::Result<'v, Self> {
unimplemented!()
}
}
#[cfg(feature="sea-orm")]
pub async fn get_user_account_by_external_id(
conn: &DatabaseConnection,
external_id: &str,
) -> Result<Option<crate::user_accounts::Model>, anyhow::Error> {
Ok(crate::user_accounts::Entity::find()
.filter(crate::user_accounts::Column::ExternalUserId.eq(external_id))
.one(conn)
.await?)
}
#[cfg(feature="sea-orm")]
pub async fn get_user_by_account(
conn: &sea_orm::DatabaseConnection,
account: &crate::user_accounts::Model,
) -> Result<Option<crate::user::Model>, anyhow::Error> {
Ok(crate::user::Entity::find_by_id(account.user_id)
.one(conn)
.await?)
}
#[cfg(feature="sea-orm")]
pub async fn get_user_by_external_id(
conn: &DatabaseConnection,
external_id: &str,
) -> Result<Option<crate::user::Model>, anyhow::Error> {
let user_account = get_user_account_by_external_id(conn, external_id).await?;
if user_account.is_none() {
return Ok(None);
}
Ok(crate::user::Entity::find_by_id(user_account.unwrap().id)
.one(conn)
.await?)
}
#[cfg(feature="sea-orm")]
pub async fn create_user_and_account_from_external_id(
conn: &DatabaseConnection,
external_id: &str,
) -> Result<(crate::user::Model, crate::user_accounts::Model), anyhow::Error> {
let user_active_model = crate::user::ActiveModel::new();
let user = user_active_model.insert(conn).await?;
let mut user_account_active_model = crate::user_accounts::ActiveModel::new();
user_account_active_model.user_id = ActiveValue::Set(user.id);
user_account_active_model.external_user_id = ActiveValue::Set(external_id.to_string());
let user_account = user_account_active_model.insert(conn).await?;
Ok((user, user_account))
}
#[cfg(feature="sea-orm")]
pub async fn get_bills(
conn: &sea_orm::DatabaseConnection,
user_id: Option<i64>,
from_date: Option<NaiveDate>,
to_date: Option<NaiveDate>,
) -> Result<Vec<crate::bills::Model>, anyhow::Error> {
let mut query = crate::bills::Entity::find();
if let Some(user_id) = user_id {
query = query.filter(crate::bills::Column::UserId.eq(user_id));
}
let offset = chrono::FixedOffset::west_opt(0).unwrap();
let time = Time::from_hms_opt(0, 0, 0).unwrap();
if let Some(from_date) = from_date {
let date_time = DateTime::new(from_date.0, time.clone());
let offset_date_time = DateTimeWithTimeZone::from_utc(date_time, offset);
query = query.filter(crate::bills::Column::Due.gte(offset_date_time))
}
if let Some(to_date) = to_date {
let date_time = DateTime::new(to_date.0, time);
let offset_date_time = DateTimeWithTimeZone::from_utc(date_time, offset);
query = query.filter(crate::bills::Column::Due.lte(offset_date_time))
}
Ok(query.all(conn).await?)
}
#[cfg(feature="sea-orm")]
pub async fn db_connect(connection_string: Option<&str>) -> Result<sea_orm::DatabaseConnection,anyhow::Error> {
let connection_string = connection_string.map_or(std::env::var("DATABASE_URL").ok(),|v| Some(v.to_string())).ok_or_else(||anyhow::anyhow!("Missing database connection string. check env DATABASE_URL"))?;
sea_orm::Database::connect(connection_string).await.map_err(|e| anyhow::Error::new(e))
}