Skip to main content

nodedb_sql/engine_rules/
kv.rs

1//! Engine rules for key-value collections.
2
3use crate::engine_rules::*;
4use crate::error::{Result, SqlError};
5use crate::types::*;
6
7pub struct KvRules;
8
9impl EngineRules for KvRules {
10    fn plan_insert(&self, p: InsertParams) -> Result<Vec<SqlPlan>> {
11        // KV INSERT is handled separately via KvInsert plan variant.
12        // The caller (dml.rs) builds KvInsert directly because it needs
13        // to split key vs value columns. This method handles the case
14        // where a generic INSERT reaches KV — which should not happen
15        // because dml.rs checks engine type before calling engine_rules.
16        // But if it does, we error clearly.
17        Err(SqlError::Unsupported {
18            detail: format!(
19                "INSERT into KV collection '{}' must use the KV insert path",
20                p.collection
21            ),
22        })
23    }
24
25    fn plan_upsert(&self, _p: UpsertParams) -> Result<Vec<SqlPlan>> {
26        // KV upsert is handled via the KvInsert path (KV PUT is naturally an upsert).
27        // Same as plan_insert — KV INSERT uses KvInsert which is already upsert semantics.
28        Err(SqlError::Unsupported {
29            detail: "KV UPSERT must use the KV insert path (KV PUT is naturally an upsert)".into(),
30        })
31    }
32
33    fn plan_scan(&self, p: ScanParams) -> Result<SqlPlan> {
34        Ok(SqlPlan::Scan {
35            collection: p.collection,
36            alias: p.alias,
37            engine: EngineType::KeyValue,
38            filters: p.filters,
39            projection: p.projection,
40            sort_keys: p.sort_keys,
41            limit: p.limit,
42            offset: p.offset,
43            distinct: p.distinct,
44            window_functions: p.window_functions,
45        })
46    }
47
48    fn plan_point_get(&self, p: PointGetParams) -> Result<SqlPlan> {
49        Ok(SqlPlan::PointGet {
50            collection: p.collection,
51            alias: p.alias,
52            engine: EngineType::KeyValue,
53            key_column: p.key_column,
54            key_value: p.key_value,
55        })
56    }
57
58    fn plan_update(&self, p: UpdateParams) -> Result<Vec<SqlPlan>> {
59        Ok(vec![SqlPlan::Update {
60            collection: p.collection,
61            engine: EngineType::KeyValue,
62            assignments: p.assignments,
63            filters: p.filters,
64            target_keys: p.target_keys,
65            returning: p.returning,
66        }])
67    }
68
69    fn plan_delete(&self, p: DeleteParams) -> Result<Vec<SqlPlan>> {
70        Ok(vec![SqlPlan::Delete {
71            collection: p.collection,
72            engine: EngineType::KeyValue,
73            filters: p.filters,
74            target_keys: p.target_keys,
75        }])
76    }
77
78    fn plan_aggregate(&self, p: AggregateParams) -> Result<SqlPlan> {
79        let base_scan = SqlPlan::Scan {
80            collection: p.collection,
81            alias: p.alias,
82            engine: EngineType::KeyValue,
83            filters: p.filters,
84            projection: Vec::new(),
85            sort_keys: Vec::new(),
86            limit: None,
87            offset: 0,
88            distinct: false,
89            window_functions: Vec::new(),
90        };
91        Ok(SqlPlan::Aggregate {
92            input: Box::new(base_scan),
93            group_by: p.group_by,
94            aggregates: p.aggregates,
95            having: p.having,
96            limit: p.limit,
97        })
98    }
99}