1use std::sync::Arc;
2
3use axum::body::Bytes;
4use axum::extract::State;
5use axum::http::StatusCode;
6use axum::response::IntoResponse;
7use moire_types::{QueryRequest, SqlRequest};
8
9use crate::app::AppState;
10use crate::db::{Db, query_named_blocking, sql_query_blocking};
11use crate::util::http::{json_error, json_ok};
12
13pub async fn api_sql(State(state): State<AppState>, body: Bytes) -> impl IntoResponse {
14 execute_sql_request(body, state.db.clone()).await
15}
16
17pub async fn api_query(State(state): State<AppState>, body: Bytes) -> impl IntoResponse {
18 execute_named_query_request(body, state.db.clone()).await
19}
20
21pub async fn execute_sql_request(body: Bytes, db: Arc<Db>) -> impl IntoResponse {
22 let request: SqlRequest = match facet_json::from_slice(&body) {
23 Ok(request) => request,
24 Err(error) => {
25 return json_error(
26 StatusCode::BAD_REQUEST,
27 format!("invalid request json: {error}"),
28 );
29 }
30 };
31
32 match tokio::task::spawn_blocking(move || sql_query_blocking(&db, request.sql.as_str())).await {
33 Ok(Ok(response)) => json_ok(&response),
34 Ok(Err(error)) => json_error(StatusCode::BAD_REQUEST, error),
35 Err(error) => json_error(
36 StatusCode::INTERNAL_SERVER_ERROR,
37 format!("sql worker join error: {error}"),
38 ),
39 }
40}
41
42pub async fn execute_named_query_request(body: Bytes, db: Arc<Db>) -> impl IntoResponse {
43 let request: QueryRequest = match facet_json::from_slice(&body) {
44 Ok(request) => request,
45 Err(error) => {
46 return json_error(
47 StatusCode::BAD_REQUEST,
48 format!("invalid request json: {error}"),
49 );
50 }
51 };
52
53 let name = request.name.to_string();
54 let limit = request.limit.unwrap_or(50);
55 match tokio::task::spawn_blocking(move || query_named_blocking(&db, &name, limit)).await {
56 Ok(Ok(response)) => json_ok(&response),
57 Ok(Err(error)) => json_error(StatusCode::BAD_REQUEST, error),
58 Err(error) => json_error(
59 StatusCode::INTERNAL_SERVER_ERROR,
60 format!("query worker join error: {error}"),
61 ),
62 }
63}