diff --git a/src/api.rs b/src/api.rs index 74346b2..e0be6b9 100644 --- a/src/api.rs +++ b/src/api.rs @@ -2,7 +2,7 @@ use self::{ answer::NewAnswer, pg_store::Store, - question::{NewQuestion, Question, QuestionDTO}, + question::{NewQuestion, QuestionDTO}, }; use crate::*; const DEFAULT_PAGE: usize = 0; @@ -85,6 +85,7 @@ pub async fn create_question( } /// Updates an existing question +/// TODO: Better handle errors, responses in the tag updating flow - it is getting complex /// # Parameters /// `QuestionDTO` A JSON representation of a Question including its id /// # Returns @@ -92,10 +93,55 @@ pub async fn create_question( /// Http Not Found 404 and a message are returned if a question with that `id` does not already exist /// Http Unprocessable Entity 422 is returned (implicitlly) for a malformed body pub async fn update_question( - State(_store): State>>, - Json(_question): Json, + State(store): State>>, + Json(question): Json, ) -> Response { - todo!() + // 1: Update the question entity + let updated_question_result = store + .write() + .await + .update_question(question.id, question.title, question.content) + .await; + match updated_question_result { + Ok(updated_question) => { + // 2: Get the list of tags currently associated with this question + let current_tags_option = store + .read() + .await + .get_tags_for_question(updated_question.id) + .await; + match current_tags_option { + Some(current_tags) => { + let incoming_tag_labels = question.tags; + // Create (ignored if they already exist, new tags for the incoming tags) + let incoming_tags = store + .write() + .await + .add_tags(incoming_tag_labels) + .await + .unwrap(); + // Unassociated all current tags with this question + let _remove_tags = store + .write() + .await + .unassociate_tags(updated_question.id, current_tags) + .await + .unwrap(); + // Associated all of the incoming tags (now newly created if needed) with the question + let _updated_tags = store + .write() + .await + .associate_tags(updated_question.id, &incoming_tags) + .await + .unwrap(); + //Return the updated question with the updated tags + QuestionDTO::new(updated_question, incoming_tags).into_response() + } + None => (StatusCode::OK).into_response(), + } + } + Err(e) => (StatusCode::CONFLICT, e).into_response(), + } } /// Delete an existing question diff --git a/src/main.rs b/src/main.rs index 8472092..c6a1619 100644 --- a/src/main.rs +++ b/src/main.rs @@ -43,7 +43,7 @@ async fn serve_file(uri: Uri) -> impl IntoResponse { Err(_) => (StatusCode::INTERNAL_SERVER_ERROR, "Server Error").into_response(), } } - Err(_) => (StatusCode::NOT_FOUND, "404 Not Found").into_response(), + Err(_) => handler_404().await, } } diff --git a/src/pg_store.rs b/src/pg_store.rs index fe1187a..4dc016b 100644 --- a/src/pg_store.rs +++ b/src/pg_store.rs @@ -156,7 +156,7 @@ impl Store { // Takes a question id and a list of tags, and remove any existing question_tag join associations // Ignores if an association does not already exist // Returns Ok(true) on success - pub async fn _unassociate_tags( + pub async fn unassociate_tags( &mut self, question_id: u8, tags: Vec, @@ -330,9 +330,14 @@ impl Store { } //Update a question entity - just the question details (not tags) - pub async fn _update_question(&mut self, question: Question) -> Result { + pub async fn update_question( + &mut self, + id: u8, + title: String, + content: String, + ) -> Result { let result = sqlx::query("UPDATE questions SET title = $1 AND SET content = $2 WHERE id = $3 RETURNING id, title, content") - .bind(question.title).bind(question.content).bind(question.id.to_string()) + .bind(title).bind(content).bind(id.to_string()) .fetch_one(&self.connection).await; match result { Ok(pg_row) => Ok(Question::new(