From fa27bb575fc39914912c9d460a3d99030b242ad4 Mon Sep 17 00:00:00 2001 From: mykola2312 <49044616+mykola2312@users.noreply.github.com> Date: Fri, 8 Mar 2024 07:58:53 +0200 Subject: [PATCH] migrate all sql queries to postgres --- migrations/1_init.sql | 23 +++++++++++++++---- src/bot/notify.rs | 2 +- src/bot/op.rs | 8 +++---- src/bot/request.rs | 50 ++++++++++++++++++++--------------------- src/bot/request_chat.rs | 46 ++++++++++++++++++------------------- src/bot/start.rs | 2 +- src/db.rs | 36 ++++++++++++++--------------- 7 files changed, 91 insertions(+), 76 deletions(-) diff --git a/migrations/1_init.sql b/migrations/1_init.sql index 1d25a9e..8453ef8 100644 --- a/migrations/1_init.sql +++ b/migrations/1_init.sql @@ -13,6 +13,21 @@ CREATE TABLE "user" CREATE INDEX idx_user_tg_id ON "user"(tg_id); +CREATE FUNCTION set_admin() +RETURNS TRIGGER AS $$ +BEGIN + IF new.is_admin THEN + UPDATE "user" SET can_download = true WHERE "user".id = new.id; + END IF; + RETURN new; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER set_admin +AFTER UPDATE OF is_admin ON "user" +FOR EACH ROW +EXECUTE FUNCTION set_admin(); + CREATE TABLE "chat" ( id SERIAL PRIMARY KEY, @@ -34,8 +49,8 @@ CREATE TABLE "link" auto_download BOOLEAN NOT NULL ); -CREATE INDEX idx_link_domain - ON "link"(domain); +CREATE INDEX idx_link_domain_path + ON "link"(domain, path); CREATE TABLE "request" ( @@ -53,7 +68,7 @@ CREATE FUNCTION approve() RETURNS TRIGGER AS $$ BEGIN IF new.is_approved THEN - UPDATE "user" SET can_download = TRUE WHERE "user".id = new.requested_by; + UPDATE "user" SET can_download = true WHERE "user".id = new.requested_by; END IF; RETURN new; END; @@ -82,7 +97,7 @@ CREATE FUNCTION approve_chat() RETURNS TRIGGER AS $$ BEGIN IF new.is_approved THEN - UPDATE "chat" SET can_download = TRUE WHERE "chat".id = new.requested_for; + UPDATE "chat" SET can_download = true WHERE "chat".id = new.requested_for; END IF; RETURN new; END; diff --git a/src/bot/notify.rs b/src/bot/notify.rs index ce69b14..227aed5 100644 --- a/src/bot/notify.rs +++ b/src/bot/notify.rs @@ -7,7 +7,7 @@ use super::types::HandlerResult; pub async fn notify_admins(bot: &Bot, db: &DbPool, message: String) -> HandlerResult { let admins: Vec = - sqlx::query_as("SELECT * FROM user WHERE is_admin = 1 AND has_private_chat = 1;") + sqlx::query_as(r#"SELECT * FROM "user" WHERE is_admin = true AND has_private_chat = true;"#) .fetch_all(db) .await?; diff --git a/src/bot/op.rs b/src/bot/op.rs index e7f8af9..fe4f3fc 100644 --- a/src/bot/op.rs +++ b/src/bot/op.rs @@ -8,7 +8,7 @@ use crate::db::user::find_or_create_user; use crate::db::DbPool; pub async fn cmd_op(bot: Bot, msg: Message, db: DbPool) -> HandlerResult { - let admins: i64 = sqlx::query("SELECT COUNT(*) FROM user WHERE is_admin = 1") + let admins: i64 = sqlx::query(r#"SELECT COUNT(*) FROM "user" WHERE is_admin = true"#) .fetch_one(&db) .await? .get(0); @@ -16,7 +16,7 @@ pub async fn cmd_op(bot: Bot, msg: Message, db: DbPool) -> HandlerResult { if let Some(tg_user) = msg.from() { if admins == 0 { let user = find_or_create_user(&db, tg_user).await?; - sqlx::query("UPDATE user SET can_download = 1, is_admin = 1 WHERE id = $1;") + sqlx::query(r#"UPDATE "user" SET is_admin = true WHERE id = $1;"#) .bind(user.id) .execute(&db) .await?; @@ -30,10 +30,10 @@ pub async fn cmd_op(bot: Bot, msg: Message, db: DbPool) -> HandlerResult { bot.send_message(msg.chat.id, t!("op_yourself")).await?; } else { let user = find_or_create_user(&db, tg_user).await?; - if user.is_admin == 1 { + if user.is_admin { if let Some(target) = msg.reply_to_message().and_then(|m| m.from()) { let target = find_or_create_user(&db, target).await?; - sqlx::query("UPDATE user SET can_download = 1, is_admin = 1 WHERE id = $1;") + sqlx::query(r#"UPDATE "user" SET is_admin = 1 WHERE id = $1;"#) .bind(target.id) .execute(&db) .await?; diff --git a/src/bot/request.rs b/src/bot/request.rs index f6ac488..1b81d51 100644 --- a/src/bot/request.rs +++ b/src/bot/request.rs @@ -19,11 +19,11 @@ pub async fn cmd_request(bot: Bot, msg: Message, text: String, db: DbPool) -> Ha if let Some(user) = msg.from() { let user = find_or_create_user(&db, user).await?; - if user.can_download == 1 { + if user.can_download { reply_i18n_and_return!(bot, msg.chat.id, "already_can_download"); } - let requests: i64 = sqlx::query("SELECT COUNT(1) FROM request WHERE requested_by = $1;") + let requests: i64 = sqlx::query(r#"SELECT COUNT(1) FROM "request" WHERE requested_by = $1;"#) .bind(user.id) .fetch_one(&db) .await? @@ -33,7 +33,7 @@ pub async fn cmd_request(bot: Bot, msg: Message, text: String, db: DbPool) -> Ha } // put the request - sqlx::query("INSERT INTO request (requested_by,message,is_approved) VALUES ($1,$2,$3);") + sqlx::query(r#"INSERT INTO "request" (requested_by,message,is_approved) VALUES ($1,$2,$3);"#) .bind(user.id) .bind(text) .bind(0) @@ -57,7 +57,7 @@ pub async fn cmd_request(bot: Bot, msg: Message, text: String, db: DbPool) -> Ha #[derive(sqlx::FromRow, Debug)] struct RequestWithUser { - pub request_id: i64, + pub request_id: i32, pub message: String, #[sqlx(flatten)] pub user: User, @@ -66,15 +66,15 @@ struct RequestWithUser { pub async fn cmd_listrequests(bot: Bot, msg: Message, db: DbPool) -> HandlerResult { if let Some(user) = msg.from() { let user = find_or_create_user(&db, user).await?; - if user.is_admin != 1 { + if !user.is_admin { reply_i18n_and_return!(bot, msg.chat.id, "not_an_admin"); } let requests: Vec = sqlx::query_as( - "SELECT request.id AS request_id, request.message, user.* - FROM request - INNER JOIN user ON request.requested_by = user.id - WHERE request.is_approved = 0;", + r#"SELECT "request".id AS request_id, "request".message, "user".* + FROM "request" + INNER JOIN "user" ON "request".requested_by = "user".id + WHERE "request".is_approved = false;"#, ) .fetch_all(&db) .await?; @@ -99,17 +99,17 @@ pub async fn cmd_approve(bot: Bot, msg: Message, id: String, db: DbPool) -> Hand if let Some(user) = msg.from() { let user = find_or_create_user(&db, user).await?; - if user.is_admin != 1 { + if !user.is_admin { reply_i18n_and_return!(bot, msg.chat.id, "not_an_admin"); } // get request let res: Result = sqlx::query_as( - "SELECT request.id AS request_id, request.message, user.* - FROM request - INNER JOIN user ON request.requested_by = user.id - WHERE request_id = $1 AND request.is_approved = 0 - LIMIT 1;", + r#"SELECT "request".id AS request_id, "request".message, "user".* + FROM "request" + INNER JOIN "user" ON "request".requested_by = "user".id + WHERE request_id = $1 AND "request".is_approved = false + LIMIT 1;"#, ) .bind(id) .fetch_one(&db) @@ -127,7 +127,7 @@ pub async fn cmd_approve(bot: Bot, msg: Message, id: String, db: DbPool) -> Hand }; // approve request - sqlx::query("UPDATE request SET approved_by = $1, is_approved = 1 WHERE id = $2;") + sqlx::query(r#"UPDATE "request" SET approved_by = $1, is_approved = true WHERE id = $2;"#) .bind(user.id) .bind(request.request_id) .execute(&db) @@ -143,7 +143,7 @@ pub async fn cmd_approve(bot: Bot, msg: Message, id: String, db: DbPool) -> Hand .await?; // notify target user - if request.user.has_private_chat == 1 { + if request.user.has_private_chat { bot.send_message( Recipient::Id(ChatId(request.user.tg_id)), t!("your_request_approved"), @@ -160,17 +160,17 @@ pub async fn cmd_decline(bot: Bot, msg: Message, id: String, db: DbPool) -> Hand if let Some(user) = msg.from() { let user = find_or_create_user(&db, user).await?; - if user.is_admin != 1 { + if !user.is_admin { reply_i18n_and_return!(bot, msg.chat.id, "not_an_admin"); } // get request let res: Result = sqlx::query_as( - "SELECT request.id AS request_id, request.message, user.* - FROM request - INNER JOIN user ON request.requested_by = user.id - WHERE request_id = $1 AND request.is_approved = 0 - LIMIT 1;", + r#"SELECT "request".id AS request_id, "request".message, "user".* + FROM "request" + INNER JOIN "user" ON "request".requested_by = "user".id + WHERE request_id = $1 AND "request".is_approved = false + LIMIT 1;"#, ) .bind(id) .fetch_one(&db) @@ -188,7 +188,7 @@ pub async fn cmd_decline(bot: Bot, msg: Message, id: String, db: DbPool) -> Hand }; // decline request - sqlx::query("DELETE FROM request WHERE id = $1;") + sqlx::query(r#"DELETE FROM "request" WHERE id = $1;"#) .bind(request.request_id) .execute(&db) .await?; @@ -203,7 +203,7 @@ pub async fn cmd_decline(bot: Bot, msg: Message, id: String, db: DbPool) -> Hand .await?; // notify target user - if request.user.has_private_chat == 1 { + if request.user.has_private_chat { bot.send_message( Recipient::Id(ChatId(request.user.tg_id)), t!("your_request_declined"), diff --git a/src/bot/request_chat.rs b/src/bot/request_chat.rs index 5e7005d..be04598 100644 --- a/src/bot/request_chat.rs +++ b/src/bot/request_chat.rs @@ -22,12 +22,12 @@ pub async fn cmd_request_chat(bot: Bot, msg: Message, text: String, db: DbPool) let user = find_or_create_user(&db, user).await?; let chat = find_or_create_chat(&db, &msg.chat).await?; - if chat.can_download == 1 { + if chat.can_download { reply_i18n_and_return!(bot, msg.chat.id, "chat_already_can_download"); } let requests: i64 = - sqlx::query("SELECT COUNT(1) FROM request_chat WHERE requested_for = $1;") + sqlx::query(r#"SELECT COUNT(1) FROM "request_chat" WHERE requested_for = $1;"#) .bind(chat.id) .fetch_one(&db) .await? @@ -37,7 +37,7 @@ pub async fn cmd_request_chat(bot: Bot, msg: Message, text: String, db: DbPool) } // put the chat request - sqlx::query("INSERT INTO request_chat (requested_by,requested_for,message,is_approved) VALUES ($1,$2,$3,$4);") + sqlx::query(r#"INSERT INTO "request_chat" (requested_by,requested_for,message,is_approved) VALUES ($1,$2,$3,$4);"#) .bind(user.id) .bind(chat.id) .bind(text) @@ -63,7 +63,7 @@ pub async fn cmd_request_chat(bot: Bot, msg: Message, text: String, db: DbPool) #[derive(sqlx::FromRow, Debug)] struct RequestChatWithChat { - pub request_id: i64, + pub request_id: i32, pub message: String, #[sqlx(flatten)] pub chat: Chat, @@ -72,15 +72,15 @@ struct RequestChatWithChat { pub async fn cmd_listrequests_chat(bot: Bot, msg: Message, db: DbPool) -> HandlerResult { if let Some(user) = msg.from() { let user = find_or_create_user(&db, user).await?; - if user.is_admin != 1 { + if !user.is_admin { reply_i18n_and_return!(bot, msg.chat.id, "not_an_admin"); } let requests: Vec = sqlx::query_as( - "SELECT request_chat.id AS request_id, request_chat.message, chat.* - FROM request_chat - INNER JOIN chat ON request_chat.requested_for = chat.id - WHERE request_chat.is_approved = 0;", + r#"SELECT "request_chat".id AS request_id, "request_chat".message, "chat".* + FROM "request_chat" + INNER JOIN "chat" ON "request_chat".requested_for = "chat".id + WHERE "request_chat".is_approved = false;"#, ) .fetch_all(&db) .await?; @@ -105,17 +105,17 @@ pub async fn cmd_approve_chat(bot: Bot, msg: Message, id: String, db: DbPool) -> if let Some(user) = msg.from() { let user = find_or_create_user(&db, user).await?; - if user.is_admin != 1 { + if !user.is_admin { reply_i18n_and_return!(bot, msg.chat.id, "not_an_admin"); } // get request let res: Result = sqlx::query_as( - "SELECT request_chat.id AS request_id, request_chat.message, chat.* - FROM request_chat - INNER JOIN chat ON request_chat.requested_for = chat.id - WHERE request_chat.is_approved = 0 - LIMIT 1;", + r#"SELECT "request_chat".id AS request_id, "request_chat".message, "chat".* + FROM "request_chat" + INNER JOIN "chat" ON "request_chat".requested_for = "chat".id + WHERE "request_chat".is_approved = false + LIMIT 1;"#, ) .bind(id) .fetch_one(&db) @@ -133,7 +133,7 @@ pub async fn cmd_approve_chat(bot: Bot, msg: Message, id: String, db: DbPool) -> }; // approve request - sqlx::query("UPDATE request_chat SET approved_by = $1, is_approved = 1 WHERE id = $2;") + sqlx::query(r#"UPDATE "request_chat" SET approved_by = $1, is_approved = true WHERE id = $2;"#) .bind(user.id) .bind(request.request_id) .execute(&db) @@ -161,17 +161,17 @@ pub async fn cmd_decline_chat(bot: Bot, msg: Message, id: String, db: DbPool) -> if let Some(user) = msg.from() { let user = find_or_create_user(&db, user).await?; - if user.is_admin != 1 { + if !user.is_admin { reply_i18n_and_return!(bot, msg.chat.id, "not_an_admin"); } // get request let res: Result = sqlx::query_as( - "SELECT request_chat.id AS request_id, request_chat.message, chat.* - FROM request_chat - INNER JOIN chat ON request_chat.requested_for = chat.id - WHERE request_chat.is_approved = 0 - LIMIT 1;", + r#"SELECT "request_chat".id AS request_id, "request_chat".message, "chat".* + FROM "request_chat" + INNER JOIN "chat" ON "request_chat".requested_for = "chat".id + WHERE "request_chat".is_approved = false + LIMIT 1;"#, ) .bind(id) .fetch_one(&db) @@ -189,7 +189,7 @@ pub async fn cmd_decline_chat(bot: Bot, msg: Message, id: String, db: DbPool) -> }; // decline request - sqlx::query("DELETE FROM request_chat WHERE id = $1;") + sqlx::query(r#"DELETE FROM request_chat WHERE id = $1;"#) .bind(request.request_id) .execute(&db) .await?; diff --git a/src/bot/start.rs b/src/bot/start.rs index 7d2ad04..d64e094 100644 --- a/src/bot/start.rs +++ b/src/bot/start.rs @@ -12,7 +12,7 @@ pub async fn cmd_start(bot: Bot, msg: Message, db: DbPool) -> HandlerResult { if msg.chat.is_private() { if let Some(user) = msg.from() { let user = find_or_create_user(&db, user).await?; - sqlx::query("UPDATE user SET has_private_chat = 1 WHERE id = $1;") + sqlx::query(r#"UPDATE "user" SET has_private_chat = true WHERE id = $1;"#) .bind(user.id) .execute(&db) .await?; diff --git a/src/db.rs b/src/db.rs index 86881a2..9e29a15 100644 --- a/src/db.rs +++ b/src/db.rs @@ -8,14 +8,14 @@ pub type DbPool = PgPool; #[derive(sqlx::FromRow, Debug)] pub struct User { - pub id: i64, + pub id: i32, pub tg_id: i64, pub username: Option, pub first_name: String, pub last_name: Option, - pub can_download: i64, - pub is_admin: i64, - pub has_private_chat: i64, + pub can_download: bool, + pub is_admin: bool, + pub has_private_chat: bool, } impl fmt::Display for User { @@ -34,11 +34,11 @@ pub mod user; #[derive(sqlx::FromRow, Debug)] pub struct Chat { - pub id: i64, + pub id: i32, pub tg_id: i64, pub username: Option, pub title: String, - pub can_download: i64, + pub can_download: bool, } impl fmt::Display for Chat { @@ -57,30 +57,30 @@ pub mod chat; #[derive(sqlx::FromRow, Debug)] pub struct Link { - pub id: i64, + pub id: i32, pub domain: String, pub path: Option, - pub download_allowed: i64, - pub auto_download: i64, + pub download_allowed: bool, + pub auto_download: bool, } #[derive(sqlx::FromRow, Debug)] pub struct Request { - pub id: i64, - pub requested_by: i64, - pub approved_by: Option, + pub id: i32, + pub requested_by: i32, + pub approved_by: Option, pub message: String, - pub is_approved: i64, + pub is_approved: bool, } #[derive(sqlx::FromRow, Debug)] pub struct RequestChat { - pub id: i64, - pub requested_by: i64, - pub requested_for: i64, - pub approved_by: Option, + pub id: i32, + pub requested_by: i32, + pub requested_for: i32, + pub approved_by: Option, pub message: String, - pub is_approved: i64, + pub is_approved: bool, } pub fn make_database_url() -> String {