Skip to main content

brokerage_db/
security.rs

1use std::sync::Arc;
2
3use anyhow::Result;
4use bson::{doc, oid::ObjectId};
5use futures::stream::TryStreamExt;
6use mongodb::{ClientSession, Database};
7use serde::{Deserialize, Serialize};
8use tokio::sync::Mutex;
9
10use crate::db_util;
11
12#[derive(Serialize, Deserialize, Debug, PartialEq)]
13pub enum SecurityType {
14    Stock,
15}
16#[derive(Serialize, Deserialize, Debug, PartialEq)]
17pub struct Security {
18    _id: bson::oid::ObjectId,
19    listing_exchange: String,
20    security_type: SecurityType,
21    ticker: String,
22    ibkr_conid: Option<u32>,
23}
24
25impl Security {
26    pub const COLLECTION_NAME: &'static str = "securities";
27
28    pub fn new(
29        security_type: SecurityType,
30        ticker: &str,
31        listing_exchange: &str,
32        ibkr_conid: Option<u32>,
33    ) -> Self {
34        Self {
35            _id: ObjectId::new(),
36            listing_exchange: listing_exchange.to_owned(),
37            security_type,
38            ticker: ticker.to_owned(),
39            ibkr_conid,
40        }
41    }
42
43    pub fn id(&self) -> ObjectId {
44        self._id
45    }
46
47    pub fn listing_exchange(&self) -> &str {
48        &self.listing_exchange
49    }
50
51    pub fn security_type(&self) -> &SecurityType {
52        &self.security_type
53    }
54
55    pub fn ticker(&self) -> &str {
56        &self.ticker
57    }
58
59    pub fn ibkr_conid(&self) -> Option<u32> {
60        self.ibkr_conid
61    }
62
63    pub async fn insert(
64        &self,
65        db: &Database,
66        session: Option<Arc<Mutex<ClientSession>>>,
67    ) -> Result<()> {
68        db_util::insert(self, db, Self::COLLECTION_NAME, session).await
69    }
70
71    pub async fn find_by_id(db: &Database, id: ObjectId) -> Result<Option<Self>> {
72        let result = db
73            .collection::<Self>(Self::COLLECTION_NAME)
74            .find_one(bson::doc! {"_id": id})
75            .await?;
76
77        Ok(result)
78    }
79
80    pub async fn find_by_ticker_and_exchange(
81        db: &Database,
82        ticker: &str,
83        listing_exchange: &str,
84    ) -> Result<Option<Self>> {
85        let result = db
86            .collection::<Self>(Self::COLLECTION_NAME)
87            .find_one(bson::doc! {"ticker": ticker, "listing_exchange": listing_exchange})
88            .await?;
89
90        Ok(result)
91    }
92
93    pub async fn find_by_conid(db: &Database, ibkr_conid: u32) -> Result<Option<Self>> {
94        Ok(db
95            .collection::<Self>(Self::COLLECTION_NAME)
96            .find_one(doc! { "ibkr_conid": ibkr_conid })
97            .await?)
98    }
99
100    pub async fn find_by_ticker(db: &Database, ticker: &str) -> Result<Vec<Self>> {
101        let result = db
102            .collection::<Self>(Self::COLLECTION_NAME)
103            .find(doc! { "ticker": ticker })
104            .await?;
105
106        // Convert the cursor to a vector of Security objects.
107        Ok(result.try_collect().await?)
108    }
109}