Skip to main content

nova_boot_graphdb/
extractors.rs

1use axum::extract::FromRequestParts;
2use axum::http::StatusCode;
3use axum::http::request::Parts;
4use axum::response::{IntoResponse, Response};
5use std::fmt;
6
7/// Nova graph database extractor.
8///
9/// Provides access to the graph database injected by the `NovaGraphDb` plugin.
10#[derive(Clone)]
11pub struct NovaGraph(pub crate::NovaGraphDb);
12
13impl std::fmt::Debug for NovaGraph {
14    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15        f.debug_tuple("NovaGraph").field(&"<graph>").finish()
16    }
17}
18
19impl<S> FromRequestParts<S> for NovaGraph
20where
21    S: Send + Sync,
22{
23    type Rejection = NovaGraphRejection;
24
25    fn from_request_parts(
26        parts: &mut Parts,
27        _state: &S,
28    ) -> impl std::future::Future<Output = Result<Self, Self::Rejection>> + Send {
29        let result = parts
30            .extensions
31            .get::<crate::NovaGraphDb>()
32            .cloned()
33            .map(NovaGraph)
34            .ok_or(NovaGraphRejection);
35
36        async move { result }
37    }
38}
39
40#[derive(Debug)]
41pub struct NovaGraphRejection;
42
43impl fmt::Display for NovaGraphRejection {
44    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45        write!(
46            f,
47            "Graph database not found in request extensions. Did you forget to add the NovaGraphDb plugin to NovaApp?"
48        )
49    }
50}
51
52impl std::error::Error for NovaGraphRejection {}
53
54impl IntoResponse for NovaGraphRejection {
55    fn into_response(self) -> Response {
56        (
57            StatusCode::INTERNAL_SERVER_ERROR,
58            "Graph database not configured",
59        )
60            .into_response()
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67    use axum::extract::FromRequestParts;
68    use axum::http::Request;
69
70    #[tokio::test]
71    async fn extracts_graph_from_extensions() {
72        let graph = crate::NovaGraphDb::in_memory();
73        let (mut parts, _) = Request::new(()).into_parts();
74        parts.extensions.insert(graph);
75
76        let extracted = NovaGraph::from_request_parts(&mut parts, &()).await;
77
78        assert!(extracted.is_ok());
79    }
80
81    #[tokio::test]
82    async fn rejects_when_graph_is_missing() {
83        let (mut parts, _) = Request::new(()).into_parts();
84
85        let rejection = NovaGraph::from_request_parts(&mut parts, &())
86            .await
87            .expect_err("expected missing graph rejection");
88
89        assert!(rejection.to_string().contains("NovaGraphDb"));
90        assert_eq!(
91            rejection.into_response().status(),
92            StatusCode::INTERNAL_SERVER_ERROR
93        );
94    }
95}