Skip to main content

nodedb_sql/visitor/plan_visitor/
trait_def.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Executor parity contract for [`SqlPlan`]: one abstract method per variant.
4//! Trait method arity mirrors `SqlPlan` variant field counts and is not a code smell.
5#![allow(clippy::too_many_arguments)]
6
7use crate::fts_types::FtsQuery;
8use crate::temporal::TemporalScope;
9use crate::types::SqlPlan;
10use crate::types::filter::Filter;
11use crate::types::plan::{
12    ArrayPrefilter, KvInsertIntent, MergePlanClause, VectorAnnOptions, VectorPrimaryRow,
13};
14use crate::types::query::{
15    AggregateExpr, EngineType, JoinType, Projection, SortKey, SpatialPredicate, WindowSpec,
16};
17use crate::types_array::{
18    ArrayAttrAst, ArrayBinaryOpAst, ArrayCellOrderAst, ArrayCoordLiteral, ArrayDimAst,
19    ArrayInsertRow, ArrayReducerAst, ArraySliceAst, ArrayTileOrderAst,
20};
21use crate::types_expr::{SqlExpr, SqlPayloadAtom, SqlValue};
22use nodedb_types::PayloadIndexKind;
23use nodedb_types::VectorQuantization;
24use nodedb_types::vector_distance::DistanceMetric;
25
26/// Executor parity contract: every [`SqlPlan`] variant must be handled.
27/// Implement this trait and call [`dispatch`](super::dispatch) to route plans.
28pub trait PlanVisitor {
29    /// The successful result type returned by each visit method.
30    type Output;
31    /// The error type returned by each visit method.
32    type Error;
33
34    /// Handle [`SqlPlan::ConstantResult`].
35    fn constant_result(
36        &mut self,
37        columns: &[String],
38        values: &[SqlValue],
39    ) -> Result<Self::Output, Self::Error>;
40
41    /// Handle [`SqlPlan::Scan`].
42    fn scan(
43        &mut self,
44        collection: &str,
45        alias: Option<&str>,
46        engine: EngineType,
47        filters: &[Filter],
48        projection: &[Projection],
49        sort_keys: &[SortKey],
50        limit: Option<usize>,
51        offset: usize,
52        distinct: bool,
53        window_functions: &[WindowSpec],
54        temporal: &TemporalScope,
55    ) -> Result<Self::Output, Self::Error>;
56
57    /// Handle [`SqlPlan::PointGet`].
58    fn point_get(
59        &mut self,
60        collection: &str,
61        alias: Option<&str>,
62        engine: EngineType,
63        key_column: &str,
64        key_value: &SqlValue,
65    ) -> Result<Self::Output, Self::Error>;
66
67    /// Handle [`SqlPlan::DocumentIndexLookup`].
68    fn document_index_lookup(
69        &mut self,
70        collection: &str,
71        alias: Option<&str>,
72        engine: EngineType,
73        field: &str,
74        value: &SqlValue,
75        filters: &[Filter],
76        projection: &[Projection],
77        sort_keys: &[SortKey],
78        limit: Option<usize>,
79        offset: usize,
80        distinct: bool,
81        window_functions: &[WindowSpec],
82        case_insensitive: bool,
83        temporal: &TemporalScope,
84    ) -> Result<Self::Output, Self::Error>;
85
86    /// Handle [`SqlPlan::RangeScan`].
87    fn range_scan(
88        &mut self,
89        collection: &str,
90        field: &str,
91        lower: Option<&SqlValue>,
92        upper: Option<&SqlValue>,
93        limit: usize,
94    ) -> Result<Self::Output, Self::Error>;
95
96    /// Handle [`SqlPlan::Insert`].
97    fn insert(
98        &mut self,
99        collection: &str,
100        engine: EngineType,
101        rows: &[Vec<(String, SqlValue)>],
102        column_defaults: &[(String, String)],
103        if_absent: bool,
104        column_schema: &[(String, String)],
105    ) -> Result<Self::Output, Self::Error>;
106
107    /// Handle [`SqlPlan::KvInsert`].
108    fn kv_insert(
109        &mut self,
110        collection: &str,
111        entries: &[(SqlValue, Vec<(String, SqlValue)>)],
112        ttl_secs: u64,
113        intent: KvInsertIntent,
114        on_conflict_updates: &[(String, SqlExpr)],
115    ) -> Result<Self::Output, Self::Error>;
116
117    /// Handle [`SqlPlan::Upsert`].
118    fn upsert(
119        &mut self,
120        collection: &str,
121        engine: EngineType,
122        rows: &[Vec<(String, SqlValue)>],
123        column_defaults: &[(String, String)],
124        on_conflict_updates: &[(String, SqlExpr)],
125        column_schema: &[(String, String)],
126    ) -> Result<Self::Output, Self::Error>;
127
128    /// Handle [`SqlPlan::InsertSelect`].
129    fn insert_select(
130        &mut self,
131        target: &str,
132        source: &SqlPlan,
133        limit: usize,
134    ) -> Result<Self::Output, Self::Error>;
135
136    /// Handle [`SqlPlan::Update`].
137    fn update(
138        &mut self,
139        collection: &str,
140        engine: EngineType,
141        assignments: &[(String, SqlExpr)],
142        filters: &[Filter],
143        target_keys: &[SqlValue],
144        returning: bool,
145    ) -> Result<Self::Output, Self::Error>;
146
147    /// Handle [`SqlPlan::UpdateFrom`].
148    fn update_from(
149        &mut self,
150        collection: &str,
151        engine: EngineType,
152        source: &SqlPlan,
153        target_join_col: &str,
154        source_join_col: &str,
155        assignments: &[(String, SqlExpr)],
156        target_filters: &[Filter],
157        returning: bool,
158    ) -> Result<Self::Output, Self::Error>;
159
160    /// Handle [`SqlPlan::Delete`].
161    fn delete(
162        &mut self,
163        collection: &str,
164        engine: EngineType,
165        filters: &[Filter],
166        target_keys: &[SqlValue],
167    ) -> Result<Self::Output, Self::Error>;
168
169    /// Handle [`SqlPlan::Truncate`].
170    fn truncate(
171        &mut self,
172        collection: &str,
173        restart_identity: bool,
174    ) -> Result<Self::Output, Self::Error>;
175
176    /// Handle [`SqlPlan::Join`].
177    fn join(
178        &mut self,
179        left: &SqlPlan,
180        right: &SqlPlan,
181        on: &[(String, String)],
182        join_type: JoinType,
183        condition: Option<&SqlExpr>,
184        limit: usize,
185        projection: &[Projection],
186        filters: &[Filter],
187    ) -> Result<Self::Output, Self::Error>;
188
189    /// Handle [`SqlPlan::Aggregate`].
190    fn aggregate(
191        &mut self,
192        input: &SqlPlan,
193        group_by: &[SqlExpr],
194        aggregates: &[AggregateExpr],
195        having: &[Filter],
196        limit: usize,
197        grouping_sets: Option<&[Vec<usize>]>,
198        sort_keys: &[SortKey],
199    ) -> Result<Self::Output, Self::Error>;
200
201    /// Handle [`SqlPlan::TimeseriesScan`].
202    fn timeseries_scan(
203        &mut self,
204        collection: &str,
205        time_range: (i64, i64),
206        bucket_interval_ms: i64,
207        group_by: &[String],
208        aggregates: &[AggregateExpr],
209        filters: &[Filter],
210        projection: &[Projection],
211        gap_fill: &str,
212        limit: usize,
213        tiered: bool,
214        temporal: &TemporalScope,
215    ) -> Result<Self::Output, Self::Error>;
216
217    /// Handle [`SqlPlan::TimeseriesIngest`].
218    fn timeseries_ingest(
219        &mut self,
220        collection: &str,
221        rows: &[Vec<(String, SqlValue)>],
222    ) -> Result<Self::Output, Self::Error>;
223
224    /// Handle [`SqlPlan::VectorSearch`].
225    fn vector_search(
226        &mut self,
227        collection: &str,
228        field: &str,
229        query_vector: &[f32],
230        top_k: usize,
231        ef_search: usize,
232        metric: DistanceMetric,
233        filters: &[Filter],
234        array_prefilter: Option<&ArrayPrefilter>,
235        ann_options: &VectorAnnOptions,
236        skip_payload_fetch: bool,
237        payload_filters: &[SqlPayloadAtom],
238    ) -> Result<Self::Output, Self::Error>;
239
240    /// Handle [`SqlPlan::MultiVectorSearch`].
241    fn multi_vector_search(
242        &mut self,
243        collection: &str,
244        query_vector: &[f32],
245        top_k: usize,
246        ef_search: usize,
247    ) -> Result<Self::Output, Self::Error>;
248
249    /// Handle [`SqlPlan::TextSearch`].
250    fn text_search(
251        &mut self,
252        collection: &str,
253        query: &FtsQuery,
254        top_k: usize,
255        filters: &[Filter],
256        score_alias: Option<&str>,
257    ) -> Result<Self::Output, Self::Error>;
258
259    /// Handle [`SqlPlan::HybridSearch`].
260    fn hybrid_search(
261        &mut self,
262        collection: &str,
263        query_vector: &[f32],
264        query_text: &str,
265        top_k: usize,
266        ef_search: usize,
267        vector_weight: f32,
268        fuzzy: bool,
269        score_alias: Option<&str>,
270    ) -> Result<Self::Output, Self::Error>;
271
272    /// Handle [`SqlPlan::HybridSearchTriple`].
273    fn hybrid_search_triple(
274        &mut self,
275        collection: &str,
276        query_vector: &[f32],
277        query_text: &str,
278        graph_seed_id: &str,
279        graph_depth: usize,
280        graph_edge_label: Option<&str>,
281        top_k: usize,
282        ef_search: usize,
283        fuzzy: bool,
284        rrf_k: (f64, f64, f64),
285        score_alias: Option<&str>,
286    ) -> Result<Self::Output, Self::Error>;
287
288    /// Handle [`SqlPlan::SpatialScan`].
289    fn spatial_scan(
290        &mut self,
291        collection: &str,
292        field: &str,
293        predicate: &SpatialPredicate,
294        query_geometry: &nodedb_types::geometry::Geometry,
295        distance_meters: f64,
296        attribute_filters: &[Filter],
297        limit: usize,
298        projection: &[Projection],
299    ) -> Result<Self::Output, Self::Error>;
300
301    /// Handle [`SqlPlan::Union`].
302    fn union(&mut self, inputs: &[SqlPlan], distinct: bool) -> Result<Self::Output, Self::Error>;
303
304    /// Handle [`SqlPlan::Intersect`].
305    fn intersect(
306        &mut self,
307        left: &SqlPlan,
308        right: &SqlPlan,
309        all: bool,
310    ) -> Result<Self::Output, Self::Error>;
311
312    /// Handle [`SqlPlan::Except`].
313    fn except(
314        &mut self,
315        left: &SqlPlan,
316        right: &SqlPlan,
317        all: bool,
318    ) -> Result<Self::Output, Self::Error>;
319
320    /// Handle [`SqlPlan::RecursiveScan`].
321    fn recursive_scan(
322        &mut self,
323        collection: &str,
324        base_filters: &[Filter],
325        recursive_filters: &[Filter],
326        join_link: Option<&(String, String)>,
327        max_iterations: usize,
328        distinct: bool,
329        limit: usize,
330    ) -> Result<Self::Output, Self::Error>;
331
332    /// Handle [`SqlPlan::RecursiveValue`].
333    fn recursive_value(
334        &mut self,
335        cte_name: &str,
336        columns: &[String],
337        init_exprs: &[String],
338        step_exprs: &[String],
339        condition: Option<&str>,
340        max_depth: usize,
341        distinct: bool,
342    ) -> Result<Self::Output, Self::Error>;
343
344    /// Handle [`SqlPlan::Cte`].
345    fn cte(
346        &mut self,
347        definitions: &[(String, SqlPlan)],
348        outer: &SqlPlan,
349    ) -> Result<Self::Output, Self::Error>;
350
351    /// Handle [`SqlPlan::CreateArray`].
352    fn create_array(
353        &mut self,
354        name: &str,
355        dims: &[ArrayDimAst],
356        attrs: &[ArrayAttrAst],
357        tile_extents: &[i64],
358        cell_order: ArrayCellOrderAst,
359        tile_order: ArrayTileOrderAst,
360        prefix_bits: u8,
361        audit_retain_ms: Option<u64>,
362        minimum_audit_retain_ms: Option<u64>,
363    ) -> Result<Self::Output, Self::Error>;
364
365    /// Handle [`SqlPlan::DropArray`].
366    fn drop_array(&mut self, name: &str, if_exists: bool) -> Result<Self::Output, Self::Error>;
367
368    /// Handle [`SqlPlan::AlterArray`].
369    fn alter_array(
370        &mut self,
371        name: &str,
372        audit_retain_ms: Option<Option<i64>>,
373        minimum_audit_retain_ms: Option<u64>,
374    ) -> Result<Self::Output, Self::Error>;
375
376    /// Handle [`SqlPlan::InsertArray`].
377    fn insert_array(
378        &mut self,
379        name: &str,
380        rows: &[ArrayInsertRow],
381    ) -> Result<Self::Output, Self::Error>;
382
383    /// Handle [`SqlPlan::DeleteArray`].
384    fn delete_array(
385        &mut self,
386        name: &str,
387        coords: &[Vec<ArrayCoordLiteral>],
388    ) -> Result<Self::Output, Self::Error>;
389
390    /// Handle [`SqlPlan::ArraySlice`].
391    fn array_slice(
392        &mut self,
393        name: &str,
394        slice: &ArraySliceAst,
395        attr_projection: &[String],
396        limit: u32,
397        temporal: &TemporalScope,
398    ) -> Result<Self::Output, Self::Error>;
399
400    /// Handle [`SqlPlan::ArrayProject`].
401    fn array_project(
402        &mut self,
403        name: &str,
404        attr_projection: &[String],
405    ) -> Result<Self::Output, Self::Error>;
406
407    /// Handle [`SqlPlan::ArrayAgg`].
408    fn array_agg(
409        &mut self,
410        name: &str,
411        attr: &str,
412        reducer: &ArrayReducerAst,
413        group_by_dim: Option<&str>,
414        temporal: &TemporalScope,
415    ) -> Result<Self::Output, Self::Error>;
416
417    /// Handle [`SqlPlan::ArrayElementwise`].
418    fn array_elementwise(
419        &mut self,
420        left: &str,
421        right: &str,
422        op: ArrayBinaryOpAst,
423        attr: &str,
424    ) -> Result<Self::Output, Self::Error>;
425
426    /// Handle [`SqlPlan::ArrayFlush`].
427    fn array_flush(&mut self, name: &str) -> Result<Self::Output, Self::Error>;
428
429    /// Handle [`SqlPlan::ArrayCompact`].
430    fn array_compact(&mut self, name: &str) -> Result<Self::Output, Self::Error>;
431
432    /// Handle [`SqlPlan::Merge`].
433    fn merge(
434        &mut self,
435        target: &str,
436        engine: EngineType,
437        source: &SqlPlan,
438        target_join_col: &str,
439        source_join_col: &str,
440        source_alias: &str,
441        clauses: &[MergePlanClause],
442        returning: bool,
443    ) -> Result<Self::Output, Self::Error>;
444
445    /// Handle [`SqlPlan::LateralTopK`].
446    fn lateral_top_k(
447        &mut self,
448        outer: &SqlPlan,
449        outer_alias: Option<&str>,
450        inner_collection: &str,
451        inner_filters: &[Filter],
452        inner_order_by: &[SortKey],
453        inner_limit: usize,
454        correlation_keys: &[(String, String)],
455        lateral_alias: &str,
456        projection: &[Projection],
457        left_join: bool,
458    ) -> Result<Self::Output, Self::Error>;
459
460    /// Handle [`SqlPlan::LateralLoop`].
461    fn lateral_loop(
462        &mut self,
463        outer: &SqlPlan,
464        outer_alias: Option<&str>,
465        inner: &SqlPlan,
466        correlation_predicates: &[(String, String)],
467        lateral_alias: &str,
468        projection: &[Projection],
469        outer_row_cap: usize,
470        left_join: bool,
471    ) -> Result<Self::Output, Self::Error>;
472
473    /// Handle [`SqlPlan::VectorPrimaryInsert`].
474    fn vector_primary_insert(
475        &mut self,
476        collection: &str,
477        field: &str,
478        quantization: &VectorQuantization,
479        storage_dtype: &nodedb_types::VectorStorageDtype,
480        payload_indexes: &[(String, PayloadIndexKind)],
481        rows: &[VectorPrimaryRow],
482    ) -> Result<Self::Output, Self::Error>;
483
484    /// Handle [`SqlPlan::CreateIndex`].
485    fn create_index(
486        &mut self,
487        index_name: Option<&str>,
488        collection: &str,
489        field: &str,
490        unique: bool,
491        if_not_exists: bool,
492        case_insensitive: bool,
493    ) -> Result<Self::Output, Self::Error>;
494
495    /// Handle [`SqlPlan::DropIndex`].
496    fn drop_index(
497        &mut self,
498        index_name: &str,
499        collection: Option<&str>,
500        if_exists: bool,
501    ) -> Result<Self::Output, Self::Error>;
502}