Skip to main content

kmp_application/queries/
get_context.rs

1use kmp_domain::{
2    GraphNeighborhoodReader, KmpBundle, NodeDetailReader, SnapshotSaveOptions, SnapshotStore,
3};
4
5use crate::ApplicationError;
6pub use crate::queries::render_graph_bundle::RenderedContext;
7use crate::queries::{
8    ContextRenderOptions, QueryApplicationService, QueryTimingBreakdown, RehydrateSessionUseCase,
9    clamp_native_graph_traversal_depth, render_graph_bundle_with_options,
10};
11
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct GetContextQuery {
14    pub root_node_id: String,
15    pub role: String,
16    pub depth: u32,
17    pub requested_scopes: Vec<String>,
18    pub render_options: ContextRenderOptions,
19}
20
21#[derive(Debug, Clone, PartialEq)]
22pub struct GetContextResult {
23    pub bundle: KmpBundle,
24    pub rendered: RenderedContext,
25    pub requested_scopes: Vec<String>,
26    pub served_at: std::time::SystemTime,
27    pub timing: Option<QueryTimingBreakdown>,
28}
29
30#[derive(Debug)]
31pub struct GetContextUseCase<G, D, S> {
32    rehydrate_session: RehydrateSessionUseCase<G, D, S>,
33}
34
35impl<G, D, S> GetContextUseCase<G, D, S>
36where
37    G: GraphNeighborhoodReader + Send + Sync,
38    D: NodeDetailReader + Send + Sync,
39    S: SnapshotStore + Send + Sync,
40{
41    pub fn new(rehydrate_session: RehydrateSessionUseCase<G, D, S>) -> Self {
42        Self { rehydrate_session }
43    }
44
45    pub async fn execute(
46        &self,
47        root_node_id: &str,
48        role: &str,
49        depth: u32,
50        requested_scopes: &[String],
51        render_options: &ContextRenderOptions,
52    ) -> Result<GetContextResult, ApplicationError> {
53        let (bundle, timing) = self
54            .rehydrate_session
55            .execute_with_depth(
56                root_node_id,
57                role,
58                clamp_native_graph_traversal_depth(depth),
59                false,
60                SnapshotSaveOptions::default(),
61            )
62            .await?;
63        let rendered = render_graph_bundle_with_options(&bundle, render_options);
64
65        Ok(GetContextResult {
66            bundle,
67            rendered,
68            requested_scopes: requested_scopes.to_vec(),
69            served_at: std::time::SystemTime::now(),
70            timing: Some(timing),
71        })
72    }
73}
74
75impl<G, D, S> QueryApplicationService<G, D, S>
76where
77    G: GraphNeighborhoodReader + Send + Sync,
78    D: NodeDetailReader + Send + Sync,
79    S: SnapshotStore + Send + Sync,
80{
81    pub async fn get_context(
82        &self,
83        query: GetContextQuery,
84    ) -> Result<GetContextResult, ApplicationError> {
85        let rehydrate = RehydrateSessionUseCase::new(
86            std::sync::Arc::clone(&self.graph_reader),
87            std::sync::Arc::clone(&self.detail_reader),
88            std::sync::Arc::clone(&self.snapshot_store),
89            self.generator_version,
90        );
91
92        GetContextUseCase::new(rehydrate)
93            .execute(
94                &query.root_node_id,
95                &query.role,
96                query.depth,
97                &query.requested_scopes,
98                &query.render_options,
99            )
100            .await
101    }
102}