1919use actix_web:: http:: header:: ContentType ;
2020use actix_web:: web:: { self , Json } ;
2121use actix_web:: { FromRequest , HttpRequest , Responder } ;
22- use chrono:: { DateTime , Timelike , Utc } ;
22+ use arrow_schema:: Schema ;
23+ use chrono:: { DateTime , Utc } ;
2324use datafusion:: error:: DataFusionError ;
2425use datafusion:: execution:: context:: SessionState ;
2526use futures_util:: Future ;
2627use http:: StatusCode ;
2728use std:: collections:: HashMap ;
2829use std:: pin:: Pin ;
30+ use std:: sync:: Arc ;
2931use std:: time:: Instant ;
3032
33+ use crate :: event:: commit_schema;
34+ use crate :: handlers:: http:: send_schema_request;
3135use crate :: metrics:: QUERY_EXECUTE_TIME ;
36+ use crate :: option:: { Mode , CONFIG } ;
3237use crate :: query:: error:: ExecuteError ;
3338use crate :: query:: QUERY_SESSION ;
3439use crate :: rbac:: role:: { Action , Permission } ;
3540use crate :: rbac:: Users ;
3641use crate :: response:: QueryResponse ;
42+ use crate :: storage:: object_storage:: commit_schema_to_storage;
3743use crate :: utils:: actix:: extract_session_key_from_req;
3844
39- use super :: send_query_request_to_ingestor ;
45+ use super :: send_request_to_ingestor ;
4046
4147/// Query Request through http endpoint.
4248#[ derive( Debug , serde:: Deserialize , serde:: Serialize ) ]
@@ -54,19 +60,41 @@ pub struct Query {
5460}
5561
5662pub async fn query ( req : HttpRequest , query_request : Query ) -> Result < impl Responder , QueryError > {
57- // create a new query to send to the ingestors
58- let mut mmem= vec ! [ ] ;
59- if let Some ( query) = transform_query_for_ingestor ( & query_request) {
60- mmem = send_query_request_to_ingestor ( & query)
61- . await
62- . map_err ( |err| QueryError :: Custom ( err. to_string ( ) ) ) ?;
63+ let session_state = QUERY_SESSION . state ( ) ;
64+ let mut query = into_query ( & query_request, & session_state) . await ?;
65+
66+ if CONFIG . parseable . mode == Mode :: Query {
67+ if let Ok ( schs) = send_schema_request ( & query. table_name ( ) . unwrap ( ) ) . await {
68+ let new_schema =
69+ Schema :: try_merge ( schs) . map_err ( |err| QueryError :: Custom ( err. to_string ( ) ) ) ?;
70+
71+ commit_schema ( & query. table_name ( ) . unwrap ( ) , Arc :: new ( new_schema. clone ( ) ) )
72+ . map_err ( |err| QueryError :: Custom ( format ! ( "Error committing schema: {}" , err) ) ) ?;
73+
74+ commit_schema_to_storage ( & query. table_name ( ) . unwrap ( ) , new_schema)
75+ . await
76+ . map_err ( |err| {
77+ QueryError :: Custom ( format ! ( "Error committing schema to storage\n Error:{err}" ) )
78+ } ) ?;
79+ }
6380 }
6481
65- // let rbj = arrow_json::ReaderBuilder::new();
82+ let mmem = if CONFIG . parseable . mode == Mode :: Query {
83+ // create a new query to send to the ingestors
84+ if let Some ( que) = transform_query_for_ingestor ( & query_request) {
85+ let vals = send_request_to_ingestor ( & que)
86+ . await
87+ . map_err ( |err| QueryError :: Custom ( err. to_string ( ) ) ) ?;
88+ Some ( vals)
89+ } else {
90+ None
91+ }
92+ } else {
93+ None
94+ } ;
95+
6696 let creds = extract_session_key_from_req ( & req) . expect ( "expects basic auth" ) ;
6797 let permissions = Users . get_permissions ( & creds) ;
68- let session_state = QUERY_SESSION . state ( ) ;
69- let mut query = into_query ( & query_request, & session_state) . await ?;
7098
7199 // check authorization of this query if it references physical table;
72100 let table_name = query. table_name ( ) ;
@@ -105,14 +133,14 @@ pub async fn query(req: HttpRequest, query_request: Query) -> Result<impl Respon
105133
106134 let time = Instant :: now ( ) ;
107135
108- let ( records, fields) = query. execute ( Some ( mmem ) ) . await ?;
136+ let ( records, fields) = query. execute ( ) . await ?;
109137 let response = QueryResponse {
110138 records,
111139 fields,
112140 fill_null : query_request. send_null ,
113141 with_fields : query_request. fields ,
114142 }
115- . to_http ( ) ;
143+ . to_http ( mmem ) ;
116144
117145 if let Some ( table) = table_name {
118146 let time = time. elapsed ( ) . as_secs_f64 ( ) ;
@@ -195,14 +223,31 @@ async fn into_query(
195223}
196224
197225fn transform_query_for_ingestor ( query : & Query ) -> Option < Query > {
198- let end_time = DateTime :: parse_from_rfc3339 ( & query. end_time ) . ok ( ) ?;
199- let start_time = end_time - chrono:: Duration :: minutes ( 1 ) ;
226+ if query. query . is_empty ( ) {
227+ return None ;
228+ }
229+
230+ if query. start_time . is_empty ( ) {
231+ return None ;
232+ }
200233
201- dbg ! ( start_time. minute( ) ) ;
234+ if query. end_time . is_empty ( ) {
235+ return None ;
236+ }
237+
238+ let end_time: DateTime < Utc > = if query. end_time == "now" {
239+ Utc :: now ( )
240+ } else {
241+ DateTime :: parse_from_rfc3339 ( & query. end_time )
242+ . ok ( ) ?
243+ . with_timezone ( & Utc )
244+ } ;
202245
246+ let start_time = end_time - chrono:: Duration :: minutes ( 1 ) ;
247+ // when transforming the query, the ingestors are forced to return an array of values
203248 let q = Query {
204249 query : query. query . clone ( ) ,
205- fields : query . fields ,
250+ fields : false ,
206251 filter_tags : query. filter_tags . clone ( ) ,
207252 send_null : query. send_null ,
208253 start_time : start_time. to_rfc3339 ( ) ,
@@ -236,7 +281,7 @@ pub enum QueryError {
236281 Datafusion ( #[ from] DataFusionError ) ,
237282 #[ error( "Execution Error: {0}" ) ]
238283 Execute ( #[ from] ExecuteError ) ,
239- #[ error( "Query Error: {0}" ) ]
284+ #[ error( "Error: {0}" ) ]
240285 Custom ( String ) ,
241286}
242287
0 commit comments