Skip to content

Commit

Permalink
add functions to reset all tables
Browse files Browse the repository at this point in the history
  • Loading branch information
richardjlyon committed May 31, 2023
1 parent 222b628 commit 88b9cd5
Show file tree
Hide file tree
Showing 17 changed files with 217 additions and 28 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.env
config.yaml
/target
/migration/target
note.txt
Expand Down
25 changes: 23 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,6 @@ sea-orm = { version="0.11.3", features = [ "sqlx-mysql", "runtime-tokio-native-t
strum_macros = "0.24"
strum = { version = "0.24.1", features = ["derive"]}
cargo-watch = "8.4.0"
anyhow = "1.0.71"
serde_yaml = "0.9.21"
# futures = "0.3.28"
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@ A command line utility for analysing rust transactions

## Configuration

Create a file `.env` with the following content:
Create a file `config.yaml` with the following content:

```
DATABASE_URL="mysql://admin:[email protected]:3306/starling_db"
PERSONAL_TOKEN="XXX"
BUSINESS_TOKEN="YYY"
token:
- person: "XXX"
- business: "YYY"
db:
user: "admin"
password: "ZZZ"
name: starling_db
```
10 changes: 5 additions & 5 deletions src/bin/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! Transactionsa are stored in a database. Reports can be produced in [ledger](https://ledger-cli.org/features.html) format.
use clap::{Parser, Subcommand};
use money::commands::{accounts::get_accounts, transactions::get_transactions};
use money::commands::{database::initialise_database, transactions::get_transactions};
use std::{env, process};

use money::starling::client::StarlingApiClient;
Expand All @@ -20,7 +20,7 @@ struct Cli {
#[derive(Subcommand)]
enum Commands {
/// Load accounts to the database
Accounts,
Init,

/// Account balances
Balances,
Expand All @@ -42,12 +42,12 @@ async fn main() -> std::io::Result<()> {

let personal_token =
env::var("PERSONAL_TOKEN").expect("PERSONAL_TOKEN is not set in .env file");
let client = StarlingApiClient::new(personal_token);
let client = StarlingApiClient::new(&personal_token);
// let client = StarlingMockClient::new();

match cli.command {
Commands::Accounts => {
if let Err(e) = get_accounts(&client).await {
Commands::Init => {
if let Err(e) = initialise_database().await {
println!("Application error: {}", e);
process::exit(1);
}
Expand Down
14 changes: 7 additions & 7 deletions src/bin/dump-json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ use std::env;

#[tokio::main]
async fn main() {
dotenvy::dotenv().ok();
let personal_token =
env::var("PERSONAL_TOKEN").expect("PERSONAL_TOKEN is not set in .env file");
let client = StarlingApiClient::new(personal_token);
// dotenvy::dotenv().ok();
// let personal_token =
// env::var("PERSONAL_TOKEN").expect("PERSONAL_TOKEN is not set in .env file");
// let client = StarlingApiClient::new(personal_token);

for account in client.accounts().await {
println!("{:#?}", account);
}
// for account in client.accounts().await {
// println!("{:#?}", account);
// }
}
4 changes: 2 additions & 2 deletions src/commands/accounts.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
//! Command Line Interface `Accounts` commands
//!
use std::error::Error;
use anyhow::Result;

use crate::{
db,
starling::client::{StarlingApiClient, StarlingClient},
};

/// Fetch account information from Starling and populate the database
pub async fn get_accounts(client: &StarlingApiClient) -> Result<(), Box<dyn Error>> {
pub async fn get_accounts() -> Result<()> {
Ok(())
}
67 changes: 67 additions & 0 deletions src/commands/database.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//! Command Line Interface `Database` commands
//!
use std::io::Write;
use std::{io, process};

use crate::entities::account;
use crate::{
config::Config,
db,
starling::client::{StarlingApiClient, StarlingClient},
};
use anyhow::Result;
use sea_orm::*;

/// Initialise the database.
///
/// Drop and reinstate the tables if they exist, fetch account data from Starling and save, and initialise with
/// transaction data for all accounts and saving spaces.
///
pub async fn initialise_database() -> Result<()> {
let config = Config::new();

if !proceed() {
println!("Exiting.");
process::exit(1);
}

// process accounts
db::account::delete_all().await;
db::transaction::delete_all().await;
db::counterparty::delete_all().await;

// delete the old ones
let db = Database::connect(&config.db_url())
.await
.expect("getting database");

let res: DeleteResult = account::Entity::delete_many()
.exec(&db)
.await
.expect("deleting accounts");

for item in config.token.iter() {
for (name, token) in item.iter() {
// drop and reload the accounts
let client = StarlingApiClient::new(token);
for account in client.accounts().await.iter() {
db::account::insert_or_update(&account);
}
}
}

Ok(())
}

// Return true if user enters 'y' or 'Y'
fn proceed() -> bool {
println!("This will destroy the database and can't be undone");
print!("Proceed? (y/n) ");
io::stdout().flush().unwrap();
let mut response = String::new();
io::stdin()
.read_line(&mut response)
.expect("failed to read response");
response.trim().to_lowercase() == String::from("y")
}
1 change: 1 addition & 0 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod accounts;
pub mod database;
pub mod transactions;
6 changes: 3 additions & 3 deletions src/commands/transactions.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
//! Command Line Interface `Transaction` commands
//!
use std::error::Error;
use anyhow::Result;

use crate::{
db,
starling::client::{StarlingApiClient, StarlingClient},
};

/// Fetch transactions for the specified number of days and save to the database
pub async fn get_transactions(client: &StarlingApiClient, days: i64) -> Result<(), Box<dyn Error>> {
pub async fn get_transactions(client: &StarlingApiClient, days: i64) -> Result<()> {
if let Some(account) = client.accounts().await.iter().next() {
db::service::insert_or_update(client, account, days).await;
db::transaction::insert_or_update(client, account, days).await;
}

Ok(())
Expand Down
34 changes: 34 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//! Functionality for managing a config file
//!
//!
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

#[derive(Serialize, Deserialize, Debug)]
pub struct Config {
pub token: Vec<HashMap<String, String>>,
pub db: DbConfig,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct DbConfig {
pub user: String,
pub password: String,
pub name: String,
}

impl Config {
pub fn new() -> Self {
let f = std::fs::File::open("config.yaml").expect("opening file");
let d: Config = serde_yaml::from_reader(f).expect("decoding");

d
}

pub fn db_url(&self) -> String {
format!(
"mysql://{}:{}@db.kingswood:3306/{}",
self.db.user, self.db.password, self.db.name
)
}
}
21 changes: 21 additions & 0 deletions src/db/account.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//! Functions for interacting with table `accounts`
use super::get_database;
use crate::entities::account;
use crate::starling::account::Account;
use sea_orm::*;

// DELETE * FROM account;
pub async fn delete_all() {
let db = get_database().await;
account::Entity::delete_many()
.exec(&db)
.await
.expect("deleting accounts");
}

pub async fn insert_or_update(account: &Account) {
let db = get_database().await;

println!("{:#?}", account);
}
12 changes: 12 additions & 0 deletions src/db/counterparty.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use super::get_database;
use crate::entities::counterparty;
use sea_orm::*;

// DELETE * FROM account;
pub async fn delete_all() {
let db = get_database().await;
counterparty::Entity::delete_many()
.exec(&db)
.await
.expect("deleting accounts");
}
14 changes: 13 additions & 1 deletion src/db/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,13 @@
pub mod service;
pub mod account;
pub mod counterparty;
pub mod transaction;

use crate::config::Config;
use sea_orm::*;

async fn get_database() -> DatabaseConnection {
let config = Config::new();
Database::connect(&config.db_url())
.await
.expect("getting database")
}
11 changes: 10 additions & 1 deletion src/db/service.rs → src/db/transaction.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
//! Services for interacting with the database.
//!
use super::get_database;
use crate::{
entities::{counterparty, prelude::*, transaction},
starling::{account::Account, client::StarlingClient, transaction::StarlingTransaction},
};

use sea_orm::*;
use std::env;

// DELETE * FROM transaction;
pub async fn delete_all() {
let db = get_database().await;
transaction::Entity::delete_many()
.exec(&db)
.await
.expect("deleting accounts");
}

/// Inser or update a list of Starling transactions for the specified account and number of days.
///
/// If the transaction doesn't exist, insert it. If it exists and its status has changed, update it.
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod commands;
pub mod config;
pub mod db;
pub mod entities;
pub mod starling;
9 changes: 7 additions & 2 deletions src/starling/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ use super::{
use chrono::{DateTime, Utc};
use serde::Serialize;

enum AccountType {
Personal(String),
Business(String),
}

#[async_trait::async_trait]
pub trait StarlingClient {
async fn accounts(&self) -> Vec<Account>;
Expand All @@ -28,9 +33,9 @@ pub struct StarlingApiClient {
}

impl StarlingApiClient {
pub fn new(api_key: String) -> Self {
pub fn new(api_key: &String) -> Self {
Self {
key: api_key,
key: api_key.to_owned(),
base_url: "https://api.starlingbank.com/api/v2".to_string(),
}
}
Expand Down

0 comments on commit 88b9cd5

Please sign in to comment.