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