1use std::{rc::Rc, sync::Arc};
4
5use selene_core::{BindingTableId, CancellationChecker, DbString};
6use selene_graph::{
7 CANDIDATE_STATE_PROVIDER_TAG, CompactionReport, CompactionStats, GraphResult, IndexProvider,
8 Mutator, ProviderError, ProviderTag, SeleneGraph, SharedGraph, VectorCandidateSet,
9 VectorCandidateStateInfo, VectorIndexMaintenancePolicy, VectorIndexRebuildReport,
10};
11
12use crate::{BindingTable, BindingTableRegistry, ImplDefinedCaps, ProcedureTier};
13
14pub struct GraphContext<'a> {
16 snapshot: &'a SeleneGraph,
17 caps: &'a ImplDefinedCaps,
18 providers: &'a [Arc<dyn IndexProvider>],
19 cancellation: CancellationChecker<'a>,
20 binding_tables: Rc<BindingTableRegistry>,
21}
22
23impl<'a> GraphContext<'a> {
24 pub(crate) fn new(
25 snapshot: &'a SeleneGraph,
26 caps: &'a ImplDefinedCaps,
27 providers: &'a [Arc<dyn IndexProvider>],
28 cancellation: CancellationChecker<'a>,
29 binding_tables: Rc<BindingTableRegistry>,
30 ) -> Self {
31 Self {
32 snapshot,
33 caps,
34 providers,
35 cancellation,
36 binding_tables,
37 }
38 }
39
40 #[must_use]
42 pub const fn snapshot(&self) -> &'a SeleneGraph {
43 self.snapshot
44 }
45
46 #[must_use]
48 pub const fn impl_defined_caps(&self) -> &'a ImplDefinedCaps {
49 self.caps
50 }
51
52 #[must_use]
54 pub fn index_provider_by_tag(&self, tag: ProviderTag) -> Option<Arc<dyn IndexProvider>> {
55 self.providers
56 .iter()
57 .find(|provider| provider.provider_tag() == tag)
58 .map(Arc::clone)
59 }
60
61 pub fn vector_candidate_set(
68 &self,
69 name: &DbString,
70 ) -> Result<Option<VectorCandidateSet>, ProviderError> {
71 let Some(provider) = self.index_provider_by_tag(ProviderTag(CANDIDATE_STATE_PROVIDER_TAG))
72 else {
73 return Ok(None);
74 };
75 provider.vector_candidate_set(name, self.snapshot.meta.generation)
76 }
77
78 pub fn vector_candidate_state_infos(
85 &self,
86 ) -> Result<Vec<VectorCandidateStateInfo>, ProviderError> {
87 let Some(provider) = self.index_provider_by_tag(ProviderTag(CANDIDATE_STATE_PROVIDER_TAG))
88 else {
89 return Ok(Vec::new());
90 };
91 provider.vector_candidate_state_infos(self.snapshot.meta.generation)
92 }
93
94 #[must_use]
96 pub const fn cancellation_checker(&self) -> CancellationChecker<'a> {
97 self.cancellation
98 }
99
100 pub fn register_binding_table(&self, table: Arc<BindingTable>) -> BindingTableId {
102 self.binding_tables.register(table)
103 }
104}
105
106pub struct MutationContext<'a, 'g> {
108 mutator: Mutator<'a, 'g>,
109 caps: &'a ImplDefinedCaps,
110 cancellation: CancellationChecker<'a>,
111 binding_tables: Rc<BindingTableRegistry>,
112}
113
114impl<'a, 'g> MutationContext<'a, 'g> {
115 pub(crate) fn new(
116 mutator: Mutator<'a, 'g>,
117 caps: &'a ImplDefinedCaps,
118 cancellation: CancellationChecker<'a>,
119 binding_tables: Rc<BindingTableRegistry>,
120 ) -> Self {
121 Self {
122 mutator,
123 caps,
124 cancellation,
125 binding_tables,
126 }
127 }
128
129 #[cfg(any(test, feature = "test-harness"))]
131 #[must_use]
132 pub fn for_test(mutator: Mutator<'a, 'g>, caps: &'a ImplDefinedCaps) -> Self {
133 Self::new(
134 mutator,
135 caps,
136 CancellationChecker::disabled(),
137 Rc::new(BindingTableRegistry::new()),
138 )
139 }
140
141 #[must_use]
143 pub fn snapshot(&self) -> &SeleneGraph {
144 self.mutator.read()
145 }
146
147 pub fn mutator(&mut self) -> &mut Mutator<'a, 'g> {
149 &mut self.mutator
150 }
151
152 #[must_use]
154 pub fn index_provider_by_tag(&self, tag: ProviderTag) -> Option<Arc<dyn IndexProvider>> {
155 self.mutator.index_provider_by_tag(tag)
156 }
157
158 #[must_use]
160 pub const fn impl_defined_caps(&self) -> &'a ImplDefinedCaps {
161 self.caps
162 }
163
164 #[must_use]
166 pub const fn cancellation_checker(&self) -> CancellationChecker<'a> {
167 self.cancellation
168 }
169
170 pub fn register_binding_table(&self, table: Arc<BindingTable>) -> BindingTableId {
172 self.binding_tables.register(table)
173 }
174}
175
176pub struct MaintenanceContext<'a, 'g> {
178 graph: &'g SharedGraph,
179 caps: &'a ImplDefinedCaps,
180 cancellation: CancellationChecker<'a>,
181 binding_tables: Rc<BindingTableRegistry>,
182}
183
184impl<'a, 'g> MaintenanceContext<'a, 'g> {
185 pub(crate) fn new(
186 graph: &'g SharedGraph,
187 caps: &'a ImplDefinedCaps,
188 cancellation: CancellationChecker<'a>,
189 binding_tables: Rc<BindingTableRegistry>,
190 ) -> Self {
191 Self {
192 graph,
193 caps,
194 cancellation,
195 binding_tables,
196 }
197 }
198
199 #[must_use]
201 pub const fn impl_defined_caps(&self) -> &'a ImplDefinedCaps {
202 self.caps
203 }
204
205 #[must_use]
207 pub const fn cancellation_checker(&self) -> CancellationChecker<'a> {
208 self.cancellation
209 }
210
211 pub fn rebuild_vector_indexes(&self) -> GraphResult<VectorIndexRebuildReport> {
217 self.graph.rebuild_vector_indexes()
218 }
219
220 pub fn rebuild_recommended_vector_indexes(&self) -> GraphResult<VectorIndexRebuildReport> {
226 self.graph.rebuild_recommended_vector_indexes()
227 }
228
229 pub fn maintain_vector_indexes(
235 &self,
236 policy: VectorIndexMaintenancePolicy,
237 ) -> GraphResult<VectorIndexRebuildReport> {
238 self.graph.maintain_vector_indexes(policy)
239 }
240
241 #[must_use]
243 pub fn compaction_stats(&self) -> CompactionStats {
244 self.graph.compaction_stats()
245 }
246
247 pub fn compact(&self) -> GraphResult<CompactionReport> {
253 self.graph.compact()
254 }
255
256 pub fn register_binding_table(&self, table: Arc<BindingTable>) -> BindingTableId {
258 self.binding_tables.register(table)
259 }
260}
261
262#[non_exhaustive]
264pub enum ProcedureContext<'a, 'g> {
265 Graph(GraphContext<'a>),
267 Mutation(MutationContext<'a, 'g>),
269 Maintenance(MaintenanceContext<'a, 'g>),
271}
272
273impl ProcedureContext<'_, '_> {
274 #[must_use]
276 pub const fn tier(&self) -> ProcedureTier {
277 match self {
278 Self::Graph(_) => ProcedureTier::Graph,
279 Self::Mutation(_) => ProcedureTier::Mutation,
280 Self::Maintenance(_) => ProcedureTier::Maintenance,
281 }
282 }
283
284 pub fn register_binding_table(&self, table: Arc<BindingTable>) -> BindingTableId {
286 match self {
287 Self::Graph(ctx) => ctx.register_binding_table(table),
288 Self::Mutation(ctx) => ctx.register_binding_table(table),
289 Self::Maintenance(ctx) => ctx.register_binding_table(table),
290 }
291 }
292}