use crate::{datasources::projects::ProjectsDatasource, state::AppState, utils::datetime::*}; use axum::{extract::State, http::StatusCode, response::IntoResponse, routing::get, Json, Router}; use cache::Expiration; use serde::{Deserialize, Serialize}; #[derive(sqlx::FromRow, Deserialize, Serialize, Debug, Clone)] pub struct Project { pub project_id: i32, pub title: String, pub repo: Option, pub summary: String, pub tech: String, pub wip: Option, #[serde(serialize_with = "serialize_datetime")] #[serde(deserialize_with = "deserialize_datetime")] pub created_at: Option>, } pub struct ProjectsRoute; impl ProjectsRoute { pub fn routes(app_state: &AppState) -> Router { Router::new() .route("/", get(ProjectsRoute::get_all)) .with_state(app_state.clone()) } async fn get_all(State(app_state): State) -> impl IntoResponse { let mut state = app_state.lock().await; let cached: Option> = state .cache .get(String::from("projects:all")) .await .unwrap_or(None); if let Some(projects) = cached { tracing::info!("grabbing all projects from cache"); return Ok(Json(projects)); }; match ProjectsDatasource::get_all(&state.database).await { Ok(projects) => { tracing::info!("grabbing all projects from database"); if let p = &projects { let projects = p.clone(); let state = app_state.clone(); tracing::info!("storing database data in cache"); tokio::spawn(async move { let mut s = state.lock().await; let _ = s .cache .set( String::from("projects:all"), &projects, Some(Expiration::EX(10)), None, false, ) .await; }); }; Ok(Json(projects)) } Err(e) => Err((StatusCode::INTERNAL_SERVER_ERROR, e.to_string())), } } }