diff --git a/backend/public/src/datasources/comments.rs b/backend/public/src/datasources/comments.rs index 8e1a2f6..a2c2194 100644 --- a/backend/public/src/datasources/comments.rs +++ b/backend/public/src/datasources/comments.rs @@ -1,8 +1,22 @@ -use crate::routes::comments::CommentInput; -use sqlx::PgPool; +use crate::routes::comments::{Comment, CommentInputPayload}; +use sqlx::{Pool, Postgres}; pub struct CommentsDatasource; impl CommentsDatasource { - pub async fn get_posts_comments(pool: PgPool) {} - pub async fn insert_comment(pool: PgPool, comment_input: CommentInput) {} + pub async fn get_posts_comments( + pool: &Pool, + post_id: i32, + ) -> Result, sqlx::Error> { + sqlx::query_as!(Comment, "SELECT c.comment_id, c.name, c.body, c.created_at FROM comments c LEFT JOIN posts p ON p.post_id = c.post_id WHERE p.post_id = $1 AND c.deleted_at IS NULL ORDER BY created_at DESC LIMIT 20", post_id) + .fetch_all(pool) + .await + } + pub async fn insert_comment( + pool: &Pool, + comment_input: CommentInputPayload, + ) -> Result { + sqlx::query!("INSERT INTO comments (post_id, name, body) VALUES ($1, $2, $3) RETURNING comment_id, name, body, created_at", comment_input.post_id, comment_input.name, comment_input.body) + .fetch_one(pool) + .await + } } diff --git a/backend/public/src/main.rs b/backend/public/src/main.rs index 8473f1d..b9cfa46 100644 --- a/backend/public/src/main.rs +++ b/backend/public/src/main.rs @@ -55,7 +55,7 @@ async fn main() { ) .init(); - if std::env::var("RUST_ENV").expect("development") != "development" { + if std::env::var("RUST_ENV").unwrap_or_else(|_| "development".to_string()) != "development" { println!("we're not in development, starting up the rate limiter"); let governor_conf = Arc::new( GovernorConfigBuilder::default() @@ -97,11 +97,11 @@ async fn main() { TraceLayer::new_for_http() .make_span_with(trace::DefaultMakeSpan::new().level(tracing::Level::INFO)) .on_response(trace::DefaultOnResponse::new().level(tracing::Level::INFO)), + ) + .nest( + "/comments", + routes::comments::CommentsRoute::routes(&app_state), ); - // .nest( - // "/comments", - // routes::comments::CommentsRoute::routes(&app_state), - // ); // run it with hyper let listener = TcpListener::bind("0.0.0.0:3000").await.unwrap(); diff --git a/backend/public/src/routes/comments.rs b/backend/public/src/routes/comments.rs index cb38f74..845c25b 100644 --- a/backend/public/src/routes/comments.rs +++ b/backend/public/src/routes/comments.rs @@ -1,17 +1,35 @@ +use super::posts::serialize_datetime; use crate::{datasources::comments::CommentsDatasource, AppState}; use axum::{ - extract::{Form, State}, + extract::{Form, Path, State}, + http::StatusCode, + response::IntoResponse, routing::{get, post}, Json, }; -use serde::Deserialize; -use sqlx::PgPool; +use chrono::Utc; +use serde::{Deserialize, Serialize}; +use sqlx::{Pool, Postgres}; #[derive(Deserialize, Debug)] -pub struct CommentInput { - name: String, - body: String, - post_id: i32, +pub struct CommentInputPayload { + pub name: String, + pub body: String, + pub post_id: i32, +} + +#[derive(Deserialize)] +pub struct CommentPathParams { + id: i32, +} + +#[derive(sqlx::FromRow, Serialize, Debug)] +pub struct Comment { + pub comment_id: i32, + pub name: String, + pub body: String, + #[serde(serialize_with = "serialize_datetime")] + pub created_at: Option>, } pub struct CommentsRoute; @@ -19,21 +37,28 @@ impl CommentsRoute { pub fn routes(app_state: &AppState) -> axum::Router { // add more comment routes here! axum::Router::new() - // .route("/post/:id", get(CommentsRoute::get_post_comments)) - // .route("/add", post(CommentsRoute::insert_comment)) + .route("/post/:id", get(CommentsRoute::get_post_comments)) + .route("/add", post(CommentsRoute::insert_comment)) .with_state(app_state.db.clone()) } - // async fn get_post_comments(State(pool): State) -> Json<()> { - // let results = CommentsDatasource::get_posts_comments(pool).await; - // Json {} - // } + async fn get_post_comments( + State(pool): State>, + Path(params): Path, + ) -> impl IntoResponse { + match CommentsDatasource::get_posts_comments(&pool, params.id).await { + Ok(c) => Ok(Json(c)), + Err(e) => Err((StatusCode::INTERNAL_SERVER_ERROR, e.to_string())), + } + } // - // async fn insert_comment( - // State(pool): State, - // Form(comment_input): Form, - // ) -> bool { - // let results = CommentsDatasource::insert_comment(pool, comment_input).await; - // true - // } + async fn insert_comment( + State(pool): State>, + Json(comment_input): Json, + ) -> impl IntoResponse { + match CommentsDatasource::insert_comment(&pool, comment_input).await { + Ok(c) => Ok((StatusCode::CREATED, Json(c))), + Err(e) => Err((StatusCode::INTERNAL_SERVER_ERROR, e.to_string())), + } + } } diff --git a/backend/public/src/routes/posts.rs b/backend/public/src/routes/posts.rs index 5210cbd..4cce044 100644 --- a/backend/public/src/routes/posts.rs +++ b/backend/public/src/routes/posts.rs @@ -74,7 +74,7 @@ impl PostsRoute { } } -fn serialize_datetime( +pub fn serialize_datetime( date: &Option>, serializer: S, ) -> Result