Skip to content

Commit 73c1e0b

Browse files
committed
editoast: crud scenario
1 parent c3a8665 commit 73c1e0b

File tree

12 files changed

+460
-326
lines changed

12 files changed

+460
-326
lines changed

editoast/src/modelsv2/scenario.rs

+131-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
1-
use actix_web::web::Data;
1+
use crate::error::Result;
2+
use crate::models::List;
3+
use crate::models::Ordering;
4+
use crate::modelsv2::Model;
5+
use crate::modelsv2::Row;
6+
use crate::views::pagination::Paginate;
7+
use crate::views::pagination::PaginatedResponse;
8+
use crate::views::v2::scenariov2::ScenarioV2WithCountTrains;
9+
use async_trait::async_trait;
210
use chrono::NaiveDateTime;
3-
use diesel::sql_types::{BigInt, Text};
11+
use diesel::sql_query;
12+
use diesel::sql_types::{Array, BigInt, Text};
13+
use diesel::{ExpressionMethods, QueryDsl};
14+
use diesel_async::{AsyncPgConnection as PgConnection, RunQueryDsl};
415
use editoast_derive::ModelV2;
516
use serde_derive::{Deserialize, Serialize};
617
use utoipa::ToSchema;
718

8-
#[derive(Debug, Default, Clone, ModelV2, Deserialize, Serialize)]
9-
#[model(changeset(derive(Deserialize)))]
19+
#[derive(Debug, Clone, ModelV2, Deserialize, Serialize)]
1020
#[model(table = crate::tables::scenariov2)]
21+
#[model(changeset(public))]
1122
pub struct ScenarioV2 {
1223
pub id: i64,
1324
pub infra_id: i64,
@@ -19,3 +30,119 @@ pub struct ScenarioV2 {
1930
pub timetable_id: i64,
2031
pub study_id: i64,
2132
}
33+
34+
#[derive(Debug, Clone, Deserialize, Serialize, QueryableByName, ToSchema)]
35+
pub struct ScenarioV2WithDetails {
36+
#[serde(flatten)]
37+
#[diesel(embed)]
38+
pub scenario: ScenarioV2,
39+
#[diesel(sql_type = Text)]
40+
pub infra_name: String,
41+
// #[diesel(sql_type = Nullable<Text>)]
42+
// pub electrical_profile_set_name: Option<String>,
43+
#[diesel(sql_type = Array<BigInt>)]
44+
pub train_schedule_ids: Vec<i64>,
45+
#[diesel(sql_type = BigInt)]
46+
pub trains_count: i64,
47+
}
48+
49+
impl ScenarioV2 {
50+
pub async fn with_details_conn(self, conn: &mut PgConnection) -> Result<ScenarioV2WithDetails> {
51+
use crate::tables::infra::dsl as infra_dsl;
52+
use crate::tables::trainschedulev2::dsl::*;
53+
54+
let infra_name = infra_dsl::infra
55+
.filter(infra_dsl::id.eq(self.infra_id))
56+
.select(infra_dsl::name)
57+
.first::<String>(conn)
58+
.await?;
59+
60+
// let electrical_profile_set_name = match self.electrical_profile_set_id.unwrap() {
61+
// Some(electrical_profile_set) => Some(
62+
// elec_dsl::electrical_profile_set
63+
// .filter(elec_dsl::id.eq(electrical_profile_set))
64+
// .select(elec_dsl::name)
65+
// .first::<String>(conn)
66+
// .await?,
67+
// ),
68+
// None => None,
69+
// };
70+
71+
let train_schedule_ids = trainschedulev2
72+
.filter(timetable_id.eq(self.timetable_id))
73+
.select(id)
74+
.load::<i64>(conn)
75+
.await?;
76+
77+
let trains_count = train_schedule_ids.len() as i64;
78+
79+
Ok(ScenarioV2WithDetails {
80+
scenario: self,
81+
infra_name,
82+
train_schedule_ids,
83+
trains_count,
84+
})
85+
}
86+
87+
pub async fn with_trains_count(
88+
self,
89+
conn: &mut PgConnection,
90+
) -> Result<ScenarioV2WithCountTrains> {
91+
use crate::tables::infra::dsl as infra_dsl;
92+
use crate::tables::trainschedulev2::dsl as schedule_dsl;
93+
let trains_count = schedule_dsl::trainschedulev2
94+
.filter(schedule_dsl::timetable_id.eq(self.timetable_id))
95+
.count()
96+
.get_result(conn)
97+
.await?;
98+
let infra_name = infra_dsl::infra
99+
.filter(infra_dsl::id.eq(self.infra_id))
100+
.select(infra_dsl::name)
101+
.get_result(conn)
102+
.await?;
103+
Ok(ScenarioV2WithCountTrains::new_from_scenario(
104+
self,
105+
trains_count,
106+
infra_name,
107+
))
108+
}
109+
}
110+
111+
#[async_trait]
112+
impl List<(i64, Ordering)> for ScenarioV2 {
113+
/// List all scenarios with the number of trains.
114+
/// This functions takes a study_id to filter scenarios.
115+
async fn list_conn(
116+
conn: &mut PgConnection,
117+
page: i64,
118+
page_size: i64,
119+
params: (i64, Ordering),
120+
) -> Result<PaginatedResponse<Self>> {
121+
let study_id = params.0;
122+
let ordering = params.1.to_sql();
123+
let scenario_rows = sql_query(format!("WITH scenarios_with_train_counts AS (
124+
SELECT t.*, COUNT(train_schedule.id) as trains_count
125+
FROM scenariov2 as t
126+
LEFT JOIN train_schedule ON t.timetable_id = train_schedule.timetable_id WHERE t.study_id = $1
127+
GROUP BY t.id ORDER BY {ordering}
128+
)
129+
SELECT scenarios_with_train_counts.*, infra.name as infra_name
130+
FROM scenarios_with_train_counts
131+
JOIN infra ON infra.id = infra_id"))
132+
.bind::<BigInt, _>(study_id)
133+
.paginate(page, page_size)
134+
.load_and_count::<Row<ScenarioV2>>(conn).await?;
135+
136+
let results: Vec<ScenarioV2> = scenario_rows
137+
.results
138+
.into_iter()
139+
.map(Self::from_row)
140+
.collect();
141+
Ok(PaginatedResponse {
142+
count: scenario_rows.count,
143+
previous: scenario_rows.previous,
144+
next: scenario_rows.next,
145+
results,
146+
})
147+
}
148+
}

editoast/src/modelsv2/timetable.rs

+39-22
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,50 @@
1-
use std::collections::HashMap;
2-
3-
use crate::diesel::QueryDsl;
1+
use crate::diesel::query_dsl::methods::DistinctDsl;
42
use crate::error::Result;
5-
use crate::models::LightRollingStockModel;
6-
use crate::models::Retrieve;
7-
use crate::models::{
8-
train_schedule::{
9-
LightTrainSchedule, MechanicalEnergyConsumedBaseEco, TrainSchedule, TrainScheduleSummary,
10-
},
11-
SimulationOutput,
12-
};
13-
use crate::tables::timetable;
14-
use crate::DbPool;
15-
use actix_web::web::Data;
16-
use derivative::Derivative;
17-
use diesel::prelude::*;
18-
use diesel::result::Error as DieselError;
19-
use diesel::ExpressionMethods;
3+
use crate::models::List;
4+
use crate::models::NoParams;
5+
use crate::modelsv2::Model;
6+
use crate::modelsv2::Row;
7+
use crate::tables::timetablev2::dsl;
8+
use crate::views::pagination::Paginate;
9+
use crate::views::pagination::PaginatedResponse;
10+
use async_trait::async_trait;
2011
use diesel_async::AsyncPgConnection as PgConnection;
21-
use diesel_async::RunQueryDsl;
22-
use editoast_derive::Model;
2312
use editoast_derive::ModelV2;
24-
use futures::future::try_join_all;
2513
use serde::{Deserialize, Serialize};
2614

27-
#[derive(Debug, Default, Clone, Serialize, Deserialize, ModelV2)]
15+
#[derive(Debug, Default, Clone, ModelV2, Serialize, Deserialize)]
2816
#[model(table = crate::tables::timetablev2)]
2917
#[model(changeset(public))]
3018
pub struct TimetableV2 {
3119
pub id: i64,
3220
pub electrical_profile_set_id: Option<i64>,
3321
}
22+
23+
#[async_trait]
24+
impl List<NoParams> for TimetableV2 {
25+
async fn list_conn(
26+
conn: &mut PgConnection,
27+
page: i64,
28+
page_size: i64,
29+
_: NoParams,
30+
) -> Result<PaginatedResponse<Self>> {
31+
let timetable_rows = dsl::timetablev2
32+
.distinct()
33+
.paginate(page, page_size)
34+
.load_and_count::<Row<TimetableV2>>(conn)
35+
.await?;
36+
37+
let results: Vec<TimetableV2> = timetable_rows
38+
.results
39+
.into_iter()
40+
.map(Self::from_row)
41+
.collect();
42+
43+
Ok(PaginatedResponse {
44+
count: timetable_rows.count,
45+
previous: timetable_rows.previous,
46+
next: timetable_rows.next,
47+
results,
48+
})
49+
}
50+
}

editoast/src/modelsv2/trainschedule.rs

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use crate::schema::v2::trainschedulev2::{
33
};
44
use crate::DieselJson;
55
use chrono::NaiveDateTime;
6-
use diesel_async::RunQueryDsl;
76
use editoast_derive::ModelV2;
87
use serde::{Deserialize, Serialize};
98

editoast/src/schema/v2/trainschedulev2.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,11 @@ impl<'de> Deserialize<'de> for MarginValue {
8484
})?;
8585
return Ok(Self::Percentage(float_value));
8686
}
87-
return Err(serde::de::Error::custom("Invalid margin value"));
87+
if f64::from_str(&value).is_ok() {
88+
let float_value = value.parse::<f64>().unwrap();
89+
return Ok(Self::MinPerKm(float_value));
90+
}
91+
Err(serde::de::Error::custom("Invalid margin value"))
8892
}
8993
}
9094

editoast/src/views/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ fn routes_v2() -> Routes<impl HttpServiceFactory> {
4949
documents::routes(),
5050
sprites::routes(),
5151
projects::routes(),
52+
v2::routes(),
5253
search::routes(),
5354
electrical_profiles::routes(),
5455
layers::routes(),

editoast/src/views/scenario.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ impl ScenarioResponse {
124124
}
125125

126126
/// Check if project and study exist given a study ID and a project ID
127-
async fn check_project_study(
127+
pub async fn check_project_study(
128128
db_pool: Data<DbPool>,
129129
project_id: i64,
130130
study_id: i64,
@@ -133,7 +133,7 @@ async fn check_project_study(
133133
check_project_study_conn(&mut conn, project_id, study_id).await
134134
}
135135

136-
async fn check_project_study_conn(
136+
pub async fn check_project_study_conn(
137137
conn: &mut PgConnection,
138138
project_id: i64,
139139
study_id: i64,

editoast/src/views/timetable.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ crate::schemas! {
3737

3838
#[derive(Debug, Error, EditoastError)]
3939
#[editoast_error(base_id = "timetable")]
40-
enum TimetableError {
40+
pub enum TimetableError {
4141
#[error("Timetable '{timetable_id}', could not be found")]
4242
#[editoast_error(status = 404)]
4343
NotFound { timetable_id: i64 },

editoast/src/views/train_schedule/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ pub enum TrainScheduleError {
9595

9696
#[derive(IntoParams)]
9797
#[allow(unused)]
98-
struct TrainScheduleIdParam {
98+
pub struct TrainScheduleIdParam {
9999
/// A train schedule ID
100100
id: i64,
101101
}

editoast/src/views/v2/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
11
pub mod scenariov2;
22
pub mod timetablev2;
33
pub mod trainschedulev2;
4+
5+
crate::routes! {
6+
7+
trainschedulev2::routes(),
8+
timetablev2::routes(),
9+
scenariov2::routes()
10+
11+
}

0 commit comments

Comments
 (0)