Add the ability to delete tasks.

This commit is contained in:
Drew Galbraith 2024-07-06 00:06:16 -07:00
parent c07df0b094
commit d87c2e8922
4 changed files with 54 additions and 9 deletions

View File

@ -44,7 +44,12 @@ type Status a
init : Nav.Key -> ( Model, Cmd Msg ) init : Nav.Key -> ( Model, Cmd Msg )
init navKey = init navKey =
( Model navKey Loading True defaultCreateTask reloadTasks (Model navKey Loading True defaultCreateTask)
reloadTasks : Model -> ( Model, Cmd Msg )
reloadTasks model =
( model
, Http.get , Http.get
{ url = "http://localhost:3000/tasks" { url = "http://localhost:3000/tasks"
, expect = Http.expectJson GotTasks (list taskDecoder) , expect = Http.expectJson GotTasks (list taskDecoder)
@ -55,10 +60,12 @@ init navKey =
type Msg type Msg
= GotTasks (Result Http.Error (List Task)) = GotTasks (Result Http.Error (List Task))
| ToggleCreateTask | ToggleCreateTask
| CreateTask
| GotTaskCreated (Result Http.Error Task)
| CreateTaskUpdateTitle String | CreateTaskUpdateTitle String
| CreateTaskUpdateDescription String | CreateTaskUpdateDescription String
| CreateTask
| GotTaskCreated (Result Http.Error Task)
| DeleteTask Int
| GotTaskDeleted (Result Http.Error ())
update : Msg -> Model -> ( Model, Cmd Msg ) update : Msg -> Model -> ( Model, Cmd Msg )
@ -113,6 +120,22 @@ update msg model =
in in
( { model | createTask = { createTask | description = description } }, Cmd.none ) ( { model | createTask = { createTask | description = description } }, Cmd.none )
DeleteTask id ->
( model
, Http.request
{ method = "DELETE"
, headers = []
, url = "http://localhost:3000/tasks/" ++ String.fromInt id
, body = Http.emptyBody
, expect = Http.expectWhatever GotTaskDeleted
, timeout = Nothing
, tracker = Nothing
}
)
GotTaskDeleted _ ->
reloadTasks model
taskDecoder : Decoder Task taskDecoder : Decoder Task
taskDecoder = taskDecoder =
@ -186,6 +209,7 @@ viewTaskListItem task =
"" ""
) )
) )
, button [ onClick (DeleteTask task.id) ] [ text "Delete Task" ]
] ]

View File

@ -4,7 +4,7 @@ mod routes;
use axum::http::{StatusCode, Uri}; use axum::http::{StatusCode, Uri};
use axum::response::IntoResponse; use axum::response::IntoResponse;
use axum::routing::get; use axum::routing::{delete, get};
use dotenvy::dotenv; use dotenvy::dotenv;
use sqlx::SqlitePool; use sqlx::SqlitePool;
@ -28,6 +28,10 @@ async fn main() {
.post(routes::tasks::create) .post(routes::tasks::create)
.options(routes::tasks::options), .options(routes::tasks::options),
) )
.route(
"/tasks/:task_id",
delete(routes::tasks::delete).options(routes::tasks::options),
)
.with_state(state); .with_state(state);
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000") let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")

View File

@ -1,5 +1,5 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sqlx::{FromRow, SqlitePool}; use sqlx::{sqlite::SqliteQueryResult, FromRow, SqlitePool};
#[derive(Serialize, Deserialize, FromRow)] #[derive(Serialize, Deserialize, FromRow)]
pub struct Task { pub struct Task {
@ -32,4 +32,10 @@ impl Task {
.fetch_one(pool) .fetch_one(pool)
.await .await
} }
pub async fn delete(pool: &SqlitePool, id: i64) -> Result<SqliteQueryResult, sqlx::Error> {
sqlx::query!("DELETE FROM task WHERE id = ?1", id)
.execute(pool)
.await
}
} }

View File

@ -1,6 +1,4 @@
use std::collections::HashMap; use axum::extract::{Json, Path, State};
use axum::extract::{Json, State};
use axum::http::header; use axum::http::header;
use axum::http::StatusCode; use axum::http::StatusCode;
use axum::response::IntoResponse; use axum::response::IntoResponse;
@ -59,9 +57,22 @@ pub async fn options() -> impl IntoResponse {
StatusCode::OK, StatusCode::OK,
[ [
(header::ACCESS_CONTROL_ALLOW_ORIGIN, "*"), (header::ACCESS_CONTROL_ALLOW_ORIGIN, "*"),
(header::ACCESS_CONTROL_ALLOW_METHODS, "POST, GET, OPTIONS"), (
header::ACCESS_CONTROL_ALLOW_METHODS,
"POST, GET, OPTIONS, DELETE",
),
(header::ACCESS_CONTROL_ALLOW_HEADERS, "Content-Type"), (header::ACCESS_CONTROL_ALLOW_HEADERS, "Content-Type"),
(header::ACCESS_CONTROL_MAX_AGE, "86400"), (header::ACCESS_CONTROL_MAX_AGE, "86400"),
], ],
) )
} }
pub async fn delete(state: State<AppState>, Path(id): Path<i64>) -> impl IntoResponse {
Task::delete(&state.db_pool, id).await.unwrap();
(
StatusCode::OK,
[(header::ACCESS_CONTROL_ALLOW_ORIGIN, "*")],
"",
)
}