diff --git a/bank_core/src/transaction.rs b/bank_core/src/transaction.rs index e83f9ad..89920a2 100644 --- a/bank_core/src/transaction.rs +++ b/bank_core/src/transaction.rs @@ -22,8 +22,8 @@ pub struct Transaction { #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] #[cfg_attr(feature = "schemas", derive(schemars::JsonSchema))] pub struct FullTransaction { - pub from: Participant, - pub to: Participant, + pub from: Option, + pub to: Option, pub amount: u64, pub timestamp: DateTime, pub message: Option, @@ -39,9 +39,14 @@ pub enum Direction { #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] #[cfg_attr(feature = "schemas", derive(schemars::JsonSchema))] -pub struct Participant { - pub user: User, - pub account: ReducedAccountInfo, +#[serde(untagged)] +pub enum Participant { + Normal { + user: User, + account: ReducedAccountInfo, + }, + /// interop username + Interop(String), } #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] diff --git a/migrations/000000_baseline.sql b/migrations/000000_baseline.sql index c2519b1..14dca0b 100644 --- a/migrations/000000_baseline.sql +++ b/migrations/000000_baseline.sql @@ -14,11 +14,17 @@ create table accounts( create table transactions( id uuid primary key, - "from" uuid not null references accounts(id), - "to" uuid not null references accounts(id), + "from" uuid references accounts(id), + "to" uuid references accounts(id), + interop_name text, + system bool not null default false, amount bigint not null constraint positive_amount check (amount > 0), timestamp timestamp with time zone not null default now(), - message text + message text, + constraint check_interop_name_from_to_null check ( + ((("from" is null and "to" is not null) or ("from" is not null and "to" is null)) and (interop_name is not null or system)) or + ("from" is not null and "to" is not null and interop_name is null) + ) ); create index transactions_from on transactions ("from"); @@ -28,6 +34,12 @@ create view transactions_with_user_info as select t.amount, t.message, t.timestamp, + t.system, + case + when t."from" is null then t.interop_name + when t."to" is null then t.interop_name + else null + end as interop_name, -- From Participant uf.id AS from_user_id, t."from" as from_account_id, diff --git a/src/config.rs b/src/config.rs index 8fc7e90..14e7648 100644 --- a/src/config.rs +++ b/src/config.rs @@ -11,12 +11,24 @@ pub struct Config { #[serde(default = "default_port")] pub port: u16, pub jwt_key: String, + #[serde(default = "default_interop_key")] + pub interop_key: String, + #[serde(default = "default_interop_prefix")] + pub interop_prefix: String, } fn default_host() -> IpAddr { IpAddr::V6(Ipv6Addr::LOCALHOST) } +fn default_interop_key() -> String { + "".into() +} + +fn default_interop_prefix() -> String { + "".into() +} + fn default_port() -> u16 { 3845 } diff --git a/src/model/transaction.rs b/src/model/transaction.rs index fcd5869..ed56469 100644 --- a/src/model/transaction.rs +++ b/src/model/transaction.rs @@ -11,33 +11,59 @@ use uuid::{NoContext, Timestamp, Uuid}; use crate::model::count; fn full_transaction_from_row(row: Row) -> FullTransaction { + let system: bool = row.get("system"); FullTransaction { - from: Participant { - user: User { - id: row.get("from_user_id"), - name: row.get("from_user_name"), - }, - account: ReducedAccountInfo { - id: row.get("from_account_id"), - name: row.get("from_account_name"), - }, - }, - to: Participant { - user: User { - id: row.get("to_user_id"), - name: row.get("to_user_name"), - }, - account: ReducedAccountInfo { - id: row.get("to_account_id"), - name: row.get("to_account_name"), - }, - }, + from: participant_from_row( + &row, + system, + "from_user_id", + "from_user_name", + "from_account_id", + "to_account_name", + ), + to: participant_from_row( + &row, + system, + "to_user_id", + "to_user_name", + "to_account_id", + "to_account_name", + ), timestamp: row.get("timestamp"), amount: row.get::<_, i64>("amount") as u64, message: row.get("message"), } } +fn participant_from_row( + row: &Row, + system: bool, + user_id: &str, + user_name: &str, + account_id: &str, + account_name: &str, +) -> Option { + if let Some(user_id) = row.get::<_, Option>(user_id) { + let user_name = row.get(user_name); + let account_id = row.get(account_id); + let account_name = row.get(account_name); + Some(Participant::Normal { + user: User { + id: user_id, + name: user_name, + }, + account: ReducedAccountInfo { + id: account_id, + name: account_name, + }, + }) + } else if system { + None + } else { + Some(Participant::Interop(row.get("interop_name"))) + } +} + pub struct Transactions; impl Transactions {