diff --git a/src/database/role.rs b/src/database/role.rs index e045507..01096de 100644 --- a/src/database/role.rs +++ b/src/database/role.rs @@ -19,16 +19,13 @@ pub async fn create( .await } -pub async fn read( - name: &String, - database_connection: &Pool, -) -> Result { +pub async fn read(id: &i64, database_connection: &Pool) -> Result { sqlx::query_as!( Role, r#" - SELECT * FROM "role" WHERE "name" = $1 + SELECT * FROM "role" WHERE "id" = $1 "#, - name + id ) .fetch_one(database_connection) .await @@ -64,3 +61,14 @@ pub async fn delete(id: &i64, database_connection: &Pool) -> Result) -> Result, sqlx::Error> { + sqlx::query_as!( + Role, + r#" + SELECT * FROM "role" + "#, + ) + .fetch_all(database_connection) + .await +} diff --git a/src/feature/role.rs b/src/feature/role.rs index ff5287a..3736572 100644 --- a/src/feature/role.rs +++ b/src/feature/role.rs @@ -1,7 +1,42 @@ use serde::{Deserialize, Serialize}; +use sqlx::{Pool, Postgres}; + +use crate::database::role; #[derive(Debug, Serialize, Deserialize)] pub struct Role { pub id: i64, pub name: String, } + +impl Role { + pub async fn create( + name: &String, + database_connection: &Pool, + ) -> Result { + role::create(name, database_connection).await + } + + pub async fn read(id: &i64, database_connection: &Pool) -> Result { + role::read(id, database_connection).await + } + + pub async fn update( + id: &i64, + name: &String, + database_connection: &Pool, + ) -> Result { + role::update(id, name, database_connection).await + } + + pub async fn delete( + id: &i64, + database_connection: &Pool, + ) -> Result { + role::delete(id, database_connection).await + } + + pub async fn read_all(database_connection: &Pool) -> Result, sqlx::Error> { + role::read_all(database_connection).await + } +} diff --git a/src/lib.rs b/src/lib.rs index 27fc9e4..9c94eed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,8 @@ pub mod database; pub mod error; pub mod feature; +pub mod routing; +pub mod server; pub mod utils; use sqlx::{Pool, Postgres}; diff --git a/src/main.rs b/src/main.rs index 7e3d561..306bf84 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,17 @@ +use rust_forum::{ + database::{establish_connection, set_database_up}, + server::start_server, + AppState, +}; + #[tokio::main] async fn main() { println!("Hello, world!"); + + let app_state = AppState { + database_connection: establish_connection().await, + }; + set_database_up(&app_state.database_connection).await; + + start_server(app_state).await; } diff --git a/src/routing.rs b/src/routing.rs new file mode 100644 index 0000000..362f6d2 --- /dev/null +++ b/src/routing.rs @@ -0,0 +1,24 @@ +pub mod role; + +use axum::{extract::State, http::StatusCode, response::IntoResponse, routing::get, Router}; +use tower_http::cors::CorsLayer; + +use crate::{database, AppState}; + +pub async fn route(State(app_state): State) -> Router { + Router::new() + .route("/", get(alive)) + .nest( + "/role", + role::route(axum::extract::State(app_state.clone())), + ) + .layer(CorsLayer::permissive()) + .with_state(app_state) +} + +async fn alive(State(app_state): State) -> impl IntoResponse { + match database::is_alive(&app_state.database_connection).await { + true => StatusCode::OK, + false => StatusCode::SERVICE_UNAVAILABLE, + } +} diff --git a/src/routing/role.rs b/src/routing/role.rs new file mode 100644 index 0000000..f921079 --- /dev/null +++ b/src/routing/role.rs @@ -0,0 +1,72 @@ +use axum::{ + extract::{Path, State}, + http::StatusCode, + response::IntoResponse, + routing::{delete, get, patch, post}, + Json, Router, +}; + +use crate::{feature::role::Role, AppState}; + +pub fn route(State(app_state): State) -> Router { + Router::new() + .route("/:name", post(create)) + .route("/:id", get(read)) + .route("/:id/:name", patch(update)) + .route("/:id", delete(_delete)) + .route("/", get(read_all)) + .with_state(app_state) +} + +async fn create(Path(name): Path, State(app_state): State) -> impl IntoResponse { + match Role::create(&name, &app_state.database_connection).await { + Ok(role) => (StatusCode::CREATED, Json(serde_json::json!(role))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +} + +async fn read(Path(id): Path, State(app_state): State) -> impl IntoResponse { + match Role::read(&id, &app_state.database_connection).await { + Ok(role) => (StatusCode::OK, Json(serde_json::json!(role))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +} + +async fn update( + Path((id, name)): Path<(i64, String)>, + State(app_state): State, +) -> impl IntoResponse { + match Role::update(&id, &name, &app_state.database_connection).await { + Ok(role) => (StatusCode::ACCEPTED, Json(serde_json::json!(role))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +} + +async fn _delete(Path(id): Path, State(app_state): State) -> impl IntoResponse { + match Role::delete(&id, &app_state.database_connection).await { + Ok(role) => (StatusCode::NO_CONTENT, Json(serde_json::json!(role))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +} + +async fn read_all(State(app_state): State) -> impl IntoResponse { + match Role::read_all(&app_state.database_connection).await { + Ok(roles) => (StatusCode::OK, Json(serde_json::json!(roles))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +} diff --git a/src/server.rs b/src/server.rs new file mode 100644 index 0000000..8d46e11 --- /dev/null +++ b/src/server.rs @@ -0,0 +1,12 @@ +use tokio::net::TcpListener; + +use crate::{AppState, ServerConfig}; + +pub async fn start_server(app_state: AppState) { + let server_config = ServerConfig::default(); + + let router = crate::routing::route(axum::extract::State(app_state)).await; + let listener = TcpListener::bind(&server_config.address).await.unwrap(); + println!("\n\thttp://{}", server_config.address); + axum::serve(listener, router).await.unwrap() +}