duckdb_server/
interfaces.rs1use 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}