Skip to content

Commit

Permalink
editoast: crud scenario
Browse files Browse the repository at this point in the history
  • Loading branch information
younesschrifi committed Feb 13, 2024
1 parent 06cfde4 commit 7f59ae8
Show file tree
Hide file tree
Showing 12 changed files with 460 additions and 326 deletions.
135 changes: 131 additions & 4 deletions editoast/src/modelsv2/scenario.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
use actix_web::web::Data;
use crate::error::Result;
use crate::models::List;
use crate::models::Ordering;
use crate::modelsv2::Model;
use crate::modelsv2::Row;
use crate::views::pagination::Paginate;
use crate::views::pagination::PaginatedResponse;
use crate::views::v2::scenariov2::ScenarioV2WithCountTrains;
use async_trait::async_trait;
use chrono::NaiveDateTime;
use diesel::sql_types::{BigInt, Text};
use diesel::sql_query;
use diesel::sql_types::{Array, BigInt, Text};
use diesel::{ExpressionMethods, QueryDsl};
use diesel_async::{AsyncPgConnection as PgConnection, RunQueryDsl};
use editoast_derive::ModelV2;
use serde_derive::{Deserialize, Serialize};
use utoipa::ToSchema;

#[derive(Debug, Default, Clone, ModelV2, Deserialize, Serialize)]
#[model(changeset(derive(Deserialize)))]
#[derive(Debug, Clone, ModelV2, Deserialize, Serialize)]
#[model(table = crate::tables::scenariov2)]
#[model(changeset(public))]
pub struct ScenarioV2 {
pub id: i64,
pub infra_id: i64,
Expand All @@ -19,3 +30,119 @@ pub struct ScenarioV2 {
pub timetable_id: i64,
pub study_id: i64,
}

#[derive(Debug, Clone, Deserialize, Serialize, QueryableByName, ToSchema)]
pub struct ScenarioV2WithDetails {
#[serde(flatten)]
#[diesel(embed)]
pub scenario: ScenarioV2,
#[diesel(sql_type = Text)]
pub infra_name: String,
// #[diesel(sql_type = Nullable<Text>)]
// pub electrical_profile_set_name: Option<String>,
#[diesel(sql_type = Array<BigInt>)]
pub train_schedule_ids: Vec<i64>,
#[diesel(sql_type = BigInt)]
pub trains_count: i64,
}

impl ScenarioV2 {
pub async fn with_details_conn(self, conn: &mut PgConnection) -> Result<ScenarioV2WithDetails> {
use crate::tables::infra::dsl as infra_dsl;
use crate::tables::trainschedulev2::dsl::*;

let infra_name = infra_dsl::infra
.filter(infra_dsl::id.eq(self.infra_id))
.select(infra_dsl::name)
.first::<String>(conn)
.await?;

// let electrical_profile_set_name = match self.electrical_profile_set_id.unwrap() {
// Some(electrical_profile_set) => Some(
// elec_dsl::electrical_profile_set
// .filter(elec_dsl::id.eq(electrical_profile_set))
// .select(elec_dsl::name)
// .first::<String>(conn)
// .await?,
// ),
// None => None,
// };

let train_schedule_ids = trainschedulev2
.filter(timetable_id.eq(self.timetable_id))
.select(id)
.load::<i64>(conn)
.await?;

let trains_count = train_schedule_ids.len() as i64;

Ok(ScenarioV2WithDetails {
scenario: self,
infra_name,
train_schedule_ids,
trains_count,
})
}

pub async fn with_trains_count(
self,
conn: &mut PgConnection,
) -> Result<ScenarioV2WithCountTrains> {
use crate::tables::infra::dsl as infra_dsl;
use crate::tables::trainschedulev2::dsl as schedule_dsl;
let trains_count = schedule_dsl::trainschedulev2
.filter(schedule_dsl::timetable_id.eq(self.timetable_id))
.count()
.get_result(conn)
.await?;
let infra_name = infra_dsl::infra
.filter(infra_dsl::id.eq(self.infra_id))
.select(infra_dsl::name)
.get_result(conn)
.await?;
Ok(ScenarioV2WithCountTrains::new_from_scenario(
self,
trains_count,
infra_name,
))
}
}

#[async_trait]
impl List<(i64, Ordering)> for ScenarioV2 {
/// List all scenarios with the number of trains.
/// This functions takes a study_id to filter scenarios.
async fn list_conn(
conn: &mut PgConnection,
page: i64,
page_size: i64,
params: (i64, Ordering),
) -> Result<PaginatedResponse<Self>> {
let study_id = params.0;
let ordering = params.1.to_sql();
let scenario_rows = sql_query(format!("WITH scenarios_with_train_counts AS (
SELECT t.*, COUNT(train_schedule.id) as trains_count
FROM scenariov2 as t
LEFT JOIN train_schedule ON t.timetable_id = train_schedule.timetable_id WHERE t.study_id = $1
GROUP BY t.id ORDER BY {ordering}
)
SELECT scenarios_with_train_counts.*, infra.name as infra_name
FROM scenarios_with_train_counts
JOIN infra ON infra.id = infra_id"))
.bind::<BigInt, _>(study_id)
.paginate(page, page_size)
.load_and_count::<Row<ScenarioV2>>(conn).await?;

let results: Vec<ScenarioV2> = scenario_rows
.results
.into_iter()
.map(Self::from_row)
.collect();
Ok(PaginatedResponse {
count: scenario_rows.count,
previous: scenario_rows.previous,
next: scenario_rows.next,
results,
})
}
}
61 changes: 39 additions & 22 deletions editoast/src/modelsv2/timetable.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,50 @@
use std::collections::HashMap;

use crate::diesel::QueryDsl;
use crate::diesel::query_dsl::methods::DistinctDsl;
use crate::error::Result;
use crate::models::LightRollingStockModel;
use crate::models::Retrieve;
use crate::models::{
train_schedule::{
LightTrainSchedule, MechanicalEnergyConsumedBaseEco, TrainSchedule, TrainScheduleSummary,
},
SimulationOutput,
};
use crate::tables::timetable;
use crate::DbPool;
use actix_web::web::Data;
use derivative::Derivative;
use diesel::prelude::*;
use diesel::result::Error as DieselError;
use diesel::ExpressionMethods;
use crate::models::List;
use crate::models::NoParams;
use crate::modelsv2::Model;
use crate::modelsv2::Row;
use crate::tables::timetablev2::dsl;
use crate::views::pagination::Paginate;
use crate::views::pagination::PaginatedResponse;
use async_trait::async_trait;
use diesel_async::AsyncPgConnection as PgConnection;
use diesel_async::RunQueryDsl;
use editoast_derive::Model;
use editoast_derive::ModelV2;
use futures::future::try_join_all;
use serde::{Deserialize, Serialize};

#[derive(Debug, Default, Clone, Serialize, Deserialize, ModelV2)]
#[derive(Debug, Default, Clone, ModelV2, Serialize, Deserialize)]
#[model(table = crate::tables::timetablev2)]
#[model(changeset(public))]
pub struct TimetableV2 {
pub id: i64,
pub electrical_profile_set_id: Option<i64>,
}

#[async_trait]
impl List<NoParams> for TimetableV2 {
async fn list_conn(
conn: &mut PgConnection,
page: i64,
page_size: i64,
_: NoParams,
) -> Result<PaginatedResponse<Self>> {
let timetable_rows = dsl::timetablev2
.distinct()
.paginate(page, page_size)
.load_and_count::<Row<TimetableV2>>(conn)
.await?;

let results: Vec<TimetableV2> = timetable_rows
.results
.into_iter()
.map(Self::from_row)
.collect();

Ok(PaginatedResponse {
count: timetable_rows.count,
previous: timetable_rows.previous,
next: timetable_rows.next,
results,
})
}
}
1 change: 0 additions & 1 deletion editoast/src/modelsv2/trainschedule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use crate::schema::v2::trainschedulev2::{
};
use crate::DieselJson;
use chrono::NaiveDateTime;
use diesel_async::RunQueryDsl;
use editoast_derive::ModelV2;
use serde::{Deserialize, Serialize};

Expand Down
6 changes: 5 additions & 1 deletion editoast/src/schema/v2/trainschedulev2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,11 @@ impl<'de> Deserialize<'de> for MarginValue {
})?;
return Ok(Self::Percentage(float_value));
}
return Err(serde::de::Error::custom("Invalid margin value"));
if f64::from_str(&value).is_ok() {
let float_value = value.parse::<f64>().unwrap();
return Ok(Self::MinPerKm(float_value));
}
Err(serde::de::Error::custom("Invalid margin value"))
}
}

Expand Down
1 change: 1 addition & 0 deletions editoast/src/views/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ fn routes_v2() -> Routes<impl HttpServiceFactory> {
documents::routes(),
sprites::routes(),
projects::routes(),
v2::routes(),
search::routes(),
electrical_profiles::routes(),
layers::routes(),
Expand Down
4 changes: 2 additions & 2 deletions editoast/src/views/scenario.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ impl ScenarioResponse {
}

/// Check if project and study exist given a study ID and a project ID
async fn check_project_study(
pub async fn check_project_study(
db_pool: Data<DbPool>,
project_id: i64,
study_id: i64,
Expand All @@ -133,7 +133,7 @@ async fn check_project_study(
check_project_study_conn(&mut conn, project_id, study_id).await
}

async fn check_project_study_conn(
pub async fn check_project_study_conn(
conn: &mut PgConnection,
project_id: i64,
study_id: i64,
Expand Down
2 changes: 1 addition & 1 deletion editoast/src/views/timetable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ crate::schemas! {

#[derive(Debug, Error, EditoastError)]
#[editoast_error(base_id = "timetable")]
enum TimetableError {
pub enum TimetableError {
#[error("Timetable '{timetable_id}', could not be found")]
#[editoast_error(status = 404)]
NotFound { timetable_id: i64 },
Expand Down
2 changes: 1 addition & 1 deletion editoast/src/views/train_schedule/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ pub enum TrainScheduleError {

#[derive(IntoParams)]
#[allow(unused)]
struct TrainScheduleIdParam {
pub struct TrainScheduleIdParam {
/// A train schedule ID
id: i64,
}
Expand Down
8 changes: 8 additions & 0 deletions editoast/src/views/v2/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
pub mod scenariov2;
pub mod timetablev2;
pub mod trainschedulev2;

crate::routes! {

trainschedulev2::routes(),
timetablev2::routes(),
scenariov2::routes()

}
Loading

0 comments on commit 7f59ae8

Please sign in to comment.