feat: client and person management
This commit is contained in:
parent
7744a4c31e
commit
9a7f992265
8 changed files with 206 additions and 22 deletions
17
src/model.rs
17
src/model.rs
|
@ -11,7 +11,7 @@ pub struct Room {
|
|||
pub accessibility: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Address {
|
||||
pub street: String,
|
||||
|
@ -85,4 +85,19 @@ pub struct BookingBody {
|
|||
pub cost: i32,
|
||||
pub pension_type: String,
|
||||
pub client_id: i32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PersonBody {
|
||||
pub first_name: String,
|
||||
pub last_name: String,
|
||||
pub age: i32,
|
||||
pub address: Address,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ClientBody {
|
||||
pub bank_details: String,
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
use axum::{Router, routing::BoxRoute, extract::{Extension, Path}, response::IntoResponse, Json, handler::get};
|
||||
use hyper::StatusCode;
|
||||
|
||||
use crate::{Service, error::ServiceError};
|
||||
use crate::{Service, error::ServiceError, model::{ClientBody, Client}};
|
||||
|
||||
async fn clients(
|
||||
Extension(service): Extension<Service>,
|
||||
|
@ -19,9 +19,33 @@ async fn client(
|
|||
Ok(Json(client))
|
||||
}
|
||||
|
||||
async fn set_client(
|
||||
Json(payload): Json<ClientBody>,
|
||||
Path(id): Path<i32>,
|
||||
Extension(service): Extension<Service>,
|
||||
) -> Result<impl IntoResponse, ServiceError> {
|
||||
let person = service.get_person(id).await?
|
||||
.ok_or_else(|| ServiceError::ErrorResponse(StatusCode::NOT_FOUND, Some("person does not exist".to_string())))?;
|
||||
service.set_client(id, payload.clone()).await?;
|
||||
let client = Client {
|
||||
id,
|
||||
bank_details: payload.bank_details,
|
||||
person_data: person,
|
||||
};
|
||||
Ok(Json(client))
|
||||
}
|
||||
|
||||
async fn delete_client(
|
||||
Path(id): Path<i32>,
|
||||
Extension(service): Extension<Service>,
|
||||
) -> Result<impl IntoResponse, ServiceError> {
|
||||
service.delete_client(id).await?;
|
||||
Ok(StatusCode::NO_CONTENT)
|
||||
}
|
||||
|
||||
pub fn routes() -> Router<BoxRoute> {
|
||||
Router::new()
|
||||
.route("/", get(clients))
|
||||
.route("/:id", get(client))
|
||||
.route("/:id", get(client).put(set_client).delete(delete_client))
|
||||
.boxed()
|
||||
}
|
|
@ -4,6 +4,7 @@ mod rooms;
|
|||
mod clerks;
|
||||
mod bookings;
|
||||
mod clients;
|
||||
mod persons;
|
||||
|
||||
pub fn routes() -> Router<BoxRoute> {
|
||||
Router::new()
|
||||
|
@ -11,5 +12,6 @@ pub fn routes() -> Router<BoxRoute> {
|
|||
.nest("/bookings", bookings::routes())
|
||||
.nest("/clerks", clerks::routes())
|
||||
.nest("/clients", clients::routes())
|
||||
.nest("/persons", persons::routes())
|
||||
.boxed()
|
||||
}
|
35
src/routes/persons.rs
Normal file
35
src/routes/persons.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
use axum::{Router, routing::BoxRoute, extract::{Path, Extension}, response::IntoResponse, Json, handler::{get, post}};
|
||||
use hyper::StatusCode;
|
||||
|
||||
use crate::{Service, error::ServiceError, model::{PersonBody, Person}};
|
||||
|
||||
async fn person(
|
||||
Path(id): Path<i32>,
|
||||
Extension(service): Extension<Service>,
|
||||
) -> Result<impl IntoResponse, ServiceError> {
|
||||
let person = service.get_person(id).await?
|
||||
.ok_or_else(|| ServiceError::ErrorResponse(StatusCode::NOT_FOUND, Some("person not found".to_string())))?;
|
||||
Ok(Json(person))
|
||||
}
|
||||
|
||||
async fn add_person(
|
||||
Json(payload): Json<PersonBody>,
|
||||
Extension(service): Extension<Service>,
|
||||
) -> Result<impl IntoResponse, ServiceError> {
|
||||
let id = service.add_person(payload.clone()).await?;
|
||||
let person = Person {
|
||||
id,
|
||||
first_name: payload.first_name,
|
||||
last_name: payload.last_name,
|
||||
age: payload.age,
|
||||
address: payload.address,
|
||||
};
|
||||
Ok((StatusCode::CREATED, Json(person)))
|
||||
}
|
||||
|
||||
pub fn routes() -> Router<BoxRoute> {
|
||||
Router::new()
|
||||
.route("/", post(add_person))
|
||||
.route("/:id", get(person))
|
||||
.boxed()
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
use sibyl::Row;
|
||||
|
||||
use crate::{ServiceInner, model::{Person, Address, Clerk}, error::ServiceError};
|
||||
use crate::{ServiceInner, model::Clerk, error::ServiceError};
|
||||
|
||||
impl ServiceInner {
|
||||
|
||||
|
@ -97,22 +97,6 @@ impl ServiceInner {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn map_person_row(row: Row, offset: usize) -> Result<Person, ServiceError> {
|
||||
Ok(Person {
|
||||
id: row.get(0 + offset)?,
|
||||
first_name: row.get(1 + offset)?,
|
||||
last_name: row.get(2 + offset)?,
|
||||
age: row.get(3 + offset)?,
|
||||
address: Address {
|
||||
street: row.get(4 + offset)?,
|
||||
house_number: row.get(5 + offset)?,
|
||||
postal_code: row.get(6 + offset)?,
|
||||
city: row.get(7 + offset)?,
|
||||
country: row.get(8 + offset)?,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn map_clerk_row(row: Row) -> Result<Clerk, ServiceError> {
|
||||
Ok(Clerk {
|
||||
staff_number: row.get(0)?,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use sibyl::Row;
|
||||
|
||||
use crate::{ServiceInner, model::Client, error::ServiceError};
|
||||
use crate::{ServiceInner, model::{Client, ClientBody}, error::ServiceError};
|
||||
|
||||
impl ServiceInner {
|
||||
|
||||
|
@ -64,6 +64,53 @@ impl ServiceInner {
|
|||
})
|
||||
}
|
||||
|
||||
pub async fn set_client(&self, id: i32, client: ClientBody) -> Result<(), ServiceError> {
|
||||
let session = self.pool.get_session().await?;
|
||||
let stmt = session.prepare("
|
||||
UPDATE CLIENT SET
|
||||
bankDetails = :BANK
|
||||
WHERE personId = :ID
|
||||
").await?;
|
||||
|
||||
let changes = stmt.execute((
|
||||
(":ID", id),
|
||||
(":BANK", client.bank_details.clone())
|
||||
)).await?;
|
||||
|
||||
if changes == 0 {
|
||||
let stmt = session.prepare("
|
||||
INSERT INTO CLIENT
|
||||
(
|
||||
personId,
|
||||
bankDetails
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
:ID,
|
||||
:BANK
|
||||
)
|
||||
").await?;
|
||||
stmt.execute((
|
||||
(":ID", id),
|
||||
(":BANK", client.bank_details)
|
||||
)).await?;
|
||||
}
|
||||
session.commit().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delete_client(&self, id: i32) -> Result<(), ServiceError> {
|
||||
let session = self.pool.get_session().await?;
|
||||
let stmt = session.prepare("
|
||||
DELETE FROM CLIENT WHERE personId = :ID
|
||||
").await?;
|
||||
|
||||
stmt.execute(id).await?;
|
||||
|
||||
session.commit().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn map_client_row(row: Row) -> Result<Client, ServiceError> {
|
||||
Ok(Client {
|
||||
id: row.get(1)?,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
mod bookings;
|
||||
mod rooms;
|
||||
mod clerks;
|
||||
mod clients;
|
||||
mod clients;
|
||||
mod persons;
|
76
src/sql/persons.rs
Normal file
76
src/sql/persons.rs
Normal file
|
@ -0,0 +1,76 @@
|
|||
use hyper::StatusCode;
|
||||
use sibyl::Row;
|
||||
|
||||
use crate::{ServiceInner, error::ServiceError, model::{PersonBody, Person, Address}};
|
||||
|
||||
impl ServiceInner {
|
||||
|
||||
pub async fn get_person(&self, id: i32) -> Result<Option<Person>, ServiceError> {
|
||||
let session = self.pool.get_session().await?;
|
||||
let stmt = session.prepare("
|
||||
SELECT
|
||||
p.personId,
|
||||
p.name,
|
||||
p.lastName,
|
||||
p.age,
|
||||
ad.street,
|
||||
ad.houseNumber,
|
||||
ad.postalCode,
|
||||
ad.city,
|
||||
ad.country
|
||||
FROM Person p
|
||||
INNER JOIN Address ad ON p.addressId = ad.addressId
|
||||
WHERE p.personId = :ID
|
||||
").await?;
|
||||
|
||||
let row = stmt.query_single(id).await?;
|
||||
|
||||
Ok(match row {
|
||||
Some(row) => {
|
||||
Some(Self::map_person_row(row, 0)?)
|
||||
},
|
||||
None => None,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn add_person(&self, person: PersonBody) -> Result<i32, ServiceError> {
|
||||
let session = self.pool.get_session().await?;
|
||||
let stmt = session.prepare("
|
||||
BEGIN
|
||||
addPerson(:FIRST, :LAST, :AGE, :STREET, :HOUSE, :POSTAL, :CITY, :COUNTRY);
|
||||
END;
|
||||
").await?;
|
||||
stmt.execute((
|
||||
(":FIRST", person.first_name),
|
||||
(":LAST", person.last_name),
|
||||
(":AGE", person.age),
|
||||
(":STREET", person.address.street),
|
||||
(":HOUSE", person.address.house_number),
|
||||
(":POSTAL", person.address.postal_code),
|
||||
(":CITY", person.address.city),
|
||||
(":COUNTRY", person.address.country)
|
||||
)).await?;
|
||||
let stmt = session.prepare("SELECT PERSON_SEQ.currval FROM dual").await?;
|
||||
let row = stmt.query_single("").await?
|
||||
.ok_or_else(|| ServiceError::ErrorResponse(StatusCode::INTERNAL_SERVER_ERROR, None))?;
|
||||
let id: i32 = row.get(0)?;
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
pub fn map_person_row(row: Row, offset: usize) -> Result<Person, ServiceError> {
|
||||
Ok(Person {
|
||||
id: row.get(0 + offset)?,
|
||||
first_name: row.get(1 + offset)?,
|
||||
last_name: row.get(2 + offset)?,
|
||||
age: row.get(3 + offset)?,
|
||||
address: Address {
|
||||
street: row.get(4 + offset)?,
|
||||
house_number: row.get(5 + offset)?,
|
||||
postal_code: row.get(6 + offset)?,
|
||||
city: row.get(7 + offset)?,
|
||||
country: row.get(8 + offset)?,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue