add answer entity and dto

This commit is contained in:
David Westgate 2024-04-27 13:17:57 -07:00
parent 26114a37b8
commit ff4b5c7fd6
4 changed files with 79 additions and 13 deletions

49
src/answer.rs Normal file
View File

@ -0,0 +1,49 @@
/// Contains struct definitions regarding answers
use crate::*;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Answer {
content: String,
question_id: u8,
}
impl Answer {
pub fn _new(_id: u8, content: String, question_id: u8) -> Self {
Answer {
content,
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)]
pub struct AnswerDTO {
id: u8,
content: String,
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
impl AnswerDTO {
pub fn to_entity(&self) -> (u8, Answer) {
(
self.id,
Answer {
content: self.content.clone(),
question_id: self.question_id,
},
)
}
}
impl IntoResponse for &AnswerDTO {
fn into_response(self) -> Response {
(StatusCode::OK, Json(&self)).into_response()
}
}

View File

@ -1,5 +1,5 @@
/// All API route handlers of the application /// All API route handlers of the application
use self::{question::QuestionDTO, store::Store}; use self::{answer::AnswerDTO, question::QuestionDTO, store::Store};
use crate::*; use crate::*;
const DEFAULT_PAGE: usize = 0; const DEFAULT_PAGE: usize = 0;
const DEFAULT_PAGE_SIZE: usize = 10; const DEFAULT_PAGE_SIZE: usize = 10;
@ -32,7 +32,11 @@ pub async fn read_questions(
let page: usize = pagination.page.unwrap_or(DEFAULT_PAGE); let page: usize = pagination.page.unwrap_or(DEFAULT_PAGE);
let size: usize = pagination.size.unwrap_or(DEFAULT_PAGE_SIZE); let size: usize = pagination.size.unwrap_or(DEFAULT_PAGE_SIZE);
let start: usize = page * size; let start: usize = page * size;
(StatusCode::OK, Json(store.read().await.fetch_many(start, size))).into_response() (
StatusCode::OK,
Json(store.read().await.fetch_many(start, size)),
)
.into_response()
} }
/// Creates a new question /// Creates a new question
@ -89,10 +93,14 @@ pub async fn delete_question(
Err(e) => (StatusCode::NOT_FOUND, e).into_response(), Err(e) => (StatusCode::NOT_FOUND, e).into_response(),
} }
} }
/// Create an Answer /// Create an Answer - WIP
/// # Parameters /// # Parameters
/// `answer_dto` Form URL encoded answer DTO
/// # Returns /// # Returns
pub async fn create_answer(State(_store): State<Arc<RwLock<Store>>> /*TODO */) -> Response { pub async fn create_answer(
State(_store): State<Arc<RwLock<Store>>>,
Form(_answer_dto): Form<AnswerDTO>,
) -> Response {
todo!() todo!()
} }
@ -101,4 +109,3 @@ pub async fn create_answer(State(_store): State<Arc<RwLock<Store>>> /*TODO */) -
page: Option<usize>, page: Option<usize>,
size: Option<usize>, size: Option<usize>,
} }

View File

@ -1,3 +1,4 @@
mod answer;
mod api; mod api;
mod question; mod question;
mod store; mod store;
@ -6,7 +7,7 @@ use axum::{
http::StatusCode, http::StatusCode,
response::{IntoResponse, Response}, response::{IntoResponse, Response},
routing::{delete, get, post, put}, routing::{delete, get, post, put},
Json, Router, Form, Json, Router,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{ use std::{

View File

@ -4,12 +4,13 @@
use self::question::{Question, QuestionDTO}; use self::question::{Question, QuestionDTO};
use crate::*; use crate::*;
const DB_PATH: &str = "./questions.json"; const QUESTIONS_DB_PATH: &str = "./questions.json";
#[derive(Debug)] #[derive(Debug)]
pub struct Store { pub struct Store {
file: File, file: File,
questions: HashMap<u8, Question>, questions: HashMap<u8, Question>,
// answers: HashMap<u8, Answer>, //WIP, add answers to store
} }
impl Store { impl Store {
@ -17,10 +18,13 @@ impl Store {
// Otherwise we create questions.json. // Otherwise we create questions.json.
// JSON formatting and I/O errors possible here are semi-handled with a message, but ultimetly we will panic in those cases // JSON formatting and I/O errors possible here are semi-handled with a message, but ultimetly we will panic in those cases
pub fn new() -> Self { pub fn new() -> Self {
let file: File = File::create_new(DB_PATH) let file: File = File::create_new(QUESTIONS_DB_PATH)
.or_else(|e| { .or_else(|e| {
if e.kind() == ErrorKind::AlreadyExists { if e.kind() == ErrorKind::AlreadyExists {
File::options().read(true).write(true).open(DB_PATH) File::options()
.read(true)
.write(true)
.open(QUESTIONS_DB_PATH)
} else { } else {
Err(e) Err(e)
} }
@ -89,7 +93,12 @@ impl Store {
} }
//by nature of the hashmap, pagination does not follow id order //by nature of the hashmap, pagination does not follow id order
pub fn fetch_many(&self, start: usize, size: usize) -> Vec<QuestionDTO> { pub fn fetch_many(&self, start: usize, size: usize) -> Vec<QuestionDTO> {
self.questions.iter().map(|q|q.1.to_dto(*q.0)).skip(start).take(size).collect() self.questions
.iter()
.map(|q| q.1.to_dto(*q.0))
.skip(start)
.take(size)
.collect()
} }
pub fn update(&mut self, id: u8, question: Question) -> Result<Question, String> { pub fn update(&mut self, id: u8, question: Question) -> Result<Question, String> {
if !self.questions.contains_key(&id) { if !self.questions.contains_key(&id) {