144 lines
4.7 KiB
Rust

use tokio_postgres::Client as PgClient;
use std::sync::Arc;
use crate::models::car::{BindingCar, Car, Report};
use crate::storages::traits::CarRepository;
use async_trait::async_trait;
pub struct PostgresCarRepository {
pub connection: Arc<PgClient>
}
#[async_trait]
impl CarRepository for PostgresCarRepository {
async fn create(&self, car: BindingCar) -> Result<Car, String> {
let result = self.connection.query(
"INSERT INTO Car(brand, model, price, owner_id, car_station_id) \
VALUES ($1, $2, $3, $4, $5) RETURNING *",
&[&car.brand, &car.model, &car.price, &car.owner_id, &car.car_station_id]
).await;
if let Ok(rows) = result {
let row = rows.get(0).unwrap();
Ok(Car {
id: row.get("id"),
brand: row.get("brand"),
model: row.get("model"),
price: row.get("price"),
owner_id: row.get("owner_id"),
car_station_id: row.get("car_station_id")
})
} else {
Err(result.unwrap_err().to_string())
}
}
async fn read(&self, id: i32) -> Result<Car, String> {
let result = self.connection.query(
"SELECT * FROM Car WHERE id = $1", &[&id]
).await;
if let Ok(rows) = result {
let row = rows.get(0).ok_or("Car not found".to_owned())?;
Ok(Car {
id: row.get("id"),
brand: row.get("brand"),
model: row.get("model"),
price: row.get("price"),
owner_id: row.get("owner_id"),
car_station_id: row.get("car_station_id")
})
} else {
Err(result.unwrap_err().to_string())
}
}
async fn read_all(&self) -> Result<Vec<Car>, String> {
let result = self.connection.query(
"SELECT * FROM Car", &[]
).await;
if let Ok(rows) = result {
Ok(
rows.into_iter().map(|r| Car {
id: r.get("id"),
brand: r.get("brand"),
model: r.get("model"),
price: r.get("price"),
owner_id: r.get("owner_id"),
car_station_id: r.get("car_station_id")
}).collect()
)
} else {
Err(result.unwrap_err().to_string())
}
}
async fn update(&self, id: i32, car: BindingCar) -> Result<Car, String> {
let result = self.connection.query(
"UPDATE Car SET brand = $1, model = $2, price = $3, owner_id = $4, car_station_id = $5 WHERE id = $6 RETURNING *",
&[&car.brand, &car.model, &car.price, &car.owner_id, &car.car_station_id, &id]
).await;
if let Ok(rows) = &result {
let row = rows.get(0).unwrap();
Ok(Car {
id: row.get("id"),
brand: row.get("brand"),
model: row.get("model"),
price: row.get("price"),
owner_id: row.get("owner_id"),
car_station_id: row.get("car_station_id")
})
} else {
Err(result.unwrap_err().to_string())
}
}
async fn delete(&self, id: i32) -> Result<(), String> {
let result = self.connection.execute(
"DELETE FROM Car WHERE id = $1",
&[&id]
).await;
if let Ok(rows) = result {
if rows == 0 {
Err("Car not found".to_owned())
} else {
Ok(())
}
} else {
Err(result.unwrap_err().to_string())
}
}
async fn get_report(&self) -> Result<Vec<Report>, String> {
let result = self.connection.query(
"SELECT
c.id AS \"car_id\",
c.brand AS \"brand\",
c.model AS \"model\",
COUNT(r.id) AS \"times\",
ROUND(SUM(c.price * r.time_amount), 2) AS \"income\"
FROM car c
JOIN rent r ON c.id = r.car_id
WHERE date_trunc('month', r.start_time) = date_trunc('month', CURRENT_DATE)
GROUP BY c.id;", &[]
).await;
if let Ok(rows) = result {
Ok(
rows.into_iter()
.map(|row| Report {
car_id: row.get("car_id"),
brand: row.get("brand"),
model: row.get("model"),
times: row.get("times"),
income: row.get("income")
})
.collect()
)
} else {
Err(result.unwrap_err().to_string())
}
}
}