refactor: migrate sqlx macro queries to query_as and standard query methods for improved type flexibility in certificate handlers

This commit is contained in:
2026-04-14 14:09:37 -04:00
parent c21942983a
commit caa578a280
@@ -39,6 +39,17 @@ pub struct IssueCertificateRequest {
pub force_reissue: Option<bool>, // Para re-emitir si ya existe pub force_reissue: Option<bool>, // Para re-emitir si ya existe
} }
#[derive(sqlx::FromRow)]
struct CertificateRecord {
id: Uuid,
user_id: Uuid,
course_id: Uuid,
certificate_html: String,
issued_at: chrono::DateTime<chrono::Utc>,
verification_code: String,
metadata: serde_json::Value,
}
// ============= Handlers ============= // ============= Handlers =============
/// GET /courses/{id}/certificate /// GET /courses/{id}/certificate
@@ -52,12 +63,12 @@ pub async fn get_certificate(
let user_id = claims.sub; let user_id = claims.sub;
// 1. Verificar si la organización tiene certificados habilitados // 1. Verificar si la organización tiene certificados habilitados
let org_certificates_enabled = sqlx::query!( let org_certificates_enabled = sqlx::query(
"SELECT certificates_enabled FROM organizations WHERE id = ( "SELECT certificates_enabled FROM organizations WHERE id = (
SELECT organization_id FROM courses WHERE id = $1 SELECT organization_id FROM courses WHERE id = $1
)", )"
course_id
) )
.bind(course_id)
.fetch_optional(&pool) .fetch_optional(&pool)
.await .await
.map_err(|e| { .map_err(|e| {
@@ -81,7 +92,7 @@ pub async fn get_certificate(
} }
// 2. Verificar si ya existe un certificado emitido // 2. Verificar si ya existe un certificado emitido
let existing_cert = sqlx::query!( let existing_cert = sqlx::query_as::<_, CertificateRecord>(
r#" r#"
SELECT SELECT
ic.id, ic.id,
@@ -93,10 +104,10 @@ pub async fn get_certificate(
ic.metadata ic.metadata
FROM issued_certificates ic FROM issued_certificates ic
WHERE ic.user_id = $1 AND ic.course_id = $2 WHERE ic.user_id = $1 AND ic.course_id = $2
"#, "#
user_id,
course_id
) )
.bind(user_id)
.bind(course_id)
.fetch_optional(&pool) .fetch_optional(&pool)
.await .await
.map_err(|e| { .map_err(|e| {
@@ -516,23 +527,24 @@ async fn issue_certificate_internal(
"organization_id": course_data.organization_id.to_string(), "organization_id": course_data.organization_id.to_string(),
}); });
let issued_cert = sqlx::query!( use sqlx::Row;
let issued_cert = sqlx::query(
r#" r#"
INSERT INTO issued_certificates INSERT INTO issued_certificates
(user_id, course_id, certificate_html, certificate_hash, verification_code, metadata) (user_id, course_id, certificate_html, certificate_hash, verification_code, metadata)
VALUES ($1, $2, $3, $4, $5, $6) VALUES ($1, $2, $3, $4, $5, $6)
RETURNING id, issued_at RETURNING id, issued_at
"#, "#
user_id,
course_id,
certificate_html,
certificate_hash,
verification_code,
metadata
) )
.bind(user_id)
.bind(course_id)
.bind(certificate_html)
.bind(certificate_hash)
.bind(verification_code)
.bind(metadata)
.fetch_one(pool) .fetch_one(pool)
.await .await
.map_err(|e| { .map_err(|e: sqlx::Error| {
tracing::error!("Error al emitir certificado: {}", e); tracing::error!("Error al emitir certificado: {}", e);
// Manejar unique constraint violation // Manejar unique constraint violation
if e.to_string().contains("issued_certificates_user_course_unique") { if e.to_string().contains("issued_certificates_user_course_unique") {
@@ -548,13 +560,13 @@ async fn issue_certificate_internal(
})?; })?;
Ok(Json(CertificateResponse { Ok(Json(CertificateResponse {
id: issued_cert.id, id: issued_cert.get("id"),
user_id, user_id,
course_id, course_id,
course_title: course_data.title, course_title: course_data.title,
student_name: user_name, student_name: user_name,
certificate_html, certificate_html,
issued_at: issued_cert.issued_at.to_string(), issued_at: issued_cert.get::<chrono::DateTime<chrono::Utc>, _>("issued_at").to_string(),
verification_code, verification_code,
metadata, metadata,
})) }))