use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use sqlx::{FromRow, PgPool}; use uuid::Uuid; #[derive(Debug, Serialize, Deserialize, FromRow)] pub struct Application { pub id: Uuid, pub job_id: Uuid, pub job_seeker_id: Uuid, pub cover_letter: Option, pub resume_url: Option, pub status: String, // APPLIED, SHORTLISTED, INTERVIEW, OFFERED, HIRED, REJECTED, WITHDRAWN pub applied_at: DateTime, pub updated_at: DateTime, pub contact_viewed: bool, } #[derive(Debug, Serialize, Deserialize)] pub struct CreateApplicationPayload { pub job_id: Uuid, pub job_seeker_id: Uuid, pub cover_letter: Option, pub resume_url: Option, } pub struct ApplicationRepository; impl ApplicationRepository { pub async fn create( pool: &PgPool, payload: CreateApplicationPayload, ) -> Result { let app = sqlx::query_as!( Application, r#" INSERT INTO applications (job_id, job_seeker_id, cover_letter, resume_url) VALUES ($1, $2, $3, $4) RETURNING * "#, payload.job_id, payload.job_seeker_id, payload.cover_letter, payload.resume_url ) .fetch_one(pool) .await?; Ok(app) } pub async fn get_by_id(pool: &PgPool, id: Uuid) -> Result, sqlx::Error> { sqlx::query_as!(Application, "SELECT * FROM applications WHERE id = $1", id) .fetch_optional(pool) .await } pub async fn list_by_job_id( pool: &PgPool, job_id: Uuid, status: Option, page: i64, limit: i64, ) -> Result, sqlx::Error> { let offset = (page - 1) * limit; let apps = sqlx::query_as!( Application, r#" SELECT * FROM applications WHERE job_id = $1 AND ($2::VARCHAR IS NULL OR status = $2) ORDER BY applied_at DESC LIMIT $3 OFFSET $4 "#, job_id, status, limit, offset ) .fetch_all(pool) .await?; Ok(apps) } pub async fn list_by_job_seeker_id( pool: &PgPool, job_seeker_id: Uuid, page: i64, limit: i64, ) -> Result, sqlx::Error> { let offset = (page - 1) * limit; let apps = sqlx::query_as!( Application, r#" SELECT * FROM applications WHERE job_seeker_id = $1 ORDER BY applied_at DESC LIMIT $2 OFFSET $3 "#, job_seeker_id, limit, offset ) .fetch_all(pool) .await?; Ok(apps) } pub async fn update_status( pool: &PgPool, id: Uuid, status: &str, ) -> Result { let app = sqlx::query_as!( Application, "UPDATE applications SET status = $1, updated_at = NOW() WHERE id = $2 RETURNING *", status, id ) .fetch_one(pool) .await?; Ok(app) } pub async fn mark_contact_viewed(pool: &PgPool, id: Uuid) -> Result<(), sqlx::Error> { sqlx::query!( "UPDATE applications SET contact_viewed = true WHERE id = $1", id ) .execute(pool) .await?; Ok(()) } }