brokerage-db 0.2.7

Database management for trader brokerage data with a MongoDB backend.
Documentation
use std::sync::Arc;

use anyhow::Result;
use bson::oid::ObjectId;
use futures::TryStreamExt;
use mongodb::{ClientSession, Database};
use serde::{Deserialize, Serialize};
use tokio::sync::Mutex;

use crate::{account::BrokerageAccount, db_util};

#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct EODSummary {
    _id: ObjectId,
    brokerage_account_id: ObjectId,
    start_timestamp_ms: i64,
    end_timestamp_ms: i64,

    starting_cash: f64,
    ending_cash: f64,

    commissions: f64,
    commissions_mtd: Option<f64>,
    commissions_ytd: Option<f64>,

    deposits: f64,
    deposits_mtd: Option<f64>,
    deposits_ytd: Option<f64>,

    dividends: f64,
    dividends_mtd: Option<f64>,
    dividends_ytd: Option<f64>,

    interest: f64,
    interest_mtd: Option<f64>,
    interest_ytd: Option<f64>,

    net_trade_purchases: f64,
    net_trade_sales: f64,

    other_fees: f64,
    other_fees_mtd: Option<f64>,
    other_fees_ytd: Option<f64>,

    withdrawals: f64,
    withdrawals_mtd: Option<f64>,
    withdrawals_ytd: Option<f64>,
}

pub struct Builder {
    _id: ObjectId,
    brokerage_account_id: Option<ObjectId>,
    start_timestamp_ms: Option<i64>,
    end_timestamp_ms: Option<i64>,

    starting_cash: Option<f64>,
    ending_cash: Option<f64>,

    commissions: Option<f64>,
    commissions_mtd: Option<f64>,
    commissions_ytd: Option<f64>,

    deposits: Option<f64>,
    deposits_mtd: Option<f64>,
    deposits_ytd: Option<f64>,

    dividends: Option<f64>,
    dividends_mtd: Option<f64>,
    dividends_ytd: Option<f64>,

    interest: Option<f64>,
    interest_mtd: Option<f64>,
    interest_ytd: Option<f64>,

    net_trade_purchases: Option<f64>,
    net_trade_sales: Option<f64>,

    other_fees: Option<f64>,
    other_fees_mtd: Option<f64>,
    other_fees_ytd: Option<f64>,

    withdrawals: Option<f64>,
    withdrawals_mtd: Option<f64>,
    withdrawals_ytd: Option<f64>,
}

impl EODSummary {
    pub const COLLECTION_NAME: &'static str = "eod_summaries";

    pub fn builder() -> Builder {
        Builder {
            _id: ObjectId::new(),
            brokerage_account_id: None,
            start_timestamp_ms: None,
            end_timestamp_ms: None,

            starting_cash: None,
            ending_cash: None,

            commissions: None,
            commissions_mtd: None,
            commissions_ytd: None,

            deposits: None,
            deposits_mtd: None,
            deposits_ytd: None,

            dividends: None,
            dividends_mtd: None,
            dividends_ytd: None,

            interest: None,
            interest_mtd: None,
            interest_ytd: None,

            net_trade_purchases: None,
            net_trade_sales: None,

            other_fees: None,
            other_fees_mtd: None,
            other_fees_ytd: None,

            withdrawals: None,
            withdrawals_mtd: None,
            withdrawals_ytd: None,
        }
    }

    pub fn id(&self) -> ObjectId {
        self._id
    }

    pub fn brokerage_account_id(&self) -> ObjectId {
        self.brokerage_account_id
    }

    pub fn start_timestamp_ms(&self) -> i64 {
        self.start_timestamp_ms
    }

    pub fn end_timestamp_ms(&self) -> i64 {
        self.end_timestamp_ms
    }

    pub fn starting_cash(&self) -> f64 {
        self.starting_cash
    }

    pub fn ending_cash(&self) -> f64 {
        self.ending_cash
    }

    pub fn commissions(&self) -> f64 {
        self.commissions
    }

    pub fn deposits(&self) -> f64 {
        self.deposits
    }

    pub fn dividends(&self) -> f64 {
        self.dividends
    }

    pub fn interest(&self) -> f64 {
        self.interest
    }

    pub fn net_trade_purchases(&self) -> f64 {
        self.net_trade_purchases
    }

    pub fn net_trade_sales(&self) -> f64 {
        self.net_trade_sales
    }

    pub fn other_fees(&self) -> f64 {
        self.other_fees
    }

    pub fn withdrawals(&self) -> f64 {
        self.withdrawals
    }

    pub async fn insert(
        &self,
        db: &Database,
        session: Option<Arc<Mutex<ClientSession>>>,
    ) -> Result<()> {
        db_util::insert(self, db, Self::COLLECTION_NAME, session).await
    }

    pub async fn find_by_id(db: &Database, id: ObjectId) -> Result<Option<Self>> {
        let result = db
            .collection::<Self>(Self::COLLECTION_NAME)
            .find_one(bson::doc! {"_id": id})
            .await?;

        Ok(result)
    }

    pub async fn find_by_account_id(
        db: &Database,
        brokerage_account_id: ObjectId,
    ) -> Result<Vec<Self>> {
        Ok(db
            .collection::<Self>(Self::COLLECTION_NAME)
            .find(bson::doc! {"brokerage_account_id": brokerage_account_id })
            .await?
            .try_collect()
            .await?)
    }

    pub async fn brokerage_account(&self, db: &Database) -> Result<BrokerageAccount> {
        Ok(BrokerageAccount::find_by_id(db, self.brokerage_account_id)
            .await?
            .unwrap())
    }
}

impl Builder {
    pub fn build(self) -> Result<EODSummary> {
        Ok(EODSummary {
            _id: self._id,
            brokerage_account_id: self.brokerage_account_id.unwrap(),
            start_timestamp_ms: self.start_timestamp_ms.unwrap(),
            end_timestamp_ms: self.end_timestamp_ms.unwrap(),

            starting_cash: self.starting_cash.unwrap(),
            ending_cash: self.ending_cash.unwrap(),

            commissions: self.commissions.unwrap(),
            commissions_mtd: self.commissions_mtd,
            commissions_ytd: self.commissions_ytd,

            deposits: self.deposits.unwrap(),
            deposits_mtd: self.deposits_mtd,
            deposits_ytd: self.deposits_ytd,

            dividends: self.dividends.unwrap(),
            dividends_mtd: self.dividends_mtd,
            dividends_ytd: self.dividends_ytd,

            interest: self.interest.unwrap(),
            interest_mtd: self.interest_mtd,
            interest_ytd: self.interest_ytd,

            net_trade_purchases: self.net_trade_purchases.unwrap(),
            net_trade_sales: self.net_trade_sales.unwrap(),

            other_fees: self.other_fees.unwrap(),
            other_fees_mtd: self.other_fees_mtd,
            other_fees_ytd: self.other_fees_ytd,

            withdrawals: self.withdrawals.unwrap(),
            withdrawals_mtd: self.withdrawals_mtd,
            withdrawals_ytd: self.withdrawals_ytd,
        })
    }

    pub fn brokerage_account_id(mut self, brokerage_account_id: ObjectId) -> Self {
        self.brokerage_account_id = Some(brokerage_account_id);
        self
    }

    pub fn start_timestamp_ms(mut self, start_timestamp_ms: i64) -> Self {
        self.start_timestamp_ms = Some(start_timestamp_ms);
        self
    }

    pub fn end_timestamp_ms(mut self, end_timestamp_ms: i64) -> Self {
        self.end_timestamp_ms = Some(end_timestamp_ms);
        self
    }

    pub fn starting_cash(mut self, starting_cash: f64) -> Self {
        self.starting_cash = Some(starting_cash);
        self
    }

    pub fn ending_cash(mut self, ending_cash: f64) -> Self {
        self.ending_cash = Some(ending_cash);
        self
    }

    pub fn commissions(mut self, commissions: f64) -> Self {
        self.commissions = Some(commissions);
        self
    }

    pub fn deposits(mut self, deposits: f64) -> Self {
        self.deposits = Some(deposits);
        self
    }

    pub fn dividends(mut self, dividends: f64) -> Self {
        self.dividends = Some(dividends);
        self
    }

    pub fn interest(mut self, interest: f64) -> Self {
        self.interest = Some(interest);
        self
    }

    pub fn net_trade_purchases(mut self, net_trade_purchases: f64) -> Self {
        self.net_trade_purchases = Some(net_trade_purchases);
        self
    }

    pub fn net_trade_sales(mut self, net_trade_sales: f64) -> Self {
        self.net_trade_sales = Some(net_trade_sales);
        self
    }

    pub fn other_fees(mut self, other_fees: f64) -> Self {
        self.other_fees = Some(other_fees);
        self
    }

    pub fn withdrawals(mut self, withdrawals: f64) -> Self {
        self.withdrawals = Some(withdrawals);
        self
    }

    pub fn commissions_mtd(mut self, commissions_mtd: f64) -> Self {
        self.commissions_mtd = Some(commissions_mtd);
        self
    }

    pub fn commissions_ytd(mut self, commissions_ytd: f64) -> Self {
        self.commissions_ytd = Some(commissions_ytd);
        self
    }

    pub fn deposits_mtd(mut self, deposits_mtd: f64) -> Self {
        self.deposits_mtd = Some(deposits_mtd);
        self
    }

    pub fn deposits_ytd(mut self, deposits_ytd: f64) -> Self {
        self.deposits_ytd = Some(deposits_ytd);
        self
    }

    pub fn dividends_mtd(mut self, dividends_mtd: f64) -> Self {
        self.dividends_mtd = Some(dividends_mtd);
        self
    }

    pub fn dividends_ytd(mut self, dividends_ytd: f64) -> Self {
        self.dividends_ytd = Some(dividends_ytd);
        self
    }

    pub fn interest_mtd(mut self, interest_mtd: f64) -> Self {
        self.interest_mtd = Some(interest_mtd);
        self
    }

    pub fn interest_ytd(mut self, interest_ytd: f64) -> Self {
        self.interest_ytd = Some(interest_ytd);
        self
    }

    pub fn other_fees_mtd(mut self, other_fees_mtd: f64) -> Self {
        self.other_fees_mtd = Some(other_fees_mtd);
        self
    }

    pub fn other_fees_ytd(mut self, other_fees_ytd: f64) -> Self {
        self.other_fees_ytd = Some(other_fees_ytd);
        self
    }

    pub fn withdrawals_mtd(mut self, withdrawals_mtd: f64) -> Self {
        self.withdrawals_mtd = Some(withdrawals_mtd);
        self
    }

    pub fn withdrawals_ytd(mut self, withdrawals_ytd: f64) -> Self {
        self.withdrawals_ytd = Some(withdrawals_ytd);
        self
    }
}