Golden example: todo-rs (Axum + SQLx + SQLite)
This commit is contained in:
122
kipina-codebench/golden-examples/todo-rs/src/handlers.rs
Normal file
122
kipina-codebench/golden-examples/todo-rs/src/handlers.rs
Normal file
@@ -0,0 +1,122 @@
|
||||
//! Käsittelijät — CRUD-operaatiot todo-entiteetille.
|
||||
|
||||
use axum::extract::{Path, State};
|
||||
use axum::http::StatusCode;
|
||||
use axum::Json;
|
||||
use sqlx::SqlitePool;
|
||||
|
||||
use crate::models::{CreateTodo, Todo, UpdateTodo};
|
||||
|
||||
/// Luo uusi tehtävä.
|
||||
pub async fn create_todo(
|
||||
State(pool): State<SqlitePool>,
|
||||
Json(input): Json<CreateTodo>,
|
||||
) -> Result<(StatusCode, Json<Todo>), StatusCode> {
|
||||
let priority = input.priority.unwrap_or(1);
|
||||
let status = input.status.unwrap_or_else(|| "pending".to_string());
|
||||
|
||||
let result = sqlx::query_as::<_, Todo>(
|
||||
"INSERT INTO todos (title, description, due_date, priority, status)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
RETURNING id, title, description, due_date, priority, status",
|
||||
)
|
||||
.bind(&input.title)
|
||||
.bind(&input.description)
|
||||
.bind(&input.due_date)
|
||||
.bind(priority)
|
||||
.bind(&status)
|
||||
.fetch_one(&pool)
|
||||
.await
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
|
||||
Ok((StatusCode::CREATED, Json(result)))
|
||||
}
|
||||
|
||||
/// Listaa kaikki tehtävät.
|
||||
pub async fn list_todos(
|
||||
State(pool): State<SqlitePool>,
|
||||
) -> Result<Json<Vec<Todo>>, StatusCode> {
|
||||
let todos = sqlx::query_as::<_, Todo>("SELECT id, title, description, due_date, priority, status FROM todos")
|
||||
.fetch_all(&pool)
|
||||
.await
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
|
||||
Ok(Json(todos))
|
||||
}
|
||||
|
||||
/// Hae tehtävä id:llä.
|
||||
pub async fn get_todo(
|
||||
State(pool): State<SqlitePool>,
|
||||
Path(id): Path<i64>,
|
||||
) -> Result<Json<Todo>, StatusCode> {
|
||||
let todo = sqlx::query_as::<_, Todo>(
|
||||
"SELECT id, title, description, due_date, priority, status FROM todos WHERE id = ?",
|
||||
)
|
||||
.bind(id)
|
||||
.fetch_optional(&pool)
|
||||
.await
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
|
||||
match todo {
|
||||
Some(t) => Ok(Json(t)),
|
||||
None => Err(StatusCode::NOT_FOUND),
|
||||
}
|
||||
}
|
||||
|
||||
/// Päivitä tehtävä id:llä.
|
||||
pub async fn update_todo(
|
||||
State(pool): State<SqlitePool>,
|
||||
Path(id): Path<i64>,
|
||||
Json(input): Json<UpdateTodo>,
|
||||
) -> Result<Json<Todo>, StatusCode> {
|
||||
let existing = sqlx::query_as::<_, Todo>(
|
||||
"SELECT id, title, description, due_date, priority, status FROM todos WHERE id = ?",
|
||||
)
|
||||
.bind(id)
|
||||
.fetch_optional(&pool)
|
||||
.await
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
|
||||
let existing = existing.ok_or(StatusCode::NOT_FOUND)?;
|
||||
|
||||
let title = input.title.unwrap_or(existing.title);
|
||||
let description = input.description.or(existing.description);
|
||||
let due_date = input.due_date.or(existing.due_date);
|
||||
let priority = input.priority.unwrap_or(existing.priority);
|
||||
let status = input.status.unwrap_or(existing.status);
|
||||
|
||||
let updated = sqlx::query_as::<_, Todo>(
|
||||
"UPDATE todos SET title = ?, description = ?, due_date = ?, priority = ?, status = ?
|
||||
WHERE id = ?
|
||||
RETURNING id, title, description, due_date, priority, status",
|
||||
)
|
||||
.bind(&title)
|
||||
.bind(&description)
|
||||
.bind(&due_date)
|
||||
.bind(priority)
|
||||
.bind(&status)
|
||||
.bind(id)
|
||||
.fetch_one(&pool)
|
||||
.await
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
|
||||
Ok(Json(updated))
|
||||
}
|
||||
|
||||
/// Poista tehtävä id:llä.
|
||||
pub async fn delete_todo(
|
||||
State(pool): State<SqlitePool>,
|
||||
Path(id): Path<i64>,
|
||||
) -> Result<StatusCode, StatusCode> {
|
||||
let result = sqlx::query("DELETE FROM todos WHERE id = ?")
|
||||
.bind(id)
|
||||
.execute(&pool)
|
||||
.await
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
|
||||
if result.rows_affected() == 0 {
|
||||
return Err(StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
Ok(StatusCode::NO_CONTENT)
|
||||
}
|
||||
Reference in New Issue
Block a user