1616 *
1717 */
1818
19+ use std:: collections:: HashSet ;
20+
1921use actix_web:: http:: header:: ContentType ;
22+ use chrono:: Utc ;
2023use correlation_utils:: user_auth_for_query;
24+ use datafusion:: error:: DataFusionError ;
2125use http:: StatusCode ;
2226use itertools:: Itertools ;
2327use once_cell:: sync:: Lazy ;
@@ -27,8 +31,8 @@ use tokio::sync::RwLock;
2731use tracing:: { trace, warn} ;
2832
2933use crate :: {
30- handlers:: http:: rbac:: RBACError , option:: CONFIG , rbac:: map:: SessionKey ,
31- storage:: ObjectStorageError , utils :: uid :: Uid ,
34+ handlers:: http:: rbac:: RBACError , option:: CONFIG , query :: QUERY_SESSION , rbac:: map:: SessionKey ,
35+ storage:: ObjectStorageError , users :: filters :: FilterQuery , utils :: get_hash ,
3236} ;
3337
3438pub mod correlation_utils;
@@ -69,7 +73,10 @@ impl Correlation {
6973
7074 let mut user_correlations = vec ! [ ] ;
7175 for c in correlations {
72- if user_auth_for_query ( session_key, & c. query ) . await . is_ok ( ) {
76+ if user_auth_for_query ( session_key, & c. table_configs )
77+ . await
78+ . is_ok ( )
79+ {
7380 user_correlations. push ( c) ;
7481 }
7582 }
@@ -83,7 +90,7 @@ impl Correlation {
8390 let read = self . 0 . read ( ) . await ;
8491 let correlation = read
8592 . iter ( )
86- . find ( |c| c. id . to_string ( ) == correlation_id)
93+ . find ( |c| c. id == correlation_id)
8794 . cloned ( ) ;
8895
8996 if let Some ( c) = correlation {
@@ -110,7 +117,7 @@ impl Correlation {
110117 let index = read_access
111118 . iter ( )
112119 . enumerate ( )
113- . find ( |( _, c) | c. id . to_string ( ) == correlation_id)
120+ . find ( |( _, c) | c. id == correlation_id)
114121 . to_owned ( ) ;
115122
116123 if let Some ( ( index, _) ) = index {
@@ -126,6 +133,7 @@ impl Correlation {
126133}
127134
128135#[ derive( Debug , Clone , Serialize , Deserialize ) ]
136+ #[ serde( rename_all = "camelCase" ) ]
129137pub enum CorrelationVersion {
130138 V1 ,
131139}
@@ -134,8 +142,12 @@ pub enum CorrelationVersion {
134142#[ serde( rename_all = "camelCase" ) ]
135143pub struct CorrelationConfig {
136144 pub version : CorrelationVersion ,
137- pub id : Uid ,
138- pub query : String ,
145+ pub id : String ,
146+ pub table_configs : Vec < TableConfig > ,
147+ pub join_config : JoinConfig ,
148+ pub filter : Option < FilterQuery > ,
149+ pub start_time : Option < String > ,
150+ pub end_time : Option < String > ,
139151}
140152
141153impl CorrelationConfig { }
@@ -144,16 +156,91 @@ impl CorrelationConfig {}
144156#[ serde( rename_all = "camelCase" ) ]
145157pub struct CorrelationRequest {
146158 pub version : CorrelationVersion ,
147- pub query : String ,
159+ pub table_configs : Vec < TableConfig > ,
160+ pub join_config : JoinConfig ,
161+ pub filter : Option < FilterQuery > ,
162+ pub start_time : Option < String > ,
163+ pub end_time : Option < String > ,
148164}
149165
150166impl From < CorrelationRequest > for CorrelationConfig {
151167 fn from ( val : CorrelationRequest ) -> Self {
152168 Self {
153169 version : val. version ,
154- id : crate :: utils:: uid:: gen ( ) ,
155- query : val. query ,
170+ id : get_hash ( Utc :: now ( ) . timestamp_micros ( ) . to_string ( ) . as_str ( ) ) ,
171+ table_configs : val. table_configs ,
172+ join_config : val. join_config ,
173+ filter : val. filter ,
174+ start_time : val. start_time ,
175+ end_time : val. end_time ,
176+ }
177+ }
178+ }
179+
180+ impl CorrelationRequest {
181+ pub fn generate_correlation_config ( self , id : String ) -> CorrelationConfig {
182+ CorrelationConfig {
183+ version : self . version ,
184+ id,
185+ table_configs : self . table_configs ,
186+ join_config : self . join_config ,
187+ filter : self . filter ,
188+ start_time : self . start_time ,
189+ end_time : self . end_time ,
190+ }
191+ }
192+
193+ /// This function will validate the TableConfigs, JoinConfig, and user auth
194+ pub async fn validate ( & self , session_key : & SessionKey ) -> Result < ( ) , CorrelationError > {
195+ let ctx = & QUERY_SESSION ;
196+
197+ let mut h1 = HashSet :: new ( ) ;
198+
199+ h1 = self . table_configs . iter ( ) . map ( |t| & t. table_name ) . collect ( ) ;
200+ let h2 = HashSet :: from ( [ & self . join_config . table_one , & self . join_config . table_two ] ) ;
201+
202+ // check if table config tables are the same
203+ if h1. len ( ) != 2 {
204+ return Err ( CorrelationError :: Metadata (
205+ "Must provide config for two unique tables" ,
206+ ) ) ;
207+ }
208+
209+ // check that the tables mentioned in join config are
210+ // the same as those in table config
211+ if h1 != h2 {
212+ return Err ( CorrelationError :: Metadata (
213+ "Must provide same tables for join config and table config" ,
214+ ) ) ;
215+ }
216+
217+ // check if user has access to table
218+ user_auth_for_query ( session_key, & self . table_configs ) . await ?;
219+
220+ // to validate table config, we need to check whether the mentioned fields
221+ // are present in the table or not
222+ for table_config in self . table_configs . iter ( ) {
223+ // table config check
224+ let df = ctx. table ( & table_config. table_name ) . await ?;
225+
226+ let mut selected_fields = table_config
227+ . selected_fields
228+ . iter ( )
229+ . map ( |c| c. as_str ( ) )
230+ . collect_vec ( ) ;
231+ let join_field = if table_config. table_name == self . join_config . table_one {
232+ & self . join_config . field_one
233+ } else {
234+ & self . join_config . field_two
235+ } ;
236+
237+ selected_fields. push ( join_field. as_str ( ) ) ;
238+
239+ // if this errors out then the table config is incorrect or join config is incorrect
240+ df. select_columns ( selected_fields. as_slice ( ) ) ?;
156241 }
242+
243+ Ok ( ( ) )
157244 }
158245}
159246
@@ -171,6 +258,8 @@ pub enum CorrelationError {
171258 AnyhowError ( #[ from] anyhow:: Error ) ,
172259 #[ error( "Unauthorized" ) ]
173260 Unauthorized ,
261+ #[ error( "DataFusion Error: {0}" ) ]
262+ DataFusion ( #[ from] DataFusionError ) ,
174263}
175264
176265impl actix_web:: ResponseError for CorrelationError {
@@ -182,6 +271,7 @@ impl actix_web::ResponseError for CorrelationError {
182271 Self :: UserDoesNotExist ( _) => StatusCode :: NOT_FOUND ,
183272 Self :: AnyhowError ( _) => StatusCode :: INTERNAL_SERVER_ERROR ,
184273 Self :: Unauthorized => StatusCode :: BAD_REQUEST ,
274+ Self :: DataFusion ( _) => StatusCode :: INTERNAL_SERVER_ERROR ,
185275 }
186276 }
187277
@@ -191,3 +281,19 @@ impl actix_web::ResponseError for CorrelationError {
191281 . body ( self . to_string ( ) )
192282 }
193283}
284+
285+ #[ derive( Debug , Clone , Serialize , Deserialize ) ]
286+ #[ serde( rename_all = "camelCase" ) ]
287+ pub struct TableConfig {
288+ pub selected_fields : Vec < String > ,
289+ pub table_name : String ,
290+ }
291+
292+ #[ derive( Debug , Clone , Serialize , Deserialize ) ]
293+ #[ serde( rename_all = "camelCase" ) ]
294+ pub struct JoinConfig {
295+ pub table_one : String ,
296+ pub field_one : String ,
297+ pub table_two : String ,
298+ pub field_two : String ,
299+ }
0 commit comments