Skip to main content

nodedb_sql/engine_rules/
columnar.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Engine rules for plain columnar collections.
4
5use crate::engine_rules::*;
6use crate::error::{Result, SqlError};
7use crate::types::*;
8
9pub struct ColumnarRules;
10
11impl EngineRules for ColumnarRules {
12    fn plan_insert(&self, p: InsertParams) -> Result<Vec<SqlPlan>> {
13        Ok(vec![SqlPlan::Insert {
14            collection: p.collection,
15            engine: EngineType::Columnar,
16            rows: p.rows,
17            column_defaults: p.column_defaults,
18            if_absent: p.if_absent,
19        }])
20    }
21
22    /// `UPSERT` / `INSERT ... ON CONFLICT (pk) DO UPDATE` on columnar.
23    /// Duplicate PK tombstones the prior row via the segment's delete
24    /// bitmap; the new row (or its merged form, when `on_conflict_updates`
25    /// is non-empty) is appended. Sort-key semantics are unchanged.
26    fn plan_upsert(&self, p: UpsertParams) -> Result<Vec<SqlPlan>> {
27        Ok(vec![SqlPlan::Upsert {
28            collection: p.collection,
29            engine: EngineType::Columnar,
30            rows: p.rows,
31            column_defaults: p.column_defaults,
32            on_conflict_updates: p.on_conflict_updates,
33        }])
34    }
35
36    fn plan_scan(&self, p: ScanParams) -> Result<SqlPlan> {
37        if p.temporal.is_temporal() && !p.bitemporal {
38            return Err(SqlError::Unsupported {
39                detail: format!(
40                    "FOR SYSTEM_TIME / FOR VALID_TIME requires a bitemporal \
41                     collection; '{}' was not created WITH bitemporal = true",
42                    p.collection
43                ),
44            });
45        }
46        Ok(SqlPlan::Scan {
47            collection: p.collection,
48            alias: p.alias,
49            engine: EngineType::Columnar,
50            filters: p.filters,
51            projection: p.projection,
52            sort_keys: p.sort_keys,
53            limit: p.limit,
54            offset: p.offset,
55            distinct: p.distinct,
56            window_functions: p.window_functions,
57            temporal: p.temporal,
58        })
59    }
60
61    fn plan_point_get(&self, p: PointGetParams) -> Result<SqlPlan> {
62        Ok(SqlPlan::PointGet {
63            collection: p.collection,
64            alias: p.alias,
65            engine: EngineType::Columnar,
66            key_column: p.key_column,
67            key_value: p.key_value,
68        })
69    }
70
71    fn plan_update(&self, p: UpdateParams) -> Result<Vec<SqlPlan>> {
72        Ok(vec![SqlPlan::Update {
73            collection: p.collection,
74            engine: EngineType::Columnar,
75            assignments: p.assignments,
76            filters: p.filters,
77            target_keys: p.target_keys,
78            returning: p.returning,
79        }])
80    }
81
82    fn plan_update_from(&self, p: UpdateFromParams) -> Result<Vec<SqlPlan>> {
83        Ok(vec![SqlPlan::UpdateFrom {
84            collection: p.collection,
85            engine: EngineType::Columnar,
86            source: p.source,
87            target_join_col: p.target_join_col,
88            source_join_col: p.source_join_col,
89            assignments: p.assignments,
90            target_filters: p.target_filters,
91            returning: p.returning,
92        }])
93    }
94
95    fn plan_delete(&self, p: DeleteParams) -> Result<Vec<SqlPlan>> {
96        Ok(vec![SqlPlan::Delete {
97            collection: p.collection,
98            engine: EngineType::Columnar,
99            filters: p.filters,
100            target_keys: p.target_keys,
101        }])
102    }
103
104    fn plan_aggregate(&self, p: AggregateParams) -> Result<SqlPlan> {
105        if p.temporal.is_temporal() && !p.bitemporal {
106            return Err(SqlError::Unsupported {
107                detail: format!(
108                    "FOR SYSTEM_TIME / FOR VALID_TIME requires a bitemporal \
109                     collection; '{}' was not created WITH bitemporal = true",
110                    p.collection
111                ),
112            });
113        }
114        let base_scan = SqlPlan::Scan {
115            collection: p.collection,
116            alias: p.alias,
117            engine: EngineType::Columnar,
118            filters: p.filters,
119            projection: Vec::new(),
120            sort_keys: Vec::new(),
121            limit: None,
122            offset: 0,
123            distinct: false,
124            window_functions: Vec::new(),
125            temporal: p.temporal,
126        };
127        Ok(SqlPlan::Aggregate {
128            input: Box::new(base_scan),
129            group_by: p.group_by,
130            aggregates: p.aggregates,
131            having: p.having,
132            limit: p.limit,
133            grouping_sets: None,
134            sort_keys: Vec::new(),
135        })
136    }
137
138    fn plan_merge(&self, p: MergeParams) -> Result<Vec<SqlPlan>> {
139        Err(SqlError::Unsupported {
140            detail: format!(
141                "MERGE is not supported on columnar collection '{}'",
142                p.collection
143            ),
144        })
145    }
146}