Skip to main content

nodedb_sql/ddl_ast/
statement.rs

1//! The [`NodedbStatement`] enum — one variant per DDL command.
2
3/// Typed representation of every NodeDB DDL statement.
4///
5/// Handlers receive a fully-parsed variant instead of raw `&[&str]`
6/// parts, eliminating array-index panics and enabling exhaustive
7/// match coverage for new DDL commands.
8#[derive(Debug, Clone, PartialEq)]
9pub enum NodedbStatement {
10    // ── Collection lifecycle ─────────────────────────────────────
11    CreateCollection {
12        name: String,
13        if_not_exists: bool,
14        raw_sql: String,
15    },
16    DropCollection {
17        name: String,
18        if_exists: bool,
19    },
20    AlterCollection {
21        name: String,
22        raw_sql: String,
23    },
24    DescribeCollection {
25        name: String,
26    },
27    ShowCollections,
28
29    // ── Index ────────────────────────────────────────────────────
30    CreateIndex {
31        unique: bool,
32        raw_sql: String,
33    },
34    DropIndex {
35        name: String,
36        collection: Option<String>,
37        if_exists: bool,
38    },
39    ShowIndexes {
40        collection: Option<String>,
41    },
42    Reindex {
43        collection: String,
44    },
45
46    // ── Trigger ──────────────────────────────────────────────────
47    CreateTrigger {
48        or_replace: bool,
49        deferred: bool,
50        sync: bool,
51        raw_sql: String,
52    },
53    DropTrigger {
54        name: String,
55        collection: String,
56        if_exists: bool,
57    },
58    AlterTrigger {
59        raw_sql: String,
60    },
61    ShowTriggers {
62        collection: Option<String>,
63    },
64
65    // ── Schedule ─────────────────────────────────────────────────
66    CreateSchedule {
67        raw_sql: String,
68    },
69    DropSchedule {
70        name: String,
71        if_exists: bool,
72    },
73    AlterSchedule {
74        raw_sql: String,
75    },
76    ShowSchedules,
77    ShowScheduleHistory {
78        name: String,
79    },
80
81    // ── Sequence ─────────────────────────────────────────────────
82    CreateSequence {
83        name: String,
84        if_not_exists: bool,
85        raw_sql: String,
86    },
87    DropSequence {
88        name: String,
89        if_exists: bool,
90    },
91    AlterSequence {
92        raw_sql: String,
93    },
94    DescribeSequence {
95        name: String,
96    },
97    ShowSequences,
98
99    // ── Alert ────────────────────────────────────────────────────
100    CreateAlert {
101        raw_sql: String,
102    },
103    DropAlert {
104        name: String,
105        if_exists: bool,
106    },
107    AlterAlert {
108        raw_sql: String,
109    },
110    ShowAlerts,
111    ShowAlertStatus {
112        name: String,
113    },
114
115    // ── Retention policy ─────────────────────────────────────────
116    CreateRetentionPolicy {
117        raw_sql: String,
118    },
119    DropRetentionPolicy {
120        name: String,
121        if_exists: bool,
122    },
123    AlterRetentionPolicy {
124        raw_sql: String,
125    },
126    ShowRetentionPolicies,
127
128    // ── Change stream ────────────────────────────────────────────
129    CreateChangeStream {
130        raw_sql: String,
131    },
132    DropChangeStream {
133        name: String,
134        if_exists: bool,
135    },
136    AlterChangeStream {
137        raw_sql: String,
138    },
139    ShowChangeStreams,
140
141    // ── Consumer group ───────────────────────────────────────────
142    CreateConsumerGroup {
143        raw_sql: String,
144    },
145    DropConsumerGroup {
146        name: String,
147        stream: String,
148        if_exists: bool,
149    },
150    ShowConsumerGroups {
151        stream: Option<String>,
152    },
153
154    // ── RLS policy ───────────────────────────────────────────────
155    CreateRlsPolicy {
156        raw_sql: String,
157    },
158    DropRlsPolicy {
159        name: String,
160        collection: String,
161        if_exists: bool,
162    },
163    ShowRlsPolicies {
164        collection: Option<String>,
165    },
166
167    // ── Materialized view ────────────────────────────────────────
168    CreateMaterializedView {
169        raw_sql: String,
170    },
171    DropMaterializedView {
172        name: String,
173        if_exists: bool,
174    },
175    ShowMaterializedViews,
176
177    // ── Continuous aggregate ─────────────────────────────────────
178    CreateContinuousAggregate {
179        raw_sql: String,
180    },
181    DropContinuousAggregate {
182        name: String,
183        if_exists: bool,
184    },
185    ShowContinuousAggregates,
186
187    // ── Backup / restore ─────────────────────────────────────────
188    BackupTenant {
189        raw_sql: String,
190    },
191    RestoreTenant {
192        dry_run: bool,
193        raw_sql: String,
194    },
195
196    // ── Cluster admin ────────────────────────────────────────────
197    ShowNodes,
198    ShowNode {
199        node_id: String,
200    },
201    RemoveNode {
202        node_id: String,
203    },
204    ShowCluster,
205    ShowMigrations,
206    ShowRanges,
207    ShowRouting,
208    ShowSchemaVersion,
209    ShowPeerHealth,
210    Rebalance,
211    ShowRaftGroups,
212    ShowRaftGroup {
213        group_id: String,
214    },
215    AlterRaftGroup {
216        raw_sql: String,
217    },
218
219    // ── Maintenance ──────────────────────────────────────────────
220    Analyze {
221        collection: Option<String>,
222    },
223    Compact {
224        collection: String,
225    },
226    ShowStorage {
227        collection: Option<String>,
228    },
229    ShowCompactionStatus,
230
231    // ── User / auth / grant ──────────────────────────────────────
232    CreateUser {
233        raw_sql: String,
234    },
235    DropUser {
236        username: String,
237    },
238    AlterUser {
239        raw_sql: String,
240    },
241    ShowUsers,
242    GrantRole {
243        raw_sql: String,
244    },
245    RevokeRole {
246        raw_sql: String,
247    },
248    GrantPermission {
249        raw_sql: String,
250    },
251    RevokePermission {
252        raw_sql: String,
253    },
254    ShowPermissions {
255        collection: Option<String>,
256    },
257    ShowGrants {
258        username: Option<String>,
259    },
260
261    // ── Miscellaneous ────────────────────────────────────────────
262    ShowTenants,
263    ShowAuditLog,
264    ShowConstraints {
265        collection: String,
266    },
267    ShowTypeGuards {
268        collection: String,
269    },
270
271    // ── Graph DSL ─────────────────────────────────────────────────
272    //
273    // Typed variants replace substring-matched parsing in the
274    // pgwire handlers. The `ddl_ast::graph_parse` module is the
275    // single source of truth for graph-DSL syntax — quote- and
276    // brace-aware, so node ids / labels / property values that
277    // shadow DSL keywords cannot short-circuit extraction.
278    GraphInsertEdge {
279        src: String,
280        dst: String,
281        label: String,
282        properties: GraphProperties,
283    },
284    GraphDeleteEdge {
285        src: String,
286        dst: String,
287        label: String,
288    },
289    /// `GRAPH LABEL` / `GRAPH UNLABEL`.
290    GraphSetLabels {
291        node_id: String,
292        labels: Vec<String>,
293        /// `true` for `UNLABEL`, `false` for `LABEL`.
294        remove: bool,
295    },
296    GraphTraverse {
297        start: String,
298        depth: usize,
299        edge_label: Option<String>,
300        direction: GraphDirection,
301    },
302    GraphNeighbors {
303        node: String,
304        edge_label: Option<String>,
305        direction: GraphDirection,
306    },
307    GraphPath {
308        src: String,
309        dst: String,
310        max_depth: usize,
311        edge_label: Option<String>,
312    },
313    GraphAlgo {
314        algorithm: String,
315        collection: String,
316        damping: Option<f64>,
317        tolerance: Option<f64>,
318        resolution: Option<f64>,
319        max_iterations: Option<usize>,
320        sample_size: Option<usize>,
321        source_node: Option<String>,
322        direction: Option<String>,
323        mode: Option<String>,
324    },
325    /// `MATCH (x)-[:l]->(y) RETURN x, y` — the query body is
326    /// compiled deep inside the Data Plane via
327    /// `engine::graph::pattern::compiler::parse`, so the AST
328    /// variant just captures the raw SQL for that consumer.
329    MatchQuery {
330        raw_sql: String,
331    },
332
333    /// Catch-all for DDL-like commands not yet promoted to their
334    /// own variant. Preserves the raw SQL for the legacy dispatch
335    /// path so new variants can be added incrementally without
336    /// breaking existing handlers.
337    Other {
338        raw_sql: String,
339    },
340}
341
342/// Traversal direction for graph DSL variants. Mirrors the engine's
343/// own `Direction` enum so `nodedb-sql` has no dependency cycle with
344/// `nodedb`.
345#[derive(Debug, Clone, Copy, PartialEq, Eq)]
346pub enum GraphDirection {
347    In,
348    Out,
349    Both,
350}
351
352/// The `PROPERTIES` clause of `GRAPH INSERT EDGE`. Captured in its
353/// source form so the pgwire handler — which already depends on a
354/// JSON serializer (sonic_rs) — can do the conversion to storage
355/// bytes without dragging JSON deps into `nodedb-sql`.
356#[derive(Debug, Clone, PartialEq, Eq)]
357pub enum GraphProperties {
358    None,
359    /// Raw `{ ... }` object-literal span, including the outer braces
360    /// and brace-balanced inner content. Parsed by
361    /// `crate::parser::object_literal` at the handler boundary.
362    Object(String),
363    /// Content of `'...'` (outer quotes stripped, `''` un-escaped);
364    /// expected to already be a JSON document.
365    Quoted(String),
366}