Skip to main content

aurora_db/network/
http_server.rs

1#[cfg(feature = "http")]
2mod http_impl {
3    use crate::db::Aurora;
4    use crate::network::http_models::{QueryPayload, document_to_json, json_to_insert_data};
5    use crate::types::FieldType;
6    use actix_web::{App, HttpRequest, HttpResponse, HttpServer, Responder, web};
7    use serde::Deserialize;
8    use serde_json::Value as JsonValue;
9    use std::sync::Arc;
10
11    #[derive(Deserialize)]
12    struct CollectionPayload {
13        name: String,
14        fields: Vec<(String, FieldType, bool)>,
15    }
16
17    async fn get_all_docs(db: web::Data<Arc<Aurora>>, path: web::Path<String>) -> impl Responder {
18        let collection_name = path.into_inner();
19        match db.get_all_collection(&collection_name).await {
20            Ok(docs) => {
21                let json_docs: Vec<JsonValue> = docs.iter().map(document_to_json).collect();
22                HttpResponse::Ok().json(json_docs)
23            }
24            Err(e) => HttpResponse::InternalServerError().body(e.to_string()),
25        }
26    }
27
28    async fn create_collection(
29        db: web::Data<Arc<Aurora>>,
30        payload: web::Json<CollectionPayload>,
31    ) -> impl Responder {
32        let fields: Vec<(String, FieldType, bool)> = payload
33            .fields
34            .iter()
35            .map(|(name, ft, unique)| (name.clone(), ft.clone(), *unique))
36            .collect();
37
38        match db.new_collection(&payload.name, fields) {
39            Ok(_) => HttpResponse::Created().finish(),
40            Err(e) => HttpResponse::InternalServerError().body(e.to_string()),
41        }
42    }
43
44    async fn insert_document(
45        db: web::Data<Arc<Aurora>>,
46        path: web::Path<String>,
47        data: web::Json<JsonValue>,
48    ) -> impl Responder {
49        let collection_name = path.into_inner();
50        let doc_to_insert = data.into_inner();
51
52        match json_to_insert_data(doc_to_insert) {
53            Ok(insert_data) => match db.insert_map(&collection_name, insert_data) {
54                Ok(id) => match db.get_document(&collection_name, &id) {
55                    Ok(Some(doc)) => HttpResponse::Created().json(document_to_json(&doc)),
56                    Ok(None) => {
57                        HttpResponse::NotFound().body("Failed to retrieve document after creation")
58                    }
59                    Err(e) => HttpResponse::InternalServerError().body(e.to_string()),
60                },
61                Err(e) => HttpResponse::InternalServerError().body(e.to_string()),
62            },
63            Err(e) => HttpResponse::BadRequest().body(e.to_string()),
64        }
65    }
66
67    async fn delete_document(
68        db: web::Data<Arc<Aurora>>,
69        path: web::Path<(String, String)>,
70    ) -> impl Responder {
71        let (collection_name, doc_id) = path.into_inner();
72        let key = format!("{}:{}", collection_name, doc_id);
73        match db.delete(&key).await {
74            Ok(_) => HttpResponse::NoContent().finish(),
75            Err(e) => HttpResponse::InternalServerError().body(e.to_string()),
76        }
77    }
78
79    async fn query_collection(
80        db: web::Data<Arc<Aurora>>,
81        path: web::Path<String>,
82        payload: web::Json<QueryPayload>,
83    ) -> impl Responder {
84        let collection_name = path.into_inner();
85        match db.execute_dynamic_query(&collection_name, &payload).await {
86            Ok(docs) => {
87                let json_docs: Vec<JsonValue> = docs.iter().map(document_to_json).collect();
88                HttpResponse::Ok().json(json_docs)
89            }
90            Err(e) => HttpResponse::InternalServerError().body(e.to_string()),
91        }
92    }
93
94    async fn not_found(req: HttpRequest) -> impl Responder {
95        let (path, method) = (req.path().to_string(), req.method().to_string());
96        let msg = format!("404 Not Found: No route for {} {}", method, path);
97        println!("{}", msg);
98        HttpResponse::NotFound().body(msg)
99    }
100
101    pub async fn run_http_server(db: Arc<Aurora>, addr: &str) -> std::io::Result<()> {
102        let db_data = web::Data::new(db);
103        println!("🚀 Starting HTTP server at http://{}", addr);
104
105        HttpServer::new(move || {
106            App::new()
107                .app_data(db_data.clone())
108                .route("/collections", web::post().to(create_collection))
109                .service(
110                    web::scope("/collections")
111                        .route("/{name}", web::get().to(get_all_docs))
112                        .route("/{name}/docs", web::post().to(insert_document))
113                        .route("/{name}/docs/{id}", web::delete().to(delete_document))
114                        .route("/{name}/query", web::post().to(query_collection)),
115                )
116                .default_service(web::to(not_found))
117        })
118        .bind(addr)?
119        .run()
120        .await
121    }
122}
123
124#[cfg(feature = "http")]
125pub use http_impl::run_http_server;