1use std::sync::Arc;
2
3use anyhow::Result;
4use axum::{
5 routing::{get, post},
6 Router,
7};
8use lora_database::QueryRunner;
9
10mod admin;
11mod errors;
12mod routes;
13mod types;
14
15pub use admin::{AdminConfig, SnapshotAdminConfig};
16pub use errors::ErrorResponse;
17pub use types::{
18 HealthResponse, QueryFormat, QueryRequest, SnapshotRequest, SnapshotResponse,
19 WalStatusResponse, WalTruncateRequest,
20};
21
22pub fn build_app<R>(db: Arc<R>) -> Router
23where
24 R: QueryRunner,
25{
26 Router::new()
27 .route("/health", get(routes::health))
28 .route("/query", post(routes::query::<R>))
29 .route("/explain", post(routes::explain::<R>))
30 .route("/profile", post(routes::profile::<R>))
31 .with_state(db)
32}
33
34pub async fn serve<R>(listener: tokio::net::TcpListener, db: Arc<R>) -> Result<()>
35where
36 R: QueryRunner,
37{
38 let app = build_app(db);
39 axum::serve(listener, app).await?;
40 Ok(())
41}
42
43pub fn build_app_with_admin<R>(db: Arc<R>, admin_config: Option<AdminConfig>) -> Router
46where
47 R: QueryRunner,
48{
49 let router = build_app(db);
50 match admin_config {
51 Some(cfg) => router.merge(admin::build_admin_router(cfg)),
52 None => router,
53 }
54}
55
56pub async fn serve_with_admin<R>(
57 listener: tokio::net::TcpListener,
58 db: Arc<R>,
59 admin_config: Option<AdminConfig>,
60) -> Result<()>
61where
62 R: QueryRunner,
63{
64 let app = build_app_with_admin(db, admin_config);
65 axum::serve(listener, app).await?;
66 Ok(())
67}