Skip to main content

nodedb_sql/optimizer/
point_get.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Detect equality on primary key → convert Scan to PointGet.
4
5use crate::types::*;
6
7/// If a Scan has a single equality filter on the primary key, convert to PointGet.
8pub fn optimize(plan: SqlPlan) -> SqlPlan {
9    match plan {
10        SqlPlan::Scan {
11            ref collection,
12            ref alias,
13            ref engine,
14            ref filters,
15            ref projection,
16            ref temporal,
17            ..
18        } if filters.len() == 1
19            && !temporal.is_temporal()
20            && !projection
21                .iter()
22                .any(|p| matches!(p, Projection::Computed { .. })) =>
23        {
24            if let Some((key_col, key_val)) = extract_pk_equality(&filters[0]) {
25                return SqlPlan::PointGet {
26                    collection: collection.clone(),
27                    alias: alias.clone(),
28                    engine: *engine,
29                    key_column: key_col,
30                    key_value: key_val,
31                };
32            }
33            plan
34        }
35        _ => plan,
36    }
37}
38
39/// Extract a simple equality filter on a known PK column.
40fn extract_pk_equality(filter: &Filter) -> Option<(String, SqlValue)> {
41    match &filter.expr {
42        FilterExpr::Comparison {
43            field,
44            op: CompareOp::Eq,
45            value,
46        } => {
47            // Only optimize for known PK columns.
48            let f = field.to_lowercase();
49            if f == "id" || f == "document_id" || f == "key" {
50                Some((f, value.clone()))
51            } else {
52                None
53            }
54        }
55        FilterExpr::Expr(SqlExpr::BinaryOp {
56            left,
57            op: BinaryOp::Eq,
58            right,
59        }) => {
60            let col = match left.as_ref() {
61                SqlExpr::Column { name, .. } => name.to_lowercase(),
62                _ => return None,
63            };
64            if col != "id" && col != "document_id" && col != "key" {
65                return None;
66            }
67            let val = match right.as_ref() {
68                SqlExpr::Literal(v) => v.clone(),
69                _ => return None,
70            };
71            Some((col, val))
72        }
73        _ => None,
74    }
75}