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

142 lines
4.4 KiB
Rust

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use sqlx::{FromRow, PgPool};
use uuid::Uuid;
#[derive(Debug, Serialize, Deserialize, FromRow)]
pub struct CustomerProfile {
pub id: Uuid,
pub user_id: Uuid,
pub first_name: Option<String>,
pub last_name: Option<String>,
pub phone: Option<String>,
pub city: Option<String>,
pub area: Option<String>,
pub preferred_professions: Option<Vec<String>>,
pub active_requirement_count: i32,
pub status: String,
pub bio: Option<String>,
pub custom_data: Option<serde_json::Value>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct UpsertCustomerProfilePayload {
pub first_name: Option<String>,
pub last_name: Option<String>,
pub phone: Option<String>,
pub city: Option<String>,
pub area: Option<String>,
pub preferred_professions: Option<Vec<String>>,
pub bio: Option<String>,
pub custom_data: Option<serde_json::Value>,
}
pub struct CustomerRepository;
impl CustomerRepository {
pub async fn get_by_user_id(
pool: &PgPool,
user_id: Uuid,
) -> Result<Option<CustomerProfile>, sqlx::Error> {
let profile = sqlx::query_as::<_, CustomerProfile>(
r#"
SELECT
id, user_id, first_name, last_name, phone, city, area, preferred_professions,
active_requirement_count, status, bio, custom_data,
created_at, updated_at
FROM customer_profiles
WHERE user_id = $1
"#,
)
.bind(user_id)
.fetch_optional(pool)
.await?;
Ok(profile)
}
pub async fn upsert(
pool: &PgPool,
user_id: Uuid,
payload: UpsertCustomerProfilePayload,
) -> Result<CustomerProfile, sqlx::Error> {
let profile = sqlx::query_as::<_, CustomerProfile>(
r#"
INSERT INTO customer_profiles (
user_id, first_name, last_name, phone, city, area, preferred_professions, bio, custom_data, status
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, 'PENDING')
ON CONFLICT (user_id) DO UPDATE SET
first_name = EXCLUDED.first_name,
last_name = EXCLUDED.last_name,
phone = EXCLUDED.phone,
city = EXCLUDED.city,
area = EXCLUDED.area,
preferred_professions = EXCLUDED.preferred_professions,
bio = EXCLUDED.bio,
custom_data = EXCLUDED.custom_data,
status = CASE
WHEN customer_profiles.status = 'APPROVED' THEN 'APPROVED'
ELSE 'PENDING'
END,
updated_at = NOW()
RETURNING
id, user_id, first_name, last_name, phone, city, area, preferred_professions,
active_requirement_count, status, bio, custom_data,
created_at, updated_at
"#,
)
.bind(user_id)
.bind(payload.first_name)
.bind(payload.last_name)
.bind(payload.phone)
.bind(payload.city)
.bind(payload.area)
.bind(payload.preferred_professions.unwrap_or_default())
.bind(payload.bio)
.bind(payload.custom_data)
.fetch_one(pool)
.await?;
Ok(profile)
}
pub async fn update_active_requirement_count(
pool: &PgPool,
id: Uuid,
delta: i32,
) -> Result<(), sqlx::Error> {
sqlx::query(
"UPDATE customer_profiles SET active_requirement_count = active_requirement_count + $1 WHERE id = $2",
)
.bind(delta)
.bind(id)
.execute(pool)
.await?;
Ok(())
}
pub async fn submit_for_verification(
pool: &PgPool,
user_id: Uuid,
) -> Result<CustomerProfile, sqlx::Error> {
let profile = sqlx::query_as::<_, CustomerProfile>(
r#"
UPDATE customer_profiles
SET status = 'PENDING_REVIEW', updated_at = NOW()
WHERE user_id = $1
RETURNING
id, user_id, first_name, last_name, phone, city, area, preferred_professions,
active_requirement_count, status, bio, custom_data,
created_at, updated_at
"#,
)
.bind(user_id)
.fetch_one(pool)
.await?;
Ok(profile)
}
}