Skip to content

Commit

Permalink
Merge pull request #287 from GiganticMinecraft/feat/getAllAnswers
Browse files Browse the repository at this point in the history
フォームに来た回答を時系列順にすべて取得するエントリポイントの実装
  • Loading branch information
Mitama authored Sep 16, 2023
2 parents 53a44c5 + 643a3a3 commit 55f0d9e
Show file tree
Hide file tree
Showing 16 changed files with 180 additions and 7 deletions.
2 changes: 2 additions & 0 deletions server/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ serde_json = "1.0.107"
itertools = "0.11.0"
chrono = { version = "0.4.31" }
futures = "0.3.28"
uuid = "1.4.1"
uuid = { version = "1.4.1", features = ["v4"] }
deriving_via = "1.5.0"
reqwest = { version = "0.11.20", default-features = false, features = ["rustls"] }
num-traits = "0.2.16"
Expand Down
1 change: 1 addition & 0 deletions server/domain/src/repository/form_repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ pub trait FormRepository: Send + Sync + 'static {
form_update_targets: FormUpdateTargets,
) -> Result<(), Error>;
async fn post_answer(&self, answers: PostedAnswers) -> Result<(), Error>;
async fn get_all_answers(&self) -> Result<Vec<PostedAnswers>, Error>;
async fn create_questions(&self, questions: FormQuestionUpdateSchema) -> Result<(), Error>;
}
7 changes: 5 additions & 2 deletions server/entrypoint/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use presentation::{
auth::auth,
form_handler::{
create_form_handler, create_question_handler, delete_form_handler, form_list_handler,
get_form_handler, post_answer_handler, update_form_handler,
get_all_answers, get_form_handler, post_answer_handler, update_form_handler,
},
health_check_handler::health_check,
};
Expand Down Expand Up @@ -71,7 +71,10 @@ async fn main() -> anyhow::Result<()> {
.patch(update_form_handler),
)
.with_state(shared_repository.to_owned())
.route("/forms/answers", post(post_answer_handler))
.route(
"/forms/answers",
post(post_answer_handler).get(get_all_answers),
)
.with_state(shared_repository.to_owned())
.route("/forms/questions", post(create_question_handler))
.with_state(shared_repository.to_owned())
Expand Down
1 change: 1 addition & 0 deletions server/errors/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ edition = "2021"
sea-orm = { workspace = true }
strum = { workspace = true }
thiserror = "1.0.48"
uuid = { workspace = true }
5 changes: 5 additions & 0 deletions server/errors/src/infra.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ pub enum InfraError {
#[from]
source: sea_orm::error::DbErr,
},
#[error("Uuid Parse Error: {}", .source)]
UuidParse {
#[from]
source: uuid::Error,
},
#[error("Form Not Found: id = {}", .id)]
FormNotFound { id: i32 },
#[error("Outgoing Error: {}", .cause)]
Expand Down
15 changes: 15 additions & 0 deletions server/infra/entities/src/answers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use sea_orm::entity::prelude::*;
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub form_id: i32,
#[sea_orm(column_type = "Binary(BlobSize::Blob(Some(16)))")]
pub user: Vec<u8>,
pub title: String,
Expand All @@ -15,10 +16,24 @@ pub struct Model {

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::form_meta_data::Entity",
from = "Column::FormId",
to = "super::form_meta_data::Column::Id",
on_update = "NoAction",
on_delete = "NoAction"
)]
FormMetaData,
#[sea_orm(has_many = "super::real_answers::Entity")]
RealAnswers,
}

impl Related<super::form_meta_data::Entity> for Entity {
fn to() -> RelationDef {
Relation::FormMetaData.def()
}
}

impl Related<super::real_answers::Entity> for Entity {
fn to() -> RelationDef {
Relation::RealAnswers.def()
Expand Down
8 changes: 8 additions & 0 deletions server/infra/entities/src/form_meta_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ pub struct Model {

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(has_many = "super::answers::Entity")]
Answers,
#[sea_orm(has_many = "super::default_answer_titles::Entity")]
DefaultAnswerTitles,
#[sea_orm(has_many = "super::form_questions::Entity")]
Expand All @@ -25,6 +27,12 @@ pub enum Relation {
ResponsePeriod,
}

impl Related<super::answers::Entity> for Entity {
fn to() -> RelationDef {
Relation::Answers.def()
}
}

impl Related<super::default_answer_titles::Entity> for Entity {
fn to() -> RelationDef {
Relation::DefaultAnswerTitles.def()
Expand Down
1 change: 1 addition & 0 deletions server/infra/resource/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ serde = { workspace = true }
tracing = { workspace = true }
num-traits = { workspace = true }
regex = { workspace = true }
uuid = { workspace = true }
3 changes: 2 additions & 1 deletion server/infra/resource/src/database/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use domain::form::models::{
use errors::infra::InfraError;
use mockall::automock;

use crate::dto::FormDto;
use crate::dto::{FormDto, PostedAnswersDto};

#[async_trait]
pub trait DatabaseComponents: Send + Sync {
Expand Down Expand Up @@ -34,6 +34,7 @@ pub trait FormDatabase: Send + Sync {
form_update_targets: FormUpdateTargets,
) -> Result<(), InfraError>;
async fn post_answer(&self, answer: PostedAnswers) -> Result<(), InfraError>;
async fn get_all_answers(&self) -> Result<Vec<PostedAnswersDto>, InfraError>;
async fn create_questions(&self, questions: FormQuestionUpdateSchema)
-> Result<(), InfraError>;
}
46 changes: 44 additions & 2 deletions server/infra/resource/src/database/form.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use domain::form::models::{
use entities::{
answers, default_answer_titles, form_choices, form_meta_data, form_questions, form_webhooks,
prelude::{
DefaultAnswerTitles, FormChoices, FormMetaData, FormQuestions, FormWebhooks, RealAnswers,
Answers, DefaultAnswerTitles, FormChoices, FormMetaData, FormQuestions, FormWebhooks,
RealAnswers,
},
real_answers, response_period,
sea_orm_active_enums::QuestionType,
Expand All @@ -18,6 +19,7 @@ use itertools::Itertools;
use num_traits::cast::FromPrimitive;
use regex::Regex;
use sea_orm::{
prelude::Uuid,
sea_query::{Expr, SimpleExpr},
ActiveEnum, ActiveModelTrait, ActiveValue,
ActiveValue::Set,
Expand All @@ -26,7 +28,7 @@ use sea_orm::{

use crate::{
database::{components::FormDatabase, connection::ConnectionPool},
dto::{FormDto, QuestionDto},
dto::{AnswerDto, FormDto, PostedAnswersDto, QuestionDto},
};

#[async_trait]
Expand Down Expand Up @@ -405,6 +407,7 @@ impl FormDatabase for ConnectionPool {

let id = answers::ActiveModel {
id: Default::default(),
form_id: Set(answer.form_id.to_owned()),
user: Set(answer.uuid.to_owned().as_ref().to_vec()),
title: Set(embed_title),
time_stamp: Set(Utc::now()),
Expand All @@ -431,6 +434,45 @@ impl FormDatabase for ConnectionPool {
Ok(())
}

async fn get_all_answers(&self) -> Result<Vec<PostedAnswersDto>, InfraError> {
stream::iter(
Answers::find()
.order_by_desc(answers::Column::TimeStamp)
.all(&self.pool)
.await?,
)
.then(|answer| async move {
let answers = RealAnswers::find()
.filter(Expr::col(real_answers::Column::AnswerId).eq(answer.id))
.all(&self.pool)
.await?
.into_iter()
.map(
|entities::real_answers::Model {
question_id,
answer,
..
}| AnswerDto {
question_id,
answer,
},
)
.collect_vec();

Ok(PostedAnswersDto {
uuid: Uuid::from_slice(answer.user.as_slice())?,
timestamp: answer.time_stamp,
form_id: answer.form_id,
title: Some(answer.title),
answers,
})
})
.collect::<Vec<Result<PostedAnswersDto, _>>>()
.await
.into_iter()
.collect::<Result<Vec<PostedAnswersDto>, _>>()
}

async fn create_questions(
&self,
form_question_update_schema: FormQuestionUpdateSchema,
Expand Down
55 changes: 55 additions & 0 deletions server/infra/resource/src/dto.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use chrono::{DateTime, Utc};
use domain::form::models::{FormSettings, ResponsePeriod};
use uuid::Uuid;

pub struct QuestionDto {
pub id: i32,
Expand Down Expand Up @@ -79,3 +80,57 @@ impl TryFrom<FormDto> for domain::form::models::Form {
.build())
}
}

pub struct AnswerDto {
pub question_id: i32,
pub answer: String,
}

impl TryFrom<AnswerDto> for domain::form::models::Answer {
type Error = errors::domain::DomainError;

fn try_from(
AnswerDto {
question_id,
answer,
}: AnswerDto,
) -> Result<Self, Self::Error> {
Ok(domain::form::models::Answer {
question_id: question_id.into(),
answer,
})
}
}

pub struct PostedAnswersDto {
pub uuid: Uuid,
pub timestamp: DateTime<Utc>,
pub form_id: i32,
pub title: Option<String>,
pub answers: Vec<AnswerDto>,
}

impl TryFrom<PostedAnswersDto> for domain::form::models::PostedAnswers {
type Error = errors::domain::DomainError;

fn try_from(
PostedAnswersDto {
uuid,
timestamp,
form_id,
title,
answers,
}: PostedAnswersDto,
) -> Result<Self, Self::Error> {
Ok(domain::form::models::PostedAnswers {
uuid,
timestamp,
form_id: form_id.into(),
title: title.into(),
answers: answers
.into_iter()
.map(|answer| answer.try_into())
.collect::<Result<Vec<_>, _>>()?,
})
}
}
11 changes: 11 additions & 0 deletions server/infra/resource/src/repository/form_repository_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use domain::{
repository::form_repository::FormRepository,
};
use errors::Error;
use futures::{stream, stream::StreamExt};
use outgoing::form_outgoing;

use crate::{
Expand Down Expand Up @@ -77,6 +78,16 @@ impl<Client: DatabaseComponents + 'static> FormRepository for Repository<Client>
.map_err(Into::into)
}

#[tracing::instrument(skip(self))]
async fn get_all_answers(&self) -> Result<Vec<PostedAnswers>, Error> {
stream::iter(self.client.form().get_all_answers().await?)
.then(|posted_answers_dto| async { Ok(posted_answers_dto.try_into()?) })
.collect::<Vec<Result<PostedAnswers, _>>>()
.await
.into_iter()
.collect::<Result<Vec<PostedAnswers>, _>>()
}

async fn create_questions(&self, questions: FormQuestionUpdateSchema) -> Result<(), Error> {
self.client
.form()
Expand Down
13 changes: 12 additions & 1 deletion server/migration/src/m20230811_062425_create_answer_tables.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use sea_orm_migration::prelude::*;

use crate::m20221211_211233_form_questions::FormQuestionsTable;
use crate::{
m20220101_000001_create_table::FormMetaDataTable,
m20221211_211233_form_questions::FormQuestionsTable,
};

#[derive(DeriveMigrationName)]
pub struct Migration;
Expand All @@ -20,6 +23,13 @@ impl MigrationTrait for Migration {
.auto_increment()
.primary_key(),
)
.col(ColumnDef::new(AnswersTable::FormId).integer().not_null())
.foreign_key(
ForeignKey::create()
.name("fk-form-id-from-answers")
.from(AnswersTable::Answers, AnswersTable::FormId)
.to(FormMetaDataTable::FormMetaData, FormMetaDataTable::Id),
)
.col(ColumnDef::new(AnswersTable::User).uuid().not_null())
.col(
ColumnDef::new(AnswersTable::Title)
Expand Down Expand Up @@ -98,6 +108,7 @@ impl MigrationTrait for Migration {
enum AnswersTable {
Answers,
Id,
FormId,
User,
Title,
TimeStamp,
Expand Down
13 changes: 13 additions & 0 deletions server/presentation/src/form_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,19 @@ pub async fn update_form_handler(
}
}

pub async fn get_all_answers(
State(repository): State<RealInfrastructureRepository>,
) -> impl IntoResponse {
let form_use_case = FormUseCase {
repository: repository.form_repository(),
};

match form_use_case.get_all_answers().await {
Ok(answers) => (StatusCode::OK, Json(answers)).into_response(),
Err(err) => handle_error(err).into_response(),
}
}

pub async fn post_answer_handler(
State(repository): State<RealInfrastructureRepository>,
Json(answers): Json<PostedAnswers>,
Expand Down
4 changes: 4 additions & 0 deletions server/usecase/src/form.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ impl<R: FormRepository> FormUseCase<'_, R> {
self.repository.post_answer(answers).await
}

pub async fn get_all_answers(&self) -> Result<Vec<PostedAnswers>, Error> {
self.repository.get_all_answers().await
}

pub async fn create_questions(&self, questions: FormQuestionUpdateSchema) -> Result<(), Error> {
self.repository.create_questions(questions).await
}
Expand Down

0 comments on commit 55f0d9e

Please sign in to comment.