diff --git a/core/osrd-railjson/src/main/java/fr/sncf/osrd/railjson/schema/rollingstock/RJSRollingStock.java b/core/osrd-railjson/src/main/java/fr/sncf/osrd/railjson/schema/rollingstock/RJSRollingStock.java index 168f4cb3ba4..580f4ab6aba 100644 --- a/core/osrd-railjson/src/main/java/fr/sncf/osrd/railjson/schema/rollingstock/RJSRollingStock.java +++ b/core/osrd-railjson/src/main/java/fr/sncf/osrd/railjson/schema/rollingstock/RJSRollingStock.java @@ -10,7 +10,7 @@ public class RJSRollingStock implements Identified { public static final JsonAdapter adapter = new Moshi.Builder().add(RJSRollingResistance.adapter).build().adapter(RJSRollingStock.class); - public static final transient String CURRENT_VERSION = "3.2"; + public static final transient String CURRENT_VERSION = "3.3"; /** The version of the rolling stock format used */ @Json(name = "railjson_version") diff --git a/editoast/Cargo.lock b/editoast/Cargo.lock index b3d06045a45..8c69b6cdbff 100644 --- a/editoast/Cargo.lock +++ b/editoast/Cargo.lock @@ -1410,8 +1410,10 @@ version = "0.1.0" dependencies = [ "diesel", "diesel-async", + "editoast_common", "editoast_derive", "editoast_models", + "editoast_schemas", "futures 0.3.31", "futures-util", "openssl", @@ -1419,11 +1421,14 @@ dependencies = [ "postgis_diesel", "postgres-openssl", "regex", + "serde", + "strum", "thiserror 2.0.11", "tokio", "tokio-postgres", "tracing", "url", + "utoipa", ] [[package]] diff --git a/editoast/diesel.toml b/editoast/diesel.toml index d6b05bd31ef..8d52cd78f67 100644 --- a/editoast/diesel.toml +++ b/editoast/diesel.toml @@ -3,7 +3,6 @@ [print_schema] file = "editoast_models/src/tables.rs" -generate_missing_sql_type_definitions = false filter = { except_tables = ["spatial_ref_sys"] } import_types = ["diesel::sql_types::*", "postgis_diesel::sql_types::*"] diff --git a/editoast/editoast_models/Cargo.toml b/editoast/editoast_models/Cargo.toml index 63157406b03..7355ccd4944 100644 --- a/editoast/editoast_models/Cargo.toml +++ b/editoast/editoast_models/Cargo.toml @@ -10,7 +10,9 @@ testing = [] [dependencies] diesel.workspace = true diesel-async.workspace = true +editoast_common.workspace = true editoast_derive.workspace = true +editoast_schemas.workspace = true futures.workspace = true futures-util.workspace = true openssl.workspace = true @@ -18,11 +20,14 @@ opentelemetry-semantic-conventions.workspace = true postgis_diesel.workspace = true postgres-openssl.workspace = true regex.workspace = true +serde.workspace = true +strum.workspace = true thiserror.workspace = true tokio.workspace = true tokio-postgres.workspace = true tracing.workspace = true url.workspace = true +utoipa.workspace = true [dev-dependencies] # The feature 'testing' is needed for all of the doc-tests diff --git a/editoast/editoast_models/src/lib.rs b/editoast/editoast_models/src/lib.rs index d68eaa75f50..20454d933c1 100644 --- a/editoast/editoast_models/src/lib.rs +++ b/editoast/editoast_models/src/lib.rs @@ -1,5 +1,6 @@ pub mod db_connection_pool; pub mod model; +pub mod rolling_stock; pub mod tables; pub use db_connection_pool::DbConnection; diff --git a/editoast/editoast_models/src/rolling_stock.rs b/editoast/editoast_models/src/rolling_stock.rs new file mode 100644 index 00000000000..e2836d6a13f --- /dev/null +++ b/editoast/editoast_models/src/rolling_stock.rs @@ -0,0 +1,3 @@ +mod rolling_stock_category; +pub use rolling_stock_category::RollingStockCategories; +pub use rolling_stock_category::RollingStockCategory; diff --git a/editoast/editoast_models/src/rolling_stock/rolling_stock_category.rs b/editoast/editoast_models/src/rolling_stock/rolling_stock_category.rs new file mode 100644 index 00000000000..bfc0d7dc8e1 --- /dev/null +++ b/editoast/editoast_models/src/rolling_stock/rolling_stock_category.rs @@ -0,0 +1,48 @@ +use std::io::Write; +use std::str::FromStr; + +use diesel::deserialize::FromSql; +use diesel::deserialize::FromSqlRow; +use diesel::expression::AsExpression; +use diesel::pg::Pg; +use diesel::pg::PgValue; +use diesel::serialize::Output; +use diesel::serialize::ToSql; +use serde::Deserialize; +use serde::Serialize; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, FromSqlRow, AsExpression)] +#[diesel(sql_type = crate::tables::sql_types::RollingStockCategory)] +pub struct RollingStockCategory(pub editoast_schemas::rolling_stock::RollingStockCategory); + +impl FromSql for RollingStockCategory { + fn from_sql(value: PgValue) -> diesel::deserialize::Result { + let s = std::str::from_utf8(value.as_bytes()).map_err(|_| "Invalid UTF-8 data")?; + editoast_schemas::rolling_stock::RollingStockCategory::from_str(s) + .map(RollingStockCategory) + .map_err(|_| "Unrecognized enum variant for RollingStockCategory".into()) + } +} + +impl ToSql for RollingStockCategory { + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> diesel::serialize::Result { + let variant: &str = &self.0.to_string(); + out.write_all(variant.as_bytes())?; + Ok(diesel::serialize::IsNull::No) + } +} + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub struct RollingStockCategories(pub Vec); + +impl From>> for RollingStockCategories { + fn from(categories: Vec>) -> Self { + Self(categories.into_iter().flatten().collect()) + } +} + +impl From for Vec> { + fn from(categories: RollingStockCategories) -> Self { + categories.0.into_iter().map(Some).collect() + } +} diff --git a/editoast/editoast_models/src/tables.rs b/editoast/editoast_models/src/tables.rs index 2abec3f381f..c53de487a06 100644 --- a/editoast/editoast_models/src/tables.rs +++ b/editoast/editoast_models/src/tables.rs @@ -1,5 +1,15 @@ // @generated automatically by Diesel CLI. +pub mod sql_types { + #[derive(diesel::sql_types::SqlType)] + #[diesel(postgres_type(name = "geometry"))] + pub struct Geometry; + + #[derive(diesel::sql_types::SqlType)] + #[diesel(postgres_type(name = "rolling_stock_category"))] + pub struct RollingStockCategory; +} + diesel::table! { use diesel::sql_types::*; use postgis_diesel::sql_types::*; @@ -102,6 +112,7 @@ diesel::table! { diesel::table! { use diesel::sql_types::*; use postgis_diesel::sql_types::*; + use super::sql_types::Geometry; infra_layer_buffer_stop (id) { id -> Int8, @@ -115,6 +126,7 @@ diesel::table! { diesel::table! { use diesel::sql_types::*; use postgis_diesel::sql_types::*; + use super::sql_types::Geometry; infra_layer_detector (id) { id -> Int8, @@ -128,6 +140,7 @@ diesel::table! { diesel::table! { use diesel::sql_types::*; use postgis_diesel::sql_types::*; + use super::sql_types::Geometry; infra_layer_electrification (id) { id -> Int8, @@ -141,6 +154,7 @@ diesel::table! { diesel::table! { use diesel::sql_types::*; use postgis_diesel::sql_types::*; + use super::sql_types::Geometry; infra_layer_error (id) { id -> Int8, @@ -155,6 +169,7 @@ diesel::table! { diesel::table! { use diesel::sql_types::*; use postgis_diesel::sql_types::*; + use super::sql_types::Geometry; infra_layer_neutral_section (id) { id -> Int8, @@ -168,6 +183,7 @@ diesel::table! { diesel::table! { use diesel::sql_types::*; use postgis_diesel::sql_types::*; + use super::sql_types::Geometry; infra_layer_neutral_sign (id) { id -> Int8, @@ -183,6 +199,7 @@ diesel::table! { diesel::table! { use diesel::sql_types::*; use postgis_diesel::sql_types::*; + use super::sql_types::Geometry; infra_layer_operational_point (id) { id -> Int8, @@ -198,6 +215,7 @@ diesel::table! { diesel::table! { use diesel::sql_types::*; use postgis_diesel::sql_types::*; + use super::sql_types::Geometry; infra_layer_psl_sign (id) { id -> Int8, @@ -213,6 +231,7 @@ diesel::table! { diesel::table! { use diesel::sql_types::*; use postgis_diesel::sql_types::*; + use super::sql_types::Geometry; infra_layer_signal (id) { id -> Int8, @@ -231,6 +250,7 @@ diesel::table! { diesel::table! { use diesel::sql_types::*; use postgis_diesel::sql_types::*; + use super::sql_types::Geometry; infra_layer_speed_section (id) { id -> Int8, @@ -244,6 +264,7 @@ diesel::table! { diesel::table! { use diesel::sql_types::*; use postgis_diesel::sql_types::*; + use super::sql_types::Geometry; infra_layer_switch (id) { id -> Int8, @@ -257,6 +278,7 @@ diesel::table! { diesel::table! { use diesel::sql_types::*; use postgis_diesel::sql_types::*; + use super::sql_types::Geometry; infra_layer_track_section (id) { id -> Int8, @@ -455,6 +477,7 @@ diesel::table! { diesel::table! { use diesel::sql_types::*; use postgis_diesel::sql_types::*; + use super::sql_types::RollingStockCategory; rolling_stock (id) { id -> Int8, @@ -484,6 +507,8 @@ diesel::table! { version -> Int8, supported_signaling_systems -> Array>, etcs_brake_params -> Jsonb, + primary_category -> RollingStockCategory, + other_categories -> Array>, } } diff --git a/editoast/editoast_schemas/src/rolling_stock.rs b/editoast/editoast_schemas/src/rolling_stock.rs index b015d12a5ad..e5c2959e5ca 100644 --- a/editoast/editoast_schemas/src/rolling_stock.rs +++ b/editoast/editoast_schemas/src/rolling_stock.rs @@ -36,6 +36,10 @@ pub use rolling_stock_livery::RollingStockLiveryMetadata; mod towed_rolling_stock; pub use towed_rolling_stock::TowedRollingStock; +mod rolling_stock_category; +pub use rolling_stock_category::RollingStockCategories; +pub use rolling_stock_category::RollingStockCategory; + use editoast_common::units; use editoast_common::units::quantities::{ Acceleration, Deceleration, Length, Mass, Ratio, Time, Velocity, @@ -53,9 +57,10 @@ editoast_common::schemas! { rolling_resistance::schemas(), rolling_stock_livery::schemas(), supported_signaling_systems::schemas(), + rolling_stock_category::schemas(), } -pub const ROLLING_STOCK_RAILJSON_VERSION: &str = "3.2"; +pub const ROLLING_STOCK_RAILJSON_VERSION: &str = "3.3"; #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] #[serde(remote = "Self")] diff --git a/editoast/editoast_schemas/src/rolling_stock/rolling_stock_category.rs b/editoast/editoast_schemas/src/rolling_stock/rolling_stock_category.rs new file mode 100644 index 00000000000..c07d3d4e862 --- /dev/null +++ b/editoast/editoast_schemas/src/rolling_stock/rolling_stock_category.rs @@ -0,0 +1,48 @@ +use serde::Deserialize; +use serde::Serialize; +use strum::Display; +use strum::EnumString; +use strum::IntoStaticStr; +use utoipa::ToSchema; + +editoast_common::schemas! { + RollingStockCategory, + RollingStockCategories, +} + +// This enum maps to a Postgres enum type, specifically `rolling_stock_category`. +// Any changes made to this enum must be reflected in the corresponding Postgres enum, +// and vice versa, to ensure consistency between the application and the database. +#[derive( + Debug, Clone, PartialEq, Serialize, Deserialize, ToSchema, EnumString, IntoStaticStr, Display, +)] +#[strum(serialize_all = "kebab-case")] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum RollingStockCategory { + Unknown, + HighSpeedTrain, + IntercityTrain, + RegionalTrainMultipleUnit, + NightTrain, + CommuterTrain, + FreightTrain, + FastFreightTrain, + TramTrain, + TouristicTrain, + WorkTrain, +} + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, ToSchema)] +pub struct RollingStockCategories(pub Vec); + +impl From>> for RollingStockCategories { + fn from(categories: Vec>) -> Self { + Self(categories.into_iter().flatten().collect()) + } +} + +impl From for Vec> { + fn from(categories: RollingStockCategories) -> Self { + categories.0.into_iter().map(Some).collect() + } +} diff --git a/editoast/migrations/2025-02-03-094532_add_primary_and_other_categories_to_rolling_stock/down.sql b/editoast/migrations/2025-02-03-094532_add_primary_and_other_categories_to_rolling_stock/down.sql new file mode 100644 index 00000000000..3b34bd465e7 --- /dev/null +++ b/editoast/migrations/2025-02-03-094532_add_primary_and_other_categories_to_rolling_stock/down.sql @@ -0,0 +1,7 @@ +ALTER TABLE rolling_stock +DROP COLUMN primary_category, +DROP COLUMN other_categories; + +UPDATE rolling_stock SET railjson_version = '3.2'; + +DROP TYPE rolling_stock_category; diff --git a/editoast/migrations/2025-02-03-094532_add_primary_and_other_categories_to_rolling_stock/up.sql b/editoast/migrations/2025-02-03-094532_add_primary_and_other_categories_to_rolling_stock/up.sql new file mode 100644 index 00000000000..1a53c893c69 --- /dev/null +++ b/editoast/migrations/2025-02-03-094532_add_primary_and_other_categories_to_rolling_stock/up.sql @@ -0,0 +1,19 @@ +CREATE TYPE rolling_stock_category AS ENUM ( + 'unknown', + 'high-speed-train', + 'intercity-train', + 'regional-train-multiple-unit', + 'night-train', + 'commuter-train', + 'freight-train', + 'fast-freight-train', + 'tram-train', + 'touristic-train', + 'work-train' +); + +ALTER TABLE rolling_stock +ADD COLUMN primary_category rolling_stock_category NOT NULL DEFAULT 'unknown', +ADD COLUMN other_categories rolling_stock_category[] NOT NULL DEFAULT '{}'; + +UPDATE rolling_stock SET railjson_version = '3.3'; diff --git a/editoast/openapi.yaml b/editoast/openapi.yaml index a2fcbc89688..02d92dad4ee 100644 --- a/editoast/openapi.yaml +++ b/editoast/openapi.yaml @@ -9410,6 +9410,8 @@ components: - raise_pantograph_time - version - supported_signaling_systems + - primary_category + - other_categories properties: base_power_class: type: string @@ -9466,10 +9468,14 @@ components: nullable: true name: type: string + other_categories: + $ref: '#/components/schemas/RollingStockCategories' power_restrictions: type: object additionalProperties: type: string + primary_category: + $ref: '#/components/schemas/RollingStockCategory' railjson_version: type: string raise_pantograph_time: @@ -9494,6 +9500,24 @@ components: version: type: integer format: int64 + RollingStockCategories: + type: array + items: + $ref: '#/components/schemas/RollingStockCategory' + RollingStockCategory: + type: string + enum: + - UNKNOWN + - HIGH_SPEED_TRAIN + - INTERCITY_TRAIN + - REGIONAL_TRAIN_MULTIPLE_UNIT + - NIGHT_TRAIN + - COMMUTER_TRAIN + - FREIGHT_TRAIN + - FAST_FREIGHT_TRAIN + - TRAM_TRAIN + - TOURISTIC_TRAIN + - WORK_TRAIN RollingStockForm: type: object required: diff --git a/editoast/src/models/rolling_stock_model.rs b/editoast/src/models/rolling_stock_model.rs index a776316521f..d638f52cfbe 100644 --- a/editoast/src/models/rolling_stock_model.rs +++ b/editoast/src/models/rolling_stock_model.rs @@ -8,6 +8,8 @@ use editoast_common::units::quantities::{ }; use editoast_derive::Model; use editoast_models::model; +use editoast_models::rolling_stock::RollingStockCategories; +use editoast_models::rolling_stock::RollingStockCategory; use editoast_schemas::rolling_stock::EffortCurves; use editoast_schemas::rolling_stock::EnergySource; use editoast_schemas::rolling_stock::EtcsBrakeParams; @@ -100,6 +102,9 @@ pub struct RollingStockModel { #[schema(value_type = Vec)] #[model(remote = "Vec>")] pub supported_signaling_systems: RollingStockSupportedSignalingSystems, + pub primary_category: RollingStockCategory, + #[model(remote = "Vec>")] + pub other_categories: RollingStockCategories, } #[derive(Debug, thiserror::Error)] @@ -241,13 +246,16 @@ impl From for RollingStockModelChangeset { #[cfg(test)] pub mod tests { - use rstest::*; + use editoast_models::rolling_stock::RollingStockCategories; + use editoast_models::rolling_stock::RollingStockCategory; + use rstest::rstest; use serde_json::to_value; use super::RollingStockModel; use crate::error::InternalError; use crate::models::fixtures::create_fast_rolling_stock; use crate::models::fixtures::create_rolling_stock_with_energy_sources; + use crate::models::fixtures::fast_rolling_stock_changeset; use crate::models::fixtures::rolling_stock_with_energy_sources_changeset; use crate::models::prelude::*; use crate::views::rolling_stock::map_diesel_error; @@ -317,4 +325,59 @@ pub mod tests { to_value(error).unwrap() ); } + + #[rstest] + async fn test_primary_category_is_unknown_with_other_categories_are_empty() { + let db_pool = DbConnectionPoolV2::for_tests(); + + let created_fast_rolling_stock = + create_fast_rolling_stock(&mut db_pool.get_ok(), "fast_rolling_stock_name").await; + + assert_eq!( + created_fast_rolling_stock.primary_category, + RollingStockCategory(editoast_schemas::rolling_stock::RollingStockCategory::Unknown) + ); + assert_eq!( + created_fast_rolling_stock.other_categories, + RollingStockCategories(vec![]) + ); + } + + #[rstest] + async fn create_rolling_stock_with_categories() { + let db_pool = DbConnectionPoolV2::for_tests(); + + let rolling_stock = fast_rolling_stock_changeset("fast_rolling_stock_with_categories") + .primary_category(RollingStockCategory( + editoast_schemas::rolling_stock::RollingStockCategory::HighSpeedTrain, + )) + .other_categories(RollingStockCategories(vec![ + RollingStockCategory( + editoast_schemas::rolling_stock::RollingStockCategory::TramTrain, + ), + RollingStockCategory( + editoast_schemas::rolling_stock::RollingStockCategory::CommuterTrain, + ), + ])) + .create(&mut db_pool.get_ok()) + .await + .expect("Failed to create rolling stock"); + assert_eq!( + rolling_stock.primary_category, + RollingStockCategory( + editoast_schemas::rolling_stock::RollingStockCategory::HighSpeedTrain, + ), + ); + assert_eq!( + rolling_stock.other_categories, + RollingStockCategories(vec![ + RollingStockCategory( + editoast_schemas::rolling_stock::RollingStockCategory::TramTrain, + ), + RollingStockCategory( + editoast_schemas::rolling_stock::RollingStockCategory::CommuterTrain, + ), + ]) + ); + } } diff --git a/editoast/src/tests/example_rolling_stock_1.json b/editoast/src/tests/example_rolling_stock_1.json index d962911f332..0dd5251ae18 100644 --- a/editoast/src/tests/example_rolling_stock_1.json +++ b/editoast/src/tests/example_rolling_stock_1.json @@ -1,5 +1,5 @@ { - "railjson_version": "3.2", + "railjson_version": "3.3", "locked": false, "length": 400.0, "max_speed": 80.0, @@ -980,5 +980,7 @@ "power_restrictions": {"C2":"2", "C5":"5"}, "electrical_power_startup_time": 5.0, "raise_pantograph_time": 15.0, - "supported_signaling_systems": ["BAL", "BAPR", "TVM300", "TVM430"] + "supported_signaling_systems": ["BAL", "BAPR", "TVM300", "TVM430"], + "primary_category": "COMMUTER_TRAIN", + "other_categories": [] } diff --git a/editoast/src/tests/example_rolling_stock_2_energy_sources.json b/editoast/src/tests/example_rolling_stock_2_energy_sources.json index f9fc606dda8..bad7e223b90 100644 --- a/editoast/src/tests/example_rolling_stock_2_energy_sources.json +++ b/editoast/src/tests/example_rolling_stock_2_energy_sources.json @@ -1,5 +1,5 @@ { - "railjson_version": "3.2", + "railjson_version": "3.3", "locked": false, "length": 200.0, "max_speed": 40.0, @@ -207,5 +207,7 @@ "power_restrictions": {}, "electrical_power_startup_time": 6.0, "raise_pantograph_time": 16.0, - "supported_signaling_systems": ["BAL", "BAPR", "TVM300", "TVM430"] + "supported_signaling_systems": ["BAL", "BAPR", "TVM300", "TVM430"], + "primary_category": "COMMUTER_TRAIN", + "other_categories": [] } diff --git a/editoast/src/tests/example_rolling_stock_3.json b/editoast/src/tests/example_rolling_stock_3.json index ec488279879..fa9ae028cb0 100644 --- a/editoast/src/tests/example_rolling_stock_3.json +++ b/editoast/src/tests/example_rolling_stock_3.json @@ -1,5 +1,5 @@ { - "railjson_version": "3.2", + "railjson_version": "3.3", "version": 0, "locked": false, "length": 200.0, @@ -66,5 +66,7 @@ "power_restrictions": {}, "electrical_power_startup_time": 4.0, "raise_pantograph_time": 14.0, - "supported_signaling_systems": ["BAL", "BAPR", "TVM300", "TVM430"] + "supported_signaling_systems": ["BAL", "BAPR", "TVM300", "TVM430"], + "primary_category": "COMMUTER_TRAIN", + "other_categories": [] } diff --git a/editoast/src/tests/example_towed_rolling_stock_1.json b/editoast/src/tests/example_towed_rolling_stock_1.json index 39e638a1ac7..65593a74f3b 100644 --- a/editoast/src/tests/example_towed_rolling_stock_1.json +++ b/editoast/src/tests/example_towed_rolling_stock_1.json @@ -2,7 +2,7 @@ { "name": "towed_rolling_stock", "label": "some towed rolling stock", - "railjson_version": "3.2", + "railjson_version": "3.3", "locked": false, "mass": 900000.0, "length": 400.0, @@ -15,5 +15,7 @@ "B": 200, "C": 12 }, - "const_gamma": 0.5 + "const_gamma": 0.5, + "primary_category": "COMMUTER_TRAIN", + "other_categories": [] } diff --git a/editoast/src/tests/small_infra/stdcm/test_1/stdcm_core_payload.json b/editoast/src/tests/small_infra/stdcm/test_1/stdcm_core_payload.json index 5ad6ea20b0e..8661f497a05 100644 --- a/editoast/src/tests/small_infra/stdcm/test_1/stdcm_core_payload.json +++ b/editoast/src/tests/small_infra/stdcm/test_1/stdcm_core_payload.json @@ -4,7 +4,7 @@ "rolling_stock": { "id": 899, "name": "TC64700", - "version": "3.2", + "version": "3.3", "locked": true, "effort_curves": { "modes": { @@ -119,7 +119,9 @@ "energy_sources": [], "electrical_power_startup_time": null, "raise_pantograph_time": null, - "supported_signaling_systems": ["BAL", "BAPR", "TVM300", "TVM430"] + "supported_signaling_systems": ["BAL", "BAPR", "TVM300", "TVM430"], + "primary_category": "COMMUTER_TRAIN", + "other_categories": [] }, "comfort": "STANDARD", "route_occupancies": [], diff --git a/front/src/common/api/generatedEditoastApi.ts b/front/src/common/api/generatedEditoastApi.ts index 03e6712c711..6270dbd46d9 100644 --- a/front/src/common/api/generatedEditoastApi.ts +++ b/front/src/common/api/generatedEditoastApi.ts @@ -3138,6 +3138,19 @@ export type EffortCurves = { [key: string]: ModeEffortCurves; }; }; +export type RollingStockCategory = + | 'UNKNOWN' + | 'HIGH_SPEED_TRAIN' + | 'INTERCITY_TRAIN' + | 'REGIONAL_TRAIN_MULTIPLE_UNIT' + | 'NIGHT_TRAIN' + | 'COMMUTER_TRAIN' + | 'FREIGHT_TRAIN' + | 'FAST_FREIGHT_TRAIN' + | 'TRAM_TRAIN' + | 'TOURISTIC_TRAIN' + | 'WORK_TRAIN'; +export type RollingStockCategories = RollingStockCategory[]; export type RollingStock = { base_power_class: string | null; /** Acceleration in m·s⁻² */ @@ -3162,9 +3175,11 @@ export type RollingStock = { max_speed: number; metadata: RollingStockMetadata | null; name: string; + other_categories: RollingStockCategories; power_restrictions: { [key: string]: string; }; + primary_category: RollingStockCategory; railjson_version: string; /** Duration in s */ raise_pantograph_time: number | null; diff --git a/python/osrd_schemas/osrd_schemas/rolling_stock.py b/python/osrd_schemas/osrd_schemas/rolling_stock.py index abe2f90d068..1ae96c5895a 100644 --- a/python/osrd_schemas/osrd_schemas/rolling_stock.py +++ b/python/osrd_schemas/osrd_schemas/rolling_stock.py @@ -12,10 +12,28 @@ from .infra import LoadingGaugeType -RAILJSON_ROLLING_STOCK_VERSION_TYPE = Literal["3.2"] +RAILJSON_ROLLING_STOCK_VERSION_TYPE = Literal["3.3"] RAILJSON_ROLLING_STOCK_VERSION = get_args(RAILJSON_ROLLING_STOCK_VERSION_TYPE)[0] +class RollingStockCategory(str, Enum): + """ + The list of categories that can be assigned to a rolling stock. + """ + + UNKNOWN = "Unknown" + HIGH_SPEED_TRAIN = "High Speed Train" + INTERCITY_TRAIN = "Intercity Train" + REGIONAL_TRAIN_MULTIPLE_UNIT = "Regional Train Multiple Unit" + NIGHT_TRAIN = "Night Train" + COMMUTER_TRAIN = "Commuter Train" + FREIGHT_TRAIN = "Freight Train" + FAST_FREIGHT_TRAIN = "Fast Freight Train" + TRAM_TRAIN = "Tram Train" + TOURISTIC_TRAIN = "Touristic Train" + WORK_TRAIN = "Work Train" + + class ComfortType(str, Enum): """ This enum defines the comfort type that can take a train. @@ -332,6 +350,12 @@ class RollingStock(BaseModel, extra="forbid"): default=None, ) supported_signaling_systems: List[str] = Field(default_factory=list) + primary_category: RollingStockCategory = Field( + description="The primary category of the rolling stock." + ) + other_categories: List[RollingStockCategory] = Field( + description="Additional categories for the rolling stock." + ) class TowedRollingStock(BaseModel, extra="forbid"): diff --git a/python/osrd_schemas/pyproject.toml b/python/osrd_schemas/pyproject.toml index e0be8ae76d3..66eb2c63b88 100644 --- a/python/osrd_schemas/pyproject.toml +++ b/python/osrd_schemas/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "osrd_schemas" -version = "0.8.16" +version = "0.8.17" description = "" authors = [{ name = "OSRD Contributors", email = "contact@osrd.fr" }] requires-python = ">= 3.11" diff --git a/tests/data/rolling_stocks/electric_rolling_stock.json b/tests/data/rolling_stocks/electric_rolling_stock.json index 876f8925f46..99b7965194b 100644 --- a/tests/data/rolling_stocks/electric_rolling_stock.json +++ b/tests/data/rolling_stocks/electric_rolling_stock.json @@ -1,5 +1,5 @@ { - "railjson_version": "3.2", + "railjson_version": "3.3", "locked": true, "length": 400, "max_speed": 80, @@ -975,5 +975,7 @@ "BAPR", "TVM300", "TVM430" - ] + ], + "primary_category": "FREIGHT_TRAIN", + "other_categories": [] } diff --git a/tests/data/rolling_stocks/etcs_level2_rolling_stock.json b/tests/data/rolling_stocks/etcs_level2_rolling_stock.json index 1214836b12e..6e3610a141a 100644 --- a/tests/data/rolling_stocks/etcs_level2_rolling_stock.json +++ b/tests/data/rolling_stocks/etcs_level2_rolling_stock.json @@ -1,5 +1,5 @@ { - "railjson_version": "3.2", + "railjson_version": "3.3", "locked": true, "length": 400, "max_speed": 80, @@ -149,5 +149,7 @@ "TVM300", "TVM430", "ETCS_LEVEL2" - ] + ], + "primary_category": "TOURISTIC_TRAIN", + "other_categories": [] } diff --git a/tests/data/rolling_stocks/fast_rolling_stock.json b/tests/data/rolling_stocks/fast_rolling_stock.json index 860417c2ec7..b111a09a011 100644 --- a/tests/data/rolling_stocks/fast_rolling_stock.json +++ b/tests/data/rolling_stocks/fast_rolling_stock.json @@ -1,5 +1,5 @@ { - "railjson_version": "3.2", + "railjson_version": "3.3", "locked": true, "length": 400, "max_speed": 80, @@ -74,5 +74,7 @@ "BAPR", "TVM300", "TVM430" - ] + ], + "primary_category": "WORK_TRAIN", + "other_categories": [] } diff --git a/tests/data/rolling_stocks/fast_rolling_stock_high_gamma.json b/tests/data/rolling_stocks/fast_rolling_stock_high_gamma.json index 7cac0306f4a..af77db915d5 100644 --- a/tests/data/rolling_stocks/fast_rolling_stock_high_gamma.json +++ b/tests/data/rolling_stocks/fast_rolling_stock_high_gamma.json @@ -1,5 +1,5 @@ { - "railjson_version": "3.2", + "railjson_version": "3.3", "locked": true, "length": 400, "max_speed": 80, @@ -73,5 +73,7 @@ "BAPR", "TVM300", "TVM430" - ] + ], + "primary_category": "HIGH_SPEED_TRAIN", + "other_categories": [] } diff --git a/tests/data/rolling_stocks/short_fast_rolling_stock.json b/tests/data/rolling_stocks/short_fast_rolling_stock.json index f6ff59d6d17..855f94b4ee7 100644 --- a/tests/data/rolling_stocks/short_fast_rolling_stock.json +++ b/tests/data/rolling_stocks/short_fast_rolling_stock.json @@ -1,5 +1,5 @@ { - "railjson_version": "3.2", + "railjson_version": "3.3", "locked": true, "length": 15, "max_speed": 20, @@ -73,5 +73,7 @@ "BAPR", "TVM300", "TVM430" - ] + ], + "primary_category": "TRAM_TRAIN", + "other_categories": [] } diff --git a/tests/data/rolling_stocks/short_slow_rolling_stock.json b/tests/data/rolling_stocks/short_slow_rolling_stock.json index 800512c61e7..cb1360406f9 100644 --- a/tests/data/rolling_stocks/short_slow_rolling_stock.json +++ b/tests/data/rolling_stocks/short_slow_rolling_stock.json @@ -1,5 +1,5 @@ { - "railjson_version": "3.2", + "railjson_version": "3.3", "locked": true, "length": 15, "max_speed": 10, @@ -73,5 +73,7 @@ "BAPR", "TVM300", "TVM430" - ] + ], + "primary_category": "INTERCITY_TRAIN", + "other_categories": [] } diff --git a/tests/data/rolling_stocks/slow_rolling_stock.json b/tests/data/rolling_stocks/slow_rolling_stock.json index 7e6352d056c..29cc729cc74 100644 --- a/tests/data/rolling_stocks/slow_rolling_stock.json +++ b/tests/data/rolling_stocks/slow_rolling_stock.json @@ -1,5 +1,5 @@ { - "railjson_version": "3.2", + "railjson_version": "3.3", "locked": true, "length": 400, "max_speed": 10, @@ -73,5 +73,7 @@ "BAPR", "TVM300", "TVM430" - ] + ], + "primary_category": "REGIONAL_TRAIN_MULTIPLE_UNIT", + "other_categories": [] }