Skip to content

Commit

Permalink
improve connection management and perf
Browse files Browse the repository at this point in the history
  • Loading branch information
afadil committed Sep 23, 2024
1 parent 979f1cd commit 7619131
Show file tree
Hide file tree
Showing 26 changed files with 632 additions and 395 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "wealthfolio-app",
"private": true,
"version": "1.0.14",
"version": "1.0.15",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
48 changes: 25 additions & 23 deletions src-core/src/account/account_service.rs
Original file line number Diff line number Diff line change
@@ -1,40 +1,42 @@
use crate::account::AccountRepository;
use crate::fx::fx_service::CurrencyExchangeService;
use crate::models::{Account, AccountUpdate, NewAccount};
use diesel::r2d2::{ConnectionManager, Pool};
use diesel::Connection;
use diesel::SqliteConnection;

pub struct AccountService {
account_repo: AccountRepository,
pool: Pool<ConnectionManager<SqliteConnection>>,
base_currency: String,
}

impl AccountService {
pub fn new(pool: Pool<ConnectionManager<SqliteConnection>>, base_currency: String) -> Self {
pub fn new(base_currency: String) -> Self {
AccountService {
account_repo: AccountRepository::new(),
pool,
base_currency,
}
}

pub fn get_accounts(&self) -> Result<Vec<Account>, diesel::result::Error> {
let mut conn = self.pool.get().expect("Couldn't get db connection");
self.account_repo.load_accounts(&mut conn)
pub fn get_accounts(
&self,
conn: &mut SqliteConnection,
) -> Result<Vec<Account>, diesel::result::Error> {
self.account_repo.load_accounts(conn)
}

pub fn get_account_by_id(&self, account_id: &str) -> Result<Account, diesel::result::Error> {
let mut conn = self.pool.get().expect("Couldn't get db connection");
self.account_repo.load_account_by_id(&mut conn, account_id)
pub fn get_account_by_id(
&self,
conn: &mut SqliteConnection,
account_id: &str,
) -> Result<Account, diesel::result::Error> {
self.account_repo.load_account_by_id(conn, account_id)
}

pub async fn create_account(
&self,
conn: &mut SqliteConnection,
new_account: NewAccount,
) -> Result<Account, Box<dyn std::error::Error>> {
let mut conn = self.pool.get()?;
let base_currency = self.base_currency.clone();

println!(
Expand All @@ -43,9 +45,12 @@ impl AccountService {
);
conn.transaction(|conn| {
if new_account.currency != base_currency {
let fx_service = CurrencyExchangeService::new(self.pool.clone());
fx_service
.add_exchange_rate(base_currency.clone(), new_account.currency.clone())?;
let fx_service = CurrencyExchangeService::new();
fx_service.add_exchange_rate(
conn,
base_currency.clone(),
new_account.currency.clone(),
)?;
}

// Insert new account
Expand All @@ -57,28 +62,25 @@ impl AccountService {

pub fn update_account(
&self,
conn: &mut SqliteConnection,
updated_account_data: AccountUpdate,
) -> Result<Account, diesel::result::Error> {
let mut conn = self.pool.get().expect("Couldn't get db connection");
self.account_repo
.update_account(&mut conn, updated_account_data)
self.account_repo.update_account(conn, updated_account_data)
}

pub fn delete_account(
&self,
conn: &mut SqliteConnection,
account_id_to_delete: String,
) -> Result<usize, diesel::result::Error> {
let mut conn = self.pool.get().expect("Couldn't get db connection");
self.account_repo
.delete_account(&mut conn, account_id_to_delete)
self.account_repo.delete_account(conn, account_id_to_delete)
}

pub fn get_accounts_by_ids(
&self,
conn: &mut SqliteConnection,
account_ids: &[String],
) -> Result<Vec<Account>, diesel::result::Error> {
let mut conn = self.pool.get().expect("Couldn't get db connection");
self.account_repo
.load_accounts_by_ids(&mut conn, account_ids)
self.account_repo.load_accounts_by_ids(conn, account_ids)
}
}
110 changes: 63 additions & 47 deletions src-core/src/activity/activity_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,39 +11,42 @@ use crate::schema::activities;

use csv::ReaderBuilder;
use diesel::prelude::*;
use diesel::r2d2::{ConnectionManager, Pool};

use uuid::Uuid;

pub struct ActivityService {
repo: ActivityRepository,
pool: Pool<ConnectionManager<SqliteConnection>>,
base_currency: String,
}

impl ActivityService {
pub fn new(pool: Pool<ConnectionManager<SqliteConnection>>, base_currency: String) -> Self {
pub fn new(base_currency: String) -> Self {
ActivityService {
repo: ActivityRepository::new(),
pool,
base_currency,
}
}

//load all activities
pub fn get_activities(&self) -> Result<Vec<Activity>, diesel::result::Error> {
let mut conn = self.pool.get().expect("Couldn't get db connection");
self.repo.get_activities(&mut conn)
pub fn get_activities(
&self,
conn: &mut SqliteConnection,
) -> Result<Vec<Activity>, diesel::result::Error> {
self.repo.get_activities(conn)
}

pub fn get_trading_activities(&self) -> Result<Vec<Activity>, diesel::result::Error> {
let mut conn = self.pool.get().expect("Couldn't get db connection");
self.repo.get_trading_activities(&mut conn)
pub fn get_trading_activities(
&self,
conn: &mut SqliteConnection,
) -> Result<Vec<Activity>, diesel::result::Error> {
self.repo.get_trading_activities(conn)
}

pub fn get_income_data(&self) -> Result<Vec<IncomeData>, diesel::result::Error> {
let mut conn = self.pool.get().expect("Couldn't get db connection");
self.repo.get_income_activities(&mut conn).map(|results| {
pub fn get_income_data(
&self,
conn: &mut SqliteConnection,
) -> Result<Vec<IncomeData>, diesel::result::Error> {
self.repo.get_income_activities(conn).map(|results| {
results
.into_iter()
.map(|activity| IncomeData {
Expand All @@ -59,16 +62,16 @@ impl ActivityService {

pub fn search_activities(
&self,
conn: &mut SqliteConnection,
page: i64, // Page number, 1-based
page_size: i64, // Number of items per page
account_id_filter: Option<Vec<String>>, // Optional account_id filter
activity_type_filter: Option<Vec<String>>, // Optional activity_type filter
asset_id_keyword: Option<String>, // Optional asset_id keyword for search
sort: Option<Sort>, // Optional sort
) -> Result<ActivitySearchResponse, diesel::result::Error> {
let mut conn = self.pool.get().expect("Couldn't get db connection");
self.repo.search_activities(
&mut conn,
conn,
page,
page_size,
account_id_filter,
Expand All @@ -81,16 +84,16 @@ impl ActivityService {
//create a new activity and fetch related the asset profile
pub async fn create_activity(
&self,
conn: &mut SqliteConnection,
mut activity: NewActivity,
) -> Result<Activity, Box<dyn std::error::Error>> {
let mut conn = self.pool.get()?;
let asset_id = activity.asset_id.clone();
let asset_service = AssetService::new(self.pool.clone()).await;
let account_service = AccountService::new(self.pool.clone(), self.base_currency.clone());
let asset_service = AssetService::new().await;
let account_service = AccountService::new(self.base_currency.clone());
let asset_profile = asset_service
.get_asset_profile(&asset_id, Some(true))
.get_asset_profile(conn, &asset_id, Some(true))
.await?;
let account = account_service.get_account_by_id(&activity.account_id)?;
let account = account_service.get_account_by_id(conn, &activity.account_id)?;

conn.transaction(|conn| {
// Update activity currency if asset_profile.currency is available
Expand All @@ -106,9 +109,12 @@ impl ActivityService {

// Create exchange rate if asset currency is different from account currency
if activity.currency != account.currency {
let fx_service = CurrencyExchangeService::new(self.pool.clone());
fx_service
.add_exchange_rate(account.currency.clone(), activity.currency.clone())?;
let fx_service = CurrencyExchangeService::new();
fx_service.add_exchange_rate(
conn,
account.currency.clone(),
activity.currency.clone(),
)?;
}

// Insert the new activity into the database
Expand All @@ -121,15 +127,15 @@ impl ActivityService {
// update an activity
pub async fn update_activity(
&self,
conn: &mut SqliteConnection,
mut activity: ActivityUpdate,
) -> Result<Activity, Box<dyn std::error::Error>> {
let mut conn = self.pool.get()?;
let asset_service = AssetService::new(self.pool.clone()).await;
let account_service = AccountService::new(self.pool.clone(), self.base_currency.clone());
let asset_service = AssetService::new().await;
let account_service = AccountService::new(self.base_currency.clone());
let asset_profile = asset_service
.get_asset_profile(&activity.asset_id, Some(true))
.get_asset_profile(conn, &activity.asset_id, Some(true))
.await?;
let account = account_service.get_account_by_id(&activity.account_id)?;
let account = account_service.get_account_by_id(conn, &activity.account_id)?;

conn.transaction(|conn| {
// Update activity currency if asset_profile.currency is available
Expand All @@ -145,9 +151,12 @@ impl ActivityService {

// Create exchange rate if asset currency is different from account currency
if activity.currency != account.currency {
let fx_service = CurrencyExchangeService::new(self.pool.clone());
fx_service
.add_exchange_rate(account.currency.clone(), activity.currency.clone())?;
let fx_service = CurrencyExchangeService::new();
fx_service.add_exchange_rate(
conn,
account.currency.clone(),
activity.currency.clone(),
)?;
}

// Update the activity in the database
Expand All @@ -160,14 +169,15 @@ impl ActivityService {
// verify the activities import from csv file
pub async fn check_activities_import(
&self,
conn: &mut SqliteConnection,
_account_id: String,
file_path: String,
) -> Result<Vec<ActivityImport>, String> {
let asset_service = AssetService::new(self.pool.clone()).await;
let account_service = AccountService::new(self.pool.clone(), self.base_currency.clone());
let fx_service = CurrencyExchangeService::new(self.pool.clone());
let asset_service = AssetService::new().await;
let account_service = AccountService::new(self.base_currency.clone());
let fx_service = CurrencyExchangeService::new();
let account = account_service
.get_account_by_id(&_account_id)
.get_account_by_id(conn, &_account_id)
.map_err(|e| e.to_string())?;

let file = File::open(&file_path).map_err(|e| e.to_string())?;
Expand All @@ -184,7 +194,7 @@ impl ActivityService {

// Load the symbol profile here, now awaiting the async call
let symbol_profile_result = asset_service
.get_asset_profile(&activity_import.symbol, Some(false))
.get_asset_profile(conn, &activity_import.symbol, Some(false))
.await;

// Check if symbol profile is valid
Expand All @@ -196,9 +206,11 @@ impl ActivityService {
// Add exchange rate if the activity currency is different from the account currency
let currency = &activity_import.currency;
if currency != &account.currency {
match fx_service
.add_exchange_rate(account.currency.clone(), currency.clone())
{
match fx_service.add_exchange_rate(
conn,
account.currency.clone(),
currency.clone(),
) {
Ok(_) => (),
Err(e) => {
let error_msg = format!(
Expand Down Expand Up @@ -234,7 +246,9 @@ impl ActivityService {

// Sync quotes for all valid symbols
if !symbols_to_sync.is_empty() {
asset_service.sync_symbol_quotes(&symbols_to_sync).await?;
asset_service
.sync_symbol_quotes(conn, &symbols_to_sync)
.await?;
}

Ok(activities_with_status)
Expand All @@ -243,9 +257,9 @@ impl ActivityService {
// create activities used after the import is verified
pub fn create_activities(
&self,
conn: &mut SqliteConnection,
activities: Vec<NewActivity>,
) -> Result<usize, diesel::result::Error> {
let mut conn = self.pool.get().expect("Couldn't get db connection");
conn.transaction(|conn| {
let mut insert_count = 0;
for new_activity in activities {
Expand All @@ -260,17 +274,19 @@ impl ActivityService {
}

// delete an activity
pub fn delete_activity(&self, activity_id: String) -> Result<Activity, diesel::result::Error> {
let mut conn = self.pool.get().expect("Couldn't get db connection");
self.repo.delete_activity(&mut conn, activity_id)
pub fn delete_activity(
&self,
conn: &mut SqliteConnection,
activity_id: String,
) -> Result<Activity, diesel::result::Error> {
self.repo.delete_activity(conn, activity_id)
}

pub fn get_activities_by_account_ids(
&self,
conn: &mut SqliteConnection,
account_ids: &[String],
) -> Result<Vec<Activity>, diesel::result::Error> {
let mut conn = self.pool.get().expect("Couldn't get db connection");
self.repo
.get_activities_by_account_ids(&mut conn, account_ids)
self.repo.get_activities_by_account_ids(conn, account_ids)
}
}
Loading

0 comments on commit 7619131

Please sign in to comment.