as_core 0.1.0

aspiesolutions core crate
Documentation
#[cfg(feature="sea-orm")]
use sea_orm::{prelude::*, ActiveValue, DatabaseConnection, EntityTrait};
// use crate::forms::bills::CreateBillForm;

// A new type wrapper around sea_orm's NaiveDate.
#[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()
    }
}

// use std::{str::FromStr, unimplemented};

#[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;
        // standard browser dates present as "YYYY-MM-DD"
        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!()
    }
}

/// a wrapper type around sea_orm's NaiveTime
/// 
#[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;
        // standard browser times present in 24 hour clock format as "HH:MM. seconds are assumed to be zero"
        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!()
    }
}

/// a wrapper struct around a decimal type.
#[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> {
        // standard browser times present in 24 hour clock format as "HH:MM. seconds are assumed to be zero"
        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))
}

// pub async fn create_bill_from_form(
//     conn: &DatabaseConnection,
//     form: CreateBillForm,
//     user_id: i64,
// ) -> Result<crate::bills::Model, anyhow::Error> {
//     // get the current system time in utc
//     // let current_time = chrono::Utc::now();
//     // current_time
//     let mut active_model = crate::bills::ActiveModel::new();

//     let offset = FixedOffset::west_opt(0).unwrap();
//     let date_time = DateTime::new(form.due_date.0, form.due_time.0);
//     let offset_date_time = DateTimeWithTimeZone::from_utc(date_time, offset);

//     active_model.due = ActiveValue::Set(offset_date_time);
//     active_model.budget = ActiveValue::Set(form.budget.0);
//     active_model.actual = ActiveValue::Set(form.actual.0);
//     active_model.user_id = ActiveValue::Set(user_id);
//     // let date: NaiveDate = sea_orm::prelude::Date::parse_from_str(&_form.due_date, "%m");
//     active_model.description = ActiveValue::Set(form.description);
//     Ok(active_model.insert(conn).await?)
// }
#[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))
}