Skip to content

Commit

Permalink
[WIP]
Browse files Browse the repository at this point in the history
  • Loading branch information
Leonid Kozarin committed Feb 21, 2024
1 parent dfedef3 commit 0f0c3f1
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 1 deletion.

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

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

10 changes: 10 additions & 0 deletions migrations/15_create-loans-table.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CREATE TABLE IF NOT EXISTS Loans (
id serial PRIMARY KEY,
uid bigint NOT NULL REFERENCES Users(uid),
chat_id bigint NOT NULL REFERENCES Chats(id),
left_to_pay int NOT NULL CHECK ( left_to_pay >= 0 ),
created_at date NOT NULL DEFAULT current_date,
repaid_at date
);

CREATE INDEX IF NOT EXISTS idx_loans_uid ON Loans(uid);
73 changes: 73 additions & 0 deletions src/repo/loans.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use std::collections::HashMap;
use std::sync::Arc;
use teloxide::types::UserId;
use tokio::sync::RwLock;
use crate::config::FeatureToggles;
use crate::repo;
use crate::repo::{ChatIdKind, ChatIdPartiality};

#[derive(Clone)]
pub struct Loans {
pool: sqlx::Pool<sqlx::Postgres>,
features: FeatureToggles,
chat_id_cache: Arc<RwLock<HashMap<ChatIdKind, i64>>>,
chats_repo: repo::Chats,
}

impl Loans {
pub fn new(pool: sqlx::Pool<sqlx::Postgres>, features: FeatureToggles) -> Self {
Self {
chats_repo: repo::Chats::new(pool.clone(), features),
pool,
features,
chat_id_cache: Arc::new(RwLock::new(HashMap::new())),
}
}

pub async fn get_active_loan(&self, uid: UserId, chat_id: ChatIdPartiality) -> anyhow::Result<u32> {
let internal_chat_id = match self.get_internal_chat_id(chat_id.kind()).await? {
Some(id) => id,
None => return Ok(Default::default())
};
sqlx::query_scalar!("SELECT left_to_pay FROM loans WHERE uid = $1 AND chat_id = $2 AND repaid_at IS NULL",

Check failure on line 32 in src/repo/loans.rs

View workflow job for this annotation

GitHub Actions / Run-tests

`DATABASE_URL` must be set, or `cargo sqlx prepare` must have been run and .sqlx must exist, to use query macros
uid.0 as i64, internal_chat_id)
.fetch_optional(&self.pool)
.await
.map(|maybe_loan| maybe_loan.map(|value| value as u32).unwrap_or_default())
.map_err(|e| e.into())
}

pub async fn pay(&self, uid: UserId, chat_id: ChatIdPartiality, value: u32) -> anyhow::Result<()> {
let internal_chat_id = match self.get_internal_chat_id(chat_id.kind()).await? {
Some(id) => id,
None => return Ok(()) // TODO: check or logging?
};
sqlx::query!("UPDATE Loans SET left_to_pay = left_to_pay - $3 WHERE uid = $1 AND chat_id = $2 AND repaid_at IS NULL",
uid.0 as i64, internal_chat_id, value as i64)
.execute(&self.pool)
.await
.map(|_| ())
.map_err(|e| e.into())
}

async fn get_internal_chat_id(&self, chat_id: ChatIdKind) -> anyhow::Result<Option<i64>> {
let maybe_internal_id = self.chat_id_cache
.read().await
.get(&chat_id).copied();
let internal_id = match maybe_internal_id {
None => {
let maybe_id = self.chats_repo.get_chat(chat_id.clone())
.await?
.map(|chat| chat.internal_id);
if let Some(id) = maybe_id {
self.chat_id_cache
.write().await
.insert(chat_id, id);
}
maybe_id
}
Some(id) => Some(id)
};
Ok(internal_id)
}
}
3 changes: 2 additions & 1 deletion src/repo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod dicks;
mod chats;
mod import;
mod promo;
mod loans;

#[cfg(test)]
pub(crate) mod test;
Expand Down Expand Up @@ -95,7 +96,7 @@ impl ChatIdFull {
}
}

#[derive(Debug, derive_more::Display, Clone)]
#[derive(Debug, derive_more::Display, Clone, Eq, PartialEq, Hash)]
pub enum ChatIdKind {
ID(ChatId),
Instance(String)
Expand Down

0 comments on commit 0f0c3f1

Please sign in to comment.