nxtgauge-backend-rust/crates/db/src/models/requirement.rs

179 lines
5.1 KiB
Rust
Raw Normal View History

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use sqlx::{FromRow, PgPool};
use uuid::Uuid;
#[derive(Debug, Serialize, Deserialize, FromRow)]
pub struct Requirement {
pub id: Uuid,
pub customer_id: Uuid,
pub profession_key: String,
pub title: String,
pub description: String,
pub location: String,
pub budget: Option<i32>,
pub preferred_date: Option<chrono::NaiveDate>,
pub extra_data_json: Option<serde_json::Value>,
pub status: String, // DRAFT, PENDING_APPROVAL, OPEN, CLOSED, EXPIRED, REJECTED
pub rejection_reason: Option<String>,
pub request_count: i32,
pub accepted_count: i32,
pub expires_at: Option<DateTime<Utc>>,
pub approved_at: Option<DateTime<Utc>>,
pub approved_by: Option<Uuid>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct CreateRequirementPayload {
pub customer_id: Uuid,
pub profession_key: String,
pub title: String,
pub description: String,
pub location: String,
pub budget: Option<i32>,
pub preferred_date: Option<chrono::NaiveDate>,
pub extra_data_json: Option<serde_json::Value>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct UpdateRequirementPayload {
pub title: Option<String>,
pub description: Option<String>,
pub location: Option<String>,
pub budget: Option<i32>,
pub preferred_date: Option<chrono::NaiveDate>,
pub extra_data_json: Option<serde_json::Value>,
}
pub struct RequirementRepository;
impl RequirementRepository {
pub async fn create(
pool: &PgPool,
payload: CreateRequirementPayload,
) -> Result<Requirement, sqlx::Error> {
let req = sqlx::query_as!(
Requirement,
r#"
INSERT INTO requirements (
customer_id, profession_key, title, description, location,
budget, preferred_date, extra_data_json
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
RETURNING *
"#,
payload.customer_id,
payload.profession_key,
payload.title,
payload.description,
payload.location,
payload.budget,
payload.preferred_date,
payload.extra_data_json
)
.fetch_one(pool)
.await?;
Ok(req)
}
pub async fn get_by_id(pool: &PgPool, id: Uuid) -> Result<Option<Requirement>, sqlx::Error> {
sqlx::query_as!(Requirement, "SELECT * FROM requirements WHERE id = $1", id)
.fetch_optional(pool)
.await
}
pub async fn list_by_customer_id(
pool: &PgPool,
customer_id: Uuid,
page: i64,
limit: i64,
) -> Result<Vec<Requirement>, sqlx::Error> {
let offset = (page - 1) * limit;
let reqs = sqlx::query_as!(
Requirement,
r#"
SELECT * FROM requirements
WHERE customer_id = $1
ORDER BY created_at DESC
LIMIT $2 OFFSET $3
"#,
customer_id,
limit,
offset
)
.fetch_all(pool)
.await?;
Ok(reqs)
}
pub async fn update(
pool: &PgPool,
id: Uuid,
payload: UpdateRequirementPayload,
) -> Result<Requirement, sqlx::Error> {
let req = sqlx::query_as!(
Requirement,
r#"
UPDATE requirements SET
title = COALESCE($1, title),
description = COALESCE($2, description),
location = COALESCE($3, location),
budget = COALESCE($4, budget),
preferred_date = COALESCE($5, preferred_date),
extra_data_json = COALESCE($6, extra_data_json),
updated_at = NOW()
WHERE id = $7
RETURNING *
"#,
payload.title,
payload.description,
payload.location,
payload.budget,
payload.preferred_date,
payload.extra_data_json,
id
)
.fetch_one(pool)
.await?;
Ok(req)
}
pub async fn update_status(
pool: &PgPool,
id: Uuid,
status: &str,
) -> Result<Requirement, sqlx::Error> {
let req = sqlx::query_as!(
Requirement,
"UPDATE requirements SET status = $1, updated_at = NOW() WHERE id = $2 RETURNING *",
status,
id
)
.fetch_one(pool)
.await?;
Ok(req)
}
pub async fn increment_request_count(pool: &PgPool, id: Uuid) -> Result<(), sqlx::Error> {
sqlx::query!("UPDATE requirements SET request_count = request_count + 1 WHERE id = $1", id)
.execute(pool)
.await?;
Ok(())
}
pub async fn increment_accepted_count(pool: &PgPool, id: Uuid) -> Result<(), sqlx::Error> {
sqlx::query!(
"UPDATE requirements SET accepted_count = accepted_count + 1 WHERE id = $1",
id
)
.execute(pool)
.await?;
Ok(())
}
}