mirror of
https://codeberg.org/JasterV/transactions-processor.git
synced 2026-04-26 18:10:06 +00:00
almost done
This commit is contained in:
parent
c047130d2e
commit
d08286beb6
10 changed files with 161 additions and 23 deletions
22
Cargo.lock
generated
22
Cargo.lock
generated
|
|
@ -417,6 +417,26 @@ dependencies = [
|
|||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.9.0"
|
||||
|
|
@ -466,7 +486,9 @@ dependencies = [
|
|||
"anyhow",
|
||||
"csv-async",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ edition = "2018"
|
|||
|
||||
[dependencies]
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tokio-stream = "0.1.7"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
csv-async = { version = "1.2.1", features = ["with_serde", "tokio"]}
|
||||
thiserror = "1.0.26"
|
||||
anyhow = "1.0.40"
|
||||
13
src/errors.rs
Normal file
13
src/errors.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum TransactionError {
|
||||
#[error("Not enough funds to withdraw")]
|
||||
WithdrawError,
|
||||
#[error("Not enough available funds to held")]
|
||||
HeldError,
|
||||
#[error("Not enough held funds to free")]
|
||||
UnheldError,
|
||||
#[error("Account `{0}` is locked")]
|
||||
AccountLocked(u16),
|
||||
}
|
||||
19
src/main.rs
19
src/main.rs
|
|
@ -1,12 +1,25 @@
|
|||
mod errors;
|
||||
mod models;
|
||||
mod services;
|
||||
use std::env;
|
||||
|
||||
use anyhow::Result;
|
||||
use models::{account::Account, transaction::Transaction};
|
||||
use std::{collections::HashMap, env};
|
||||
use tokio::fs::File;
|
||||
use tokio_stream::StreamExt;
|
||||
|
||||
type TransactionsMap = HashMap<u32, Transaction>;
|
||||
type AccountsMap = HashMap<u16, Account>;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let file_path = env::args().nth(1).expect("CSV path required");
|
||||
println!("Hello, World");
|
||||
let mut rdr = csv_async::AsyncDeserializer::from_reader(File::open(file_path).await?);
|
||||
let mut records = rdr.deserialize::<Transaction>();
|
||||
|
||||
while let Some(record) = records.next().await {
|
||||
let transaction = record?;
|
||||
println!("{:#?}", transaction);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
81
src/models/account.rs
Normal file
81
src/models/account.rs
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
use anyhow::Result;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::errors::TransactionError;
|
||||
|
||||
#[derive(Serialize, Debug)]
|
||||
pub struct Account {
|
||||
client: u16,
|
||||
available: f32,
|
||||
held: f32,
|
||||
total: f32,
|
||||
locked: bool,
|
||||
}
|
||||
|
||||
impl Account {
|
||||
pub fn new(client: u16) -> Self {
|
||||
Self {
|
||||
client,
|
||||
available: 0.0,
|
||||
held: 0.0,
|
||||
total: 0.0,
|
||||
locked: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deposit(&mut self, amount: f32) -> Result<()> {
|
||||
self.assert_lock()?;
|
||||
self.available += amount;
|
||||
self.total += amount;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn withdraw(&mut self, amount: f32) -> Result<()> {
|
||||
self.assert_lock()?;
|
||||
if amount > self.available {
|
||||
Err(TransactionError::WithdrawError)?;
|
||||
}
|
||||
self.available -= amount;
|
||||
self.total -= amount;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn held(&mut self, amount: f32) -> Result<()> {
|
||||
self.assert_lock()?;
|
||||
if amount > self.available {
|
||||
Err(TransactionError::HeldError)?;
|
||||
}
|
||||
self.available -= amount;
|
||||
self.held += amount;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn free(&mut self, amount: f32) -> Result<()> {
|
||||
self.assert_lock()?;
|
||||
if amount > self.held {
|
||||
Err(TransactionError::UnheldError)?;
|
||||
}
|
||||
self.held -= amount;
|
||||
self.available += amount;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn chargeback(&mut self, amount: f32) -> Result<()> {
|
||||
self.assert_lock()?;
|
||||
if amount > self.held {
|
||||
Err(TransactionError::UnheldError)?;
|
||||
}
|
||||
self.held -= amount;
|
||||
self.total -= amount;
|
||||
self.locked = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn assert_lock(&self) -> Result<()> {
|
||||
if self.locked {
|
||||
Err(TransactionError::AccountLocked(self.client))?
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +1,2 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Transaction {
|
||||
pub ty: String,
|
||||
pub client: u16,
|
||||
pub tx: u32,
|
||||
pub amount: f32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug)]
|
||||
pub struct TransactionResult {
|
||||
pub client: u16,
|
||||
pub available: f32,
|
||||
pub held: f32,
|
||||
pub total: f32,
|
||||
pub locked: bool,
|
||||
}
|
||||
pub mod account;
|
||||
pub mod transaction;
|
||||
|
|
|
|||
25
src/models/transaction.rs
Normal file
25
src/models/transaction.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub enum TransactionType {
|
||||
#[serde(alias = "deposit")]
|
||||
Deposit,
|
||||
#[serde(alias = "withdrawal")]
|
||||
Withdrawal,
|
||||
#[serde(alias = "dispute")]
|
||||
Dispute,
|
||||
#[serde(alias = "resolve")]
|
||||
Resolve,
|
||||
#[serde(alias = "chargeback")]
|
||||
Chargeback,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Transaction {
|
||||
#[serde(alias = "type")]
|
||||
pub ty: TransactionType,
|
||||
pub client: u16,
|
||||
pub tx: u32,
|
||||
#[serde(default)]
|
||||
pub amount: f32,
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
|
||||
|
|
@ -1 +0,0 @@
|
|||
|
||||
Loading…
Reference in a new issue