From caacf59466577bb3f55a4a0affc2bd47b4c1d334 Mon Sep 17 00:00:00 2001 From: Baptiste Prevot Date: Fri, 29 Sep 2023 17:26:56 +0200 Subject: [PATCH] editoast: add cli commands to list / delete electrical profile sets --- editoast/src/client/mod.rs | 35 ++++++- editoast/src/main.rs | 110 +++++++++++++++++++--- editoast/src/models/electrical_profile.rs | 10 ++ editoast/src/views/electrical_profiles.rs | 10 -- 4 files changed, 143 insertions(+), 22 deletions(-) diff --git a/editoast/src/client/mod.rs b/editoast/src/client/mod.rs index 2918369fcb5..66931f30f43 100644 --- a/editoast/src/client/mod.rs +++ b/editoast/src/client/mod.rs @@ -35,13 +35,25 @@ pub enum Commands { Generate(GenerateArgs), Clear(ClearArgs), ImportRailjson(ImportRailjsonArgs), - ImportProfileSet(ImportProfileSetArgs), + #[command( + subcommand, + about, + long_about = "Commands related to electrical profile sets" + )] + ElectricalProfiles(ElectricalProfilesCommands), ImportRollingStock(ImportRollingStockArgs), OsmToRailjson(OsmToRailjsonArgs), #[command(about, long_about = "Prints the OpenApi of the service")] Openapi, } +#[derive(Subcommand, Debug)] +pub enum ElectricalProfilesCommands { + Import(ImportProfileSetArgs), + Delete(DeleteProfileSetArgs), + List(ListProfileSetArgs), +} + #[derive(Args, Debug, Derivative, Clone)] #[derivative(Default)] pub struct MapLayersConfig { @@ -118,6 +130,27 @@ pub struct ImportProfileSetArgs { pub electrical_profile_set_path: PathBuf, } +#[derive(Args, Debug)] +#[command( + about, + long_about = "Delete electrical profile sets corresponding to the given ids" +)] +pub struct DeleteProfileSetArgs { + /// List of infra ids + pub profile_set_ids: Vec, +} + +#[derive(Args, Debug)] +#[command( + about, + long_about = "List electrical profile sets in the database, - " +)] +pub struct ListProfileSetArgs { + // Wether to display the list in a ready to parse format + #[arg(long, default_value_t = false)] + pub quiet: bool, +} + #[derive(Args, Debug)] #[command(about, long_about = "Import a rolling stock given a json file")] pub struct ImportRollingStockArgs { diff --git a/editoast/src/main.rs b/editoast/src/main.rs index 2dcd6520d1f..bbcc4c1048d 100644 --- a/editoast/src/main.rs +++ b/editoast/src/main.rs @@ -17,7 +17,7 @@ mod views; use crate::core::CoreClient; use crate::error::InternalError; use crate::map::redis_utils::RedisClient; -use crate::models::{Create, Infra}; +use crate::models::{Create, Delete, Infra}; use crate::schema::electrical_profiles::ElectricalProfileSetData; use crate::schema::RailJson; use crate::views::infra::InfraForm; @@ -30,8 +30,9 @@ use actix_web::{App, HttpServer}; use chashmap::CHashMap; use clap::Parser; use client::{ - ClearArgs, Client, Color, Commands, GenerateArgs, ImportProfileSetArgs, ImportRailjsonArgs, - ImportRollingStockArgs, PostgresConfig, RedisConfig, RunserverArgs, + ClearArgs, Client, Color, Commands, DeleteProfileSetArgs, ElectricalProfilesCommands, + GenerateArgs, ImportProfileSetArgs, ImportRailjsonArgs, ImportRollingStockArgs, + ListProfileSetArgs, PostgresConfig, RedisConfig, RunserverArgs, }; use colored::*; use diesel::{ConnectionError, ConnectionResult}; @@ -88,7 +89,6 @@ async fn run() -> Result<(), Box> { Commands::Generate(args) => generate(args, pg_config, redis_config).await, Commands::Clear(args) => clear(args, pg_config, redis_config).await, Commands::ImportRailjson(args) => import_railjson(args, pg_config).await, - Commands::ImportProfileSet(args) => add_electrical_profile_set(args, pg_config).await, Commands::ImportRollingStock(args) => import_rolling_stock(args, pg_config).await, Commands::OsmToRailjson(args) => { converters::osm_to_railjson(args.osm_pbf_in, args.railjson_out) @@ -97,6 +97,17 @@ async fn run() -> Result<(), Box> { generate_openapi(); Ok(()) } + Commands::ElectricalProfiles(subcommand) => match subcommand { + ElectricalProfilesCommands::Import(args) => { + electrical_profile_set_import(args, pg_config).await + } + ElectricalProfilesCommands::List(args) => { + electrical_profile_set_list(args, pg_config).await + } + ElectricalProfilesCommands::Delete(args) => { + electrical_profile_set_delete(args, pg_config).await + } + }, } } @@ -389,7 +400,7 @@ async fn import_railjson( Ok(()) } -async fn add_electrical_profile_set( +async fn electrical_profile_set_import( args: ImportProfileSetArgs, pg_config: PostgresConfig, ) -> Result<(), Box> { @@ -411,6 +422,44 @@ async fn add_electrical_profile_set( Ok(()) } +async fn electrical_profile_set_list( + args: ListProfileSetArgs, + pg_config: PostgresConfig, +) -> Result<(), Box> { + let mut conn = PgConnection::establish(&pg_config.url()).await?; + let electrical_profile_sets = ElectricalProfileSet::list_light(&mut conn).await.unwrap(); + if !args.quiet { + println!("Electrical profile sets:\nID - Name"); + } + for electrical_profile_set in electrical_profile_sets { + println!( + "{:<2} - {}", + electrical_profile_set.id.unwrap(), + electrical_profile_set.name.unwrap() + ); + } + Ok(()) +} + +async fn electrical_profile_set_delete( + args: DeleteProfileSetArgs, + pg_config: PostgresConfig, +) -> Result<(), Box> { + let manager = ConnectionManager::::new(pg_config.url()); + let pool = Data::new(Pool::builder(manager).max_size(1).build().unwrap()); + for profile_set_id in args.profile_set_ids { + let deleted = ElectricalProfileSet::delete(pool.clone(), profile_set_id) + .await + .unwrap(); + if !deleted { + println!("Electrical profile set {} not found", profile_set_id); + } else { + println!("Electrical profile set {} deleted", profile_set_id); + } + } + Ok(()) +} + /// Run the clear subcommand /// This command clear all generated data for the given infra async fn clear( @@ -475,18 +524,16 @@ fn generate_openapi() { #[cfg(test)] mod tests { - use crate::client::{ImportRailjsonArgs, PostgresConfig}; + use super::*; - use crate::import_railjson; - use crate::schema::RailJson; + use crate::fixtures::tests::{electrical_profile_set, TestFixture}; use actix_web::test as actix_test; use diesel::sql_query; use diesel::sql_types::Text; - use diesel_async::{ - AsyncConnection as Connection, AsyncPgConnection as PgConnection, RunQueryDsl, - }; + use diesel_async::RunQueryDsl; use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; + use rstest::rstest; use std::io::Write; use tempfile::NamedTempFile; @@ -548,4 +595,45 @@ mod tests { write!(tmp_file, "{}", serde_json::to_string(railjson).unwrap()).unwrap(); tmp_file } + + #[rstest] + async fn test_electrical_profile_set_delete( + #[future] electrical_profile_set: TestFixture, + ) { + let pg_config = PostgresConfig::default(); + let electrical_profile_set = electrical_profile_set.await; + + let mut conn = PgConnection::establish(&pg_config.url()).await.unwrap(); + let previous_length = ElectricalProfileSet::list_light(&mut conn) + .await + .unwrap() + .len(); + + let args = DeleteProfileSetArgs { + profile_set_ids: vec![electrical_profile_set.id()], + }; + electrical_profile_set_delete(args, pg_config.clone()) + .await + .unwrap(); + + let mut conn = PgConnection::establish(&pg_config.url()).await.unwrap(); + let new_length = ElectricalProfileSet::list_light(&mut conn) + .await + .unwrap() + .len(); + assert_eq!(new_length, previous_length - 1); + } + + #[rstest] + async fn test_electrical_profile_set_list_doesnt_fail( + #[future] electrical_profile_set: TestFixture, + ) { + let _electrical_profile_set = electrical_profile_set.await; + for quiet in [true, false] { + let args = ListProfileSetArgs { quiet }; + electrical_profile_set_list(args, PostgresConfig::default()) + .await + .unwrap(); + } + } } diff --git a/editoast/src/models/electrical_profile.rs b/editoast/src/models/electrical_profile.rs index 8b6ebc73968..367fa71aaaa 100644 --- a/editoast/src/models/electrical_profile.rs +++ b/editoast/src/models/electrical_profile.rs @@ -1,3 +1,4 @@ +use crate::error::Result; use crate::schema::electrical_profiles::ElectricalProfileSetData; use crate::tables::electrical_profile_set; @@ -7,6 +8,7 @@ use crate::models::Identifiable; use crate::DieselJson; use derivative::Derivative; use diesel::result::Error as DieselError; +use diesel_async::{AsyncPgConnection as PgConnection, RunQueryDsl}; use editoast_derive::Model; use serde::{Deserialize, Serialize}; @@ -42,6 +44,14 @@ impl Identifiable for ElectricalProfileSet { } } +impl ElectricalProfileSet { + pub async fn list_light(conn: &mut PgConnection) -> Result> { + use crate::tables::electrical_profile_set::dsl::*; + let result = electrical_profile_set.select((id, name)).load(conn).await?; + Ok(result) + } +} + #[derive(Debug, Default, Queryable, Identifiable, Serialize, Deserialize)] #[diesel(table_name = electrical_profile_set)] pub struct LightElectricalProfileSet { diff --git a/editoast/src/views/electrical_profiles.rs b/editoast/src/views/electrical_profiles.rs index f93e81a1c65..2b9c05f4f34 100644 --- a/editoast/src/views/electrical_profiles.rs +++ b/editoast/src/views/electrical_profiles.rs @@ -1,4 +1,3 @@ -use crate::diesel::QueryDsl; use crate::error::Result; use crate::models::electrical_profile::{ElectricalProfileSet, LightElectricalProfileSet}; use crate::models::{Create, Retrieve}; @@ -9,7 +8,6 @@ use crate::DieselJson; use actix_web::dev::HttpServiceFactory; use actix_web::web::{self, Data, Json, Path, Query}; use actix_web::{get, post}; -use diesel_async::{AsyncPgConnection as PgConnection, RunQueryDsl}; use editoast_derive::EditoastError; use serde::Deserialize; use std::collections::HashMap; @@ -82,14 +80,6 @@ async fn get_level_order( Ok(Json(ep_set.data.unwrap().0.level_order)) } -impl ElectricalProfileSet { - async fn list_light(conn: &mut PgConnection) -> Result> { - use crate::tables::electrical_profile_set::dsl::*; - let result = electrical_profile_set.select((id, name)).load(conn).await?; - Ok(result) - } -} - #[derive(Debug, Error, EditoastError)] #[editoast_error(base_id = "electrical_profiles")] pub enum ElectricalProfilesError {