diff --git a/editoast/editoast_schemas/src/train_schedule.rs b/editoast/editoast_schemas/src/train_schedule.rs index 650c6ac51bc..fad6191fcc1 100644 --- a/editoast/editoast_schemas/src/train_schedule.rs +++ b/editoast/editoast_schemas/src/train_schedule.rs @@ -7,6 +7,7 @@ pub use schedule_item::ReceptionSignal; pub use schedule_item::ScheduleItem; mod path_item; +pub use path_item::OperationalPointIdentifier; pub use path_item::PathItem; pub use path_item::PathItemLocation; diff --git a/editoast/editoast_schemas/src/train_schedule/path_item.rs b/editoast/editoast_schemas/src/train_schedule/path_item.rs index 0ae69acb9ef..8c5dcb543bc 100644 --- a/editoast/editoast_schemas/src/train_schedule/path_item.rs +++ b/editoast/editoast_schemas/src/train_schedule/path_item.rs @@ -32,6 +32,18 @@ pub struct PathItem { #[serde(untagged, deny_unknown_fields)] pub enum PathItemLocation { TrackOffset(#[schema(inline)] TrackOffset), + OperationalPointReference { + #[schema(inline)] + reference: OperationalPointIdentifier, + #[schema(inline)] + track: Option, + track_label: Option, + }, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ToSchema, Hash)] +#[serde(untagged, deny_unknown_fields)] +pub enum OperationalPointIdentifier { OperationalPointId { /// The object id of an operational point #[schema(inline)] diff --git a/editoast/editoast_schemas/src/train_schedule/train_schedule_base.rs b/editoast/editoast_schemas/src/train_schedule/train_schedule_base.rs index d01d0642d03..3feff062634 100644 --- a/editoast/editoast_schemas/src/train_schedule/train_schedule_base.rs +++ b/editoast/editoast_schemas/src/train_schedule/train_schedule_base.rs @@ -162,6 +162,7 @@ mod tests { use serde_json::from_str; use serde_json::to_string; + use crate::train_schedule::path_item::OperationalPointIdentifier::OperationalPointId; use crate::train_schedule::schedule_item::ReceptionSignal; use crate::train_schedule::Margins; use crate::train_schedule::PathItemLocation; @@ -180,8 +181,12 @@ mod tests { /// Test deserialize an invalid train schedule #[test] fn deserialize_duplicate_path_id_train_schedule() { - let location = PathItemLocation::OperationalPointId { - operational_point: "op".into(), + let location = PathItemLocation::OperationalPointReference { + reference: OperationalPointId { + operational_point: "op".into(), + }, + track: None, + track_label: None, }; let path_item = PathItem { id: "a".into(), @@ -235,8 +240,12 @@ mod tests { /// Test deserialize an invalid train schedule #[test] fn deserialize_duplicate_schedule_points_train_schedule() { - let location = PathItemLocation::OperationalPointId { - operational_point: "op".into(), + let location = PathItemLocation::OperationalPointReference { + reference: OperationalPointId { + operational_point: "op".into(), + }, + track: None, + track_label: None, }; let path_item = PathItem { id: "a".into(), @@ -270,8 +279,12 @@ mod tests { /// Test deserialize an invalid train schedule #[test] fn deserialize_arrival_time_first_waypoint_schedule_train_schedule() { - let location = PathItemLocation::OperationalPointId { - operational_point: "op".into(), + let location = PathItemLocation::OperationalPointReference { + reference: OperationalPointId { + operational_point: "op".into(), + }, + track: None, + track_label: None, }; let path_item = PathItem { id: "a".into(), diff --git a/editoast/openapi.yaml b/editoast/openapi.yaml index ebbc3507d24..bbd2a41e8ad 100644 --- a/editoast/openapi.yaml +++ b/editoast/openapi.yaml @@ -7236,36 +7236,51 @@ components: - $ref: '#/components/schemas/TrackOffset' - type: object required: - - operational_point - properties: - operational_point: - type: string - maxLength: 255 - minLength: 1 - - type: object - required: - - trigram + - reference properties: - secondary_code: - type: string - description: An optional secondary code to identify a more specific location + reference: + oneOf: + - type: object + required: + - operational_point + properties: + operational_point: + type: string + maxLength: 255 + minLength: 1 + - type: object + required: + - trigram + properties: + secondary_code: + type: string + description: An optional secondary code to identify a more specific location + nullable: true + trigram: + type: string + minLength: 1 + - type: object + required: + - uic + properties: + secondary_code: + type: string + description: An optional secondary code to identify a more specific location + nullable: true + uic: + type: integer + format: int32 + description: The [UIC](https://en.wikipedia.org/wiki/List_of_UIC_country_codes) code of an operational point + minimum: 0 + track: + allOf: + - type: string + maxLength: 255 + minLength: 1 nullable: true - trigram: + track_label: type: string - minLength: 1 - - type: object - required: - - uic - properties: - secondary_code: - type: string - description: An optional secondary code to identify a more specific location nullable: true - uic: - type: integer - format: int32 - description: The [UIC](https://en.wikipedia.org/wiki/List_of_UIC_country_codes) code of an operational point - minimum: 0 description: The location of a path waypoint PathProperties: type: object diff --git a/editoast/src/views/path/path_item_cache.rs b/editoast/src/views/path/path_item_cache.rs index 59b63c9514c..16342a2ced3 100644 --- a/editoast/src/views/path/path_item_cache.rs +++ b/editoast/src/views/path/path_item_cache.rs @@ -8,6 +8,7 @@ use std::collections::HashMap; use std::collections::HashSet; use editoast_models::DbConnection; +use editoast_schemas::train_schedule::OperationalPointIdentifier; use editoast_schemas::train_schedule::PathItemLocation; use crate::models::OperationalPointModel; @@ -97,21 +98,26 @@ impl PathItemCache { PathItemLocation::TrackOffset(track_offset) => { vec![track_offset.clone()] } - PathItemLocation::OperationalPointId { operational_point } => { - match self.get_from_id(&operational_point.0) { - Some(op) => op.track_offset(), - None => { - invalid_path_items.push(InvalidPathItem { - index, - path_item: path_item.clone(), - }); - continue; - } + PathItemLocation::OperationalPointReference { + reference: OperationalPointIdentifier::OperationalPointId { operational_point }, + .. + } => match self.get_from_id(&operational_point.0) { + Some(op) => op.track_offset(), + None => { + invalid_path_items.push(InvalidPathItem { + index, + path_item: path_item.clone(), + }); + continue; } - } - PathItemLocation::OperationalPointDescription { - trigram, - secondary_code, + }, + PathItemLocation::OperationalPointReference { + reference: + OperationalPointIdentifier::OperationalPointDescription { + trigram, + secondary_code, + }, + .. } => { let ops = self .get_from_trigram(&trigram.0) @@ -127,9 +133,13 @@ impl PathItemCache { } track_offsets_from_ops(&ops) } - PathItemLocation::OperationalPointUic { - uic, - secondary_code, + PathItemLocation::OperationalPointReference { + reference: + OperationalPointIdentifier::OperationalPointUic { + uic, + secondary_code, + }, + .. } => { let ops = self .get_from_uic(i64::from(*uic)) @@ -183,14 +193,24 @@ fn collect_path_item_ids(path_items: &[&PathItemLocation]) -> (Vec, Vec< for item in path_items { match item { - PathItemLocation::OperationalPointDescription { trigram, .. } => { + PathItemLocation::OperationalPointReference { + reference: OperationalPointIdentifier::OperationalPointDescription { trigram, .. }, + .. + } => { trigrams.push(trigram.clone().0); } - PathItemLocation::OperationalPointUic { uic, .. } => { + PathItemLocation::OperationalPointReference { + reference: OperationalPointIdentifier::OperationalPointUic { uic, .. }, + .. + } => { ops_uic.push(i64::from(*uic)); } - PathItemLocation::OperationalPointId { - operational_point, .. + PathItemLocation::OperationalPointReference { + reference: + OperationalPointIdentifier::OperationalPointId { + operational_point, .. + }, + .. } => { ops_id.push(operational_point.clone().0); } diff --git a/editoast/src/views/path/pathfinding.rs b/editoast/src/views/path/pathfinding.rs index ff892b9a171..08df4c8789c 100644 --- a/editoast/src/views/path/pathfinding.rs +++ b/editoast/src/views/path/pathfinding.rs @@ -431,6 +431,7 @@ fn path_input_hash(infra: i64, infra_version: &String, path_input: &PathfindingI pub mod tests { use axum::http::StatusCode; use editoast_models::DbConnectionPoolV2; + use editoast_schemas::train_schedule::OperationalPointIdentifier; use editoast_schemas::train_schedule::PathItemLocation; use pretty_assertions::assert_eq; use rstest::rstest; @@ -457,7 +458,7 @@ pub mod tests { "path_items":[ {"trigram":"WS","secondary_code":"BV"}, {"trigram":"NO_TRIGRAM","secondary_code":null}, - {"trigram":"SWS","secondary_code":"BV"} + {"trigram":"SWS","secondary_code":"BV",} ], "rolling_stock_is_thermal":true, "rolling_stock_loading_gauge":"G1", @@ -475,9 +476,13 @@ pub mod tests { PathfindingInputError::InvalidPathItems { items: vec![InvalidPathItem { index: 1, - path_item: PathItemLocation::OperationalPointDescription { - trigram: "NO_TRIGRAM".into(), - secondary_code: None + path_item: PathItemLocation::OperationalPointReference { + reference: OperationalPointIdentifier::OperationalPointDescription { + trigram: "NO_TRIGRAM".into(), + secondary_code: None + }, + track: None, + track_label: None } }] } diff --git a/front/src/common/api/generatedEditoastApi.ts b/front/src/common/api/generatedEditoastApi.ts index 561d8e83a6e..e2664243ed8 100644 --- a/front/src/common/api/generatedEditoastApi.ts +++ b/front/src/common/api/generatedEditoastApi.ts @@ -2424,18 +2424,23 @@ export type TrackOffset = { export type PathItemLocation = | TrackOffset | { - operational_point: string; - } - | { - /** An optional secondary code to identify a more specific location */ - secondary_code?: string | null; - trigram: string; - } - | { - /** An optional secondary code to identify a more specific location */ - secondary_code?: string | null; - /** The [UIC](https://en.wikipedia.org/wiki/List_of_UIC_country_codes) code of an operational point */ - uic: number; + reference: + | { + operational_point: string; + } + | { + /** An optional secondary code to identify a more specific location */ + secondary_code?: string | null; + trigram: string; + } + | { + /** An optional secondary code to identify a more specific location */ + secondary_code?: string | null; + /** The [UIC](https://en.wikipedia.org/wiki/List_of_UIC_country_codes) code of an operational point */ + uic: number; + }; + track?: string | null; + track_label?: string | null; }; export type PathfindingInputError = | {