-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
editoast: add attached objects endpoint
- Loading branch information
1 parent
f3fd9df
commit a00fe81
Showing
5 changed files
with
182 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
use std::collections::HashMap; | ||
|
||
use crate::error::Result; | ||
use crate::infra::Infra; | ||
use crate::infra_cache::InfraCache; | ||
use crate::schema::ObjectType; | ||
use crate::DbPool; | ||
use actix_web::dev::HttpServiceFactory; | ||
use actix_web::get; | ||
use actix_web::web::{block, Data, Json, Path}; | ||
use chashmap::CHashMap; | ||
use editoast_derive::EditoastError; | ||
use serde_json::{json, Map, Value}; | ||
use thiserror::Error; | ||
|
||
/// Objects types that can be attached to a track | ||
const ATTACHED_OBJECTS_TYPES: &[ObjectType] = &[ | ||
ObjectType::Signal, | ||
ObjectType::SpeedSection, | ||
ObjectType::Detector, | ||
ObjectType::TrackSectionLink, | ||
ObjectType::Switch, | ||
ObjectType::BufferStop, | ||
ObjectType::OperationalPoint, | ||
ObjectType::Catenary, | ||
]; | ||
|
||
/// Return `/infra/<infra_id>/attached` routes | ||
pub fn routes() -> impl HttpServiceFactory { | ||
attached | ||
} | ||
|
||
#[derive(Debug, Error, EditoastError)] | ||
#[editoast_error(base_id = "attached", context = "Self::context")] | ||
enum AttachedError { | ||
#[error("Track '{0}' not found")] | ||
#[editoast_error(status = 404)] | ||
TrackNotFound(String), | ||
} | ||
|
||
impl AttachedError { | ||
fn context(&self) -> Map<String, Value> { | ||
match self { | ||
Self::TrackNotFound(track_id) => json!({ | ||
"track_id": track_id, | ||
}) | ||
.as_object() | ||
.cloned() | ||
.unwrap(), | ||
} | ||
} | ||
} | ||
|
||
/// This endpoint returns attached objects of given track | ||
#[get("/attached/{track_id}")] | ||
async fn attached( | ||
infra: Path<(i64, String)>, | ||
infra_caches: Data<CHashMap<i64, InfraCache>>, | ||
db_pool: Data<DbPool>, | ||
) -> Result<Json<HashMap<ObjectType, Vec<String>>>> { | ||
let (infra, track_id) = infra.into_inner(); | ||
|
||
block::<_, Result<_>>(move || { | ||
let mut conn = db_pool.get().expect("Failed to get DB connection"); | ||
let infra = Infra::retrieve_for_update(&mut conn, infra)?; | ||
let infra_cache = InfraCache::get_or_load(&mut conn, &infra_caches, &infra)?; | ||
// Check track existence | ||
if !infra_cache.track_sections().contains_key(&track_id) { | ||
return Err(AttachedError::TrackNotFound(track_id.clone()).into()); | ||
} | ||
// Get attached objects | ||
let res: HashMap<_, Vec<_>> = ATTACHED_OBJECTS_TYPES | ||
.iter() | ||
.map(|obj_type| { | ||
( | ||
*obj_type, | ||
infra_cache | ||
.get_track_refs_type(&track_id, *obj_type) | ||
.into_iter() | ||
.map(|obj_ref| obj_ref.obj_id.clone()) | ||
.collect(), | ||
) | ||
}) | ||
.collect(); | ||
Ok(Json(res)) | ||
}) | ||
.await | ||
.unwrap() | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use std::collections::HashMap; | ||
|
||
use actix_http::StatusCode; | ||
use actix_web::test as actix_test; | ||
use actix_web::test::{call_and_read_body_json, call_service, TestRequest}; | ||
|
||
use crate::infra::Infra; | ||
use crate::schema::operation::RailjsonObject; | ||
use crate::schema::{Detector, OSRDIdentified, ObjectType, TrackSection}; | ||
use crate::views::infra::tests::{ | ||
create_infra_request, create_object_request, delete_infra_request, | ||
}; | ||
use crate::views::tests::create_test_service; | ||
|
||
#[actix_test] | ||
async fn get_attached_detector() { | ||
let app = create_test_service().await; | ||
|
||
let infra: Infra = | ||
call_and_read_body_json(&app, create_infra_request("get_speed_tags_test")).await; | ||
|
||
// Create a track and a detector on it | ||
let track: RailjsonObject = TrackSection::default().into(); | ||
let req = create_object_request(infra.id, track.clone()); | ||
assert_eq!(call_service(&app, req).await.status(), StatusCode::OK); | ||
let req = create_object_request( | ||
infra.id, | ||
Detector { | ||
track: track.get_id().clone().into(), | ||
..Default::default() | ||
} | ||
.into(), | ||
); | ||
assert_eq!(call_service(&app, req).await.status(), StatusCode::OK); | ||
|
||
let req = TestRequest::get() | ||
.uri(format!("/infra/{}/attached/{}/", infra.id, track.get_id()).as_str()) | ||
.to_request(); | ||
let response: HashMap<ObjectType, Vec<String>> = call_and_read_body_json(&app, req).await; | ||
assert_eq!(response.get(&ObjectType::Detector).unwrap().len(), 1); | ||
|
||
let response = call_service(&app, delete_infra_request(infra.id)).await; | ||
assert_eq!(response.status(), StatusCode::NO_CONTENT); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters