Skip to main content

nodedb_sql/visitor/plan_visitor/
dispatch.rs

1// SPDX-License-Identifier: Apache-2.0
2//! Exhaustive [`SqlPlan`] → [`PlanVisitor`] dispatcher; missing arms fail to compile.
3//!
4//! Split across two files to stay under the file-size limit: this file
5//! handles the read/DML/search variant family and forwards everything else
6//! to [`super::dispatch_rest::dispatch_rest`], which exhaustively matches
7//! the remaining variants (set-ops, array, merge, lateral, index DDL).
8use super::args::{
9    AggregateVisitArgs, DocumentIndexLookupVisitArgs, HybridSearchTripleVisitArgs,
10    HybridSearchVisitArgs, InsertVisitArgs, JoinVisitArgs, RecursiveScanVisitArgs,
11    RecursiveValueVisitArgs, ScanVisitArgs, SpatialScanVisitArgs, TimeseriesScanVisitArgs,
12    UpdateFromVisitArgs, UpsertVisitArgs, VectorSearchVisitArgs,
13};
14use super::dispatch_rest::dispatch_rest;
15use super::trait_def::PlanVisitor;
16use crate::types::SqlPlan;
17
18pub fn dispatch<V: PlanVisitor>(visitor: &mut V, plan: &SqlPlan) -> Result<V::Output, V::Error> {
19    match plan {
20        SqlPlan::ConstantResult { columns, values } => visitor.constant_result(columns, values),
21        SqlPlan::Scan {
22            collection,
23            alias,
24            engine,
25            filters,
26            projection,
27            sort_keys,
28            limit,
29            offset,
30            distinct,
31            window_functions,
32            temporal,
33        } => visitor.scan(ScanVisitArgs {
34            collection,
35            alias: alias.as_deref(),
36            engine: *engine,
37            filters,
38            projection,
39            sort_keys,
40            limit: *limit,
41            offset: *offset,
42            distinct: *distinct,
43            window_functions,
44            temporal,
45        }),
46        SqlPlan::PointGet {
47            collection,
48            alias,
49            engine,
50            key_column,
51            key_value,
52            projection: _,
53        } => visitor.point_get(collection, alias.as_deref(), *engine, key_column, key_value),
54        SqlPlan::DocumentIndexLookup {
55            collection,
56            alias,
57            engine,
58            field,
59            value,
60            filters,
61            projection,
62            sort_keys,
63            limit,
64            offset,
65            distinct,
66            window_functions,
67            case_insensitive,
68            temporal,
69        } => visitor.document_index_lookup(DocumentIndexLookupVisitArgs {
70            collection,
71            alias: alias.as_deref(),
72            engine: *engine,
73            field,
74            value,
75            filters,
76            projection,
77            sort_keys,
78            limit: *limit,
79            offset: *offset,
80            distinct: *distinct,
81            window_functions,
82            case_insensitive: *case_insensitive,
83            temporal,
84        }),
85        SqlPlan::RangeScan {
86            collection,
87            field,
88            lower,
89            upper,
90            limit,
91            projection: _,
92        } => visitor.range_scan(collection, field, lower.as_ref(), upper.as_ref(), *limit),
93        SqlPlan::Insert {
94            collection,
95            engine,
96            rows,
97            column_defaults,
98            if_absent,
99            column_schema,
100            primary_key,
101        } => visitor.insert(InsertVisitArgs {
102            collection,
103            engine: *engine,
104            rows,
105            column_defaults,
106            if_absent: *if_absent,
107            column_schema,
108            primary_key: primary_key.as_deref(),
109        }),
110        SqlPlan::KvInsert {
111            collection,
112            entries,
113            ttl_secs,
114            intent,
115            on_conflict_updates,
116        } => visitor.kv_insert(collection, entries, *ttl_secs, *intent, on_conflict_updates),
117        SqlPlan::Upsert {
118            collection,
119            engine,
120            rows,
121            column_defaults,
122            on_conflict_updates,
123            column_schema,
124            primary_key,
125        } => visitor.upsert(UpsertVisitArgs {
126            collection,
127            engine: *engine,
128            rows,
129            column_defaults,
130            on_conflict_updates,
131            column_schema,
132            primary_key: primary_key.as_deref(),
133        }),
134        SqlPlan::InsertSelect {
135            target,
136            source,
137            limit,
138        } => visitor.insert_select(target, source, *limit),
139        SqlPlan::Update {
140            collection,
141            engine,
142            assignments,
143            filters,
144            target_keys,
145            returning,
146        } => visitor.update(
147            collection,
148            *engine,
149            assignments,
150            filters,
151            target_keys,
152            *returning,
153        ),
154        SqlPlan::UpdateFrom {
155            collection,
156            engine,
157            source,
158            target_join_col,
159            source_join_col,
160            assignments,
161            target_filters,
162            returning,
163        } => visitor.update_from(UpdateFromVisitArgs {
164            collection,
165            engine: *engine,
166            source,
167            target_join_col,
168            source_join_col,
169            assignments,
170            target_filters,
171            returning: *returning,
172        }),
173        SqlPlan::Delete {
174            collection,
175            engine,
176            filters,
177            target_keys,
178        } => visitor.delete(collection, *engine, filters, target_keys),
179        SqlPlan::Truncate {
180            collection,
181            restart_identity,
182        } => visitor.truncate(collection, *restart_identity),
183        SqlPlan::Join {
184            left,
185            right,
186            on,
187            join_type,
188            condition,
189            limit,
190            projection,
191            filters,
192        } => visitor.join(JoinVisitArgs {
193            left,
194            right,
195            on,
196            join_type: *join_type,
197            condition: condition.as_ref(),
198            limit: *limit,
199            projection,
200            filters,
201        }),
202        SqlPlan::Aggregate {
203            input,
204            group_by,
205            group_by_aliases: _,
206            output_order: _,
207            aggregates,
208            having,
209            limit,
210            grouping_sets,
211            sort_keys,
212        } => visitor.aggregate(AggregateVisitArgs {
213            input,
214            group_by,
215            aggregates,
216            having,
217            limit: *limit,
218            grouping_sets: grouping_sets.as_deref(),
219            sort_keys,
220        }),
221        SqlPlan::TimeseriesScan {
222            collection,
223            time_range,
224            bucket_interval_ms,
225            group_by,
226            aggregates,
227            filters,
228            projection,
229            gap_fill,
230            limit,
231            tiered,
232            temporal,
233        } => visitor.timeseries_scan(TimeseriesScanVisitArgs {
234            collection,
235            time_range: *time_range,
236            bucket_interval_ms: *bucket_interval_ms,
237            group_by,
238            aggregates,
239            filters,
240            projection,
241            gap_fill,
242            limit: *limit,
243            tiered: *tiered,
244            temporal,
245        }),
246        SqlPlan::TimeseriesIngest { collection, rows } => {
247            visitor.timeseries_ingest(collection, rows)
248        }
249        SqlPlan::VectorSearch {
250            collection,
251            field,
252            query_vector,
253            top_k,
254            ef_search,
255            metric,
256            filters,
257            array_prefilter,
258            ann_options,
259            skip_payload_fetch,
260            payload_filters,
261            projection: _,
262        } => visitor.vector_search(VectorSearchVisitArgs {
263            collection,
264            field,
265            query_vector,
266            top_k: *top_k,
267            ef_search: *ef_search,
268            metric: *metric,
269            filters,
270            array_prefilter: array_prefilter.as_ref(),
271            ann_options,
272            skip_payload_fetch: *skip_payload_fetch,
273            payload_filters,
274        }),
275        SqlPlan::MultiVectorSearch {
276            collection,
277            query_vector,
278            top_k,
279            ef_search,
280            projection: _,
281        } => visitor.multi_vector_search(collection, query_vector, *top_k, *ef_search),
282        SqlPlan::SparseSearch {
283            collection,
284            field,
285            query_entries,
286            top_k,
287            projection: _,
288        } => visitor.sparse_search(collection, field, query_entries, *top_k),
289        SqlPlan::TextSearch {
290            collection,
291            query,
292            top_k,
293            filters,
294            score_alias,
295            projection: _,
296        } => visitor.text_search(collection, query, *top_k, filters, score_alias.as_deref()),
297        SqlPlan::HybridSearch {
298            collection,
299            query_vector,
300            query_text,
301            top_k,
302            ef_search,
303            vector_weight,
304            fuzzy,
305            score_alias,
306            projection: _,
307        } => visitor.hybrid_search(HybridSearchVisitArgs {
308            collection,
309            query_vector,
310            query_text,
311            top_k: *top_k,
312            ef_search: *ef_search,
313            vector_weight: *vector_weight,
314            fuzzy: *fuzzy,
315            score_alias: score_alias.as_deref(),
316        }),
317        SqlPlan::HybridSearchTriple {
318            collection,
319            query_vector,
320            query_text,
321            graph_seed_id,
322            graph_depth,
323            graph_edge_label,
324            top_k,
325            ef_search,
326            fuzzy,
327            rrf_k,
328            score_alias,
329            projection: _,
330        } => visitor.hybrid_search_triple(HybridSearchTripleVisitArgs {
331            collection,
332            query_vector,
333            query_text,
334            graph_seed_id,
335            graph_depth: *graph_depth,
336            graph_edge_label: graph_edge_label.as_deref(),
337            top_k: *top_k,
338            ef_search: *ef_search,
339            fuzzy: *fuzzy,
340            rrf_k: *rrf_k,
341            score_alias: score_alias.as_deref(),
342        }),
343        SqlPlan::SpatialScan {
344            collection,
345            field,
346            predicate,
347            query_geometry,
348            distance_meters,
349            attribute_filters,
350            limit,
351            projection,
352        } => visitor.spatial_scan(SpatialScanVisitArgs {
353            collection,
354            field,
355            predicate,
356            query_geometry,
357            distance_meters: *distance_meters,
358            attribute_filters,
359            limit: *limit,
360            projection,
361        }),
362        SqlPlan::RecursiveScan {
363            collection,
364            base_filters,
365            recursive_filters,
366            join_link,
367            max_iterations,
368            distinct,
369            limit,
370            projection: _,
371        } => visitor.recursive_scan(RecursiveScanVisitArgs {
372            collection,
373            base_filters,
374            recursive_filters,
375            join_link: join_link.as_ref(),
376            max_iterations: *max_iterations,
377            distinct: *distinct,
378            limit: *limit,
379        }),
380        SqlPlan::RecursiveValue {
381            cte_name,
382            columns,
383            init_exprs,
384            step_exprs,
385            condition,
386            max_depth,
387            distinct,
388        } => visitor.recursive_value(RecursiveValueVisitArgs {
389            cte_name,
390            columns,
391            init_exprs,
392            step_exprs,
393            condition: condition.as_deref(),
394            max_depth: *max_depth,
395            distinct: *distinct,
396        }),
397        other => dispatch_rest(visitor, other),
398    }
399}