ig_client/utils/
transactions.rs

1// src/utils/transactions.rs
2//
3// Transaction utilities for the IG client
4
5use chrono::{DateTime, Duration, Utc};
6use sqlx::PgPool;
7use tracing::{debug, info};
8
9use crate::application::models::transaction::Transaction;
10use crate::constants::DAYS_TO_BACK_LOOK;
11use crate::{
12    application::services::ig_tx_client::{IgTxClient, IgTxFetcher},
13    config::Config,
14    error::AppError,
15    session::auth::IgAuth,
16    session::interface::IgAuthenticator,
17    storage::utils::store_transactions,
18};
19
20/// Fetch transactions from IG API and store them in the database
21///
22/// This function handles the entire process of:
23/// 1. Authenticating with IG
24/// 2. Creating a transaction client
25/// 3. Fetching transactions for a date range
26/// 4. Storing them in the database
27///
28/// # Arguments
29///
30/// * `cfg` - The configuration object
31/// * `pool` - PostgreSQL connection pool
32/// * `from_days_ago` - Optional number of days to look back (defaults to 10 days)
33///
34/// # Returns
35///
36/// * `Result<usize, AppError>` - Number of transactions inserted, or an error
37///
38/// # Example
39///
40/// ```
41/// use ig_client::utils::transactions::fetch_and_store_transactions;
42/// use ig_client::config::Config;
43///
44/// async fn example() -> Result<(), Box<dyn std::error::Error>> {
45///     let cfg = Config::new();
46///     let pool = cfg.pg_pool().await?;
47///     
48///     // Fetch transactions from the last 30 days
49///     let inserted = fetch_and_store_transactions(&cfg, &pool, Some(30)).await?;
50///     println!("Inserted {} transactions", inserted);
51///     
52///     Ok(())
53/// }
54/// ```
55pub async fn fetch_and_store_transactions(
56    cfg: &Config,
57    pool: &PgPool,
58    from_days_ago: Option<i64>,
59) -> Result<usize, AppError> {
60    // Authenticate with IG
61    let auth = IgAuth::new(cfg);
62    let sess = auth.login().await?;
63    info!("Successfully authenticated with IG");
64
65    // Create the transaction client
66    let tx_client = IgTxClient::new(cfg);
67
68    // Calculate date range
69    let to = Utc::now();
70    let from = if let Some(days) = from_days_ago {
71        to - Duration::days(days)
72    } else {
73        to - Duration::days(DAYS_TO_BACK_LOOK)
74    };
75
76    debug!("Fetching transactions from {} to {}", from, to);
77    let txs = tx_client.fetch_range(&sess, from, to).await?;
78    info!("Fetched {} transactions", txs.len());
79
80    // Store the transactions
81    let inserted = store_transactions(pool, &txs).await?;
82    info!("Inserted {} rows", inserted);
83
84    Ok(inserted)
85}
86
87/// Fetch transactions for a specific date range
88///
89/// This is a simpler version that only fetches transactions without storing them
90///
91/// # Arguments
92///
93/// * `cfg` - The configuration object
94/// * `from` - Start date
95/// * `to` - End date
96///
97/// # Returns
98///
99/// * `Result<Vec<Transaction>, AppError>` - List of transactions, or an error
100pub async fn fetch_transactions(
101    cfg: &Config,
102    from: DateTime<Utc>,
103    to: DateTime<Utc>,
104) -> Result<Vec<Transaction>, AppError> {
105    // Authenticate with IG
106    let auth = IgAuth::new(cfg);
107    let sess = auth.login().await?;
108    debug!("Successfully authenticated with IG");
109
110    // Create the transaction client
111    let tx_client = IgTxClient::new(cfg);
112
113    // Fetch transactions
114    debug!("Fetching transactions from {} to {}", from, to);
115    let txs = tx_client.fetch_range(&sess, from, to).await?;
116    debug!("Fetched {} transactions", txs.len());
117
118    Ok(txs)
119}