implement tag DB functions
This commit is contained in:
parent
6e428b4b97
commit
132906b548
@ -2,47 +2,38 @@
|
|||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct Answer {
|
pub struct NewAnswer {
|
||||||
content: String,
|
pub content: String,
|
||||||
question_id: u8,
|
pub question_id: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Answer {
|
impl NewAnswer {
|
||||||
pub fn _new(_id: u8, content: String, question_id: u8) -> Self {
|
pub fn _new(content: String, question_id: u8) -> Self {
|
||||||
Answer {
|
NewAnswer {
|
||||||
content,
|
content,
|
||||||
question_id,
|
question_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn to_dto(&self, id: u8) -> AnswerDTO {
|
|
||||||
AnswerDTO {
|
|
||||||
id,
|
|
||||||
content: self.content.clone(),
|
|
||||||
question_id: self.question_id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||||
pub struct AnswerDTO {
|
pub struct Answer {
|
||||||
id: u8,
|
id: u8,
|
||||||
content: String,
|
content: String,
|
||||||
question_id: u8,
|
question_id: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Answer Data Transfer Object, a representation of the expected serialized JSON formated of answer regarding requests, responses, and our answer json file
|
/// Answer Data Transfer Object, a representation of the expected serialized JSON formated of answer regarding requests, responses, and our answer json file
|
||||||
impl AnswerDTO {
|
impl Answer {
|
||||||
pub fn to_entity(&self) -> (u8, Answer) {
|
pub fn new(id: u8, content: String, question_id: u8) -> Self {
|
||||||
(
|
Answer {
|
||||||
self.id,
|
id,
|
||||||
Answer {
|
content,
|
||||||
content: self.content.clone(),
|
question_id,
|
||||||
question_id: self.question_id,
|
}
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl IntoResponse for &AnswerDTO {
|
impl IntoResponse for &Answer {
|
||||||
fn into_response(self) -> Response {
|
fn into_response(self) -> Response {
|
||||||
(StatusCode::OK, Json(&self)).into_response()
|
(StatusCode::OK, Json(&self)).into_response()
|
||||||
}
|
}
|
||||||
|
27
src/api.rs
27
src/api.rs
@ -1,6 +1,6 @@
|
|||||||
/// All API route handlers of the application
|
/// All API route handlers of the application
|
||||||
use self::{
|
use self::{
|
||||||
answer::AnswerDTO,
|
answer::NewAnswer,
|
||||||
pg_store::Store,
|
pg_store::Store,
|
||||||
question::{NewQuestion, Question, QuestionDTO},
|
question::{NewQuestion, Question, QuestionDTO},
|
||||||
};
|
};
|
||||||
@ -99,19 +99,19 @@ 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 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
|
/// Http Unprocessable Entity 422 is returned (implicitlly) for a malformed body
|
||||||
pub async fn update_question(
|
pub async fn update_question(
|
||||||
State(store): State<Arc<RwLock<Store>>>,
|
State(_store): State<Arc<RwLock<Store>>>,
|
||||||
Json(question): Json<Question>,
|
Json(_question): Json<Question>,
|
||||||
) -> Response {
|
) -> Response {
|
||||||
// Step 0: Update the question entry
|
// Step 0: Update the question entry
|
||||||
// Step 1: Fetch the question_tags for the given tags
|
// Step 1: Fetch the question_tags for the given tags
|
||||||
// Step 2: Fetch the tags for the given question tags
|
// Step 2: Fetch the tags for the given question tags
|
||||||
// Step 3: new_tags_labels = list of tag labels not already on question
|
// Step 3: new_tags_labels = list of tag labels not already on question
|
||||||
// Step 3a: Fetch existing_new_tag as tags which already by given name exist, but do not yet have a question_tag association
|
// Step 3a: Fetch existing_new_tag as tags which already by given name exist, but do not yet have a question_tag association
|
||||||
// Step 3b: Create question_tag association for 3a
|
// Step 3b: Create question_tag association for 3a
|
||||||
// Step 3c: Create new tags which do not already exist
|
// Step 3c: Create new tags which do not already exist
|
||||||
// Step 3d: Create question_tag association for 3c
|
// Step 3d: Create question_tag association for 3c
|
||||||
// Step 4: remove_tag_labls = list of tag labs which should no longer have a question_tag association with the question
|
// Step 4: remove_tag_labls = list of tag labs which should no longer have a question_tag association with the question
|
||||||
// Step 4a: Fetch existing_old_tags as tags by given na
|
// Step 4a: Fetch existing_old_tags as tags by given na
|
||||||
|
|
||||||
// match store.write().await.update_question(question) {
|
// match store.write().await.update_question(question) {
|
||||||
// Ok(question) => question.into_response(),
|
// Ok(question) => question.into_response(),
|
||||||
@ -130,8 +130,8 @@ pub async fn delete_question(
|
|||||||
State(store): State<Arc<RwLock<Store>>>,
|
State(store): State<Arc<RwLock<Store>>>,
|
||||||
Path(id): Path<u8>,
|
Path(id): Path<u8>,
|
||||||
) -> Response {
|
) -> Response {
|
||||||
match store.write().await.remove_question(id) {
|
match store.write().await.remove_question(id).await {
|
||||||
Ok(question) => question.into_response(),
|
Ok(_) => (StatusCode::OK, format!("Question with id {} deleted", id)).into_response(),
|
||||||
Err(e) => (StatusCode::NOT_FOUND, e).into_response(),
|
Err(e) => (StatusCode::NOT_FOUND, e).into_response(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -145,11 +145,10 @@ pub async fn delete_question(
|
|||||||
/// Status Unprocessable Entity 422 is returned (implicitlly) for a malformed body
|
/// Status Unprocessable Entity 422 is returned (implicitlly) for a malformed body
|
||||||
pub async fn create_answer(
|
pub async fn create_answer(
|
||||||
State(store): State<Arc<RwLock<Store>>>,
|
State(store): State<Arc<RwLock<Store>>>,
|
||||||
Form(answer_dto): Form<AnswerDTO>,
|
Form(new_answer): Form<NewAnswer>,
|
||||||
) -> Response {
|
) -> Response {
|
||||||
let (id, answer) = answer_dto.to_entity();
|
match store.write().await.add_answer(new_answer).await {
|
||||||
match store.write().await.add_answer(id, answer) {
|
Ok(answer) => (StatusCode::CREATED, Json(answer)).into_response(),
|
||||||
Ok(answer) => (StatusCode::CREATED, Json(&answer.to_dto(id))).into_response(),
|
|
||||||
Err(e) => (StatusCode::CONFLICT, e).into_response(),
|
Err(e) => (StatusCode::CONFLICT, e).into_response(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use answer::NewAnswer;
|
||||||
|
|
||||||
/// Store is responsible for manageing the in-memory hashmap of questions by providing initialization read/write functions,
|
/// Store is responsible for manageing the in-memory hashmap of questions by providing initialization read/write functions,
|
||||||
/// and file I/O operations to persist these questions
|
/// and file I/O operations to persist these questions
|
||||||
/// TODO - Results returning errors should use specified types, not strings
|
/// TODO - Results returning errors should use specified types, not strings
|
||||||
@ -125,8 +127,15 @@ impl Store {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_question(&mut self, _id: u8) -> Result<Question, String> {
|
pub async fn remove_question(&mut self, id: u8) -> Result<bool, String> {
|
||||||
Err("To Do".to_string())
|
let result = sqlx::query("DELETE FROM questions WHERE id = $1")
|
||||||
|
.bind(id.to_string())
|
||||||
|
.execute(&self.connection)
|
||||||
|
.await;
|
||||||
|
match result {
|
||||||
|
Ok(_) => Ok(true),
|
||||||
|
Err(e) => Err(e.to_string()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn fetch_one_question_by_id(&self, id: u8) -> Option<Question> {
|
pub async fn fetch_one_question_by_id(&self, id: u8) -> Option<Question> {
|
||||||
@ -169,28 +178,57 @@ impl Store {
|
|||||||
|
|
||||||
/// Remove tags from tags table, which have no question tag association
|
/// Remove tags from tags table, which have no question tag association
|
||||||
/// Returns true if any tags were removed, false otherwise
|
/// Returns true if any tags were removed, false otherwise
|
||||||
pub fn remove_orphan_tags(&mut self){
|
pub async fn _remove_orphan_tags(&mut self) -> Result<bool, String> {
|
||||||
todo!()
|
let result = sqlx::query(
|
||||||
|
"DELETE FROM tags where id NOT IN (SELECT DISTINCT tag_id from question_tag)",
|
||||||
|
)
|
||||||
|
.execute(&self.connection)
|
||||||
|
.await;
|
||||||
|
match result {
|
||||||
|
Ok(_) => Ok(true),
|
||||||
|
Err(e) => Err(e.to_string()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates passed in tag labels in the tags table, only if they do not already exists
|
/// Creates passed in tag labels in the tags table, only if they do not already exists
|
||||||
/// Returns list of all tags from passed in labels, regardless of if they already existed
|
/// Returns list of all tags from passed in labels, regardless of if they already existed
|
||||||
pub fn add_tags_if_not_exists(&mut self, tags_labels: Vec<String>){
|
pub fn _add_tags_if_not_exists(&mut self, _tags_labels: Vec<String>) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pub fn sync_question_tags(&mut self, tags: Vec<Tag>){
|
pub fn _sync_question_tags(&mut self, _tags: Vec<Tag>) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn _update_question(&mut self, question: Question) -> Result<Question, String> {
|
||||||
|
let result = sqlx::query("UPDATE questions SET title = $1 AND SET content = $2 WHERE id = $3 RETURNING id, title, content")
|
||||||
pub fn update_question(&mut self, _question: Question) -> Result<Question, String> {
|
.bind(question.title).bind(question.content).bind(question.id.to_string())
|
||||||
todo!()
|
.fetch_one(&self.connection).await;
|
||||||
|
match result {
|
||||||
|
Ok(pg_row) => Ok(Question::new(
|
||||||
|
Store::id_to_u8(&pg_row, "id"),
|
||||||
|
pg_row.get("title"),
|
||||||
|
pg_row.get("content"),
|
||||||
|
)),
|
||||||
|
Err(e) => Err(e.to_string()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_answer(&mut self, _id: u8, _answer: Answer) -> Result<Answer, String> {
|
pub async fn add_answer(&mut self, new_answer: NewAnswer) -> Result<Answer, String> {
|
||||||
todo!()
|
let result =
|
||||||
|
sqlx::query("INSERT INTO answers VALUES ($1,$2) RETURNING id, content, question_id")
|
||||||
|
.bind(new_answer.content)
|
||||||
|
.bind(new_answer.question_id.to_string())
|
||||||
|
.fetch_one(&self.connection)
|
||||||
|
.await;
|
||||||
|
match result {
|
||||||
|
Ok(pg_row) => Ok(Answer::new(
|
||||||
|
Store::id_to_u8(&pg_row, "id"),
|
||||||
|
pg_row.get("content"),
|
||||||
|
Store::id_to_u8(&pg_row, "question_id"),
|
||||||
|
)),
|
||||||
|
Err(e) => Err(e.to_string()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user