feat: create a model for tasks with subtasks
This commit is contained in:
		| @@ -7,7 +7,7 @@ use validator::Validate; | ||||
| const TITLE_LENGTH_MIN: u64 = 1; | ||||
| const TITLE_LENGTH_MAX: u64 = 255; | ||||
|  | ||||
| #[derive(Queryable, Selectable, Serialize, Deserialize, PartialEq, Clone, Debug)] | ||||
| #[derive(Queryable, Selectable, Identifiable, Serialize, Deserialize, PartialEq, Clone, Debug)] | ||||
| #[diesel(table_name = crate::schema::projects)] | ||||
| #[diesel(check_for_backend(diesel::pg::Pg))] | ||||
| pub struct Project { | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| use chrono::NaiveDateTime; | ||||
| use crate::models::task::Task; | ||||
| use crate::schema::subtasks; | ||||
| use chrono::NaiveDateTime; | ||||
| use diesel::prelude::*; | ||||
| use serde::{Deserialize, Serialize}; | ||||
| use validator::Validate; | ||||
| @@ -7,7 +8,9 @@ use validator::Validate; | ||||
| const TITLE_LENGTH_MIN: u64 = 1; | ||||
| const TITLE_LENGTH_MAX: u64 = 255; | ||||
|  | ||||
| #[derive(Queryable, Selectable, Serialize, Deserialize, PartialEq, Clone, Debug)] | ||||
| #[derive(Queryable, Selectable, Identifiable, Associations, Serialize, Deserialize, PartialEq, | ||||
|     Clone, Debug)] | ||||
| #[diesel(belongs_to(Task, foreign_key = task_id))] | ||||
| #[diesel(table_name = subtasks)] | ||||
| #[diesel(check_for_backend(diesel::pg::Pg))] | ||||
| pub struct Subtask { | ||||
|   | ||||
| @@ -4,11 +4,12 @@ use crate::schema::tasks; | ||||
| use diesel::prelude::*; | ||||
| use serde::{Deserialize, Serialize}; | ||||
| use validator::Validate; | ||||
| use crate::models::subtask::Subtask; | ||||
|  | ||||
| const TITLE_LENGTH_MIN: u64 = 1; | ||||
| const TITLE_LENGTH_MAX: u64 = 255; | ||||
|  | ||||
| #[derive(Queryable, Selectable, Serialize, Deserialize, PartialEq, Clone, Debug)] | ||||
| #[derive(Queryable, Selectable, Identifiable, Serialize, Deserialize, PartialEq, Clone, Debug)] | ||||
| #[diesel(table_name = tasks)] | ||||
| #[diesel(check_for_backend(diesel::pg::Pg))] | ||||
| pub struct Task { | ||||
| @@ -51,6 +52,26 @@ impl Task { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Serialize, Deserialize, PartialEq, Clone, Debug)] | ||||
| pub struct TaskWithSubtasks { | ||||
|     task: Task, | ||||
|     subtasks: Vec<Subtask>, | ||||
| } | ||||
|  | ||||
| impl TaskWithSubtasks { | ||||
|     pub fn new(task: Task, subtasks: Vec<Subtask>) -> Self { | ||||
|         Self { task, subtasks } | ||||
|     } | ||||
|  | ||||
|     pub fn task(&self) -> &Task { | ||||
|         &self.task | ||||
|     } | ||||
|  | ||||
|     pub fn subtasks(&self) -> &Vec<Subtask> { | ||||
|         &self.subtasks | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Insertable, Serialize, Deserialize, Validate, Clone, Debug)] | ||||
| #[diesel(table_name = tasks)] | ||||
| pub struct NewTask { | ||||
|   | ||||
| @@ -3,7 +3,7 @@ use crate::errors::error_vec::ErrorVec; | ||||
| use crate::models::category::Category; | ||||
| use crate::models::project::Project; | ||||
| use crate::models::subtask::Subtask; | ||||
| use crate::models::task::Task; | ||||
| use crate::models::task::{Task, TaskWithSubtasks}; | ||||
|  | ||||
| pub(crate) mod tasks; | ||||
| pub(crate) mod projects; | ||||
| @@ -13,6 +13,7 @@ pub(crate) mod subtasks; | ||||
| pub(crate) enum QueryValue { | ||||
|     Projects(Vec<Project>), | ||||
|     Tasks(Vec<Task>), | ||||
|     TasksWithSubtasks(Vec<TaskWithSubtasks>), | ||||
|     Subtasks(Vec<Subtask>), | ||||
| } | ||||
|  | ||||
| @@ -26,5 +27,6 @@ pub(crate) enum QueryKey { | ||||
|     Projects, | ||||
|     Tasks, | ||||
|     TasksInCategory(Category), | ||||
|     TasksWithSubtasksInCategory(Category), | ||||
|     SubtasksOfTaskId(i32), | ||||
| } | ||||
|   | ||||
| @@ -2,7 +2,7 @@ use dioxus::prelude::ServerFnError; | ||||
| use dioxus_query::prelude::{use_get_query, QueryResult, UseQuery}; | ||||
| use crate::models::category::Category; | ||||
| use crate::query::{QueryErrors, QueryKey, QueryValue}; | ||||
| use crate::server::tasks::get_tasks_in_category; | ||||
| use crate::server::tasks::{get_tasks_in_category, get_tasks_with_subtasks_in_category}; | ||||
|  | ||||
|  | ||||
|  | ||||
| @@ -22,3 +22,29 @@ async fn fetch_tasks_in_category(keys: Vec<QueryKey>) -> QueryResult<QueryValue, | ||||
|         panic!("Unexpected query keys: {:?}", keys); | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub(crate) fn use_tasks_with_subtasks_in_category_query(category: Category) | ||||
|                                           -> UseQuery<QueryValue, QueryErrors, QueryKey> { | ||||
|     use_get_query( | ||||
|         [ | ||||
|             QueryKey::TasksWithSubtasksInCategory( | ||||
|             category.clone()), | ||||
|             QueryKey::TasksInCategory(category), | ||||
|             QueryKey::Tasks | ||||
|         ], | ||||
|         fetch_tasks_with_subtasks_in_category | ||||
|     ) | ||||
| } | ||||
|  | ||||
| async fn fetch_tasks_with_subtasks_in_category(keys: Vec<QueryKey>) | ||||
|     -> QueryResult<QueryValue, QueryErrors> { | ||||
|     if let Some(QueryKey::TasksWithSubtasksInCategory(category)) = keys.first() { | ||||
|         match get_tasks_with_subtasks_in_category(category.clone()).await { | ||||
|             Ok(tasks) => Ok(QueryValue::TasksWithSubtasks(tasks)), | ||||
|             Err(ServerFnError::WrappedServerError(errors)) => Err(QueryErrors::Error(errors)), | ||||
|             Err(error) => panic!("Unexpected error: {:?}", error) | ||||
|         }.into() | ||||
|     } else { | ||||
|         panic!("Unexpected query keys: {:?}", keys); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,14 +1,16 @@ | ||||
| use chrono::{Datelike, Days, Months, NaiveDate}; | ||||
| use crate::errors::error::Error; | ||||
| use crate::errors::error_vec::ErrorVec; | ||||
| use crate::models::task::{NewTask, Task}; | ||||
| use crate::models::task::{NewTask, Task, TaskWithSubtasks}; | ||||
| use crate::server::database_connection::establish_database_connection; | ||||
| use diesel::{ExpressionMethods, OptionalExtension, QueryDsl, RunQueryDsl, SelectableHelper}; | ||||
| use dioxus::prelude::*; | ||||
| use diesel::prelude::*; | ||||
| use time::util::days_in_year_month; | ||||
| use validator::Validate; | ||||
| use crate::errors::task_error::TaskError; | ||||
| use crate::models::category::{Category, ReoccurrenceInterval}; | ||||
| use crate::models::subtask::Subtask; | ||||
| use crate::server::subtasks::restore_subtasks_of_task; | ||||
|  | ||||
| #[server] | ||||
| @@ -72,6 +74,36 @@ pub(crate) async fn get_tasks_in_category(filtered_category: Category) | ||||
|     Ok(results) | ||||
| } | ||||
|  | ||||
| #[server] | ||||
| pub(crate) async fn get_tasks_with_subtasks_in_category(filtered_category: Category) -> Result< | ||||
|     Vec<TaskWithSubtasks>, | ||||
|     ServerFnError<ErrorVec<Error>> | ||||
| > { | ||||
|     use crate::schema::tasks; | ||||
|      | ||||
|     let mut connection = establish_database_connection() | ||||
|         .map_err::<ErrorVec<Error>, _>(|_| vec![Error::ServerInternal].into())?; | ||||
|  | ||||
|     let tasks_in_category = tasks::table | ||||
|         .filter(filtered_category.eq_sql_predicate()) | ||||
|         .select(Task::as_select()).load(&mut connection) | ||||
|         .map_err::<ErrorVec<Error>, _>(|_| vec![Error::ServerInternal].into())?; | ||||
|  | ||||
|     let subtasks = Subtask::belonging_to(&tasks_in_category) | ||||
|         .select(Subtask::as_select()) | ||||
|         .load(&mut connection) | ||||
|         .map_err::<ErrorVec<Error>, _>(|_| vec![Error::ServerInternal].into())?; | ||||
|  | ||||
|     let tasks_with_subtasks = subtasks | ||||
|         .grouped_by(&tasks_in_category) | ||||
|         .into_iter() | ||||
|         .zip(tasks_in_category) | ||||
|         .map(|(pages, book)| TaskWithSubtasks::new(book, pages)) | ||||
|         .collect(); | ||||
|  | ||||
|     Ok(tasks_with_subtasks) | ||||
| } | ||||
|  | ||||
| #[server] | ||||
| pub(crate) async fn edit_task(task_id: i32, new_task: NewTask) | ||||
|                               -> Result<Task, ServerFnError<ErrorVec<TaskError>>> { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user