nodedb-sql 0.4.0

SQL parser, planner, and optimizer for NodeDB
Documentation
// SPDX-License-Identifier: Apache-2.0
//! Exhaustive [`SqlPlan`] → [`PlanVisitor`] dispatcher; missing arms fail to compile.
//!
//! Split across two files to stay under the file-size limit: this file
//! handles the read/DML/search variant family and forwards everything else
//! to [`super::dispatch_rest::dispatch_rest`], which exhaustively matches
//! the remaining variants (set-ops, array, merge, lateral, index DDL).
use super::args::{
    AggregateVisitArgs, DocumentIndexLookupVisitArgs, HybridSearchTripleVisitArgs,
    HybridSearchVisitArgs, InsertVisitArgs, JoinVisitArgs, RecursiveScanVisitArgs,
    RecursiveValueVisitArgs, ScanVisitArgs, SpatialScanVisitArgs, TimeseriesScanVisitArgs,
    UpdateFromVisitArgs, UpsertVisitArgs, VectorSearchVisitArgs,
};
use super::dispatch_rest::dispatch_rest;
use super::trait_def::PlanVisitor;
use crate::types::SqlPlan;

pub fn dispatch<V: PlanVisitor>(visitor: &mut V, plan: &SqlPlan) -> Result<V::Output, V::Error> {
    match plan {
        SqlPlan::ConstantResult { columns, values } => visitor.constant_result(columns, values),
        SqlPlan::Scan {
            collection,
            alias,
            engine,
            filters,
            projection,
            sort_keys,
            limit,
            offset,
            distinct,
            window_functions,
            temporal,
        } => visitor.scan(ScanVisitArgs {
            collection,
            alias: alias.as_deref(),
            engine: *engine,
            filters,
            projection,
            sort_keys,
            limit: *limit,
            offset: *offset,
            distinct: *distinct,
            window_functions,
            temporal,
        }),
        SqlPlan::PointGet {
            collection,
            alias,
            engine,
            key_column,
            key_value,
            projection: _,
        } => visitor.point_get(collection, alias.as_deref(), *engine, key_column, key_value),
        SqlPlan::DocumentIndexLookup {
            collection,
            alias,
            engine,
            field,
            value,
            filters,
            projection,
            sort_keys,
            limit,
            offset,
            distinct,
            window_functions,
            case_insensitive,
            temporal,
        } => visitor.document_index_lookup(DocumentIndexLookupVisitArgs {
            collection,
            alias: alias.as_deref(),
            engine: *engine,
            field,
            value,
            filters,
            projection,
            sort_keys,
            limit: *limit,
            offset: *offset,
            distinct: *distinct,
            window_functions,
            case_insensitive: *case_insensitive,
            temporal,
        }),
        SqlPlan::RangeScan {
            collection,
            field,
            lower,
            upper,
            limit,
            projection: _,
        } => visitor.range_scan(collection, field, lower.as_ref(), upper.as_ref(), *limit),
        SqlPlan::Insert {
            collection,
            engine,
            rows,
            column_defaults,
            if_absent,
            column_schema,
            primary_key,
        } => visitor.insert(InsertVisitArgs {
            collection,
            engine: *engine,
            rows,
            column_defaults,
            if_absent: *if_absent,
            column_schema,
            primary_key: primary_key.as_deref(),
        }),
        SqlPlan::KvInsert {
            collection,
            entries,
            ttl_secs,
            intent,
            on_conflict_updates,
        } => visitor.kv_insert(collection, entries, *ttl_secs, *intent, on_conflict_updates),
        SqlPlan::Upsert {
            collection,
            engine,
            rows,
            column_defaults,
            on_conflict_updates,
            column_schema,
            primary_key,
        } => visitor.upsert(UpsertVisitArgs {
            collection,
            engine: *engine,
            rows,
            column_defaults,
            on_conflict_updates,
            column_schema,
            primary_key: primary_key.as_deref(),
        }),
        SqlPlan::InsertSelect {
            target,
            source,
            limit,
        } => visitor.insert_select(target, source, *limit),
        SqlPlan::Update {
            collection,
            engine,
            assignments,
            filters,
            target_keys,
            returning,
        } => visitor.update(
            collection,
            *engine,
            assignments,
            filters,
            target_keys,
            *returning,
        ),
        SqlPlan::UpdateFrom {
            collection,
            engine,
            source,
            target_join_col,
            source_join_col,
            assignments,
            target_filters,
            returning,
        } => visitor.update_from(UpdateFromVisitArgs {
            collection,
            engine: *engine,
            source,
            target_join_col,
            source_join_col,
            assignments,
            target_filters,
            returning: *returning,
        }),
        SqlPlan::Delete {
            collection,
            engine,
            filters,
            target_keys,
        } => visitor.delete(collection, *engine, filters, target_keys),
        SqlPlan::Truncate {
            collection,
            restart_identity,
        } => visitor.truncate(collection, *restart_identity),
        SqlPlan::Join {
            left,
            right,
            on,
            join_type,
            condition,
            limit,
            projection,
            filters,
        } => visitor.join(JoinVisitArgs {
            left,
            right,
            on,
            join_type: *join_type,
            condition: condition.as_ref(),
            limit: *limit,
            projection,
            filters,
        }),
        SqlPlan::Aggregate {
            input,
            group_by,
            group_by_aliases: _,
            output_order: _,
            aggregates,
            having,
            limit,
            grouping_sets,
            sort_keys,
        } => visitor.aggregate(AggregateVisitArgs {
            input,
            group_by,
            aggregates,
            having,
            limit: *limit,
            grouping_sets: grouping_sets.as_deref(),
            sort_keys,
        }),
        SqlPlan::TimeseriesScan {
            collection,
            time_range,
            bucket_interval_ms,
            group_by,
            aggregates,
            filters,
            projection,
            gap_fill,
            limit,
            tiered,
            temporal,
        } => visitor.timeseries_scan(TimeseriesScanVisitArgs {
            collection,
            time_range: *time_range,
            bucket_interval_ms: *bucket_interval_ms,
            group_by,
            aggregates,
            filters,
            projection,
            gap_fill,
            limit: *limit,
            tiered: *tiered,
            temporal,
        }),
        SqlPlan::TimeseriesIngest { collection, rows } => {
            visitor.timeseries_ingest(collection, rows)
        }
        SqlPlan::VectorSearch {
            collection,
            field,
            query_vector,
            top_k,
            ef_search,
            metric,
            filters,
            array_prefilter,
            ann_options,
            skip_payload_fetch,
            payload_filters,
            projection: _,
        } => visitor.vector_search(VectorSearchVisitArgs {
            collection,
            field,
            query_vector,
            top_k: *top_k,
            ef_search: *ef_search,
            metric: *metric,
            filters,
            array_prefilter: array_prefilter.as_ref(),
            ann_options,
            skip_payload_fetch: *skip_payload_fetch,
            payload_filters,
        }),
        SqlPlan::MultiVectorSearch {
            collection,
            query_vector,
            top_k,
            ef_search,
            projection: _,
        } => visitor.multi_vector_search(collection, query_vector, *top_k, *ef_search),
        SqlPlan::SparseSearch {
            collection,
            field,
            query_entries,
            top_k,
            projection: _,
        } => visitor.sparse_search(collection, field, query_entries, *top_k),
        SqlPlan::TextSearch {
            collection,
            query,
            top_k,
            filters,
            score_alias,
            projection: _,
        } => visitor.text_search(collection, query, *top_k, filters, score_alias.as_deref()),
        SqlPlan::HybridSearch {
            collection,
            query_vector,
            query_text,
            top_k,
            ef_search,
            vector_weight,
            fuzzy,
            score_alias,
            projection: _,
        } => visitor.hybrid_search(HybridSearchVisitArgs {
            collection,
            query_vector,
            query_text,
            top_k: *top_k,
            ef_search: *ef_search,
            vector_weight: *vector_weight,
            fuzzy: *fuzzy,
            score_alias: score_alias.as_deref(),
        }),
        SqlPlan::HybridSearchTriple {
            collection,
            query_vector,
            query_text,
            graph_seed_id,
            graph_depth,
            graph_edge_label,
            top_k,
            ef_search,
            fuzzy,
            rrf_k,
            score_alias,
            projection: _,
        } => visitor.hybrid_search_triple(HybridSearchTripleVisitArgs {
            collection,
            query_vector,
            query_text,
            graph_seed_id,
            graph_depth: *graph_depth,
            graph_edge_label: graph_edge_label.as_deref(),
            top_k: *top_k,
            ef_search: *ef_search,
            fuzzy: *fuzzy,
            rrf_k: *rrf_k,
            score_alias: score_alias.as_deref(),
        }),
        SqlPlan::SpatialScan {
            collection,
            field,
            predicate,
            query_geometry,
            distance_meters,
            attribute_filters,
            limit,
            projection,
        } => visitor.spatial_scan(SpatialScanVisitArgs {
            collection,
            field,
            predicate,
            query_geometry,
            distance_meters: *distance_meters,
            attribute_filters,
            limit: *limit,
            projection,
        }),
        SqlPlan::RecursiveScan {
            collection,
            base_filters,
            recursive_filters,
            join_link,
            max_iterations,
            distinct,
            limit,
            projection: _,
        } => visitor.recursive_scan(RecursiveScanVisitArgs {
            collection,
            base_filters,
            recursive_filters,
            join_link: join_link.as_ref(),
            max_iterations: *max_iterations,
            distinct: *distinct,
            limit: *limit,
        }),
        SqlPlan::RecursiveValue {
            cte_name,
            columns,
            init_exprs,
            step_exprs,
            condition,
            max_depth,
            distinct,
        } => visitor.recursive_value(RecursiveValueVisitArgs {
            cte_name,
            columns,
            init_exprs,
            step_exprs,
            condition: condition.as_deref(),
            max_depth: *max_depth,
            distinct: *distinct,
        }),
        other => dispatch_rest(visitor, other),
    }
}