Lines
100 %
Functions
47.06 %
Branches
use crate::error::{FinanceError, PriceError};
use sqlx::types::Uuid;
use sqlx::types::chrono::{DateTime, Utc};
use sqlx::{Connection, query_file};
use supp_macro::Builder;
#[derive(Debug, sqlx::FromRow, Builder)]
#[builder(error_kind = "FinanceError")]
pub struct Price {
pub id: Uuid,
pub date: DateTime<Utc>,
pub commodity_id: Uuid,
pub currency_id: Uuid,
pub commodity_split: Option<Uuid>,
pub currency_split: Option<Uuid>,
pub value_num: i64,
pub value_denom: i64,
}
impl Price {
pub async fn commit<E>(&self, conn: &mut E) -> Result<(), FinanceError>
where
E: Connection<Database = sqlx::Postgres>,
{
let mut tr = conn.begin().await?;
query_file!(
"sql/price_insert.sql",
&self.id,
&self.commodity_id,
&self.currency_id,
match &self.commodity_split {
&Some(s) => Some(s),
_ => None,
},
match &self.currency_split {
&self.date,
&self.value_num,
&self.value_denom,
)
.execute(&mut *tr)
.await?;
tr.commit().await?;
Ok(())
#[cfg(test)]
mod price_tests {
use super::*;
use crate::account::{Account, AccountBuilder};
use crate::commodity::{Commodity, CommodityBuilder};
#[cfg(feature = "testlog")]
use env_logger;
use log;
use sqlx::PgPool;
use sqlx::types::chrono::Local;
use tokio::sync::OnceCell;
/// Context for keeping environment intact
static CONTEXT: OnceCell<()> = OnceCell::const_new();
static COMMODITY_1: OnceCell<Commodity> = OnceCell::const_new();
static COMMODITY_2: OnceCell<Commodity> = OnceCell::const_new();
static ACCOUNT_1: OnceCell<Account> = OnceCell::const_new();
static ACCOUNT_2: OnceCell<Account> = OnceCell::const_new();
async fn setup(pool: &PgPool) {
CONTEXT
.get_or_init(|| async {
let _ = env_logger::builder()
.is_test(true)
.filter_level(log::LevelFilter::Trace)
.try_init();
})
.await;
COMMODITY_1
CommodityBuilder::new()
.fraction(1000)
.id(Uuid::new_v4())
.build()
.unwrap()
let mut conn = pool.acquire().await.unwrap();
COMMODITY_1.get().unwrap().commit(&mut *conn).await.unwrap();
COMMODITY_2
.fraction(100)
COMMODITY_2.get().unwrap().commit(&mut *conn).await.unwrap();
ACCOUNT_1
.get_or_init(|| async { AccountBuilder::new().id(Uuid::new_v4()).build().unwrap() })
ACCOUNT_1.get().unwrap().commit(&mut *conn).await.unwrap();
ACCOUNT_2
ACCOUNT_2.get().unwrap().commit(&mut *conn).await.unwrap();
#[sqlx::test(migrations = "../migrations")]
async fn test_price_store(pool: PgPool) -> anyhow::Result<()> {
setup(&pool).await;
let price = Price {
id: Uuid::new_v4(),
date: Local::now().into(),
commodity_id: COMMODITY_1.get().unwrap().id,
currency_id: COMMODITY_2.get().unwrap().id,
commodity_split: None,
currency_split: None,
value_num: 100,
value_denom: 1,
};
let mut conn = pool.acquire().await?;
price.commit(&mut *conn).await?;
let result = sqlx::query!("SELECT id FROM prices WHERE value_num = 100")
.fetch_one(&mut *conn)
.await
.unwrap();
assert_eq!(price.id, result.id);
async fn test_price_builder(pool: PgPool) -> anyhow::Result<()> {
let price = Price::builder()
.date(Local::now().into())
.commodity_id(COMMODITY_1.get().unwrap().id)
.currency_id(COMMODITY_2.get().unwrap().id)
.value_num(100)
.value_denom(1)
.build()?;
assert_eq!(price.value_num, 100);