fix: convert all SQLx macros to runtime API, remove SQLX_OFFLINE requirement

This commit is contained in:
Ashwin Kumar 2026-04-09 07:40:15 +02:00
parent 58eff5ce63
commit 83c62a1c5e
52 changed files with 553 additions and 572 deletions

View file

@ -11,7 +11,6 @@ COPY Cargo.toml Cargo.lock ./
COPY crates ./crates COPY crates ./crates
COPY apps ./apps COPY apps ./apps
ENV SQLX_OFFLINE=true
ENV CARGO_BUILD_JOBS=2 ENV CARGO_BUILD_JOBS=2
RUN cargo build --release --bin catering_services RUN cargo build --release --bin catering_services

View file

@ -40,14 +40,13 @@ pub fn router() -> Router<ProfessionState> {
async fn list_catering_services( async fn list_catering_services(
State(state): State<ProfessionState>, State(state): State<ProfessionState>,
) -> Result<impl IntoResponse, (StatusCode, String)> { ) -> Result<impl IntoResponse, (StatusCode, String)> {
let services = sqlx::query_as!( let services = sqlx::query_as::<_, CateringServiceProfile>(
CateringServiceProfile,
r#" r#"
SELECT id, user_id, business_name, bio, location, custom_data, status, created_at, updated_at SELECT id, user_id, business_name, bio, location, custom_data, status, created_at, updated_at
FROM catering_service_profiles FROM catering_service_profiles
ORDER BY created_at DESC ORDER BY created_at DESC
LIMIT 100 LIMIT 100
"# "#,
) )
.fetch_all(&state.pool) .fetch_all(&state.pool)
.await .await
@ -61,15 +60,14 @@ async fn get_catering_service(
State(state): State<ProfessionState>, State(state): State<ProfessionState>,
Path(id): Path<Uuid>, Path(id): Path<Uuid>,
) -> Result<impl IntoResponse, (StatusCode, String)> { ) -> Result<impl IntoResponse, (StatusCode, String)> {
let service = sqlx::query_as!( let service = sqlx::query_as::<_, CateringServiceProfile>(
CateringServiceProfile,
r#" r#"
SELECT id, user_id, business_name, bio, location, custom_data, status, created_at, updated_at SELECT id, user_id, business_name, bio, location, custom_data, status, created_at, updated_at
FROM catering_service_profiles FROM catering_service_profiles
WHERE id = $1 WHERE id = $1
"#, "#,
id
) )
.bind(id)
.fetch_optional(&state.pool) .fetch_optional(&state.pool)
.await .await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?; .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?;

View file

@ -11,7 +11,6 @@ COPY Cargo.toml Cargo.lock ./
COPY crates ./crates COPY crates ./crates
COPY apps ./apps COPY apps ./apps
ENV SQLX_OFFLINE=true
ENV CARGO_BUILD_JOBS=2 ENV CARGO_BUILD_JOBS=2
RUN cargo build --release --bin companies RUN cargo build --release --bin companies

View file

@ -11,7 +11,6 @@ COPY Cargo.toml Cargo.lock ./
COPY crates ./crates COPY crates ./crates
COPY apps ./apps COPY apps ./apps
ENV SQLX_OFFLINE=true
ENV CARGO_BUILD_JOBS=2 ENV CARGO_BUILD_JOBS=2
RUN cargo build --release --bin cron RUN cargo build --release --bin cron

View file

@ -11,7 +11,6 @@ COPY Cargo.toml Cargo.lock ./
COPY crates ./crates COPY crates ./crates
COPY apps ./apps COPY apps ./apps
ENV SQLX_OFFLINE=true
ENV CARGO_BUILD_JOBS=2 ENV CARGO_BUILD_JOBS=2
RUN cargo build --release --bin customers RUN cargo build --release --bin customers

View file

@ -40,8 +40,7 @@ pub fn router() -> Router<AppState> {
async fn list_leads( async fn list_leads(
State(state): State<AppState>, State(state): State<AppState>,
) -> Result<impl IntoResponse, (StatusCode, String)> { ) -> Result<impl IntoResponse, (StatusCode, String)> {
let requirements = sqlx::query_as!( let requirements = sqlx::query_as::<_, Requirement>(
Requirement,
r#" r#"
SELECT id, customer_id, profession_key, title, description, location, budget, SELECT id, customer_id, profession_key, title, description, location, budget,
preferred_date, extra_data_json, status, rejection_reason, request_count, accepted_count, preferred_date, extra_data_json, status, rejection_reason, request_count, accepted_count,
@ -49,7 +48,7 @@ async fn list_leads(
FROM requirements FROM requirements
ORDER BY created_at DESC ORDER BY created_at DESC
LIMIT 100 LIMIT 100
"# "#,
) )
.fetch_all(&state.pool) .fetch_all(&state.pool)
.await .await

View file

@ -11,7 +11,6 @@ COPY Cargo.toml Cargo.lock ./
COPY crates ./crates COPY crates ./crates
COPY apps ./apps COPY apps ./apps
ENV SQLX_OFFLINE=true
ENV CARGO_BUILD_JOBS=2 ENV CARGO_BUILD_JOBS=2
RUN cargo build --release --bin developers RUN cargo build --release --bin developers

View file

@ -40,14 +40,13 @@ pub fn router() -> Router<ProfessionState> {
async fn list_developers( async fn list_developers(
State(state): State<ProfessionState>, State(state): State<ProfessionState>,
) -> Result<impl IntoResponse, (StatusCode, String)> { ) -> Result<impl IntoResponse, (StatusCode, String)> {
let developers = sqlx::query_as!( let developers = sqlx::query_as::<_, DeveloperProfile>(
DeveloperProfile,
r#" r#"
SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at
FROM developer_profiles FROM developer_profiles
ORDER BY created_at DESC ORDER BY created_at DESC
LIMIT 100 LIMIT 100
"# "#,
) )
.fetch_all(&state.pool) .fetch_all(&state.pool)
.await .await
@ -61,15 +60,14 @@ async fn get_developer(
State(state): State<ProfessionState>, State(state): State<ProfessionState>,
Path(id): Path<Uuid>, Path(id): Path<Uuid>,
) -> Result<impl IntoResponse, (StatusCode, String)> { ) -> Result<impl IntoResponse, (StatusCode, String)> {
let developer = sqlx::query_as!( let developer = sqlx::query_as::<_, DeveloperProfile>(
DeveloperProfile,
r#" r#"
SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at
FROM developer_profiles FROM developer_profiles
WHERE id = $1 WHERE id = $1
"#, "#,
id
) )
.bind(id)
.fetch_optional(&state.pool) .fetch_optional(&state.pool)
.await .await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?; .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?;

View file

@ -11,7 +11,6 @@ COPY Cargo.toml Cargo.lock ./
COPY crates ./crates COPY crates ./crates
COPY apps ./apps COPY apps ./apps
ENV SQLX_OFFLINE=true
ENV CARGO_BUILD_JOBS=2 ENV CARGO_BUILD_JOBS=2
RUN cargo build --release --bin employees RUN cargo build --release --bin employees

View file

@ -11,7 +11,6 @@ COPY Cargo.toml Cargo.lock ./
COPY crates ./crates COPY crates ./crates
COPY apps ./apps COPY apps ./apps
ENV SQLX_OFFLINE=true
ENV CARGO_BUILD_JOBS=2 ENV CARGO_BUILD_JOBS=2
RUN cargo build --release --bin fitness_trainers RUN cargo build --release --bin fitness_trainers

View file

@ -40,14 +40,13 @@ pub fn router() -> Router<ProfessionState> {
async fn list_fitness_trainers( async fn list_fitness_trainers(
State(state): State<ProfessionState>, State(state): State<ProfessionState>,
) -> Result<impl IntoResponse, (StatusCode, String)> { ) -> Result<impl IntoResponse, (StatusCode, String)> {
let trainers = sqlx::query_as!( let trainers = sqlx::query_as::<_, FitnessTrainerProfile>(
FitnessTrainerProfile,
r#" r#"
SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at
FROM fitness_trainer_profiles FROM fitness_trainer_profiles
ORDER BY created_at DESC ORDER BY created_at DESC
LIMIT 100 LIMIT 100
"# "#,
) )
.fetch_all(&state.pool) .fetch_all(&state.pool)
.await .await
@ -61,15 +60,14 @@ async fn get_fitness_trainer(
State(state): State<ProfessionState>, State(state): State<ProfessionState>,
Path(id): Path<Uuid>, Path(id): Path<Uuid>,
) -> Result<impl IntoResponse, (StatusCode, String)> { ) -> Result<impl IntoResponse, (StatusCode, String)> {
let trainer = sqlx::query_as!( let trainer = sqlx::query_as::<_, FitnessTrainerProfile>(
FitnessTrainerProfile,
r#" r#"
SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at
FROM fitness_trainer_profiles FROM fitness_trainer_profiles
WHERE id = $1 WHERE id = $1
"#, "#,
id
) )
.bind(id)
.fetch_optional(&state.pool) .fetch_optional(&state.pool)
.await .await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?; .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?;

View file

@ -11,7 +11,6 @@ COPY Cargo.toml Cargo.lock ./
COPY crates ./crates COPY crates ./crates
COPY apps ./apps COPY apps ./apps
ENV SQLX_OFFLINE=true
ENV CARGO_BUILD_JOBS=2 ENV CARGO_BUILD_JOBS=2
RUN cargo build --release --bin gateway RUN cargo build --release --bin gateway

View file

@ -11,7 +11,6 @@ COPY Cargo.toml Cargo.lock ./
COPY crates ./crates COPY crates ./crates
COPY apps ./apps COPY apps ./apps
ENV SQLX_OFFLINE=true
ENV CARGO_BUILD_JOBS=2 ENV CARGO_BUILD_JOBS=2
RUN cargo build --release --bin graphic_designers RUN cargo build --release --bin graphic_designers

View file

@ -40,14 +40,13 @@ pub fn router() -> Router<ProfessionState> {
async fn list_graphic_designers( async fn list_graphic_designers(
State(state): State<ProfessionState>, State(state): State<ProfessionState>,
) -> Result<impl IntoResponse, (StatusCode, String)> { ) -> Result<impl IntoResponse, (StatusCode, String)> {
let designers = sqlx::query_as!( let designers = sqlx::query_as::<_, GraphicDesignerProfile>(
GraphicDesignerProfile,
r#" r#"
SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at
FROM graphic_designer_profiles FROM graphic_designer_profiles
ORDER BY created_at DESC ORDER BY created_at DESC
LIMIT 100 LIMIT 100
"# "#,
) )
.fetch_all(&state.pool) .fetch_all(&state.pool)
.await .await
@ -61,15 +60,14 @@ async fn get_graphic_designer(
State(state): State<ProfessionState>, State(state): State<ProfessionState>,
Path(id): Path<Uuid>, Path(id): Path<Uuid>,
) -> Result<impl IntoResponse, (StatusCode, String)> { ) -> Result<impl IntoResponse, (StatusCode, String)> {
let designer = sqlx::query_as!( let designer = sqlx::query_as::<_, GraphicDesignerProfile>(
GraphicDesignerProfile,
r#" r#"
SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at
FROM graphic_designer_profiles FROM graphic_designer_profiles
WHERE id = $1 WHERE id = $1
"#, "#,
id
) )
.bind(id)
.fetch_optional(&state.pool) .fetch_optional(&state.pool)
.await .await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?; .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?;

View file

@ -11,7 +11,6 @@ COPY Cargo.toml Cargo.lock ./
COPY crates ./crates COPY crates ./crates
COPY apps ./apps COPY apps ./apps
ENV SQLX_OFFLINE=true
ENV CARGO_BUILD_JOBS=2 ENV CARGO_BUILD_JOBS=2
RUN cargo build --release --bin job_seekers RUN cargo build --release --bin job_seekers

View file

@ -11,7 +11,6 @@ COPY Cargo.toml Cargo.lock ./
COPY crates ./crates COPY crates ./crates
COPY apps ./apps COPY apps ./apps
ENV SQLX_OFFLINE=true
ENV CARGO_BUILD_JOBS=2 ENV CARGO_BUILD_JOBS=2
RUN cargo build --release --bin makeup_artists RUN cargo build --release --bin makeup_artists

View file

@ -40,14 +40,13 @@ pub fn router() -> Router<ProfessionState> {
async fn list_makeup_artists( async fn list_makeup_artists(
State(state): State<ProfessionState>, State(state): State<ProfessionState>,
) -> Result<impl IntoResponse, (StatusCode, String)> { ) -> Result<impl IntoResponse, (StatusCode, String)> {
let artists = sqlx::query_as!( let artists = sqlx::query_as::<_, MakeupArtistProfile>(
MakeupArtistProfile,
r#" r#"
SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at
FROM makeup_artist_profiles FROM makeup_artist_profiles
ORDER BY created_at DESC ORDER BY created_at DESC
LIMIT 100 LIMIT 100
"# "#,
) )
.fetch_all(&state.pool) .fetch_all(&state.pool)
.await .await
@ -61,15 +60,14 @@ async fn get_makeup_artist(
State(state): State<ProfessionState>, State(state): State<ProfessionState>,
Path(id): Path<Uuid>, Path(id): Path<Uuid>,
) -> Result<impl IntoResponse, (StatusCode, String)> { ) -> Result<impl IntoResponse, (StatusCode, String)> {
let artist = sqlx::query_as!( let artist = sqlx::query_as::<_, MakeupArtistProfile>(
MakeupArtistProfile,
r#" r#"
SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at
FROM makeup_artist_profiles FROM makeup_artist_profiles
WHERE id = $1 WHERE id = $1
"#, "#,
id
) )
.bind(id)
.fetch_optional(&state.pool) .fetch_optional(&state.pool)
.await .await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?; .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?;

View file

@ -11,7 +11,6 @@ COPY Cargo.toml Cargo.lock ./
COPY crates ./crates COPY crates ./crates
COPY apps ./apps COPY apps ./apps
ENV SQLX_OFFLINE=true
ENV CARGO_BUILD_JOBS=2 ENV CARGO_BUILD_JOBS=2
RUN cargo build --release --bin payments RUN cargo build --release --bin payments

View file

@ -10,6 +10,7 @@ use std::net::SocketAddr;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
use uuid::Uuid; use uuid::Uuid;
use sqlx::postgres::PgPool; use sqlx::postgres::PgPool;
use sqlx::FromRow;
#[derive(Clone)] #[derive(Clone)]
struct AppState { struct AppState {
@ -57,6 +58,18 @@ struct PaymentStatusResponse {
currency: String, currency: String,
} }
#[derive(Debug, FromRow)]
struct PricingPackageRow {
tracecoins_amount: i32,
}
#[derive(Debug, FromRow)]
struct PaymentRow {
id: Uuid,
user_id: Uuid,
tracecoins_credited: i32,
}
async fn create_order( async fn create_order(
auth: AuthUser, auth: AuthUser,
State(state): State<AppState>, State(state): State<AppState>,
@ -69,10 +82,10 @@ async fn create_order(
let package_id = Uuid::parse_str(package_id_str).map_err(|_| (StatusCode::BAD_REQUEST, "Invalid package id".to_string()))?; let package_id = Uuid::parse_str(package_id_str).map_err(|_| (StatusCode::BAD_REQUEST, "Invalid package id".to_string()))?;
// Fetch package to get tracecoins amount // Fetch package to get tracecoins amount
let package = sqlx::query!( let package = sqlx::query_as::<_, PricingPackageRow>(
"SELECT tracecoins_amount FROM pricing_packages WHERE id = $1 AND is_active = true", "SELECT tracecoins_amount FROM pricing_packages WHERE id = $1 AND is_active = true",
package_id
) )
.bind(package_id)
.fetch_optional(&state.pool) .fetch_optional(&state.pool)
.await .await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?; .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?;
@ -118,14 +131,14 @@ async fn create_order(
.to_string(); .to_string();
// Insert payment record // Insert payment record
sqlx::query!( sqlx::query(
"INSERT INTO payments (user_id, package_id, razorpay_order_id, amount_inr, tracecoins_credited, status) VALUES ($1, $2, $3, $4, $5, 'PENDING')", "INSERT INTO payments (user_id, package_id, razorpay_order_id, amount_inr, tracecoins_credited, status) VALUES ($1, $2, $3, $4, $5, 'PENDING')",
auth.user_id,
package_id,
order_id,
payload.amount as i64,
tracecoins_credited
) )
.bind(auth.user_id)
.bind(package_id)
.bind(&order_id)
.bind(payload.amount as i64)
.bind(tracecoins_credited)
.execute(&state.pool) .execute(&state.pool)
.await .await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?; .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?;
@ -173,10 +186,10 @@ async fn verify_payment(
} }
// Find pending payment by razorpay_order_id // Find pending payment by razorpay_order_id
let payment = sqlx::query!( let payment = sqlx::query_as::<_, PaymentRow>(
"SELECT id, user_id, tracecoins_credited FROM payments WHERE razorpay_order_id = $1 AND status = 'PENDING'", "SELECT id, user_id, tracecoins_credited FROM payments WHERE razorpay_order_id = $1 AND status = 'PENDING'",
payload.order_id
) )
.bind(&payload.order_id)
.fetch_optional(&state.pool) .fetch_optional(&state.pool)
.await .await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?; .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?;
@ -192,41 +205,41 @@ async fn verify_payment(
} }
// Update payment status to SUCCESS // Update payment status to SUCCESS
sqlx::query!( sqlx::query(
"UPDATE payments SET status = 'SUCCESS', verified_at = NOW(), razorpay_payment_id = $1 WHERE id = $2", "UPDATE payments SET status = 'SUCCESS', verified_at = NOW(), razorpay_payment_id = $1 WHERE id = $2",
payload.payment_id,
payment.id
) )
.bind(&payload.payment_id)
.bind(payment.id)
.execute(&state.pool) .execute(&state.pool)
.await .await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?; .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?;
// Credit wallet (increase balance) // Credit wallet (increase balance)
sqlx::query!( sqlx::query(
"INSERT INTO tracecoin_wallets (user_id, balance, reserved) VALUES ($1, $2, 0) ON CONFLICT (user_id) DO UPDATE SET balance = tracecoin_wallets.balance + excluded.balance", "INSERT INTO tracecoin_wallets (user_id, balance, reserved) VALUES ($1, $2, 0) ON CONFLICT (user_id) DO UPDATE SET balance = tracecoin_wallets.balance + excluded.balance",
payment.user_id,
payment.tracecoins_credited
) )
.bind(payment.user_id)
.bind(payment.tracecoins_credited)
.execute(&state.pool) .execute(&state.pool)
.await .await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?; .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?;
// Get wallet id for ledger // Get wallet id for ledger
match sqlx::query_scalar!( match sqlx::query_scalar::<_, Uuid>(
"SELECT id FROM tracecoin_wallets WHERE user_id = $1", "SELECT id FROM tracecoin_wallets WHERE user_id = $1",
payment.user_id
) )
.bind(payment.user_id)
.fetch_optional(&state.pool) .fetch_optional(&state.pool)
.await .await
{ {
Ok(Some(wallet_id)) => { Ok(Some(wallet_id)) => {
sqlx::query!( sqlx::query(
"INSERT INTO tracecoin_ledger (wallet_id, type, amount, reason, reference_id) VALUES ($1, 'CREDIT', $2, $3, $4)", "INSERT INTO tracecoin_ledger (wallet_id, type, amount, reason, reference_id) VALUES ($1, 'CREDIT', $2, $3, $4)",
wallet_id,
payment.tracecoins_credited as i64,
"PURCHASE",
payment.id
) )
.bind(wallet_id)
.bind(payment.tracecoins_credited as i64)
.bind("PURCHASE")
.bind(payment.id)
.execute(&state.pool) .execute(&state.pool)
.await .await
.ok(); .ok();
@ -235,17 +248,17 @@ async fn verify_payment(
} }
// Send notification to user about successful purchase // Send notification to user about successful purchase
let _ = sqlx::query!( let _ = sqlx::query(
r#" r#"
INSERT INTO notifications (user_id, title, body, type, reference_id) INSERT INTO notifications (user_id, title, body, type, reference_id)
VALUES ($1, $2, $3, $4, $5) VALUES ($1, $2, $3, $4, $5)
"#, "#,
payment.user_id,
"Tracecoins Purchased Successfully",
format!("Your {} Tracecoin package has been credited to your wallet.", payment.tracecoins_credited),
"PAYMENT",
payment.id
) )
.bind(payment.user_id)
.bind("Tracecoins Purchased Successfully")
.bind(format!("Your {} Tracecoin package has been credited to your wallet.", payment.tracecoins_credited))
.bind("PAYMENT")
.bind(payment.id)
.execute(&state.pool) .execute(&state.pool)
.await .await
.ok(); .ok();

View file

@ -11,7 +11,6 @@ COPY Cargo.toml Cargo.lock ./
COPY crates ./crates COPY crates ./crates
COPY apps ./apps COPY apps ./apps
ENV SQLX_OFFLINE=true
ENV CARGO_BUILD_JOBS=2 ENV CARGO_BUILD_JOBS=2
RUN cargo build --release --bin photographers RUN cargo build --release --bin photographers

View file

@ -40,14 +40,13 @@ pub fn router() -> Router<ProfessionState> {
async fn list_photographers( async fn list_photographers(
State(state): State<ProfessionState>, State(state): State<ProfessionState>,
) -> Result<impl IntoResponse, (StatusCode, String)> { ) -> Result<impl IntoResponse, (StatusCode, String)> {
let photographers = sqlx::query_as!( let photographers = sqlx::query_as::<_, PhotographerProfile>(
PhotographerProfile,
r#" r#"
SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at
FROM photographer_profiles FROM photographer_profiles
ORDER BY created_at DESC ORDER BY created_at DESC
LIMIT 100 LIMIT 100
"# "#,
) )
.fetch_all(&state.pool) .fetch_all(&state.pool)
.await .await
@ -61,15 +60,14 @@ async fn get_photographer(
State(state): State<ProfessionState>, State(state): State<ProfessionState>,
Path(id): Path<Uuid>, Path(id): Path<Uuid>,
) -> Result<impl IntoResponse, (StatusCode, String)> { ) -> Result<impl IntoResponse, (StatusCode, String)> {
let photographer = sqlx::query_as!( let photographer = sqlx::query_as::<_, PhotographerProfile>(
PhotographerProfile,
r#" r#"
SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at
FROM photographer_profiles FROM photographer_profiles
WHERE id = $1 WHERE id = $1
"#, "#,
id
) )
.bind(id)
.fetch_optional(&state.pool) .fetch_optional(&state.pool)
.await .await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?; .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?;

View file

@ -11,7 +11,6 @@ COPY Cargo.toml Cargo.lock ./
COPY crates ./crates COPY crates ./crates
COPY apps ./apps COPY apps ./apps
ENV SQLX_OFFLINE=true
ENV CARGO_BUILD_JOBS=2 ENV CARGO_BUILD_JOBS=2
RUN cargo build --release --bin social_media_managers RUN cargo build --release --bin social_media_managers

View file

@ -40,14 +40,13 @@ pub fn router() -> Router<ProfessionState> {
async fn list_social_media_managers( async fn list_social_media_managers(
State(state): State<ProfessionState>, State(state): State<ProfessionState>,
) -> Result<impl IntoResponse, (StatusCode, String)> { ) -> Result<impl IntoResponse, (StatusCode, String)> {
let managers = sqlx::query_as!( let managers = sqlx::query_as::<_, SocialMediaManagerProfile>(
SocialMediaManagerProfile,
r#" r#"
SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at
FROM social_media_manager_profiles FROM social_media_manager_profiles
ORDER BY created_at DESC ORDER BY created_at DESC
LIMIT 100 LIMIT 100
"# "#,
) )
.fetch_all(&state.pool) .fetch_all(&state.pool)
.await .await
@ -61,15 +60,14 @@ async fn get_social_media_manager(
State(state): State<ProfessionState>, State(state): State<ProfessionState>,
Path(id): Path<Uuid>, Path(id): Path<Uuid>,
) -> Result<impl IntoResponse, (StatusCode, String)> { ) -> Result<impl IntoResponse, (StatusCode, String)> {
let manager = sqlx::query_as!( let manager = sqlx::query_as::<_, SocialMediaManagerProfile>(
SocialMediaManagerProfile,
r#" r#"
SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at
FROM social_media_manager_profiles FROM social_media_manager_profiles
WHERE id = $1 WHERE id = $1
"#, "#,
id
) )
.bind(id)
.fetch_optional(&state.pool) .fetch_optional(&state.pool)
.await .await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?; .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?;

View file

@ -11,7 +11,6 @@ COPY Cargo.toml Cargo.lock ./
COPY crates ./crates COPY crates ./crates
COPY apps ./apps COPY apps ./apps
ENV SQLX_OFFLINE=true
ENV CARGO_BUILD_JOBS=2 ENV CARGO_BUILD_JOBS=2
RUN cargo build --release --bin tutors RUN cargo build --release --bin tutors

View file

@ -43,14 +43,13 @@ pub fn router() -> Router<ProfessionState> {
async fn list_tutors( async fn list_tutors(
State(state): State<ProfessionState>, State(state): State<ProfessionState>,
) -> Result<impl IntoResponse, (StatusCode, String)> { ) -> Result<impl IntoResponse, (StatusCode, String)> {
let tutors = sqlx::query_as!( let tutors = sqlx::query_as::<_, TutorProfile>(
TutorProfile,
r#" r#"
SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at
FROM tutor_profiles FROM tutor_profiles
ORDER BY created_at DESC ORDER BY created_at DESC
LIMIT 100 LIMIT 100
"# "#,
) )
.fetch_all(&state.pool) .fetch_all(&state.pool)
.await .await
@ -64,15 +63,14 @@ async fn get_tutor(
State(state): State<ProfessionState>, State(state): State<ProfessionState>,
Path(id): Path<Uuid>, Path(id): Path<Uuid>,
) -> Result<impl IntoResponse, (StatusCode, String)> { ) -> Result<impl IntoResponse, (StatusCode, String)> {
let tutor = sqlx::query_as!( let tutor = sqlx::query_as::<_, TutorProfile>(
TutorProfile,
r#" r#"
SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at
FROM tutor_profiles FROM tutor_profiles
WHERE id = $1 WHERE id = $1
"#, "#,
id
) )
.bind(id)
.fetch_optional(&state.pool) .fetch_optional(&state.pool)
.await .await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?; .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?;

View file

@ -11,7 +11,6 @@ COPY Cargo.toml Cargo.lock ./
COPY crates ./crates COPY crates ./crates
COPY apps ./apps COPY apps ./apps
ENV SQLX_OFFLINE=true
ENV CARGO_BUILD_JOBS=2 ENV CARGO_BUILD_JOBS=2
RUN cargo build --release --bin ugc_content_creators RUN cargo build --release --bin ugc_content_creators

View file

@ -11,7 +11,6 @@ COPY Cargo.toml Cargo.lock ./
COPY crates ./crates COPY crates ./crates
COPY apps ./apps COPY apps ./apps
ENV SQLX_OFFLINE=true
ENV CARGO_BUILD_JOBS=2 ENV CARGO_BUILD_JOBS=2
RUN cargo build --release --bin users RUN cargo build --release --bin users

View file

@ -11,7 +11,6 @@ COPY Cargo.toml Cargo.lock ./
COPY crates ./crates COPY crates ./crates
COPY apps ./apps COPY apps ./apps
ENV SQLX_OFFLINE=true
ENV CARGO_BUILD_JOBS=2 ENV CARGO_BUILD_JOBS=2
RUN cargo build --release --bin video_editors RUN cargo build --release --bin video_editors

View file

@ -40,14 +40,13 @@ pub fn router() -> Router<ProfessionState> {
async fn list_video_editors( async fn list_video_editors(
State(state): State<ProfessionState>, State(state): State<ProfessionState>,
) -> Result<impl IntoResponse, (StatusCode, String)> { ) -> Result<impl IntoResponse, (StatusCode, String)> {
let editors = sqlx::query_as!( let editors = sqlx::query_as::<_, VideoEditorProfile>(
VideoEditorProfile,
r#" r#"
SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at
FROM video_editor_profiles FROM video_editor_profiles
ORDER BY created_at DESC ORDER BY created_at DESC
LIMIT 100 LIMIT 100
"# "#,
) )
.fetch_all(&state.pool) .fetch_all(&state.pool)
.await .await
@ -61,15 +60,14 @@ async fn get_video_editor(
State(state): State<ProfessionState>, State(state): State<ProfessionState>,
Path(id): Path<Uuid>, Path(id): Path<Uuid>,
) -> Result<impl IntoResponse, (StatusCode, String)> { ) -> Result<impl IntoResponse, (StatusCode, String)> {
let editor = sqlx::query_as!( let editor = sqlx::query_as::<_, VideoEditorProfile>(
VideoEditorProfile,
r#" r#"
SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at SELECT id, user_id, display_name, bio, location, custom_data, status, created_at, updated_at
FROM video_editor_profiles FROM video_editor_profiles
WHERE id = $1 WHERE id = $1
"#, "#,
id
) )
.bind(id)
.fetch_optional(&state.pool) .fetch_optional(&state.pool)
.await .await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?; .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?;

View file

@ -31,18 +31,17 @@ impl ApplicationRepository {
pool: &PgPool, pool: &PgPool,
payload: CreateApplicationPayload, payload: CreateApplicationPayload,
) -> Result<Application, sqlx::Error> { ) -> Result<Application, sqlx::Error> {
let app = sqlx::query_as!( let app = sqlx::query_as::<_, Application>(
Application,
r#" r#"
INSERT INTO applications (job_id, job_seeker_id, cover_letter, resume_url) INSERT INTO applications (job_id, job_seeker_id, cover_letter, resume_url)
VALUES ($1, $2, $3, $4) VALUES ($1, $2, $3, $4)
RETURNING * RETURNING *
"#, "#,
payload.job_id,
payload.job_seeker_id,
payload.cover_letter,
payload.resume_url
) )
.bind(payload.job_id)
.bind(payload.job_seeker_id)
.bind(payload.cover_letter)
.bind(payload.resume_url)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
@ -50,7 +49,8 @@ impl ApplicationRepository {
} }
pub async fn get_by_id(pool: &PgPool, id: Uuid) -> Result<Option<Application>, sqlx::Error> { pub async fn get_by_id(pool: &PgPool, id: Uuid) -> Result<Option<Application>, sqlx::Error> {
sqlx::query_as!(Application, "SELECT * FROM applications WHERE id = $1", id) sqlx::query_as::<_, Application>("SELECT * FROM applications WHERE id = $1")
.bind(id)
.fetch_optional(pool) .fetch_optional(pool)
.await .await
} }
@ -63,19 +63,18 @@ impl ApplicationRepository {
limit: i64, limit: i64,
) -> Result<Vec<Application>, sqlx::Error> { ) -> Result<Vec<Application>, sqlx::Error> {
let offset = (page - 1) * limit; let offset = (page - 1) * limit;
let apps = sqlx::query_as!( let apps = sqlx::query_as::<_, Application>(
Application,
r#" r#"
SELECT * FROM applications SELECT * FROM applications
WHERE job_id = $1 AND ($2::VARCHAR IS NULL OR status = $2) WHERE job_id = $1 AND ($2::VARCHAR IS NULL OR status = $2)
ORDER BY applied_at DESC ORDER BY applied_at DESC
LIMIT $3 OFFSET $4 LIMIT $3 OFFSET $4
"#, "#,
job_id,
status,
limit,
offset
) )
.bind(job_id)
.bind(status)
.bind(limit)
.bind(offset)
.fetch_all(pool) .fetch_all(pool)
.await?; .await?;
@ -89,18 +88,17 @@ impl ApplicationRepository {
limit: i64, limit: i64,
) -> Result<Vec<Application>, sqlx::Error> { ) -> Result<Vec<Application>, sqlx::Error> {
let offset = (page - 1) * limit; let offset = (page - 1) * limit;
let apps = sqlx::query_as!( let apps = sqlx::query_as::<_, Application>(
Application,
r#" r#"
SELECT * FROM applications SELECT * FROM applications
WHERE job_seeker_id = $1 WHERE job_seeker_id = $1
ORDER BY applied_at DESC ORDER BY applied_at DESC
LIMIT $2 OFFSET $3 LIMIT $2 OFFSET $3
"#, "#,
job_seeker_id,
limit,
offset
) )
.bind(job_seeker_id)
.bind(limit)
.bind(offset)
.fetch_all(pool) .fetch_all(pool)
.await?; .await?;
Ok(apps) Ok(apps)
@ -111,22 +109,21 @@ impl ApplicationRepository {
id: Uuid, id: Uuid,
status: &str, status: &str,
) -> Result<Application, sqlx::Error> { ) -> Result<Application, sqlx::Error> {
let app = sqlx::query_as!( let app = sqlx::query_as::<_, Application>(
Application,
"UPDATE applications SET status = $1, updated_at = NOW() WHERE id = $2 RETURNING *", "UPDATE applications SET status = $1, updated_at = NOW() WHERE id = $2 RETURNING *",
status,
id
) )
.bind(status)
.bind(id)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
Ok(app) Ok(app)
} }
pub async fn mark_contact_viewed(pool: &PgPool, id: Uuid) -> Result<(), sqlx::Error> { pub async fn mark_contact_viewed(pool: &PgPool, id: Uuid) -> Result<(), sqlx::Error> {
sqlx::query!( sqlx::query(
"UPDATE applications SET contact_viewed = true WHERE id = $1", "UPDATE applications SET contact_viewed = true WHERE id = $1",
id
) )
.bind(id)
.execute(pool) .execute(pool)
.await?; .await?;
Ok(()) Ok(())

View file

@ -30,19 +30,19 @@ pub struct CateringServiceRepository;
impl CateringServiceRepository { impl CateringServiceRepository {
pub async fn get_by_user_id(pool: &PgPool, user_id: Uuid) -> Result<Option<CateringServiceProfile>, sqlx::Error> { pub async fn get_by_user_id(pool: &PgPool, user_id: Uuid) -> Result<Option<CateringServiceProfile>, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, CateringServiceProfile>(
CateringServiceProfile,
r#"SELECT id, user_id, business_name, bio, location, r#"SELECT id, user_id, business_name, bio, location,
custom_data, custom_data,
status, created_at, updated_at status, created_at, updated_at
FROM catering_service_profiles WHERE user_id = $1"#, FROM catering_service_profiles WHERE user_id = $1"#,
user_id )
).fetch_optional(pool).await .bind(user_id)
.fetch_optional(pool)
.await
} }
pub async fn upsert(pool: &PgPool, user_id: Uuid, p: UpsertCateringServiceProfilePayload) -> Result<CateringServiceProfile, sqlx::Error> { pub async fn upsert(pool: &PgPool, user_id: Uuid, p: UpsertCateringServiceProfilePayload) -> Result<CateringServiceProfile, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, CateringServiceProfile>(
CateringServiceProfile,
r#"INSERT INTO catering_service_profiles (user_id, business_name, bio, location, custom_data) r#"INSERT INTO catering_service_profiles (user_id, business_name, bio, location, custom_data)
VALUES ($1, $2, $3, $4, $5) VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (user_id) DO UPDATE SET ON CONFLICT (user_id) DO UPDATE SET
@ -54,7 +54,13 @@ impl CateringServiceRepository {
RETURNING id, user_id, business_name, bio, location, RETURNING id, user_id, business_name, bio, location,
custom_data, custom_data,
status, created_at, updated_at"#, status, created_at, updated_at"#,
user_id, p.business_name, p.bio, p.location, p.custom_data )
).fetch_one(pool).await .bind(user_id)
.bind(p.business_name)
.bind(p.bio)
.bind(p.location)
.bind(p.custom_data)
.fetch_one(pool)
.await
} }
} }

View file

@ -56,11 +56,10 @@ impl CompanyRepository {
pool: &PgPool, pool: &PgPool,
user_id: Uuid, user_id: Uuid,
) -> Result<Option<CompanyProfile>, sqlx::Error> { ) -> Result<Option<CompanyProfile>, sqlx::Error> {
let profile = sqlx::query_as!( let profile = sqlx::query_as::<_, CompanyProfile>(
CompanyProfile,
r#" r#"
SELECT SELECT
id, user_id, company_name, registration_number, industry, id, user_id, company_name, registration_number, industry,
website_url, employee_count, business_type, gst_number, website_url, employee_count, business_type, gst_number,
contact_name, contact_email, contact_phone, address_line1, contact_name, contact_email, contact_phone, address_line1,
city, state, country, postal_code, status, city, state, country, postal_code, status,
@ -69,8 +68,8 @@ impl CompanyRepository {
FROM company_profiles FROM company_profiles
WHERE user_id = $1 WHERE user_id = $1
"#, "#,
user_id
) )
.bind(user_id)
.fetch_optional(pool) .fetch_optional(pool)
.await?; .await?;
@ -82,12 +81,11 @@ impl CompanyRepository {
user_id: Uuid, user_id: Uuid,
payload: UpsertCompanyProfilePayload, payload: UpsertCompanyProfilePayload,
) -> Result<CompanyProfile, sqlx::Error> { ) -> Result<CompanyProfile, sqlx::Error> {
let profile = sqlx::query_as!( let profile = sqlx::query_as::<_, CompanyProfile>(
CompanyProfile,
r#" r#"
INSERT INTO company_profiles ( INSERT INTO company_profiles (
user_id, company_name, registration_number, industry, website_url, user_id, company_name, registration_number, industry, website_url,
employee_count, business_type, gst_number, contact_name, employee_count, business_type, gst_number, contact_name,
contact_email, contact_phone, address_line1, city, state, postal_code, status contact_email, contact_phone, address_line1, city, state, postal_code, status
) )
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, 'PENDING') VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, 'PENDING')
@ -111,30 +109,30 @@ impl CompanyRepository {
ELSE 'PENDING' ELSE 'PENDING'
END, END,
updated_at = NOW() updated_at = NOW()
RETURNING RETURNING
id, user_id, company_name, registration_number, industry, id, user_id, company_name, registration_number, industry,
website_url, employee_count, business_type, gst_number, website_url, employee_count, business_type, gst_number,
contact_name, contact_email, contact_phone, address_line1, contact_name, contact_email, contact_phone, address_line1,
city, state, country, postal_code, status, city, state, country, postal_code, status,
free_job_slots, purchased_job_slots, free_contact_views, purchased_contact_views, free_job_slots, purchased_job_slots, free_contact_views, purchased_contact_views,
created_at, updated_at created_at, updated_at
"#, "#,
user_id,
payload.company_name,
payload.registration_number,
payload.industry,
payload.website_url,
payload.employee_count,
payload.business_type,
payload.gst_number,
payload.contact_name,
payload.contact_email,
payload.contact_phone,
payload.address_line1,
payload.city,
payload.state,
payload.postal_code
) )
.bind(user_id)
.bind(payload.company_name)
.bind(payload.registration_number)
.bind(payload.industry)
.bind(payload.website_url)
.bind(payload.employee_count)
.bind(payload.business_type)
.bind(payload.gst_number)
.bind(payload.contact_name)
.bind(payload.contact_email)
.bind(payload.contact_phone)
.bind(payload.address_line1)
.bind(payload.city)
.bind(payload.state)
.bind(payload.postal_code)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
@ -145,22 +143,21 @@ impl CompanyRepository {
pool: &PgPool, pool: &PgPool,
user_id: Uuid, user_id: Uuid,
) -> Result<CompanyProfile, sqlx::Error> { ) -> Result<CompanyProfile, sqlx::Error> {
let profile = sqlx::query_as!( let profile = sqlx::query_as::<_, CompanyProfile>(
CompanyProfile,
r#" r#"
UPDATE company_profiles UPDATE company_profiles
SET status = 'PENDING_REVIEW', updated_at = NOW() SET status = 'PENDING_REVIEW', updated_at = NOW()
WHERE user_id = $1 WHERE user_id = $1
RETURNING RETURNING
id, user_id, company_name, registration_number, industry, id, user_id, company_name, registration_number, industry,
website_url, employee_count, business_type, gst_number, website_url, employee_count, business_type, gst_number,
contact_name, contact_email, contact_phone, address_line1, contact_name, contact_email, contact_phone, address_line1,
city, state, country, postal_code, status, city, state, country, postal_code, status,
free_job_slots, purchased_job_slots, free_contact_views, purchased_contact_views, free_job_slots, purchased_job_slots, free_contact_views, purchased_contact_views,
created_at, updated_at created_at, updated_at
"#, "#,
user_id
) )
.bind(user_id)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;

View file

@ -82,33 +82,32 @@ impl ConfigRepository {
payload: CreateOnboardingConfigPayload, payload: CreateOnboardingConfigPayload,
) -> Result<OnboardingConfig, sqlx::Error> { ) -> Result<OnboardingConfig, sqlx::Error> {
// Soft-disable previous active configs for this role // Soft-disable previous active configs for this role
sqlx::query!( sqlx::query(
r#" r#"
UPDATE onboarding_configs UPDATE onboarding_configs
SET is_active = false SET is_active = false
WHERE role_id = $1 AND is_active = true WHERE role_id = $1 AND is_active = true
"#, "#,
payload.role_id
) )
.bind(payload.role_id)
.execute(pool) .execute(pool)
.await?; .await?;
// Insert new config // Insert new config
let config = sqlx::query_as!( let config = sqlx::query_as::<_, OnboardingConfig>(
OnboardingConfig,
r#" r#"
INSERT INTO onboarding_configs (role_id, schema_json, version, is_active) INSERT INTO onboarding_configs (role_id, schema_json, version, is_active)
VALUES ( VALUES (
$1, $1,
$2, $2,
COALESCE((SELECT MAX(version) FROM onboarding_configs WHERE role_id = $1), 0) + 1, COALESCE((SELECT MAX(version) FROM onboarding_configs WHERE role_id = $1), 0) + 1,
true true
) )
RETURNING id, role_id, schema_json, version, is_active, updated_at RETURNING id, role_id, schema_json, version, is_active, updated_at
"#, "#,
payload.role_id,
payload.schema_json
) )
.bind(payload.role_id)
.bind(payload.schema_json)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
@ -119,15 +118,14 @@ impl ConfigRepository {
pool: &PgPool, pool: &PgPool,
role_id: Uuid, role_id: Uuid,
) -> Result<OnboardingConfig, sqlx::Error> { ) -> Result<OnboardingConfig, sqlx::Error> {
let config = sqlx::query_as!( let config = sqlx::query_as::<_, OnboardingConfig>(
OnboardingConfig,
r#" r#"
SELECT id, role_id, schema_json, version, is_active, updated_at SELECT id, role_id, schema_json, version, is_active, updated_at
FROM onboarding_configs FROM onboarding_configs
WHERE role_id = $1 AND is_active = true WHERE role_id = $1 AND is_active = true
"#, "#,
role_id
) )
.bind(role_id)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
@ -137,16 +135,15 @@ impl ConfigRepository {
pub async fn get_all_onboarding_configs( pub async fn get_all_onboarding_configs(
pool: &PgPool, pool: &PgPool,
) -> Result<Vec<OnboardingConfigListItem>, sqlx::Error> { ) -> Result<Vec<OnboardingConfigListItem>, sqlx::Error> {
let configs = sqlx::query_as!( let configs = sqlx::query_as::<_, OnboardingConfigListItem>(
OnboardingConfigListItem,
r#" r#"
SELECT SELECT
c.id, c.role_id, r.key as role_key, c.id, c.role_id, r.key as role_key,
c.version, c.is_active, c.updated_at c.version, c.is_active, c.updated_at
FROM onboarding_configs c FROM onboarding_configs c
JOIN roles r ON c.role_id = r.id JOIN roles r ON c.role_id = r.id
ORDER BY c.updated_at DESC ORDER BY c.updated_at DESC
"# "#,
) )
.fetch_all(pool) .fetch_all(pool)
.await?; .await?;
@ -158,16 +155,15 @@ impl ConfigRepository {
pool: &PgPool, pool: &PgPool,
role_key: &str, role_key: &str,
) -> Result<OnboardingConfig, sqlx::Error> { ) -> Result<OnboardingConfig, sqlx::Error> {
let config = sqlx::query_as!( let config = sqlx::query_as::<_, OnboardingConfig>(
OnboardingConfig,
r#" r#"
SELECT c.id, c.role_id, c.schema_json, c.version, c.is_active, c.updated_at SELECT c.id, c.role_id, c.schema_json, c.version, c.is_active, c.updated_at
FROM onboarding_configs c FROM onboarding_configs c
JOIN roles r ON c.role_id = r.id JOIN roles r ON c.role_id = r.id
WHERE r.key = $1 AND c.is_active = true WHERE r.key = $1 AND c.is_active = true
"#, "#,
role_key.to_uppercase()
) )
.bind(role_key.to_uppercase())
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
@ -179,36 +175,35 @@ impl ConfigRepository {
payload: CreateDashboardConfigPayload, payload: CreateDashboardConfigPayload,
) -> Result<DashboardConfig, sqlx::Error> { ) -> Result<DashboardConfig, sqlx::Error> {
// Soft-disable previous active configs for this role // Soft-disable previous active configs for this role
sqlx::query!( sqlx::query(
r#" r#"
UPDATE dashboard_configs UPDATE dashboard_configs
SET is_active = false SET is_active = false
WHERE role_id = $1 AND audience = $2::text AND is_active = true WHERE role_id = $1 AND audience = $2::text AND is_active = true
"#, "#,
payload.role_id,
payload.audience
) )
.bind(payload.role_id)
.bind(&payload.audience)
.execute(pool) .execute(pool)
.await?; .await?;
// Insert new config // Insert new config
let config = sqlx::query_as!( let config = sqlx::query_as::<_, DashboardConfig>(
DashboardConfig,
r#" r#"
INSERT INTO dashboard_configs (role_id, audience, config_json, version, is_active) INSERT INTO dashboard_configs (role_id, audience, config_json, version, is_active)
VALUES ( VALUES (
$1, $1,
$2::text, $2::text,
$3, $3,
COALESCE((SELECT MAX(version) FROM dashboard_configs WHERE role_id = $1 AND audience = $2::text), 0) + 1, COALESCE((SELECT MAX(version) FROM dashboard_configs WHERE role_id = $1 AND audience = $2::text), 0) + 1,
true true
) )
RETURNING id, role_id, audience, config_json, version, is_active, updated_at RETURNING id, role_id, audience, config_json, version, is_active, updated_at
"#, "#,
payload.role_id,
payload.audience,
payload.config_json
) )
.bind(payload.role_id)
.bind(&payload.audience)
.bind(payload.config_json)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
@ -220,16 +215,15 @@ impl ConfigRepository {
role_id: Uuid, role_id: Uuid,
audience: &str, audience: &str,
) -> Result<DashboardConfig, sqlx::Error> { ) -> Result<DashboardConfig, sqlx::Error> {
let config = sqlx::query_as!( let config = sqlx::query_as::<_, DashboardConfig>(
DashboardConfig,
r#" r#"
SELECT id, role_id, audience, config_json, version, is_active, updated_at SELECT id, role_id, audience, config_json, version, is_active, updated_at
FROM dashboard_configs FROM dashboard_configs
WHERE role_id = $1 AND audience = $2 AND is_active = true WHERE role_id = $1 AND audience = $2 AND is_active = true
"#, "#,
role_id,
audience
) )
.bind(role_id)
.bind(audience)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
@ -239,16 +233,15 @@ impl ConfigRepository {
pub async fn get_all_dashboard_configs( pub async fn get_all_dashboard_configs(
pool: &PgPool, pool: &PgPool,
) -> Result<Vec<DashboardConfigListItem>, sqlx::Error> { ) -> Result<Vec<DashboardConfigListItem>, sqlx::Error> {
let configs = sqlx::query_as!( let configs = sqlx::query_as::<_, DashboardConfigListItem>(
DashboardConfigListItem,
r#" r#"
SELECT SELECT
c.id, c.role_id, r.key as role_key, c.audience, c.id, c.role_id, r.key as role_key, c.audience,
c.version, c.is_active, c.updated_at c.version, c.is_active, c.updated_at
FROM dashboard_configs c FROM dashboard_configs c
JOIN roles r ON c.role_id = r.id JOIN roles r ON c.role_id = r.id
ORDER BY c.updated_at DESC ORDER BY c.updated_at DESC
"# "#,
) )
.fetch_all(pool) .fetch_all(pool)
.await?; .await?;
@ -261,17 +254,16 @@ impl ConfigRepository {
role_key: &str, role_key: &str,
audience: &str, audience: &str,
) -> Result<DashboardConfig, sqlx::Error> { ) -> Result<DashboardConfig, sqlx::Error> {
let config = sqlx::query_as!( let config = sqlx::query_as::<_, DashboardConfig>(
DashboardConfig,
r#" r#"
SELECT c.id, c.role_id, c.audience, c.config_json, c.version, c.is_active, c.updated_at SELECT c.id, c.role_id, c.audience, c.config_json, c.version, c.is_active, c.updated_at
FROM dashboard_configs c FROM dashboard_configs c
JOIN roles r ON c.role_id = r.id JOIN roles r ON c.role_id = r.id
WHERE r.key = $1 AND c.audience = $2 AND c.is_active = true WHERE r.key = $1 AND c.audience = $2 AND c.is_active = true
"#, "#,
role_key.to_uppercase(),
audience
) )
.bind(role_key.to_uppercase())
.bind(audience)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
@ -283,33 +275,32 @@ impl ConfigRepository {
payload: CreateRuntimeConfigPayload, payload: CreateRuntimeConfigPayload,
) -> Result<RuntimeConfig, sqlx::Error> { ) -> Result<RuntimeConfig, sqlx::Error> {
// Soft-disable previous active configs for this role // Soft-disable previous active configs for this role
sqlx::query!( sqlx::query(
r#" r#"
UPDATE runtime_configs UPDATE runtime_configs
SET is_active = false SET is_active = false
WHERE role_id = $1 AND is_active = true WHERE role_id = $1 AND is_active = true
"#, "#,
payload.role_id
) )
.bind(payload.role_id)
.execute(pool) .execute(pool)
.await?; .await?;
// Insert new config // Insert new config
let config = sqlx::query_as!( let config = sqlx::query_as::<_, RuntimeConfig>(
RuntimeConfig,
r#" r#"
INSERT INTO runtime_configs (role_id, config_json, version, is_active) INSERT INTO runtime_configs (role_id, config_json, version, is_active)
VALUES ( VALUES (
$1, $1,
$2, $2,
COALESCE((SELECT MAX(version) FROM runtime_configs WHERE role_id = $1), 0) + 1, COALESCE((SELECT MAX(version) FROM runtime_configs WHERE role_id = $1), 0) + 1,
true true
) )
RETURNING id, role_id, config_json, version, is_active, updated_at RETURNING id, role_id, config_json, version, is_active, updated_at
"#, "#,
payload.role_id,
payload.config_json
) )
.bind(payload.role_id)
.bind(payload.config_json)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
@ -320,15 +311,14 @@ impl ConfigRepository {
pool: &PgPool, pool: &PgPool,
role_id: Uuid, role_id: Uuid,
) -> Result<RuntimeConfig, sqlx::Error> { ) -> Result<RuntimeConfig, sqlx::Error> {
let config = sqlx::query_as!( let config = sqlx::query_as::<_, RuntimeConfig>(
RuntimeConfig,
r#" r#"
SELECT id, role_id, config_json, version, is_active, updated_at SELECT id, role_id, config_json, version, is_active, updated_at
FROM runtime_configs FROM runtime_configs
WHERE role_id = $1 AND is_active = true WHERE role_id = $1 AND is_active = true
"#, "#,
role_id
) )
.bind(role_id)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
@ -339,16 +329,15 @@ impl ConfigRepository {
pool: &PgPool, pool: &PgPool,
role_key: &str, role_key: &str,
) -> Result<RuntimeConfig, sqlx::Error> { ) -> Result<RuntimeConfig, sqlx::Error> {
let config = sqlx::query_as!( let config = sqlx::query_as::<_, RuntimeConfig>(
RuntimeConfig,
r#" r#"
SELECT rc.id, rc.role_id, rc.config_json, rc.version, rc.is_active, rc.updated_at SELECT rc.id, rc.role_id, rc.config_json, rc.version, rc.is_active, rc.updated_at
FROM runtime_configs rc FROM runtime_configs rc
JOIN roles r ON rc.role_id = r.id JOIN roles r ON rc.role_id = r.id
WHERE r.key = $1 AND rc.is_active = true WHERE r.key = $1 AND rc.is_active = true
"#, "#,
role_key.to_uppercase()
) )
.bind(role_key.to_uppercase())
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;

View file

@ -39,18 +39,17 @@ impl CustomerRepository {
pool: &PgPool, pool: &PgPool,
user_id: Uuid, user_id: Uuid,
) -> Result<Option<CustomerProfile>, sqlx::Error> { ) -> Result<Option<CustomerProfile>, sqlx::Error> {
let profile = sqlx::query_as!( let profile = sqlx::query_as::<_, CustomerProfile>(
CustomerProfile,
r#" r#"
SELECT SELECT
id, user_id, full_name, phone, city, area, preferred_professions, id, user_id, full_name, phone, city, area, preferred_professions,
active_requirement_count, status, bio, experience_years, custom_data, active_requirement_count, status, bio, experience_years, custom_data,
created_at, updated_at created_at, updated_at
FROM customer_profiles FROM customer_profiles
WHERE user_id = $1 WHERE user_id = $1
"#, "#,
user_id
) )
.bind(user_id)
.fetch_optional(pool) .fetch_optional(pool)
.await?; .await?;
@ -62,8 +61,7 @@ impl CustomerRepository {
user_id: Uuid, user_id: Uuid,
payload: UpsertCustomerProfilePayload, payload: UpsertCustomerProfilePayload,
) -> Result<CustomerProfile, sqlx::Error> { ) -> Result<CustomerProfile, sqlx::Error> {
let profile = sqlx::query_as!( let profile = sqlx::query_as::<_, CustomerProfile>(
CustomerProfile,
r#" r#"
INSERT INTO customer_profiles ( INSERT INTO customer_profiles (
user_id, full_name, phone, city, area, preferred_professions, bio, custom_data, status user_id, full_name, phone, city, area, preferred_professions, bio, custom_data, status
@ -82,20 +80,20 @@ impl CustomerRepository {
ELSE 'PENDING' ELSE 'PENDING'
END, END,
updated_at = NOW() updated_at = NOW()
RETURNING RETURNING
id, user_id, full_name, phone, city, area, preferred_professions, id, user_id, full_name, phone, city, area, preferred_professions,
active_requirement_count, status, bio, experience_years, custom_data, active_requirement_count, status, bio, experience_years, custom_data,
created_at, updated_at created_at, updated_at
"#, "#,
user_id,
payload.full_name,
payload.phone,
payload.city,
payload.area,
&payload.preferred_professions.unwrap_or_default(),
payload.bio,
payload.custom_data
) )
.bind(user_id)
.bind(payload.full_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) .fetch_one(pool)
.await?; .await?;
@ -107,11 +105,11 @@ impl CustomerRepository {
id: Uuid, id: Uuid,
delta: i32, delta: i32,
) -> Result<(), sqlx::Error> { ) -> Result<(), sqlx::Error> {
sqlx::query!( sqlx::query(
"UPDATE customer_profiles SET active_requirement_count = active_requirement_count + $1 WHERE id = $2", "UPDATE customer_profiles SET active_requirement_count = active_requirement_count + $1 WHERE id = $2",
delta,
id
) )
.bind(delta)
.bind(id)
.execute(pool) .execute(pool)
.await?; .await?;
Ok(()) Ok(())
@ -121,19 +119,18 @@ impl CustomerRepository {
pool: &PgPool, pool: &PgPool,
user_id: Uuid, user_id: Uuid,
) -> Result<CustomerProfile, sqlx::Error> { ) -> Result<CustomerProfile, sqlx::Error> {
let profile = sqlx::query_as!( let profile = sqlx::query_as::<_, CustomerProfile>(
CustomerProfile,
r#" r#"
UPDATE customer_profiles UPDATE customer_profiles
SET status = 'PENDING_REVIEW', updated_at = NOW() SET status = 'PENDING_REVIEW', updated_at = NOW()
WHERE user_id = $1 WHERE user_id = $1
RETURNING RETURNING
id, user_id, full_name, phone, city, area, preferred_professions, id, user_id, full_name, phone, city, area, preferred_professions,
active_requirement_count, status, bio, experience_years, custom_data, active_requirement_count, status, bio, experience_years, custom_data,
created_at, updated_at created_at, updated_at
"#, "#,
user_id
) )
.bind(user_id)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;

View file

@ -28,19 +28,19 @@ pub struct DeveloperRepository;
impl DeveloperRepository { impl DeveloperRepository {
pub async fn get_by_user_id(pool: &PgPool, user_id: Uuid) -> Result<Option<DeveloperProfile>, sqlx::Error> { pub async fn get_by_user_id(pool: &PgPool, user_id: Uuid) -> Result<Option<DeveloperProfile>, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, DeveloperProfile>(
DeveloperProfile,
r#"SELECT id, user_id, display_name, bio, location, r#"SELECT id, user_id, display_name, bio, location,
custom_data, custom_data,
status, created_at, updated_at status, created_at, updated_at
FROM developer_profiles WHERE user_id = $1"#, FROM developer_profiles WHERE user_id = $1"#,
user_id )
).fetch_optional(pool).await .bind(user_id)
.fetch_optional(pool)
.await
} }
pub async fn upsert(pool: &PgPool, user_id: Uuid, p: UpsertDeveloperProfilePayload) -> Result<DeveloperProfile, sqlx::Error> { pub async fn upsert(pool: &PgPool, user_id: Uuid, p: UpsertDeveloperProfilePayload) -> Result<DeveloperProfile, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, DeveloperProfile>(
DeveloperProfile,
r#"INSERT INTO developer_profiles (user_id, display_name, bio, location, custom_data) r#"INSERT INTO developer_profiles (user_id, display_name, bio, location, custom_data)
VALUES ($1, $2, $3, $4, $5) VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (user_id) DO UPDATE SET ON CONFLICT (user_id) DO UPDATE SET
@ -52,7 +52,13 @@ impl DeveloperRepository {
RETURNING id, user_id, display_name, bio, location, RETURNING id, user_id, display_name, bio, location,
custom_data, custom_data,
status, created_at, updated_at"#, status, created_at, updated_at"#,
user_id, p.display_name, p.bio, p.location, p.custom_data )
).fetch_one(pool).await .bind(user_id)
.bind(p.display_name)
.bind(p.bio)
.bind(p.location)
.bind(p.custom_data)
.fetch_one(pool)
.await
} }
} }

View file

@ -104,7 +104,8 @@ impl EmployeeRepository {
} }
pub async fn delete(pool: &PgPool, id: Uuid) -> Result<(), sqlx::Error> { pub async fn delete(pool: &PgPool, id: Uuid) -> Result<(), sqlx::Error> {
sqlx::query!("DELETE FROM employees WHERE id = $1", id) sqlx::query("DELETE FROM employees WHERE id = $1")
.bind(id)
.execute(pool) .execute(pool)
.await?; .await?;
Ok(()) Ok(())

View file

@ -28,19 +28,19 @@ pub struct FitnessTrainerRepository;
impl FitnessTrainerRepository { impl FitnessTrainerRepository {
pub async fn get_by_user_id(pool: &PgPool, user_id: Uuid) -> Result<Option<FitnessTrainerProfile>, sqlx::Error> { pub async fn get_by_user_id(pool: &PgPool, user_id: Uuid) -> Result<Option<FitnessTrainerProfile>, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, FitnessTrainerProfile>(
FitnessTrainerProfile,
r#"SELECT id, user_id, display_name, bio, location, r#"SELECT id, user_id, display_name, bio, location,
custom_data, custom_data,
status, created_at, updated_at status, created_at, updated_at
FROM fitness_trainer_profiles WHERE user_id = $1"#, FROM fitness_trainer_profiles WHERE user_id = $1"#,
user_id )
).fetch_optional(pool).await .bind(user_id)
.fetch_optional(pool)
.await
} }
pub async fn upsert(pool: &PgPool, user_id: Uuid, p: UpsertFitnessTrainerProfilePayload) -> Result<FitnessTrainerProfile, sqlx::Error> { pub async fn upsert(pool: &PgPool, user_id: Uuid, p: UpsertFitnessTrainerProfilePayload) -> Result<FitnessTrainerProfile, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, FitnessTrainerProfile>(
FitnessTrainerProfile,
r#"INSERT INTO fitness_trainer_profiles (user_id, display_name, bio, location, custom_data) r#"INSERT INTO fitness_trainer_profiles (user_id, display_name, bio, location, custom_data)
VALUES ($1, $2, $3, $4, $5) VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (user_id) DO UPDATE SET ON CONFLICT (user_id) DO UPDATE SET
@ -52,7 +52,13 @@ impl FitnessTrainerRepository {
RETURNING id, user_id, display_name, bio, location, RETURNING id, user_id, display_name, bio, location,
custom_data, custom_data,
status, created_at, updated_at"#, status, created_at, updated_at"#,
user_id, p.display_name, p.bio, p.location, p.custom_data )
).fetch_one(pool).await .bind(user_id)
.bind(p.display_name)
.bind(p.bio)
.bind(p.location)
.bind(p.custom_data)
.fetch_one(pool)
.await
} }
} }

View file

@ -28,19 +28,19 @@ pub struct GraphicDesignerRepository;
impl GraphicDesignerRepository { impl GraphicDesignerRepository {
pub async fn get_by_user_id(pool: &PgPool, user_id: Uuid) -> Result<Option<GraphicDesignerProfile>, sqlx::Error> { pub async fn get_by_user_id(pool: &PgPool, user_id: Uuid) -> Result<Option<GraphicDesignerProfile>, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, GraphicDesignerProfile>(
GraphicDesignerProfile,
r#"SELECT id, user_id, display_name, bio, location, r#"SELECT id, user_id, display_name, bio, location,
custom_data, custom_data,
status, created_at, updated_at status, created_at, updated_at
FROM graphic_designer_profiles WHERE user_id = $1"#, FROM graphic_designer_profiles WHERE user_id = $1"#,
user_id )
).fetch_optional(pool).await .bind(user_id)
.fetch_optional(pool)
.await
} }
pub async fn upsert(pool: &PgPool, user_id: Uuid, p: UpsertGraphicDesignerProfilePayload) -> Result<GraphicDesignerProfile, sqlx::Error> { pub async fn upsert(pool: &PgPool, user_id: Uuid, p: UpsertGraphicDesignerProfilePayload) -> Result<GraphicDesignerProfile, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, GraphicDesignerProfile>(
GraphicDesignerProfile,
r#"INSERT INTO graphic_designer_profiles (user_id, display_name, bio, location, custom_data) r#"INSERT INTO graphic_designer_profiles (user_id, display_name, bio, location, custom_data)
VALUES ($1, $2, $3, $4, $5) VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (user_id) DO UPDATE SET ON CONFLICT (user_id) DO UPDATE SET
@ -52,7 +52,13 @@ impl GraphicDesignerRepository {
RETURNING id, user_id, display_name, bio, location, RETURNING id, user_id, display_name, bio, location,
custom_data, custom_data,
status, created_at, updated_at"#, status, created_at, updated_at"#,
user_id, p.display_name, p.bio, p.location, p.custom_data )
).fetch_one(pool).await .bind(user_id)
.bind(p.display_name)
.bind(p.bio)
.bind(p.location)
.bind(p.custom_data)
.fetch_one(pool)
.await
} }
} }

View file

@ -56,27 +56,26 @@ pub struct JobRepository;
impl JobRepository { impl JobRepository {
pub async fn create(pool: &PgPool, payload: CreateJobPayload) -> Result<Job, sqlx::Error> { pub async fn create(pool: &PgPool, payload: CreateJobPayload) -> Result<Job, sqlx::Error> {
let job = sqlx::query_as!( let job = sqlx::query_as::<_, Job>(
Job,
r#" r#"
INSERT INTO jobs ( INSERT INTO jobs (
company_id, title, category, description, location, company_id, title, category, description, location,
job_type, salary_min, salary_max, experience_years, skills job_type, salary_min, salary_max, experience_years, skills
) )
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
RETURNING * RETURNING *
"#, "#,
payload.company_id,
payload.title,
payload.category,
payload.description,
payload.location,
payload.job_type.unwrap_or_else(|| "FULL_TIME".to_string()),
payload.salary_min,
payload.salary_max,
payload.experience_years,
&payload.skills.unwrap_or_default()
) )
.bind(payload.company_id)
.bind(payload.title)
.bind(payload.category)
.bind(payload.description)
.bind(payload.location)
.bind(payload.job_type.unwrap_or_else(|| "FULL_TIME".to_string()))
.bind(payload.salary_min)
.bind(payload.salary_max)
.bind(payload.experience_years)
.bind(payload.skills.unwrap_or_default())
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
@ -84,7 +83,8 @@ impl JobRepository {
} }
pub async fn get_by_id(pool: &PgPool, id: Uuid) -> Result<Option<Job>, sqlx::Error> { pub async fn get_by_id(pool: &PgPool, id: Uuid) -> Result<Option<Job>, sqlx::Error> {
sqlx::query_as!(Job, "SELECT * FROM jobs WHERE id = $1", id) sqlx::query_as::<_, Job>("SELECT * FROM jobs WHERE id = $1")
.bind(id)
.fetch_optional(pool) .fetch_optional(pool)
.await .await
} }
@ -97,19 +97,18 @@ impl JobRepository {
limit: i64, limit: i64,
) -> Result<Vec<Job>, sqlx::Error> { ) -> Result<Vec<Job>, sqlx::Error> {
let offset = (page - 1) * limit; let offset = (page - 1) * limit;
let jobs = sqlx::query_as!( let jobs = sqlx::query_as::<_, Job>(
Job,
r#" r#"
SELECT * FROM jobs SELECT * FROM jobs
WHERE company_id = $1 AND ($2::VARCHAR IS NULL OR status = $2) WHERE company_id = $1 AND ($2::VARCHAR IS NULL OR status = $2)
ORDER BY created_at DESC ORDER BY created_at DESC
LIMIT $3 OFFSET $4 LIMIT $3 OFFSET $4
"#, "#,
company_id,
status,
limit,
offset
) )
.bind(company_id)
.bind(status)
.bind(limit)
.bind(offset)
.fetch_all(pool) .fetch_all(pool)
.await?; .await?;
@ -121,8 +120,7 @@ impl JobRepository {
id: Uuid, id: Uuid,
payload: UpdateJobPayload, payload: UpdateJobPayload,
) -> Result<Job, sqlx::Error> { ) -> Result<Job, sqlx::Error> {
let job = sqlx::query_as!( let job = sqlx::query_as::<_, Job>(
Job,
r#" r#"
UPDATE jobs SET UPDATE jobs SET
title = COALESCE($1, title), title = COALESCE($1, title),
@ -138,17 +136,17 @@ impl JobRepository {
WHERE id = $10 WHERE id = $10
RETURNING * RETURNING *
"#, "#,
payload.title,
payload.category,
payload.description,
payload.location,
payload.job_type,
payload.salary_min,
payload.salary_max,
payload.experience_years,
payload.skills.as_deref(),
id
) )
.bind(payload.title)
.bind(payload.category)
.bind(payload.description)
.bind(payload.location)
.bind(payload.job_type)
.bind(payload.salary_min)
.bind(payload.salary_max)
.bind(payload.experience_years)
.bind(payload.skills)
.bind(id)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
@ -160,12 +158,11 @@ impl JobRepository {
id: Uuid, id: Uuid,
status: &str, status: &str,
) -> Result<Job, sqlx::Error> { ) -> Result<Job, sqlx::Error> {
let job = sqlx::query_as!( let job = sqlx::query_as::<_, Job>(
Job,
"UPDATE jobs SET status = $1, updated_at = NOW() WHERE id = $2 RETURNING *", "UPDATE jobs SET status = $1, updated_at = NOW() WHERE id = $2 RETURNING *",
status,
id
) )
.bind(status)
.bind(id)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
Ok(job) Ok(job)
@ -176,17 +173,16 @@ impl JobRepository {
id: Uuid, id: Uuid,
admin_user_id: Uuid, admin_user_id: Uuid,
) -> Result<Job, sqlx::Error> { ) -> Result<Job, sqlx::Error> {
let job = sqlx::query_as!( let job = sqlx::query_as::<_, Job>(
Job,
r#" r#"
UPDATE jobs UPDATE jobs
SET status = 'LIVE', approved_at = NOW(), approved_by = $1, rejection_reason = NULL, updated_at = NOW() SET status = 'LIVE', approved_at = NOW(), approved_by = $1, rejection_reason = NULL, updated_at = NOW()
WHERE id = $2 WHERE id = $2
RETURNING * RETURNING *
"#, "#,
admin_user_id,
id
) )
.bind(admin_user_id)
.bind(id)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
Ok(job) Ok(job)
@ -197,17 +193,16 @@ impl JobRepository {
id: Uuid, id: Uuid,
reason: Option<String>, reason: Option<String>,
) -> Result<Job, sqlx::Error> { ) -> Result<Job, sqlx::Error> {
let job = sqlx::query_as!( let job = sqlx::query_as::<_, Job>(
Job,
r#" r#"
UPDATE jobs UPDATE jobs
SET status = 'REJECTED', rejection_reason = $1, approved_at = NULL, approved_by = NULL, updated_at = NOW() SET status = 'REJECTED', rejection_reason = $1, approved_at = NULL, approved_by = NULL, updated_at = NOW()
WHERE id = $2 WHERE id = $2
RETURNING * RETURNING *
"#, "#,
reason,
id
) )
.bind(reason)
.bind(id)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
Ok(job) Ok(job)
@ -217,19 +212,19 @@ impl JobRepository {
pool: &PgPool, pool: &PgPool,
company_id: Uuid, company_id: Uuid,
) -> Result<i64, sqlx::Error> { ) -> Result<i64, sqlx::Error> {
let count = sqlx::query!( let count = sqlx::query_scalar::<_, i64>(
r#" r#"
SELECT COUNT(*) as "count!" SELECT COUNT(*)
FROM jobs FROM jobs
WHERE company_id = $1 WHERE company_id = $1
AND created_at >= date_trunc('month', now()) AND created_at >= date_trunc('month', now())
AND status != 'REJECTED' AND status != 'REJECTED'
"#, "#,
company_id
) )
.bind(company_id)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
Ok(count.count) Ok(count)
} }
} }

View file

@ -40,18 +40,17 @@ impl JobSeekerRepository {
pool: &PgPool, pool: &PgPool,
user_id: Uuid, user_id: Uuid,
) -> Result<Option<JobSeekerProfile>, sqlx::Error> { ) -> Result<Option<JobSeekerProfile>, sqlx::Error> {
let profile = sqlx::query_as!( let profile = sqlx::query_as::<_, JobSeekerProfile>(
JobSeekerProfile,
r#" r#"
SELECT SELECT
id, user_id, full_name, location, summary, experience_years, id, user_id, full_name, location, summary, experience_years,
skills, resume_url, active_application_count, status, bio, custom_data, skills, resume_url, active_application_count, status, bio, custom_data,
created_at, updated_at created_at, updated_at
FROM job_seeker_profiles FROM job_seeker_profiles
WHERE user_id = $1 WHERE user_id = $1
"#, "#,
user_id
) )
.bind(user_id)
.fetch_optional(pool) .fetch_optional(pool)
.await?; .await?;
@ -63,11 +62,10 @@ impl JobSeekerRepository {
user_id: Uuid, user_id: Uuid,
payload: UpsertJobSeekerProfilePayload, payload: UpsertJobSeekerProfilePayload,
) -> Result<JobSeekerProfile, sqlx::Error> { ) -> Result<JobSeekerProfile, sqlx::Error> {
let profile = sqlx::query_as!( let profile = sqlx::query_as::<_, JobSeekerProfile>(
JobSeekerProfile,
r#" r#"
INSERT INTO job_seeker_profiles ( INSERT INTO job_seeker_profiles (
user_id, full_name, location, summary, experience_years, user_id, full_name, location, summary, experience_years,
skills, resume_url, bio, custom_data skills, resume_url, bio, custom_data
) )
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
@ -81,21 +79,21 @@ impl JobSeekerRepository {
bio = EXCLUDED.bio, bio = EXCLUDED.bio,
custom_data = EXCLUDED.custom_data, custom_data = EXCLUDED.custom_data,
updated_at = NOW() updated_at = NOW()
RETURNING RETURNING
id, user_id, full_name, location, summary, experience_years, id, user_id, full_name, location, summary, experience_years,
skills, resume_url, active_application_count, status, bio, custom_data, skills, resume_url, active_application_count, status, bio, custom_data,
created_at, updated_at created_at, updated_at
"#, "#,
user_id,
payload.full_name,
payload.location,
payload.summary,
payload.experience_years.unwrap_or(0),
&payload.skills.unwrap_or_default(),
payload.resume_url,
payload.bio,
payload.custom_data
) )
.bind(user_id)
.bind(payload.full_name)
.bind(payload.location)
.bind(payload.summary)
.bind(payload.experience_years.unwrap_or(0))
.bind(payload.skills.unwrap_or_default())
.bind(payload.resume_url)
.bind(payload.bio)
.bind(payload.custom_data)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
@ -107,11 +105,11 @@ impl JobSeekerRepository {
id: Uuid, id: Uuid,
delta: i32, delta: i32,
) -> Result<(), sqlx::Error> { ) -> Result<(), sqlx::Error> {
sqlx::query!( sqlx::query(
"UPDATE job_seeker_profiles SET active_application_count = active_application_count + $1 WHERE id = $2", "UPDATE job_seeker_profiles SET active_application_count = active_application_count + $1 WHERE id = $2",
delta,
id
) )
.bind(delta)
.bind(id)
.execute(pool) .execute(pool)
.await?; .await?;
Ok(()) Ok(())
@ -121,23 +119,21 @@ impl JobSeekerRepository {
pool: &PgPool, pool: &PgPool,
user_id: Uuid, user_id: Uuid,
) -> Result<JobSeekerProfile, sqlx::Error> { ) -> Result<JobSeekerProfile, sqlx::Error> {
let profile = sqlx::query_as!( let profile = sqlx::query_as::<_, JobSeekerProfile>(
JobSeekerProfile,
r#" r#"
UPDATE job_seeker_profiles UPDATE job_seeker_profiles
SET status = 'PENDING_REVIEW', updated_at = NOW() SET status = 'PENDING_REVIEW', updated_at = NOW()
WHERE user_id = $1 WHERE user_id = $1
RETURNING RETURNING
id, user_id, full_name, location, summary, experience_years, id, user_id, full_name, location, summary, experience_years,
skills, resume_url, active_application_count, status, bio, custom_data, skills, resume_url, active_application_count, status, bio, custom_data,
created_at, updated_at created_at, updated_at
"#, "#,
user_id
) )
.bind(user_id)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
Ok(profile) Ok(profile)
} }
} }

View file

@ -31,17 +31,16 @@ impl LeadRequestRepository {
pool: &PgPool, pool: &PgPool,
payload: CreateLeadRequestPayload, payload: CreateLeadRequestPayload,
) -> Result<LeadRequest, sqlx::Error> { ) -> Result<LeadRequest, sqlx::Error> {
let req = sqlx::query_as!( let req = sqlx::query_as::<_, LeadRequest>(
LeadRequest,
r#" r#"
INSERT INTO lead_requests (requirement_id, professional_id, expires_at) INSERT INTO lead_requests (requirement_id, professional_id, expires_at)
VALUES ($1, $2, $3) VALUES ($1, $2, $3)
RETURNING * RETURNING *
"#, "#,
payload.requirement_id,
payload.professional_id,
payload.expires_at
) )
.bind(payload.requirement_id)
.bind(payload.professional_id)
.bind(payload.expires_at)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
@ -49,7 +48,8 @@ impl LeadRequestRepository {
} }
pub async fn get_by_id(pool: &PgPool, id: Uuid) -> Result<Option<LeadRequest>, sqlx::Error> { pub async fn get_by_id(pool: &PgPool, id: Uuid) -> Result<Option<LeadRequest>, sqlx::Error> {
sqlx::query_as!(LeadRequest, "SELECT * FROM lead_requests WHERE id = $1", id) sqlx::query_as::<_, LeadRequest>("SELECT * FROM lead_requests WHERE id = $1")
.bind(id)
.fetch_optional(pool) .fetch_optional(pool)
.await .await
} }
@ -61,18 +61,17 @@ impl LeadRequestRepository {
limit: i64, limit: i64,
) -> Result<Vec<LeadRequest>, sqlx::Error> { ) -> Result<Vec<LeadRequest>, sqlx::Error> {
let offset = (page - 1) * limit; let offset = (page - 1) * limit;
let reqs = sqlx::query_as!( let reqs = sqlx::query_as::<_, LeadRequest>(
LeadRequest,
r#" r#"
SELECT * FROM lead_requests SELECT * FROM lead_requests
WHERE requirement_id = $1 WHERE requirement_id = $1
ORDER BY requested_at DESC ORDER BY requested_at DESC
LIMIT $2 OFFSET $3 LIMIT $2 OFFSET $3
"#, "#,
requirement_id,
limit,
offset
) )
.bind(requirement_id)
.bind(limit)
.bind(offset)
.fetch_all(pool) .fetch_all(pool)
.await?; .await?;
@ -84,17 +83,16 @@ impl LeadRequestRepository {
id: Uuid, id: Uuid,
status: &str, status: &str,
) -> Result<LeadRequest, sqlx::Error> { ) -> Result<LeadRequest, sqlx::Error> {
let req = sqlx::query_as!( let req = sqlx::query_as::<_, LeadRequest>(
LeadRequest,
r#" r#"
UPDATE lead_requests UPDATE lead_requests
SET status = $1, resolved_at = NOW(), updated_at = NOW() SET status = $1, resolved_at = NOW(), updated_at = NOW()
WHERE id = $2 WHERE id = $2
RETURNING * RETURNING *
"#, "#,
status,
id
) )
.bind(status)
.bind(id)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
Ok(req) Ok(req)

View file

@ -28,19 +28,19 @@ pub struct MakeupArtistRepository;
impl MakeupArtistRepository { impl MakeupArtistRepository {
pub async fn get_by_user_id(pool: &PgPool, user_id: Uuid) -> Result<Option<MakeupArtistProfile>, sqlx::Error> { pub async fn get_by_user_id(pool: &PgPool, user_id: Uuid) -> Result<Option<MakeupArtistProfile>, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, MakeupArtistProfile>(
MakeupArtistProfile,
r#"SELECT id, user_id, display_name, bio, location, r#"SELECT id, user_id, display_name, bio, location,
custom_data, custom_data,
status, created_at, updated_at status, created_at, updated_at
FROM makeup_artist_profiles WHERE user_id = $1"#, FROM makeup_artist_profiles WHERE user_id = $1"#,
user_id )
).fetch_optional(pool).await .bind(user_id)
.fetch_optional(pool)
.await
} }
pub async fn upsert(pool: &PgPool, user_id: Uuid, p: UpsertMakeupArtistProfilePayload) -> Result<MakeupArtistProfile, sqlx::Error> { pub async fn upsert(pool: &PgPool, user_id: Uuid, p: UpsertMakeupArtistProfilePayload) -> Result<MakeupArtistProfile, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, MakeupArtistProfile>(
MakeupArtistProfile,
r#"INSERT INTO makeup_artist_profiles (user_id, display_name, bio, location, custom_data) r#"INSERT INTO makeup_artist_profiles (user_id, display_name, bio, location, custom_data)
VALUES ($1, $2, $3, $4, $5) VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (user_id) DO UPDATE SET ON CONFLICT (user_id) DO UPDATE SET
@ -52,7 +52,13 @@ impl MakeupArtistRepository {
RETURNING id, user_id, display_name, bio, location, RETURNING id, user_id, display_name, bio, location,
custom_data, custom_data,
status, created_at, updated_at"#, status, created_at, updated_at"#,
user_id, p.display_name, p.bio, p.location, p.custom_data )
).fetch_one(pool).await .bind(user_id)
.bind(p.display_name)
.bind(p.bio)
.bind(p.location)
.bind(p.custom_data)
.fetch_one(pool)
.await
} }
} }

View file

@ -41,17 +41,16 @@ impl OnboardingStateRepository {
user_id: Uuid, user_id: Uuid,
role_id: Uuid, role_id: Uuid,
) -> Result<Option<OnboardingState>, sqlx::Error> { ) -> Result<Option<OnboardingState>, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, OnboardingState>(
OnboardingState,
r#" r#"
SELECT id, user_id, role_id, status, progress_json, SELECT id, user_id, role_id, status, progress_json,
completed_at, created_at, updated_at completed_at, created_at, updated_at
FROM onboarding_states FROM onboarding_states
WHERE user_id = $1 AND role_id = $2 WHERE user_id = $1 AND role_id = $2
"#, "#,
user_id,
role_id,
) )
.bind(user_id)
.bind(role_id)
.fetch_optional(pool) .fetch_optional(pool)
.await .await
} }
@ -63,8 +62,7 @@ impl OnboardingStateRepository {
role_id: Uuid, role_id: Uuid,
progress: &Value, progress: &Value,
) -> Result<OnboardingState, sqlx::Error> { ) -> Result<OnboardingState, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, OnboardingState>(
OnboardingState,
r#" r#"
INSERT INTO onboarding_states (user_id, role_id, status, progress_json) INSERT INTO onboarding_states (user_id, role_id, status, progress_json)
VALUES ($1, $2, 'IN_PROGRESS', $3) VALUES ($1, $2, 'IN_PROGRESS', $3)
@ -78,10 +76,10 @@ impl OnboardingStateRepository {
RETURNING id, user_id, role_id, status, progress_json, RETURNING id, user_id, role_id, status, progress_json,
completed_at, created_at, updated_at completed_at, created_at, updated_at
"#, "#,
user_id,
role_id,
progress,
) )
.bind(user_id)
.bind(role_id)
.bind(progress)
.fetch_one(pool) .fetch_one(pool)
.await .await
} }
@ -93,8 +91,7 @@ impl OnboardingStateRepository {
role_id: Uuid, role_id: Uuid,
final_answers: &Value, final_answers: &Value,
) -> Result<OnboardingState, sqlx::Error> { ) -> Result<OnboardingState, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, OnboardingState>(
OnboardingState,
r#" r#"
INSERT INTO onboarding_states (user_id, role_id, status, progress_json, completed_at) INSERT INTO onboarding_states (user_id, role_id, status, progress_json, completed_at)
VALUES ($1, $2, 'COMPLETED', $3, NOW()) VALUES ($1, $2, 'COMPLETED', $3, NOW())
@ -106,10 +103,10 @@ impl OnboardingStateRepository {
RETURNING id, user_id, role_id, status, progress_json, RETURNING id, user_id, role_id, status, progress_json,
completed_at, created_at, updated_at completed_at, created_at, updated_at
"#, "#,
user_id,
role_id,
final_answers,
) )
.bind(user_id)
.bind(role_id)
.bind(final_answers)
.fetch_one(pool) .fetch_one(pool)
.await .await
} }
@ -120,14 +117,14 @@ impl OnboardingStateRepository {
user_id: Uuid, user_id: Uuid,
role_id: Uuid, role_id: Uuid,
) -> Result<bool, sqlx::Error> { ) -> Result<bool, sqlx::Error> {
let status = sqlx::query_scalar!( let status = sqlx::query_scalar::<_, String>(
r#" r#"
SELECT status FROM onboarding_states SELECT status FROM onboarding_states
WHERE user_id = $1 AND role_id = $2 WHERE user_id = $1 AND role_id = $2
"#, "#,
user_id,
role_id,
) )
.bind(user_id)
.bind(role_id)
.fetch_optional(pool) .fetch_optional(pool)
.await?; .await?;
Ok(status.map(|s| s == "COMPLETED").unwrap_or(false)) Ok(status.map(|s| s == "COMPLETED").unwrap_or(false))

View file

@ -28,19 +28,19 @@ pub struct PhotographerRepository;
impl PhotographerRepository { impl PhotographerRepository {
pub async fn get_by_user_id(pool: &PgPool, user_id: Uuid) -> Result<Option<PhotographerProfile>, sqlx::Error> { pub async fn get_by_user_id(pool: &PgPool, user_id: Uuid) -> Result<Option<PhotographerProfile>, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, PhotographerProfile>(
PhotographerProfile,
r#"SELECT id, user_id, display_name, bio, location, r#"SELECT id, user_id, display_name, bio, location,
custom_data, custom_data,
status, created_at, updated_at status, created_at, updated_at
FROM photographer_profiles WHERE user_id = $1"#, FROM photographer_profiles WHERE user_id = $1"#,
user_id )
).fetch_optional(pool).await .bind(user_id)
.fetch_optional(pool)
.await
} }
pub async fn upsert(pool: &PgPool, user_id: Uuid, p: UpsertPhotographerProfilePayload) -> Result<PhotographerProfile, sqlx::Error> { pub async fn upsert(pool: &PgPool, user_id: Uuid, p: UpsertPhotographerProfilePayload) -> Result<PhotographerProfile, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, PhotographerProfile>(
PhotographerProfile,
r#"INSERT INTO photographer_profiles (user_id, display_name, bio, location, custom_data) r#"INSERT INTO photographer_profiles (user_id, display_name, bio, location, custom_data)
VALUES ($1, $2, $3, $4, $5) VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (user_id) DO UPDATE SET ON CONFLICT (user_id) DO UPDATE SET
@ -52,7 +52,13 @@ impl PhotographerRepository {
RETURNING id, user_id, display_name, bio, location, RETURNING id, user_id, display_name, bio, location,
custom_data, custom_data,
status, created_at, updated_at"#, status, created_at, updated_at"#,
user_id, p.display_name, p.bio, p.location, p.custom_data )
).fetch_one(pool).await .bind(user_id)
.bind(p.display_name)
.bind(p.bio)
.bind(p.location)
.bind(p.custom_data)
.fetch_one(pool)
.await
} }
} }

View file

@ -116,11 +116,10 @@ pub struct ProfessionalRepository;
impl ProfessionalRepository { impl ProfessionalRepository {
pub async fn get_by_user_id(pool: &PgPool, user_id: Uuid) -> Result<Professional, sqlx::Error> { pub async fn get_by_user_id(pool: &PgPool, user_id: Uuid) -> Result<Professional, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, Professional>(
Professional,
"SELECT * FROM professionals WHERE user_id = $1", "SELECT * FROM professionals WHERE user_id = $1",
user_id
) )
.bind(user_id)
.fetch_one(pool) .fetch_one(pool)
.await .await
} }
@ -132,48 +131,44 @@ impl ProfessionalRepository {
limit: i64, limit: i64,
) -> Result<Vec<Requirement>, sqlx::Error> { ) -> Result<Vec<Requirement>, sqlx::Error> {
let offset = (page - 1) * limit; let offset = (page - 1) * limit;
sqlx::query_as!( sqlx::query_as::<_, Requirement>(
Requirement,
r#" r#"
SELECT * FROM requirements SELECT * FROM requirements
WHERE profession_key = $1 AND status = 'OPEN' AND (expires_at IS NULL OR expires_at > NOW()) WHERE profession_key = $1 AND status = 'OPEN' AND (expires_at IS NULL OR expires_at > NOW())
ORDER BY created_at DESC ORDER BY created_at DESC
LIMIT $2 OFFSET $3 LIMIT $2 OFFSET $3
"#, "#,
profession_key,
limit,
offset
) )
.bind(profession_key)
.bind(limit)
.bind(offset)
.fetch_all(pool) .fetch_all(pool)
.await .await
} }
pub async fn get_portfolio(pool: &PgPool, professional_id: Uuid) -> Result<Vec<PortfolioItem>, sqlx::Error> { pub async fn get_portfolio(pool: &PgPool, professional_id: Uuid) -> Result<Vec<PortfolioItem>, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, PortfolioItem>(
PortfolioItem,
"SELECT * FROM portfolio_items WHERE professional_id = $1 ORDER BY created_at DESC", "SELECT * FROM portfolio_items WHERE professional_id = $1 ORDER BY created_at DESC",
professional_id
) )
.bind(professional_id)
.fetch_all(pool) .fetch_all(pool)
.await .await
} }
pub async fn get_services(pool: &PgPool, professional_id: Uuid) -> Result<Vec<Service>, sqlx::Error> { pub async fn get_services(pool: &PgPool, professional_id: Uuid) -> Result<Vec<Service>, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, Service>(
Service,
"SELECT * FROM services WHERE professional_id = $1 AND is_active = true ORDER BY name ASC", "SELECT * FROM services WHERE professional_id = $1 AND is_active = true ORDER BY name ASC",
professional_id
) )
.bind(professional_id)
.fetch_all(pool) .fetch_all(pool)
.await .await
} }
pub async fn get_wallet(pool: &PgPool, user_id: Uuid) -> Result<Wallet, sqlx::Error> { pub async fn get_wallet(pool: &PgPool, user_id: Uuid) -> Result<Wallet, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, Wallet>(
Wallet,
"SELECT * FROM tracecoin_wallets WHERE user_id = $1", "SELECT * FROM tracecoin_wallets WHERE user_id = $1",
user_id
) )
.bind(user_id)
.fetch_one(pool) .fetch_one(pool)
.await .await
} }
@ -566,11 +561,10 @@ impl ProfessionalRepository {
pool: &PgPool, pool: &PgPool,
user_id: Uuid, user_id: Uuid,
) -> Result<Professional, sqlx::Error> { ) -> Result<Professional, sqlx::Error> {
let prof = sqlx::query_as!( let prof = sqlx::query_as::<_, Professional>(
Professional,
"SELECT * FROM professionals WHERE user_id = $1", "SELECT * FROM professionals WHERE user_id = $1",
user_id
) )
.bind(user_id)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
@ -578,16 +572,15 @@ impl ProfessionalRepository {
return Err(sqlx::Error::Protocol(format!("Professional profile is already {}", prof.status).into())); return Err(sqlx::Error::Protocol(format!("Professional profile is already {}", prof.status).into()));
} }
let prof = sqlx::query_as!( let prof = sqlx::query_as::<_, Professional>(
Professional,
r#" r#"
UPDATE professionals UPDATE professionals
SET status = 'PENDING_REVIEW', updated_at = NOW() SET status = 'PENDING_REVIEW', updated_at = NOW()
WHERE user_id = $1 WHERE user_id = $1
RETURNING * RETURNING *
"#, "#,
user_id
) )
.bind(user_id)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;

View file

@ -54,25 +54,24 @@ impl RequirementRepository {
pool: &PgPool, pool: &PgPool,
payload: CreateRequirementPayload, payload: CreateRequirementPayload,
) -> Result<Requirement, sqlx::Error> { ) -> Result<Requirement, sqlx::Error> {
let req = sqlx::query_as!( let req = sqlx::query_as::<_, Requirement>(
Requirement,
r#" r#"
INSERT INTO requirements ( INSERT INTO requirements (
customer_id, profession_key, title, description, location, customer_id, profession_key, title, description, location,
budget, preferred_date, extra_data_json budget, preferred_date, extra_data_json
) )
VALUES ($1, $2, $3, $4, $5, $6, $7, $8) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
RETURNING * RETURNING *
"#, "#,
payload.customer_id,
payload.profession_key,
payload.title,
payload.description,
payload.location,
payload.budget,
payload.preferred_date,
payload.extra_data_json
) )
.bind(payload.customer_id)
.bind(payload.profession_key)
.bind(payload.title)
.bind(payload.description)
.bind(payload.location)
.bind(payload.budget)
.bind(payload.preferred_date)
.bind(payload.extra_data_json)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
@ -80,7 +79,8 @@ impl RequirementRepository {
} }
pub async fn get_by_id(pool: &PgPool, id: Uuid) -> Result<Option<Requirement>, sqlx::Error> { 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) sqlx::query_as::<_, Requirement>("SELECT * FROM requirements WHERE id = $1")
.bind(id)
.fetch_optional(pool) .fetch_optional(pool)
.await .await
} }
@ -92,18 +92,17 @@ impl RequirementRepository {
limit: i64, limit: i64,
) -> Result<Vec<Requirement>, sqlx::Error> { ) -> Result<Vec<Requirement>, sqlx::Error> {
let offset = (page - 1) * limit; let offset = (page - 1) * limit;
let reqs = sqlx::query_as!( let reqs = sqlx::query_as::<_, Requirement>(
Requirement,
r#" r#"
SELECT * FROM requirements SELECT * FROM requirements
WHERE customer_id = $1 WHERE customer_id = $1
ORDER BY created_at DESC ORDER BY created_at DESC
LIMIT $2 OFFSET $3 LIMIT $2 OFFSET $3
"#, "#,
customer_id,
limit,
offset
) )
.bind(customer_id)
.bind(limit)
.bind(offset)
.fetch_all(pool) .fetch_all(pool)
.await?; .await?;
@ -115,8 +114,7 @@ impl RequirementRepository {
id: Uuid, id: Uuid,
payload: UpdateRequirementPayload, payload: UpdateRequirementPayload,
) -> Result<Requirement, sqlx::Error> { ) -> Result<Requirement, sqlx::Error> {
let req = sqlx::query_as!( let req = sqlx::query_as::<_, Requirement>(
Requirement,
r#" r#"
UPDATE requirements SET UPDATE requirements SET
title = COALESCE($1, title), title = COALESCE($1, title),
@ -129,14 +127,14 @@ impl RequirementRepository {
WHERE id = $7 WHERE id = $7
RETURNING * RETURNING *
"#, "#,
payload.title,
payload.description,
payload.location,
payload.budget,
payload.preferred_date,
payload.extra_data_json,
id
) )
.bind(payload.title)
.bind(payload.description)
.bind(payload.location)
.bind(payload.budget)
.bind(payload.preferred_date)
.bind(payload.extra_data_json)
.bind(id)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
@ -148,29 +146,29 @@ impl RequirementRepository {
id: Uuid, id: Uuid,
status: &str, status: &str,
) -> Result<Requirement, sqlx::Error> { ) -> Result<Requirement, sqlx::Error> {
let req = sqlx::query_as!( let req = sqlx::query_as::<_, Requirement>(
Requirement,
"UPDATE requirements SET status = $1, updated_at = NOW() WHERE id = $2 RETURNING *", "UPDATE requirements SET status = $1, updated_at = NOW() WHERE id = $2 RETURNING *",
status,
id
) )
.bind(status)
.bind(id)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
Ok(req) Ok(req)
} }
pub async fn increment_request_count(pool: &PgPool, id: Uuid) -> Result<(), sqlx::Error> { 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) sqlx::query("UPDATE requirements SET request_count = request_count + 1 WHERE id = $1")
.bind(id)
.execute(pool) .execute(pool)
.await?; .await?;
Ok(()) Ok(())
} }
pub async fn increment_accepted_count(pool: &PgPool, id: Uuid) -> Result<(), sqlx::Error> { pub async fn increment_accepted_count(pool: &PgPool, id: Uuid) -> Result<(), sqlx::Error> {
sqlx::query!( sqlx::query(
"UPDATE requirements SET accepted_count = accepted_count + 1 WHERE id = $1", "UPDATE requirements SET accepted_count = accepted_count + 1 WHERE id = $1",
id
) )
.bind(id)
.execute(pool) .execute(pool)
.await?; .await?;
Ok(()) Ok(())
@ -180,16 +178,15 @@ impl RequirementRepository {
pool: &PgPool, pool: &PgPool,
id: Uuid, id: Uuid,
) -> Result<Requirement, sqlx::Error> { ) -> Result<Requirement, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, Requirement>(
Requirement,
r#" r#"
UPDATE requirements UPDATE requirements
SET accepted_count = accepted_count + 1, updated_at = NOW() SET accepted_count = accepted_count + 1, updated_at = NOW()
WHERE id = $1 WHERE id = $1
RETURNING * RETURNING *
"#, "#,
id
) )
.bind(id)
.fetch_one(pool) .fetch_one(pool)
.await .await
} }
@ -199,17 +196,16 @@ impl RequirementRepository {
id: Uuid, id: Uuid,
admin_user_id: Uuid, admin_user_id: Uuid,
) -> Result<Requirement, sqlx::Error> { ) -> Result<Requirement, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, Requirement>(
Requirement,
r#" r#"
UPDATE requirements UPDATE requirements
SET status = 'OPEN', approved_at = NOW(), approved_by = $1, rejection_reason = NULL, updated_at = NOW() SET status = 'OPEN', approved_at = NOW(), approved_by = $1, rejection_reason = NULL, updated_at = NOW()
WHERE id = $2 WHERE id = $2
RETURNING * RETURNING *
"#, "#,
admin_user_id,
id
) )
.bind(admin_user_id)
.bind(id)
.fetch_one(pool) .fetch_one(pool)
.await .await
} }
@ -219,17 +215,16 @@ impl RequirementRepository {
id: Uuid, id: Uuid,
reason: Option<String>, reason: Option<String>,
) -> Result<Requirement, sqlx::Error> { ) -> Result<Requirement, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, Requirement>(
Requirement,
r#" r#"
UPDATE requirements UPDATE requirements
SET status = 'REJECTED', rejection_reason = $1, approved_at = NULL, approved_by = NULL, updated_at = NOW() SET status = 'REJECTED', rejection_reason = $1, approved_at = NULL, approved_by = NULL, updated_at = NOW()
WHERE id = $2 WHERE id = $2
RETURNING * RETURNING *
"#, "#,
reason,
id
) )
.bind(reason)
.bind(id)
.fetch_one(pool) .fetch_one(pool)
.await .await
} }

View file

@ -27,17 +27,16 @@ impl RoleRepository {
pool: &sqlx::PgPool, pool: &sqlx::PgPool,
payload: CreateRolePayload, payload: CreateRolePayload,
) -> Result<Role, sqlx::Error> { ) -> Result<Role, sqlx::Error> {
let role = sqlx::query_as!( let role = sqlx::query_as::<_, Role>(
Role,
r#" r#"
INSERT INTO roles (key, name, audience) INSERT INTO roles (key, name, audience)
VALUES ($1, $2, $3) VALUES ($1, $2, $3)
RETURNING id, key, name, audience, is_active, created_at RETURNING id, key, name, audience, is_active, created_at
"#, "#,
payload.key,
payload.name,
payload.audience
) )
.bind(payload.key)
.bind(payload.name)
.bind(payload.audience)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
@ -45,13 +44,12 @@ impl RoleRepository {
} }
pub async fn get_all(pool: &sqlx::PgPool) -> Result<Vec<Role>, sqlx::Error> { pub async fn get_all(pool: &sqlx::PgPool) -> Result<Vec<Role>, sqlx::Error> {
let roles = sqlx::query_as!( let roles = sqlx::query_as::<_, Role>(
Role,
r#" r#"
SELECT id, key, name, audience, is_active, created_at SELECT id, key, name, audience, is_active, created_at
FROM roles FROM roles
ORDER BY created_at DESC ORDER BY created_at DESC
"# "#,
) )
.fetch_all(pool) .fetch_all(pool)
.await?; .await?;
@ -60,15 +58,14 @@ impl RoleRepository {
} }
pub async fn get_by_key(pool: &sqlx::PgPool, key: &str) -> Result<Role, sqlx::Error> { pub async fn get_by_key(pool: &sqlx::PgPool, key: &str) -> Result<Role, sqlx::Error> {
let role = sqlx::query_as!( let role = sqlx::query_as::<_, Role>(
Role,
r#" r#"
SELECT id, key, name, audience, is_active, created_at SELECT id, key, name, audience, is_active, created_at
FROM roles FROM roles
WHERE key = $1 WHERE key = $1
"#, "#,
key
) )
.bind(key)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;

View file

@ -28,19 +28,19 @@ pub struct SocialMediaManagerRepository;
impl SocialMediaManagerRepository { impl SocialMediaManagerRepository {
pub async fn get_by_user_id(pool: &PgPool, user_id: Uuid) -> Result<Option<SocialMediaManagerProfile>, sqlx::Error> { pub async fn get_by_user_id(pool: &PgPool, user_id: Uuid) -> Result<Option<SocialMediaManagerProfile>, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, SocialMediaManagerProfile>(
SocialMediaManagerProfile,
r#"SELECT id, user_id, display_name, bio, location, r#"SELECT id, user_id, display_name, bio, location,
custom_data, custom_data,
status, created_at, updated_at status, created_at, updated_at
FROM social_media_manager_profiles WHERE user_id = $1"#, FROM social_media_manager_profiles WHERE user_id = $1"#,
user_id )
).fetch_optional(pool).await .bind(user_id)
.fetch_optional(pool)
.await
} }
pub async fn upsert(pool: &PgPool, user_id: Uuid, p: UpsertSocialMediaManagerProfilePayload) -> Result<SocialMediaManagerProfile, sqlx::Error> { pub async fn upsert(pool: &PgPool, user_id: Uuid, p: UpsertSocialMediaManagerProfilePayload) -> Result<SocialMediaManagerProfile, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, SocialMediaManagerProfile>(
SocialMediaManagerProfile,
r#"INSERT INTO social_media_manager_profiles (user_id, display_name, bio, location, custom_data) r#"INSERT INTO social_media_manager_profiles (user_id, display_name, bio, location, custom_data)
VALUES ($1, $2, $3, $4, $5) VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (user_id) DO UPDATE SET ON CONFLICT (user_id) DO UPDATE SET
@ -52,7 +52,13 @@ impl SocialMediaManagerRepository {
RETURNING id, user_id, display_name, bio, location, RETURNING id, user_id, display_name, bio, location,
custom_data, custom_data,
status, created_at, updated_at"#, status, created_at, updated_at"#,
user_id, p.display_name, p.bio, p.location, p.custom_data )
).fetch_one(pool).await .bind(user_id)
.bind(p.display_name)
.bind(p.bio)
.bind(p.location)
.bind(p.custom_data)
.fetch_one(pool)
.await
} }
} }

View file

@ -28,19 +28,19 @@ pub struct TutorRepository;
impl TutorRepository { impl TutorRepository {
pub async fn get_by_user_id(pool: &PgPool, user_id: Uuid) -> Result<Option<TutorProfile>, sqlx::Error> { pub async fn get_by_user_id(pool: &PgPool, user_id: Uuid) -> Result<Option<TutorProfile>, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, TutorProfile>(
TutorProfile,
r#"SELECT id, user_id, display_name, bio, location, r#"SELECT id, user_id, display_name, bio, location,
custom_data, custom_data,
status, created_at, updated_at status, created_at, updated_at
FROM tutor_profiles WHERE user_id = $1"#, FROM tutor_profiles WHERE user_id = $1"#,
user_id )
).fetch_optional(pool).await .bind(user_id)
.fetch_optional(pool)
.await
} }
pub async fn upsert(pool: &PgPool, user_id: Uuid, p: UpsertTutorProfilePayload) -> Result<TutorProfile, sqlx::Error> { pub async fn upsert(pool: &PgPool, user_id: Uuid, p: UpsertTutorProfilePayload) -> Result<TutorProfile, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, TutorProfile>(
TutorProfile,
r#"INSERT INTO tutor_profiles (user_id, display_name, bio, location, custom_data) r#"INSERT INTO tutor_profiles (user_id, display_name, bio, location, custom_data)
VALUES ($1, $2, $3, $4, $5) VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (user_id) DO UPDATE SET ON CONFLICT (user_id) DO UPDATE SET
@ -52,7 +52,13 @@ impl TutorRepository {
RETURNING id, user_id, display_name, bio, location, RETURNING id, user_id, display_name, bio, location,
custom_data, custom_data,
status, created_at, updated_at"#, status, created_at, updated_at"#,
user_id, p.display_name, p.bio, p.location, p.custom_data )
).fetch_one(pool).await .bind(user_id)
.bind(p.display_name)
.bind(p.bio)
.bind(p.location)
.bind(p.custom_data)
.fetch_one(pool)
.await
} }
} }

View file

@ -28,19 +28,19 @@ pub struct UgcContentCreatorRepository;
impl UgcContentCreatorRepository { impl UgcContentCreatorRepository {
pub async fn get_by_user_id(pool: &PgPool, user_id: Uuid) -> Result<Option<UgcContentCreatorProfile>, sqlx::Error> { pub async fn get_by_user_id(pool: &PgPool, user_id: Uuid) -> Result<Option<UgcContentCreatorProfile>, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, UgcContentCreatorProfile>(
UgcContentCreatorProfile,
r#"SELECT id, user_id, display_name, bio, location, r#"SELECT id, user_id, display_name, bio, location,
custom_data, custom_data,
status, created_at, updated_at status, created_at, updated_at
FROM ugc_content_creator_profiles WHERE user_id = $1"#, FROM ugc_content_creator_profiles WHERE user_id = $1"#,
user_id )
).fetch_optional(pool).await .bind(user_id)
.fetch_optional(pool)
.await
} }
pub async fn upsert(pool: &PgPool, user_id: Uuid, p: UpsertUgcContentCreatorProfilePayload) -> Result<UgcContentCreatorProfile, sqlx::Error> { pub async fn upsert(pool: &PgPool, user_id: Uuid, p: UpsertUgcContentCreatorProfilePayload) -> Result<UgcContentCreatorProfile, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, UgcContentCreatorProfile>(
UgcContentCreatorProfile,
r#"INSERT INTO ugc_content_creator_profiles (user_id, display_name, bio, location, custom_data) r#"INSERT INTO ugc_content_creator_profiles (user_id, display_name, bio, location, custom_data)
VALUES ($1, $2, $3, $4, $5) VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (user_id) DO UPDATE SET ON CONFLICT (user_id) DO UPDATE SET
@ -52,7 +52,13 @@ impl UgcContentCreatorRepository {
RETURNING id, user_id, display_name, bio, location, RETURNING id, user_id, display_name, bio, location,
custom_data, custom_data,
status, created_at, updated_at"#, status, created_at, updated_at"#,
user_id, p.display_name, p.bio, p.location, p.custom_data )
).fetch_one(pool).await .bind(user_id)
.bind(p.display_name)
.bind(p.bio)
.bind(p.location)
.bind(p.custom_data)
.fetch_one(pool)
.await
} }
} }

View file

@ -49,8 +49,7 @@ pub struct UserRepository;
impl UserRepository { impl UserRepository {
pub async fn create(pool: &PgPool, payload: CreateUserPayload) -> Result<User, sqlx::Error> { pub async fn create(pool: &PgPool, payload: CreateUserPayload) -> Result<User, sqlx::Error> {
let user = sqlx::query_as!( let user = sqlx::query_as::<_, User>(
User,
r#" r#"
INSERT INTO users (full_name, email, phone, password_hash, email_verified, phone_verified) INSERT INTO users (full_name, email, phone, password_hash, email_verified, phone_verified)
VALUES ($1, $2, $3, $4, false, false) VALUES ($1, $2, $3, $4, false, false)
@ -61,11 +60,11 @@ impl UserRepository {
reset_password_token, reset_password_expires_at, reset_password_token, reset_password_expires_at,
created_at, updated_at, deleted_at created_at, updated_at, deleted_at
"#, "#,
payload.full_name,
payload.email.to_lowercase(),
payload.phone as Option<String>,
payload.password_hash,
) )
.bind(payload.full_name)
.bind(payload.email.to_lowercase())
.bind(payload.phone)
.bind(payload.password_hash)
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
@ -73,8 +72,7 @@ impl UserRepository {
} }
pub async fn get_by_email(pool: &PgPool, email: &str) -> Result<User, sqlx::Error> { pub async fn get_by_email(pool: &PgPool, email: &str) -> Result<User, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, User>(
User,
r#" r#"
SELECT id, email, password_hash, full_name, phone, SELECT id, email, password_hash, full_name, phone,
email_verified, phone_verified, status, email_verified, phone_verified, status,
@ -84,15 +82,14 @@ impl UserRepository {
FROM users FROM users
WHERE email = $1 AND deleted_at IS NULL WHERE email = $1 AND deleted_at IS NULL
"#, "#,
email.to_lowercase()
) )
.bind(email.to_lowercase())
.fetch_one(pool) .fetch_one(pool)
.await .await
} }
pub async fn get_by_id(pool: &PgPool, id: Uuid) -> Result<User, sqlx::Error> { pub async fn get_by_id(pool: &PgPool, id: Uuid) -> Result<User, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, User>(
User,
r#" r#"
SELECT id, email, password_hash, full_name, phone, SELECT id, email, password_hash, full_name, phone,
email_verified, phone_verified, status, email_verified, phone_verified, status,
@ -102,15 +99,15 @@ impl UserRepository {
FROM users FROM users
WHERE id = $1 AND deleted_at IS NULL WHERE id = $1 AND deleted_at IS NULL
"#, "#,
id
) )
.bind(id)
.fetch_one(pool) .fetch_one(pool)
.await .await
} }
/// Returns all approved role keys for a user (e.g. ["COMPANY", "JOB_SEEKER"]) /// Returns all approved role keys for a user (e.g. ["COMPANY", "JOB_SEEKER"])
pub async fn get_user_role_keys(pool: &PgPool, user_id: Uuid) -> Result<Vec<String>, sqlx::Error> { pub async fn get_user_role_keys(pool: &PgPool, user_id: Uuid) -> Result<Vec<String>, sqlx::Error> {
let rows = sqlx::query_scalar!( let rows = sqlx::query_scalar::<_, String>(
r#" r#"
SELECT r.key SELECT r.key
FROM user_roles ur FROM user_roles ur
@ -118,8 +115,8 @@ impl UserRepository {
WHERE ur.user_id = $1 AND ur.status = 'APPROVED' WHERE ur.user_id = $1 AND ur.status = 'APPROVED'
ORDER BY ur.approved_at ASC ORDER BY ur.approved_at ASC
"#, "#,
user_id
) )
.bind(user_id)
.fetch_all(pool) .fetch_all(pool)
.await?; .await?;
@ -133,24 +130,23 @@ impl UserRepository {
token: &str, token: &str,
expires_at: DateTime<Utc>, expires_at: DateTime<Utc>,
) -> Result<(), sqlx::Error> { ) -> Result<(), sqlx::Error> {
sqlx::query!( sqlx::query(
r#" r#"
UPDATE users UPDATE users
SET email_verification_token = $1, email_verification_expires_at = $2, updated_at = NOW() SET email_verification_token = $1, email_verification_expires_at = $2, updated_at = NOW()
WHERE id = $3 WHERE id = $3
"#, "#,
token,
expires_at,
user_id
) )
.bind(token)
.bind(expires_at)
.bind(user_id)
.execute(pool) .execute(pool)
.await?; .await?;
Ok(()) Ok(())
} }
pub async fn get_by_verification_token(pool: &PgPool, token: &str) -> Result<User, sqlx::Error> { pub async fn get_by_verification_token(pool: &PgPool, token: &str) -> Result<User, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, User>(
User,
r#" r#"
SELECT id, email, password_hash, full_name, phone, SELECT id, email, password_hash, full_name, phone,
email_verified, phone_verified, status, email_verified, phone_verified, status,
@ -160,17 +156,17 @@ impl UserRepository {
FROM users FROM users
WHERE email_verification_token = $1 AND deleted_at IS NULL WHERE email_verification_token = $1 AND deleted_at IS NULL
"#, "#,
token
) )
.bind(token)
.fetch_one(pool) .fetch_one(pool)
.await .await
} }
pub async fn set_email_verified(pool: &PgPool, user_id: Uuid) -> Result<(), sqlx::Error> { pub async fn set_email_verified(pool: &PgPool, user_id: Uuid) -> Result<(), sqlx::Error> {
sqlx::query!( sqlx::query(
"UPDATE users SET email_verified = true, email_verification_token = NULL, email_verification_expires_at = NULL, updated_at = NOW() WHERE id = $1", "UPDATE users SET email_verified = true, email_verification_token = NULL, email_verification_expires_at = NULL, updated_at = NOW() WHERE id = $1",
user_id
) )
.bind(user_id)
.execute(pool) .execute(pool)
.await?; .await?;
Ok(()) Ok(())
@ -182,24 +178,23 @@ impl UserRepository {
token: &str, token: &str,
expires_at: DateTime<Utc>, expires_at: DateTime<Utc>,
) -> Result<(), sqlx::Error> { ) -> Result<(), sqlx::Error> {
sqlx::query!( sqlx::query(
r#" r#"
UPDATE users UPDATE users
SET reset_password_token = $1, reset_password_expires_at = $2, updated_at = NOW() SET reset_password_token = $1, reset_password_expires_at = $2, updated_at = NOW()
WHERE id = $3 WHERE id = $3
"#, "#,
token,
expires_at,
user_id
) )
.bind(token)
.bind(expires_at)
.bind(user_id)
.execute(pool) .execute(pool)
.await?; .await?;
Ok(()) Ok(())
} }
pub async fn get_by_reset_token(pool: &PgPool, token: &str) -> Result<User, sqlx::Error> { pub async fn get_by_reset_token(pool: &PgPool, token: &str) -> Result<User, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, User>(
User,
r#" r#"
SELECT id, email, password_hash, full_name, phone, SELECT id, email, password_hash, full_name, phone,
email_verified, phone_verified, status, email_verified, phone_verified, status,
@ -209,39 +204,39 @@ impl UserRepository {
FROM users FROM users
WHERE reset_password_token = $1 AND deleted_at IS NULL WHERE reset_password_token = $1 AND deleted_at IS NULL
"#, "#,
token
) )
.bind(token)
.fetch_one(pool) .fetch_one(pool)
.await .await
} }
pub async fn clear_reset_token(pool: &PgPool, user_id: Uuid) -> Result<(), sqlx::Error> { pub async fn clear_reset_token(pool: &PgPool, user_id: Uuid) -> Result<(), sqlx::Error> {
sqlx::query!( sqlx::query(
"UPDATE users SET reset_password_token = NULL, reset_password_expires_at = NULL, updated_at = NOW() WHERE id = $1", "UPDATE users SET reset_password_token = NULL, reset_password_expires_at = NULL, updated_at = NOW() WHERE id = $1",
user_id
) )
.bind(user_id)
.execute(pool) .execute(pool)
.await?; .await?;
Ok(()) Ok(())
} }
pub async fn update_password(pool: &PgPool, user_id: Uuid, password_hash: &str) -> Result<(), sqlx::Error> { pub async fn update_password(pool: &PgPool, user_id: Uuid, password_hash: &str) -> Result<(), sqlx::Error> {
sqlx::query!( sqlx::query(
"UPDATE users SET password_hash = $1, updated_at = NOW() WHERE id = $2", "UPDATE users SET password_hash = $1, updated_at = NOW() WHERE id = $2",
password_hash,
user_id
) )
.bind(password_hash)
.bind(user_id)
.execute(pool) .execute(pool)
.await?; .await?;
Ok(()) Ok(())
} }
pub async fn update_status(pool: &PgPool, user_id: Uuid, status: &str) -> Result<(), sqlx::Error> { pub async fn update_status(pool: &PgPool, user_id: Uuid, status: &str) -> Result<(), sqlx::Error> {
sqlx::query!( sqlx::query(
"UPDATE users SET status = $1, updated_at = NOW() WHERE id = $2", "UPDATE users SET status = $1, updated_at = NOW() WHERE id = $2",
status,
user_id
) )
.bind(status)
.bind(user_id)
.execute(pool) .execute(pool)
.await?; .await?;
Ok(()) Ok(())
@ -253,17 +248,16 @@ impl UserRepository {
token_hash: &str, token_hash: &str,
expires_at: DateTime<Utc>, expires_at: DateTime<Utc>,
) -> Result<RefreshToken, sqlx::Error> { ) -> Result<RefreshToken, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, RefreshToken>(
RefreshToken,
r#" r#"
INSERT INTO refresh_tokens (user_id, token_hash, expires_at) INSERT INTO refresh_tokens (user_id, token_hash, expires_at)
VALUES ($1, $2, $3) VALUES ($1, $2, $3)
RETURNING id, user_id, token_hash, expires_at, revoked, created_at RETURNING id, user_id, token_hash, expires_at, revoked, created_at
"#, "#,
user_id,
token_hash,
expires_at
) )
.bind(user_id)
.bind(token_hash)
.bind(expires_at)
.fetch_one(pool) .fetch_one(pool)
.await .await
} }
@ -272,8 +266,7 @@ impl UserRepository {
pool: &PgPool, pool: &PgPool,
token_hash: &str, token_hash: &str,
) -> Result<RefreshToken, sqlx::Error> { ) -> Result<RefreshToken, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, RefreshToken>(
RefreshToken,
r#" r#"
SELECT id, user_id, token_hash, expires_at, revoked, created_at SELECT id, user_id, token_hash, expires_at, revoked, created_at
FROM refresh_tokens FROM refresh_tokens
@ -281,27 +274,27 @@ impl UserRepository {
AND revoked = false AND revoked = false
AND expires_at > NOW() AND expires_at > NOW()
"#, "#,
token_hash
) )
.bind(token_hash)
.fetch_one(pool) .fetch_one(pool)
.await .await
} }
pub async fn revoke_refresh_token(pool: &PgPool, token_hash: &str) -> Result<(), sqlx::Error> { pub async fn revoke_refresh_token(pool: &PgPool, token_hash: &str) -> Result<(), sqlx::Error> {
sqlx::query!( sqlx::query(
"UPDATE refresh_tokens SET revoked = true WHERE token_hash = $1", "UPDATE refresh_tokens SET revoked = true WHERE token_hash = $1",
token_hash
) )
.bind(token_hash)
.execute(pool) .execute(pool)
.await?; .await?;
Ok(()) Ok(())
} }
pub async fn revoke_all_for_user(pool: &PgPool, user_id: Uuid) -> Result<(), sqlx::Error> { pub async fn revoke_all_for_user(pool: &PgPool, user_id: Uuid) -> Result<(), sqlx::Error> {
sqlx::query!( sqlx::query(
"UPDATE refresh_tokens SET revoked = true WHERE user_id = $1", "UPDATE refresh_tokens SET revoked = true WHERE user_id = $1",
user_id
) )
.bind(user_id)
.execute(pool) .execute(pool)
.await?; .await?;
Ok(()) Ok(())

View file

@ -28,19 +28,19 @@ pub struct VideoEditorRepository;
impl VideoEditorRepository { impl VideoEditorRepository {
pub async fn get_by_user_id(pool: &PgPool, user_id: Uuid) -> Result<Option<VideoEditorProfile>, sqlx::Error> { pub async fn get_by_user_id(pool: &PgPool, user_id: Uuid) -> Result<Option<VideoEditorProfile>, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, VideoEditorProfile>(
VideoEditorProfile,
r#"SELECT id, user_id, display_name, bio, location, r#"SELECT id, user_id, display_name, bio, location,
custom_data, custom_data,
status, created_at, updated_at status, created_at, updated_at
FROM video_editor_profiles WHERE user_id = $1"#, FROM video_editor_profiles WHERE user_id = $1"#,
user_id )
).fetch_optional(pool).await .bind(user_id)
.fetch_optional(pool)
.await
} }
pub async fn upsert(pool: &PgPool, user_id: Uuid, p: UpsertVideoEditorProfilePayload) -> Result<VideoEditorProfile, sqlx::Error> { pub async fn upsert(pool: &PgPool, user_id: Uuid, p: UpsertVideoEditorProfilePayload) -> Result<VideoEditorProfile, sqlx::Error> {
sqlx::query_as!( sqlx::query_as::<_, VideoEditorProfile>(
VideoEditorProfile,
r#"INSERT INTO video_editor_profiles (user_id, display_name, bio, location, custom_data) r#"INSERT INTO video_editor_profiles (user_id, display_name, bio, location, custom_data)
VALUES ($1, $2, $3, $4, $5) VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (user_id) DO UPDATE SET ON CONFLICT (user_id) DO UPDATE SET
@ -52,7 +52,13 @@ impl VideoEditorRepository {
RETURNING id, user_id, display_name, bio, location, RETURNING id, user_id, display_name, bio, location,
custom_data, custom_data,
status, created_at, updated_at"#, status, created_at, updated_at"#,
user_id, p.display_name, p.bio, p.location, p.custom_data )
).fetch_one(pool).await .bind(user_id)
.bind(p.display_name)
.bind(p.bio)
.bind(p.location)
.bind(p.custom_data)
.fetch_one(pool)
.await
} }
} }