@@ -14,6 +14,9 @@ use amalthea::comm::data_explorer_comm::BackendState;
14
14
use amalthea:: comm:: data_explorer_comm:: CodeSyntaxName ;
15
15
use amalthea:: comm:: data_explorer_comm:: ColumnDisplayType ;
16
16
use amalthea:: comm:: data_explorer_comm:: ColumnFilter ;
17
+ use amalthea:: comm:: data_explorer_comm:: ColumnFilterParams ;
18
+ use amalthea:: comm:: data_explorer_comm:: ColumnFilterType ;
19
+ use amalthea:: comm:: data_explorer_comm:: ColumnFilterTypeSupportStatus ;
17
20
use amalthea:: comm:: data_explorer_comm:: ColumnProfileType ;
18
21
use amalthea:: comm:: data_explorer_comm:: ColumnProfileTypeSupportStatus ;
19
22
use amalthea:: comm:: data_explorer_comm:: ColumnSchema ;
@@ -53,6 +56,7 @@ use amalthea::comm::data_explorer_comm::TableRowLabels;
53
56
use amalthea:: comm:: data_explorer_comm:: TableSchema ;
54
57
use amalthea:: comm:: data_explorer_comm:: TableSelection ;
55
58
use amalthea:: comm:: data_explorer_comm:: TableShape ;
59
+ use amalthea:: comm:: data_explorer_comm:: TextSearchType ;
56
60
use amalthea:: comm:: event:: CommManagerEvent ;
57
61
use amalthea:: socket:: comm:: CommInitiator ;
58
62
use amalthea:: socket:: comm:: CommSocket ;
@@ -532,9 +536,7 @@ impl RDataExplorer {
532
536
return Err ( anyhow ! ( "Data Explorer: Not yet supported" ) ) ;
533
537
} ,
534
538
535
- DataExplorerBackendRequest :: SearchSchema ( _) => {
536
- return Err ( anyhow ! ( "Data Explorer: Not yet supported" ) ) ;
537
- } ,
539
+ DataExplorerBackendRequest :: SearchSchema ( params) => self . search_schema ( params) ,
538
540
539
541
DataExplorerBackendRequest :: SetColumnFilters ( _) => {
540
542
return Err ( anyhow ! ( "Data Explorer: Not yet supported" ) ) ;
@@ -859,6 +861,104 @@ impl RDataExplorer {
859
861
self . view_indices = Some ( view_indices) ;
860
862
}
861
863
864
+ /// Search the schema for columns matching the given filters and sort order.
865
+ ///
866
+ /// - `params`: The search parameters including filters and sort order.
867
+ fn search_schema (
868
+ & self ,
869
+ params : amalthea:: comm:: data_explorer_comm:: SearchSchemaParams ,
870
+ ) -> anyhow:: Result < DataExplorerBackendReply > {
871
+ let all_columns = & self . shape . columns ;
872
+
873
+ // Apply column filters to find matching columns using iterator chaining
874
+ let mut matching_indices: Vec < i64 > = all_columns
875
+ . iter ( )
876
+ . enumerate ( )
877
+ . filter_map ( |( index, column) | {
878
+ let column_index = index as i64 ;
879
+
880
+ // Check if column matches all filters
881
+ let matches = params
882
+ . filters
883
+ . iter ( )
884
+ . all ( |filter| self . column_matches_filter ( column, filter) ) ;
885
+
886
+ if matches {
887
+ Some ( column_index)
888
+ } else {
889
+ None
890
+ }
891
+ } )
892
+ . collect ( ) ;
893
+
894
+ // Apply sort order
895
+ match params. sort_order {
896
+ amalthea:: comm:: data_explorer_comm:: SearchSchemaSortOrder :: Original => {
897
+ // matching_indices is already in original order
898
+ } ,
899
+ order => {
900
+ let ascending = matches ! (
901
+ order,
902
+ amalthea:: comm:: data_explorer_comm:: SearchSchemaSortOrder :: Ascending
903
+ ) ;
904
+ matching_indices. sort_by ( |& a, & b| {
905
+ let ord = all_columns[ a as usize ]
906
+ . column_name
907
+ . cmp ( & all_columns[ b as usize ] . column_name ) ;
908
+ if ascending { ord } else { ord. reverse ( ) }
909
+ } ) ;
910
+ }
911
+ }
912
+
913
+ Ok ( DataExplorerBackendReply :: SearchSchemaReply (
914
+ amalthea:: comm:: data_explorer_comm:: SearchSchemaResult {
915
+ matches : matching_indices,
916
+ } ,
917
+ ) )
918
+ }
919
+
920
+ /// Check if a column matches a given column filter.
921
+ fn column_matches_filter ( & self , column : & ColumnSchema , filter : & ColumnFilter ) -> bool {
922
+ match filter. filter_type {
923
+ ColumnFilterType :: TextSearch => {
924
+ if let ColumnFilterParams :: TextSearch ( text_search) = & filter. params {
925
+ let column_name = if text_search. case_sensitive {
926
+ column. column_name . to_owned ( )
927
+ } else {
928
+ column. column_name . to_lowercase ( )
929
+ } ;
930
+
931
+ let search_term = if text_search. case_sensitive {
932
+ text_search. term . to_owned ( )
933
+ } else {
934
+ text_search. term . to_lowercase ( )
935
+ } ;
936
+
937
+ match text_search. search_type {
938
+ TextSearchType :: Contains => column_name. contains ( & search_term) ,
939
+ TextSearchType :: NotContains => !column_name. contains ( & search_term) ,
940
+ TextSearchType :: StartsWith => column_name. starts_with ( & search_term) ,
941
+ TextSearchType :: EndsWith => column_name. ends_with ( & search_term) ,
942
+ TextSearchType :: RegexMatch => {
943
+ // For regex matching, we use simple string matching as a fallback
944
+ // A full regex implementation would require additional dependencies
945
+ column_name. contains ( & search_term)
946
+ } ,
947
+ }
948
+ } else {
949
+ false
950
+ }
951
+ } ,
952
+ ColumnFilterType :: MatchDataTypes => {
953
+ if let ColumnFilterParams :: MatchDataTypes ( type_filter) = & filter. params {
954
+ type_filter. display_types . contains ( & column. type_display )
955
+ } else {
956
+ false
957
+ }
958
+ } ,
959
+ }
960
+ }
961
+
862
962
/// Get the schema for a vector of columns in the data object.
863
963
///
864
964
/// - `column_indices`: The vector of columns in the data object.
@@ -950,8 +1050,17 @@ impl RDataExplorer {
950
1050
] ,
951
1051
} ,
952
1052
search_schema : SearchSchemaFeatures {
953
- support_status : SupportStatus :: Unsupported ,
954
- supported_types : vec ! [ ] ,
1053
+ support_status : SupportStatus :: Supported ,
1054
+ supported_types : vec ! [
1055
+ ColumnFilterTypeSupportStatus {
1056
+ column_filter_type: ColumnFilterType :: TextSearch ,
1057
+ support_status: SupportStatus :: Supported ,
1058
+ } ,
1059
+ ColumnFilterTypeSupportStatus {
1060
+ column_filter_type: ColumnFilterType :: MatchDataTypes ,
1061
+ support_status: SupportStatus :: Supported ,
1062
+ } ,
1063
+ ] ,
955
1064
} ,
956
1065
set_row_filters : SetRowFiltersFeatures {
957
1066
support_status : SupportStatus :: Supported ,
0 commit comments