@@ -9,6 +9,8 @@ use graph::components::server::query::ServerResponse;
99use graph:: components:: server:: query:: ServerResult ;
1010use graph:: components:: versions:: ApiVersion ;
1111use graph:: data:: query:: QueryResult ;
12+ use graph:: data:: query:: SqlQueryMode ;
13+ use graph:: data:: query:: SqlQueryReq ;
1214use graph:: data:: subgraph:: DeploymentHash ;
1315use graph:: data:: subgraph:: SubgraphName ;
1416use graph:: env:: ENV_VARS ;
@@ -21,6 +23,8 @@ use graph::hyper::{body::Body, header::HeaderValue};
2123use graph:: hyper:: { Method , Request , Response , StatusCode } ;
2224use graph:: prelude:: serde_json;
2325use graph:: prelude:: serde_json:: json;
26+ use graph:: prelude:: CacheWeight as _;
27+ use graph:: prelude:: QueryError ;
2428use graph:: semver:: VersionReq ;
2529use graph:: slog:: error;
2630use graph:: slog:: Logger ;
@@ -195,6 +199,51 @@ where
195199 Ok ( result. as_http_response ( ) )
196200 }
197201
202+ async fn handle_sql_query < T : Body > ( & self , request : Request < T > ) -> ServerResult {
203+ let body = request
204+ . collect ( )
205+ . await
206+ . map_err ( |_| ServerError :: InternalError ( "Failed to read request body" . into ( ) ) ) ?
207+ . to_bytes ( ) ;
208+ let sql_req: SqlQueryReq = serde_json:: from_slice ( & body)
209+ . map_err ( |e| ServerError :: ClientError ( format ! ( "{}" , e) ) ) ?;
210+
211+ let mode = sql_req. mode ;
212+ let result = self
213+ . graphql_runner
214+ . cheap_clone ( )
215+ . run_sql_query ( sql_req)
216+ . await
217+ . map_err ( |e| ServerError :: QueryError ( QueryError :: from ( e) ) ) ;
218+
219+ use SqlQueryMode :: * ;
220+ let response_obj = match ( result, mode) {
221+ ( Ok ( result) , Info ) => {
222+ json ! ( {
223+ "count" : result. len( ) ,
224+ "bytes" : result. weight( ) ,
225+ } )
226+ }
227+ ( Ok ( result) , Data ) => {
228+ json ! ( {
229+ "data" : result,
230+ } )
231+ }
232+ ( Err ( e) , _) => json ! ( {
233+ "error" : e. to_string( ) ,
234+ } ) ,
235+ } ;
236+
237+ let response_str = serde_json:: to_string ( & response_obj) . unwrap ( ) ;
238+
239+ Ok ( Response :: builder ( )
240+ . status ( 200 )
241+ . header ( ACCESS_CONTROL_ALLOW_ORIGIN , "*" )
242+ . header ( CONTENT_TYPE , "application/json" )
243+ . body ( Full :: from ( response_str) )
244+ . unwrap ( ) )
245+ }
246+
198247 // Handles OPTIONS requests
199248 fn handle_graphql_options < T > ( & self , _request : Request < T > ) -> ServerResult {
200249 Ok ( Response :: builder ( )
@@ -327,7 +376,9 @@ where
327376 let dest = format ! ( "/{}/graphql" , filtered_path) ;
328377 self . handle_temp_redirect ( dest)
329378 }
330-
379+ ( Method :: POST , & [ "subgraphs" , "sql" ] | & [ "subgraphs" , "sql" , "" ] ) => {
380+ self . handle_sql_query ( req) . await
381+ }
331382 ( Method :: POST , & [ "subgraphs" , "id" , subgraph_id] ) => {
332383 self . handle_graphql_query_by_id ( subgraph_id. to_owned ( ) , req)
333384 . await
@@ -395,14 +446,15 @@ where
395446
396447#[ cfg( test) ]
397448mod tests {
449+ use graph:: data:: store:: SqlQueryObject ;
398450 use graph:: data:: value:: { Object , Word } ;
399451 use graph:: http_body_util:: { BodyExt , Full } ;
400452 use graph:: hyper:: body:: Bytes ;
401453 use graph:: hyper:: header:: { CONTENT_LENGTH , CONTENT_TYPE } ;
402454 use graph:: hyper:: { Method , Request , StatusCode } ;
403455 use graph:: prelude:: serde_json:: json;
404456
405- use graph:: data:: query:: { QueryResults , QueryTarget } ;
457+ use graph:: data:: query:: { QueryResults , QueryTarget , SqlQueryReq } ;
406458 use graph:: prelude:: * ;
407459
408460 use crate :: test_utils;
@@ -449,6 +501,13 @@ mod tests {
449501 fn metrics ( & self ) -> Arc < dyn GraphQLMetrics > {
450502 Arc :: new ( TestGraphQLMetrics )
451503 }
504+
505+ async fn run_sql_query (
506+ self : Arc < Self > ,
507+ _req : SqlQueryReq ,
508+ ) -> Result < Vec < SqlQueryObject > , QueryExecutionError > {
509+ unimplemented ! ( )
510+ }
452511 }
453512
454513 #[ tokio:: test]
0 commit comments