nodedb_sql/engine_rules/
kv.rs1use crate::engine_rules::*;
6use crate::error::{Result, SqlError};
7use crate::types::*;
8
9pub struct KvRules;
10
11impl EngineRules for KvRules {
12 fn plan_insert(&self, p: InsertParams) -> Result<Vec<SqlPlan>> {
13 Err(SqlError::Unsupported {
20 detail: format!(
21 "INSERT into KV collection '{}' must use the KV insert path",
22 p.collection
23 ),
24 })
25 }
26
27 fn plan_insert_select(&self, p: InsertSelectParams) -> Result<Vec<SqlPlan>> {
28 Err(SqlError::Unsupported {
29 detail: format!(
30 "INSERT ... SELECT into key-value collection '{}' is not supported; \
31 the target must be a document collection",
32 p.collection
33 ),
34 })
35 }
36
37 fn plan_upsert(&self, _p: UpsertParams) -> Result<Vec<SqlPlan>> {
38 Err(SqlError::Unsupported {
41 detail: "KV UPSERT must use the KV insert path (KV PUT is naturally an upsert)".into(),
42 })
43 }
44
45 fn plan_scan(&self, p: ScanParams) -> Result<SqlPlan> {
46 if p.temporal.is_temporal() {
47 return Err(SqlError::Unsupported {
48 detail: format!(
49 "FOR SYSTEM_TIME / FOR VALID_TIME is not supported on KV collection '{}'",
50 p.collection
51 ),
52 });
53 }
54 Ok(SqlPlan::Scan {
55 collection: p.collection,
56 alias: p.alias,
57 engine: EngineType::KeyValue,
58 filters: p.filters,
59 projection: p.projection,
60 sort_keys: p.sort_keys,
61 limit: p.limit,
62 offset: p.offset,
63 distinct: p.distinct,
64 window_functions: p.window_functions,
65 temporal: p.temporal,
66 })
67 }
68
69 fn plan_point_get(&self, p: PointGetParams) -> Result<SqlPlan> {
70 Ok(SqlPlan::PointGet {
71 collection: p.collection,
72 alias: p.alias,
73 engine: EngineType::KeyValue,
74 key_column: p.key_column,
75 key_value: p.key_value,
76 projection: p.projection,
77 })
78 }
79
80 fn plan_update(&self, p: UpdateParams) -> Result<Vec<SqlPlan>> {
81 Ok(vec![SqlPlan::Update {
82 collection: p.collection,
83 engine: EngineType::KeyValue,
84 assignments: p.assignments,
85 filters: p.filters,
86 target_keys: p.target_keys,
87 returning: p.returning,
88 }])
89 }
90
91 fn plan_update_from(&self, p: UpdateFromParams) -> Result<Vec<SqlPlan>> {
92 Err(SqlError::Unsupported {
93 detail: format!(
94 "UPDATE ... FROM is not supported on KV collection '{}'; \
95 KV keys are opaque and cannot participate in cross-table join updates",
96 p.collection
97 ),
98 })
99 }
100
101 fn plan_delete(&self, p: DeleteParams) -> Result<Vec<SqlPlan>> {
102 Ok(vec![SqlPlan::Delete {
103 collection: p.collection,
104 engine: EngineType::KeyValue,
105 filters: p.filters,
106 target_keys: p.target_keys,
107 }])
108 }
109
110 fn plan_truncate(&self, p: TruncateParams) -> Result<Vec<SqlPlan>> {
111 Ok(vec![SqlPlan::Truncate {
112 collection: p.collection,
113 engine: EngineType::KeyValue,
114 restart_identity: p.restart_identity,
115 }])
116 }
117
118 fn plan_aggregate(&self, p: AggregateParams) -> Result<SqlPlan> {
119 let base_scan = SqlPlan::Scan {
120 collection: p.collection,
121 alias: p.alias,
122 engine: EngineType::KeyValue,
123 filters: p.filters,
124 projection: Vec::new(),
125 sort_keys: Vec::new(),
126 limit: None,
127 offset: 0,
128 distinct: false,
129 window_functions: Vec::new(),
130 temporal: crate::temporal::TemporalScope::default(),
131 };
132 Ok(SqlPlan::Aggregate {
133 input: Box::new(base_scan),
134 group_by: p.group_by,
135 group_by_aliases: Vec::new(),
136 output_order: Vec::new(),
137 aggregates: p.aggregates,
138 having: p.having,
139 limit: p.limit,
140 grouping_sets: p.grouping_sets,
141 sort_keys: Vec::new(),
142 })
143 }
144
145 fn plan_merge(&self, p: MergeParams) -> Result<Vec<SqlPlan>> {
146 Err(SqlError::Unsupported {
147 detail: format!(
148 "MERGE is not supported on key-value collection '{}'",
149 p.collection
150 ),
151 })
152 }
153
154 fn accepts_undeclared_columns(&self) -> bool {
156 false
157 }
158
159 fn implicit_columns(&self) -> &'static [&'static str] {
162 &["key", "value", "ttl"]
163 }
164
165 fn value_column_name_is_free(&self) -> bool {
166 true
167 }
168}