From 50ce8cb96b2b218751c2fc2a6b19372f51846acc Mon Sep 17 00:00:00 2001 From: Dawid Rycerz Date: Mon, 14 Jul 2025 19:34:59 +0300 Subject: feat: rewrite in rust --- src/users.rs | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 src/users.rs (limited to 'src/users.rs') diff --git a/src/users.rs b/src/users.rs new file mode 100644 index 0000000..baca6dd --- /dev/null +++ b/src/users.rs @@ -0,0 +1,139 @@ +use serde::{Deserialize, Serialize}; +use sqlx::FromRow; +use uuid::Uuid; + +#[derive(Debug, Serialize, Deserialize, FromRow, Clone, PartialEq, Eq)] +pub struct User { + pub id: i64, + pub user_id: String, // API token + pub role: UserRole, +} + +#[derive(Debug, Serialize, Deserialize, sqlx::Type, Clone, PartialEq, Eq)] +#[sqlx(type_name = "TEXT")] +pub enum UserRole { + #[serde(rename = "user")] + User, + #[serde(rename = "admin")] + Admin, +} + +impl Default for UserRole { + fn default() -> Self { + UserRole::User + } +} + +pub struct UserRepository<'a> { + pub db: &'a sqlx::SqlitePool, +} + +impl<'a> UserRepository<'a> { + pub async fn list_users(&self) -> Result, sqlx::Error> { + sqlx::query_as::<_, User>("SELECT id, user_id, role FROM users") + .fetch_all(self.db) + .await + } + + pub async fn get_user_by_id(&self, id: i64) -> Result, sqlx::Error> { + sqlx::query_as::<_, User>("SELECT id, user_id, role FROM users WHERE id = ?") + .bind(id) + .fetch_optional(self.db) + .await + } + + pub async fn get_user_by_user_id(&self, user_id: &str) -> Result, sqlx::Error> { + sqlx::query_as::<_, User>("SELECT id, user_id, role FROM users WHERE user_id = ?") + .bind(user_id) + .fetch_optional(self.db) + .await + } + + pub async fn create_user(&self, user_id: Option, role: Option) -> Result { + let user_id = user_id.unwrap_or_else(|| Uuid::new_v4().to_string()); + let role = role.unwrap_or_default(); + sqlx::query_as::<_, User>( + "INSERT INTO users (user_id, role) VALUES (?, ?) RETURNING id, user_id, role" + ) + .bind(user_id) + .bind(role) + .fetch_one(self.db) + .await + } + + pub async fn update_user(&self, id: i64, role: UserRole) -> Result { + sqlx::query_as::<_, User>( + "UPDATE users SET role = ? WHERE id = ? RETURNING id, user_id, role" + ) + .bind(role) + .bind(id) + .fetch_one(self.db) + .await + } + + pub async fn delete_user(&self, id: i64) -> Result<(), sqlx::Error> { + sqlx::query("DELETE FROM users WHERE id = ?") + .bind(id) + .execute(self.db) + .await?; + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use sqlx::{SqlitePool, Executor}; + use tokio; + + async fn setup_db() -> SqlitePool { + let pool = SqlitePool::connect(":memory:").await.unwrap(); + pool.execute( + "CREATE TABLE users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id TEXT NOT NULL UNIQUE, + role TEXT NOT NULL DEFAULT 'user' + );" + ).await.unwrap(); + pool + } + + #[tokio::test] + async fn test_create_and_get_user() { + let db = setup_db().await; + let repo = UserRepository { db: &db }; + let user = repo.create_user(None, Some(UserRole::Admin)).await.unwrap(); + assert_eq!(user.role, UserRole::Admin); + let fetched = repo.get_user_by_user_id(&user.user_id).await.unwrap().unwrap(); + assert_eq!(fetched.user_id, user.user_id); + } + + #[tokio::test] + async fn test_update_user() { + let db = setup_db().await; + let repo = UserRepository { db: &db }; + let user = repo.create_user(None, Some(UserRole::User)).await.unwrap(); + let updated = repo.update_user(user.id, UserRole::Admin).await.unwrap(); + assert_eq!(updated.role, UserRole::Admin); + } + + #[tokio::test] + async fn test_delete_user() { + let db = setup_db().await; + let repo = UserRepository { db: &db }; + let user = repo.create_user(None, None).await.unwrap(); + repo.delete_user(user.id).await.unwrap(); + let fetched = repo.get_user_by_id(user.id).await.unwrap(); + assert!(fetched.is_none()); + } + + #[tokio::test] + async fn test_list_users() { + let db = setup_db().await; + let repo = UserRepository { db: &db }; + repo.create_user(None, Some(UserRole::User)).await.unwrap(); + repo.create_user(None, Some(UserRole::Admin)).await.unwrap(); + let users = repo.list_users().await.unwrap(); + assert_eq!(users.len(), 2); + } +} \ No newline at end of file -- cgit v1.2.3