Skip to content

Commit

Permalink
refactor: reduced duplication in db types
Browse files Browse the repository at this point in the history
  • Loading branch information
harshkhandeparkar committed Jan 11, 2025
1 parent 5a89942 commit 5a245ef
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 56 deletions.
30 changes: 15 additions & 15 deletions backend/src/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ impl Database {
query: &str,
exam_filter: ExamFilter,
exam_filter_str: String,
) -> Result<Vec<qp::SearchQP>, sqlx::Error> {
) -> Result<Vec<qp::BaseQP>, sqlx::Error> {
let (query_sql, use_exam_arg) = queries::get_qp_search_query(exam_filter);
let query = sqlx::query_as(&query_sql).bind(query);

Expand All @@ -80,11 +80,11 @@ impl Database {
query
};

let papers: Vec<models::DBSearchQP> = query.fetch_all(&self.connection).await?;
let papers: Vec<models::DBBaseQP> = query.fetch_all(&self.connection).await?;

Ok(papers
.iter()
.map(|qp| qp::SearchQP::from(qp.clone()))
.map(|qp| qp::BaseQP::from(qp.clone()))
.collect())
}

Expand Down Expand Up @@ -125,24 +125,24 @@ impl Database {
let current_details = self.get_paper_by_id(id).await?;

// Construct the final values to be inserted into the db
let course_code = course_code.unwrap_or(current_details.course_code);
let course_name = course_name.unwrap_or(current_details.course_name);
let year = year.unwrap_or(current_details.year);
let course_code = course_code.unwrap_or(current_details.qp.course_code);
let course_name = course_name.unwrap_or(current_details.qp.course_name);
let year = year.unwrap_or(current_details.qp.year);
let semester: String = semester
.map(|sem| Semester::try_from(&sem))
.transpose()?
.unwrap_or(current_details.semester)
.unwrap_or(current_details.qp.semester)
.into();
let exam: String = exam
.map(|exam| Exam::try_from(&exam))
.transpose()?
.unwrap_or(current_details.exam)
.unwrap_or(current_details.qp.exam)
.into();
let approve_status = approve_status.unwrap_or(current_details.approve_status);

// Set the new filelink
let old_filelink = current_details.filelink;
let new_filelink = if current_details.from_library {
let old_filelink = current_details.qp.filelink;
let new_filelink = if current_details.qp.from_library {
old_filelink.clone()
} else if approve_status {
env_vars.paths.get_slug(
Expand Down Expand Up @@ -186,9 +186,9 @@ impl Database {
Ok((tx, old_filelink, new_qp))
}

/// Adds a new upload paper's details to the database. Sets the `from_library` field to false.
///
/// Returns the database transaction and the id of the uploaded paper
// /// Adds a new upload paper's details to the database. Sets the `from_library` field to false.
// ///
// /// Returns the database transaction and the id of the uploaded paper
// pub async fn add_uploaded_paper<'c>(
// &self,
// file_details:
Expand Down Expand Up @@ -276,9 +276,9 @@ impl Database {
}

// /// Updates filelink for an uploaded question paper uploaded using the [crate::db::Database::update_uploaded_filelink] function. Takes the same transaction that the previous function used.
pub async fn update_uploaded_filelink<'c>(
pub async fn update_uploaded_filelink(
&self,
tx: &mut Transaction<'c, Postgres>,
tx: &mut Transaction<'_, Postgres>,
id: i32,
file_link: &str,
) -> Result<(), color_eyre::eyre::Error> {
Expand Down
27 changes: 7 additions & 20 deletions backend/src/db/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use super::qp;
use sqlx::{prelude::FromRow, types::chrono};

#[derive(FromRow, Clone)]
/// The fields of a question paper sent to the search endpoint
pub struct DBSearchQP {
/// Base/common fields of a question paper
pub struct DBBaseQP {
id: i32,
filelink: String,
from_library: bool,
Expand All @@ -25,37 +25,24 @@ pub struct DBSearchQP {
#[derive(FromRow, Clone)]
/// The fields of a question paper sent to the admin dashboard endpoint
pub struct DBAdminDashboardQP {
id: i32,
filelink: String,
from_library: bool,
course_code: String,
course_name: String,
year: i32,
semester: String,
exam: String,
#[sqlx(flatten)]
qp: DBBaseQP,
upload_timestamp: chrono::NaiveDateTime,
approve_status: bool,
}

impl From<DBAdminDashboardQP> for qp::AdminDashboardQP {
fn from(value: DBAdminDashboardQP) -> Self {
Self {
id: value.id,
filelink: value.filelink,
from_library: value.from_library,
course_code: value.course_code,
course_name: value.course_name,
year: value.year,
semester: (&value.semester).try_into().unwrap_or(Semester::Unknown),
exam: (&value.exam).try_into().unwrap_or(qp::Exam::Unknown),
qp: value.qp.into(),
upload_timestamp: value.upload_timestamp.to_string(),
approve_status: value.approve_status,
}
}
}

impl From<DBSearchQP> for qp::SearchQP {
fn from(value: DBSearchQP) -> Self {
impl From<DBBaseQP> for qp::BaseQP {
fn from(value: DBBaseQP) -> Self {
Self {
id: value.id,
filelink: value.filelink,
Expand Down
36 changes: 19 additions & 17 deletions backend/src/qp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,14 @@ impl Serialize for ExamSem {
}
}

pub trait WithUrl: Sized {
/// Returns the question paper with the full static files URL in the `filelink` field instead of just the slug. See the [`crate::pathutils`] module for what a slug is.
fn with_url(self, env_vars: &EnvVars) -> Result<Self, color_eyre::eyre::Error>;
}

#[derive(Serialize, Clone)]
/// The fields of a question paper sent from the search endpoint
pub struct SearchQP {
pub struct BaseQP {
pub id: i32,
pub filelink: String,
pub from_library: bool,
Expand All @@ -136,29 +141,26 @@ pub struct SearchQP {
///
/// This includes fields such as `approve_status` and `upload_timestamp` that would only be relevant to the dashboard.
pub struct AdminDashboardQP {
pub id: i32,
pub filelink: String,
pub from_library: bool,
pub course_code: String,
pub course_name: String,
pub year: i32,
pub semester: Semester,
pub exam: Exam,
#[serde(flatten)]
pub qp: BaseQP,
pub upload_timestamp: String,
pub approve_status: bool,
}

#[duplicate_item(
QP;
[ SearchQP ];
[ AdminDashboardQP ];
)]
impl QP {
/// Returns the question paper with the full static files URL in the `filelink` field instead of just the slug. See the [`crate::pathutils`] module for what a slug is.
pub fn with_url(self, env_vars: &EnvVars) -> Result<Self, color_eyre::eyre::Error> {
impl WithUrl for BaseQP {
fn with_url(self, env_vars: &EnvVars) -> Result<Self, color_eyre::eyre::Error> {
Ok(Self {
filelink: env_vars.paths.get_url_from_slug(&self.filelink)?,
..self
})
}
}

impl WithUrl for AdminDashboardQP {
fn with_url(self, env_vars: &EnvVars) -> Result<Self, color_eyre::eyre::Error> {
Ok(Self {
qp: self.qp.with_url(env_vars)?,
..self
})
}
}
8 changes: 4 additions & 4 deletions backend/src/routing/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use serde::Deserialize;
use crate::{
auth::{self, Auth},
pathutils::PaperCategory,
qp::{self, AdminDashboardQP},
qp::{self, AdminDashboardQP, WithUrl},
};

use super::{AppError, BackendResponse, RouterState, Status};
Expand Down Expand Up @@ -61,7 +61,7 @@ pub async fn get_unapproved(
pub async fn search(
State(state): State<RouterState>,
Query(params): Query<HashMap<String, String>>,
) -> HandlerReturn<Vec<qp::SearchQP>> {
) -> HandlerReturn<Vec<qp::BaseQP>> {
let response = if let Some(query) = params.get("query") {
let exam_query_str = params
.get("exam")
Expand All @@ -77,7 +77,7 @@ pub async fn search(
let papers = papers
.iter()
.map(|paper| paper.clone().with_url(&state.env_vars))
.collect::<Result<Vec<qp::SearchQP>, color_eyre::eyre::Error>>()?;
.collect::<Result<Vec<qp::BaseQP>, color_eyre::eyre::Error>>()?;

Ok(BackendResponse::ok(
format!("Successfully fetched {} papers.", papers.len()),
Expand Down Expand Up @@ -179,7 +179,7 @@ pub async fn edit(

// Copy the actual file
let old_filepath = state.env_vars.paths.get_path_from_slug(&old_filelink);
let new_filepath = state.env_vars.paths.get_path_from_slug(&new_qp.filelink);
let new_filepath = state.env_vars.paths.get_path_from_slug(&new_qp.qp.filelink);

if old_filepath != new_filepath {
if let Err(e) = fs::copy(old_filepath, new_filepath).await {
Expand Down

0 comments on commit 5a245ef

Please sign in to comment.