duckdb_server/
interfaces.rs

1use axum::{
2    body::Bytes,
3    http::StatusCode,
4    response::{IntoResponse, Response},
5};
6use serde::{Deserialize, Serialize};
7use tokio::sync::Mutex;
8
9use crate::bundle::Query as BundleQuery;
10use crate::db::Database;
11
12pub struct AppState {
13    pub db: Box<dyn Database>,
14    pub cache: Mutex<lru::LruCache<String, Vec<u8>>>,
15}
16
17#[derive(Deserialize, Serialize, Debug, Clone)]
18#[serde(rename_all = "kebab-case")]
19pub enum Command {
20    Arrow,
21    Exec,
22    Json,
23    CreateBundle,
24    LoadBundle,
25}
26
27#[derive(Deserialize, Serialize, Debug, Default)]
28pub struct QueryParams {
29    #[serde(rename = "type")]
30    pub query_type: Option<Command>,
31    pub persist: Option<bool>,
32    pub sql: Option<String>,
33    pub name: Option<String>,
34    pub queries: Option<Vec<BundleQuery>>,
35}
36
37pub enum QueryResponse {
38    Arrow(Vec<u8>),
39    Json(String),
40    Response(Response),
41    Empty,
42}
43
44impl IntoResponse for QueryResponse {
45    fn into_response(self) -> Response {
46        match self {
47            QueryResponse::Arrow(bytes) => (
48                StatusCode::OK,
49                [("Content-Type", "application/vnd.apache.arrow.stream")],
50                Bytes::from(bytes),
51            )
52                .into_response(),
53            QueryResponse::Json(value) => (
54                StatusCode::OK,
55                [("Content-Type", "application/json")],
56                value,
57            )
58                .into_response(),
59            QueryResponse::Response(response) => response,
60            QueryResponse::Empty => StatusCode::OK.into_response(),
61        }
62    }
63}
64
65#[derive(Debug)]
66pub enum AppError {
67    Error(anyhow::Error),
68    BadRequest,
69}
70
71impl IntoResponse for AppError {
72    fn into_response(self) -> Response {
73        match self {
74            AppError::Error(error) => {
75                tracing::error!("Error: {:?}", error);
76                (
77                    StatusCode::INTERNAL_SERVER_ERROR,
78                    format!("Something went wrong: {error}"),
79                )
80                    .into_response()
81            }
82            AppError::BadRequest => (StatusCode::BAD_REQUEST).into_response(),
83        }
84    }
85}
86
87impl<E> From<E> for AppError
88where
89    E: Into<anyhow::Error>,
90{
91    fn from(err: E) -> Self {
92        AppError::Error(err.into())
93    }
94}