@@ -203,7 +203,9 @@ use axum::extract::Json;
203
203
use axum:: extract:: Query ;
204
204
use axum:: extract:: State ;
205
205
use axum:: Extension ;
206
+ use chrono:: DateTime ;
206
207
use chrono:: NaiveDateTime ;
208
+ use chrono:: Utc ;
207
209
use diesel:: pg:: Pg ;
208
210
use diesel:: sql_query;
209
211
use diesel:: sql_types:: Jsonb ;
@@ -215,6 +217,11 @@ use editoast_common::geometry::GeoJsonPoint;
215
217
use editoast_derive:: EditoastError ;
216
218
use editoast_derive:: Search ;
217
219
use editoast_derive:: SearchConfigStore ;
220
+ use editoast_schemas:: train_schedule:: Margins ;
221
+ use editoast_schemas:: train_schedule:: PathItem ;
222
+ use editoast_schemas:: train_schedule:: PowerRestrictionItem ;
223
+ use editoast_schemas:: train_schedule:: ScheduleItem ;
224
+ use editoast_schemas:: train_schedule:: TrainScheduleOptions ;
218
225
use editoast_search:: query_into_sql;
219
226
use editoast_search:: SearchConfigStore as _;
220
227
use editoast_search:: SearchError ;
@@ -345,6 +352,7 @@ async fn search(
345
352
) -> Result < Json < serde_json:: Value > > {
346
353
let roles: HashSet < BuiltinRole > = match object. as_str ( ) {
347
354
"track" | "operationalpoint" | "signal" => HashSet :: from ( [ BuiltinRole :: InfraRead ] ) ,
355
+ "trainschedule" => HashSet :: from ( [ BuiltinRole :: TimetableRead ] ) ,
348
356
"project" | "study" | "scenario" => HashSet :: from ( [ BuiltinRole :: OpsRead ] ) ,
349
357
_ => {
350
358
return Err ( SearchApiError :: ObjectType {
@@ -683,6 +691,48 @@ pub(super) struct SearchResultItemScenario {
683
691
tags : Vec < String > ,
684
692
}
685
693
694
+ #[ derive( Search , Serialize , ToSchema ) ]
695
+ #[ cfg_attr( test, derive( serde:: Deserialize ) ) ]
696
+ #[ search(
697
+ table = "train_schedule" ,
698
+ column( name = "timetable_id" , data_type = "integer" ) ,
699
+ column( name = "train_name" , data_type = "string" )
700
+ ) ]
701
+ #[ allow( unused) ]
702
+ /// A search result item for a query with `object = "trainschedule"`
703
+ pub ( super ) struct SearchResultItemTrainSchedule {
704
+ #[ search( sql = "train_schedule.id" ) ]
705
+ id : u64 ,
706
+ #[ search( sql = "train_schedule.train_name" ) ]
707
+ train_name : String ,
708
+ #[ search( sql = "train_schedule.labels" ) ]
709
+ labels : Vec < Option < String > > ,
710
+ #[ search( sql = "train_schedule.rolling_stock_name" ) ]
711
+ rolling_stock_name : String ,
712
+ #[ search( sql = "train_schedule.timetable_id" ) ]
713
+ timetable_id : i64 ,
714
+ #[ search( sql = "train_schedule.start_time" ) ]
715
+ start_time : DateTime < Utc > ,
716
+ #[ search( sql = "train_schedule.schedule" ) ]
717
+ schedule : Vec < ScheduleItem > ,
718
+ #[ search( sql = "train_schedule.margins" ) ]
719
+ margins : Margins ,
720
+ #[ search( sql = "train_schedule.initial_speed" ) ]
721
+ initial_speed : f64 ,
722
+ #[ search( sql = "train_schedule.comfort" ) ]
723
+ comfort : i64 ,
724
+ #[ search( sql = "train_schedule.path" ) ]
725
+ path : Vec < PathItem > ,
726
+ #[ search( sql = "train_schedule.constraint_distribution" ) ]
727
+ constraint_distribution : i64 ,
728
+ #[ search( sql = "train_schedule.speed_limit_tag" ) ]
729
+ speed_limit_tag : Option < String > ,
730
+ #[ search( sql = "train_schedule.power_restrictions" ) ]
731
+ power_restrictions : Vec < PowerRestrictionItem > ,
732
+ #[ search( sql = "train_schedule.options" ) ]
733
+ options : TrainScheduleOptions ,
734
+ }
735
+
686
736
/// See [editoast_search::SearchConfigStore::find]
687
737
#[ derive( SearchConfigStore ) ]
688
738
#[ search_config_store(
@@ -692,5 +742,72 @@ pub(super) struct SearchResultItemScenario {
692
742
object( name = "project" , config = SearchResultItemProject ) ,
693
743
object( name = "study" , config = SearchResultItemStudy ) ,
694
744
object( name = "scenario" , config = SearchResultItemScenario ) ,
745
+ object( name = "trainschedule" , config = SearchResultItemTrainSchedule ) ,
695
746
) ]
696
747
pub struct SearchConfigFinder ;
748
+
749
+ #[ cfg( test) ]
750
+ pub mod test {
751
+
752
+ use axum:: http:: StatusCode ;
753
+ use pretty_assertions:: assert_eq;
754
+ use rstest:: rstest;
755
+ use serde_json:: json;
756
+
757
+ use super :: * ;
758
+ use crate :: models:: fixtures:: { create_simple_train_schedule, create_timetable} ;
759
+ use crate :: views:: test_app:: TestAppBuilder ;
760
+
761
+ #[ rstest]
762
+ async fn search_trainschedule_post_found ( ) {
763
+ let app = TestAppBuilder :: default_app ( ) ;
764
+ let pool = app. db_pool ( ) ;
765
+
766
+ // Create the timetable in the database
767
+ let timetable = create_timetable ( & mut pool. get_ok ( ) ) . await ;
768
+ let timetable_id = timetable. id ;
769
+
770
+ // Add a train_schedule in the database
771
+ let train = create_simple_train_schedule ( & mut pool. get_ok ( ) , timetable_id) . await ;
772
+
773
+ // The body
774
+ let request = app. post ( "/search" ) . json ( & json ! ( {
775
+ "object" : "trainschedule" ,
776
+ "query" : [ "and" , [ "=" , [ "train_name" ] , train. train_name] ,
777
+ [ "=" , [ "timetable_id" ] , timetable_id] ] ,
778
+ } ) ) ;
779
+
780
+ let response: Vec < SearchResultItemTrainSchedule > =
781
+ app. fetch ( request) . assert_status ( StatusCode :: OK ) . json_into ( ) ;
782
+
783
+ assert_eq ! ( response. len( ) , 1 ) ;
784
+ assert_eq ! ( response[ 0 ] . train_name, train. train_name) ;
785
+ }
786
+
787
+ #[ rstest]
788
+ async fn search_trainschedule_post_not_found ( ) {
789
+ let app = TestAppBuilder :: default_app ( ) ;
790
+ let pool = app. db_pool ( ) ;
791
+
792
+ // Create the timetable in the database
793
+ let timetable = create_timetable ( & mut pool. get_ok ( ) ) . await ;
794
+ let timetable_id = timetable. id ;
795
+
796
+ // Add a train_schedule in the database
797
+ create_simple_train_schedule ( & mut pool. get_ok ( ) , timetable_id) . await ;
798
+
799
+ let train_name = "NonExistingTrain" ;
800
+
801
+ // The body
802
+ let request = app. post ( "/search" ) . json ( & json ! ( {
803
+ "object" : "trainschedule" ,
804
+ "query" : [ "and" , [ "=" , [ "train_name" ] , train_name] ,
805
+ [ "=" , [ "timetable_id" ] , timetable_id] ] ,
806
+ } ) ) ;
807
+
808
+ let response: Vec < SearchResultItemTrainSchedule > =
809
+ app. fetch ( request) . assert_status ( StatusCode :: OK ) . json_into ( ) ;
810
+
811
+ assert_eq ! ( response. len( ) , 0 ) ;
812
+ }
813
+ }
0 commit comments