Skip to main content

qql_core/ast/statement/
mod.rs

1//! Typed AST for QQL statements (`Stmt` and its variants).
2
3pub mod batch;
4pub mod ddl;
5pub mod mutation;
6pub mod query;
7pub mod retrieval;
8pub mod types;
9
10pub use batch::*;
11pub use ddl::*;
12pub use mutation::*;
13pub use query::*;
14pub use retrieval::*;
15pub use types::*;
16
17use alloc::boxed::Box;
18use alloc::string::String;
19
20/// Top-level QQL statement parsed from a script.
21#[derive(Debug, Clone, PartialEq)]
22pub enum Stmt {
23    /// `QUERY …` retrieval (all `QueryExpr` forms).
24    Query(Box<QueryStmt>),
25    /// `SCROLL …` cursor iteration.
26    Scroll(Box<ScrollStmt>),
27    /// `UPSERT INTO …` point write.
28    Upsert(Box<UpsertStmt>),
29    /// `CREATE COLLECTION …` DDL.
30    CreateCollection(Box<CreateCollectionStmt>),
31    /// `CREATE INDEX …` DDL.
32    CreateIndex(Box<CreateIndexStmt>),
33    /// `DROP INDEX …` DDL.
34    DropIndex(Box<DropIndexStmt>),
35    /// `CREATE SHARD KEY …` DDL.
36    CreateShardKey(Box<CreateShardKeyStmt>),
37    /// `DROP SHARD KEY …` DDL.
38    DropShardKey(Box<DropShardKeyStmt>),
39    /// `ALTER COLLECTION …` DDL.
40    AlterCollection(Box<AlterCollectionStmt>),
41    /// `DROP COLLECTION …` DDL.
42    DropCollection(Box<DropCollectionStmt>),
43    /// `SHOW COLLECTIONS` listing.
44    ShowCollections,
45    /// `SHOW COLLECTION <name>` detail.
46    ShowCollection(String),
47    /// `SHOW SHARD KEYS ON COLLECTION <name>` listing.
48    ShowShardKeys(String),
49    /// `DELETE FROM …` point removal.
50    Delete(Box<DeleteStmt>),
51    /// `CLEAR PAYLOAD …` payload wipe.
52    ClearPayload(Box<ClearPayloadStmt>),
53    /// `DELETE PAYLOAD <keys> …` payload key removal.
54    DeletePayload(Box<DeletePayloadStmt>),
55    /// `DELETE VECTOR <names> …` named vector removal.
56    DeleteVector(Box<DeleteVectorStmt>),
57    /// `UPDATE … SET VECTOR …` vector replacement.
58    UpdateVector(Box<UpdateVectorStmt>),
59    /// `UPDATE … SET PAYLOAD …` payload merge.
60    UpdatePayload(Box<UpdatePayloadStmt>),
61    /// `COUNT …` point counting.
62    Count(Box<CountStmt>),
63    /// `FACET …` categorical aggregation.
64    Facet(Box<FacetStmt>),
65    /// `SHOW QUOTAS` listing.
66    ShowQuotas,
67    /// `SET QUOTA (…)` cluster quota replacement.
68    SetQuota(Box<SetQuotaStmt>),
69    /// `BATCH { … }` single-RPC batch of homogeneous members.
70    Batch(Box<BatchStmt>),
71}
72
73#[cfg(feature = "serde")]
74impl serde::Serialize for Stmt {
75    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
76    where
77        S: serde::Serializer,
78    {
79        use serde::ser::SerializeMap;
80        match self {
81            Stmt::Query(s) => serializer.serialize_newtype_variant("Stmt", 0, "Query", s),
82            Stmt::Scroll(s) => serializer.serialize_newtype_variant("Stmt", 1, "Scroll", s),
83            Stmt::Upsert(s) => serializer.serialize_newtype_variant("Stmt", 2, "Upsert", s),
84            Stmt::CreateCollection(s) => {
85                serializer.serialize_newtype_variant("Stmt", 3, "CreateCollection", s)
86            }
87            Stmt::CreateIndex(s) => {
88                serializer.serialize_newtype_variant("Stmt", 4, "CreateIndex", s)
89            }
90            Stmt::DropIndex(s) => serializer.serialize_newtype_variant("Stmt", 5, "DropIndex", s),
91            Stmt::CreateShardKey(s) => {
92                serializer.serialize_newtype_variant("Stmt", 6, "CreateShardKey", s)
93            }
94            Stmt::DropShardKey(s) => {
95                serializer.serialize_newtype_variant("Stmt", 7, "DropShardKey", s)
96            }
97            Stmt::AlterCollection(s) => {
98                serializer.serialize_newtype_variant("Stmt", 8, "AlterCollection", s)
99            }
100            Stmt::DropCollection(s) => {
101                serializer.serialize_newtype_variant("Stmt", 9, "DropCollection", s)
102            }
103            // Unit variant. The serialized form is the empty-object tag
104            // `{"ShowCollections": {}}` (kept for backward compatibility with
105            // consumers that already emit that shape). The manual
106            // `Deserialize` accepts both this form and the derived string
107            // form `"ShowCollections"`, so serde round-trips.
108            Stmt::ShowCollections => {
109                let mut map = serializer.serialize_map(Some(1))?;
110                let empty = alloc::collections::BTreeMap::<String, String>::new();
111                map.serialize_entry("ShowCollections", &empty)?;
112                map.end()
113            }
114            Stmt::ShowCollection(s) => {
115                serializer.serialize_newtype_variant("Stmt", 11, "ShowCollection", s)
116            }
117            Stmt::ShowShardKeys(s) => {
118                serializer.serialize_newtype_variant("Stmt", 12, "ShowShardKeys", s)
119            }
120            Stmt::Delete(s) => serializer.serialize_newtype_variant("Stmt", 13, "Delete", s),
121            Stmt::ClearPayload(s) => {
122                serializer.serialize_newtype_variant("Stmt", 14, "ClearPayload", s)
123            }
124            Stmt::DeletePayload(s) => {
125                serializer.serialize_newtype_variant("Stmt", 15, "DeletePayload", s)
126            }
127            Stmt::DeleteVector(s) => {
128                serializer.serialize_newtype_variant("Stmt", 16, "DeleteVector", s)
129            }
130            Stmt::UpdateVector(s) => {
131                serializer.serialize_newtype_variant("Stmt", 17, "UpdateVector", s)
132            }
133            Stmt::UpdatePayload(s) => {
134                serializer.serialize_newtype_variant("Stmt", 18, "UpdatePayload", s)
135            }
136            Stmt::Count(s) => serializer.serialize_newtype_variant("Stmt", 19, "Count", s),
137            Stmt::Facet(s) => serializer.serialize_newtype_variant("Stmt", 20, "Facet", s),
138            Stmt::ShowQuotas => {
139                let mut map = serializer.serialize_map(Some(1))?;
140                let empty = alloc::collections::BTreeMap::<String, String>::new();
141                map.serialize_entry("ShowQuotas", &empty)?;
142                map.end()
143            }
144            Stmt::SetQuota(s) => serializer.serialize_newtype_variant("Stmt", 22, "SetQuota", s),
145            Stmt::Batch(s) => serializer.serialize_newtype_variant("Stmt", 23, "Batch", s),
146        }
147    }
148}
149
150#[cfg(feature = "serde")]
151impl<'de> serde::Deserialize<'de> for Stmt {
152    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
153    where
154        D: serde::Deserializer<'de>,
155    {
156        use core::fmt;
157        use serde::de::{Error as _, IgnoredAny, MapAccess, Visitor};
158
159        struct StmtVisitor;
160
161        impl<'de> Visitor<'de> for StmtVisitor {
162            type Value = Stmt;
163
164            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
165                formatter.write_str("an externally tagged QQL statement")
166            }
167
168            /// Derived externally-tagged form of the unit variant.
169            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
170            where
171                E: serde::de::Error,
172            {
173                if value == "ShowCollections" {
174                    Ok(Stmt::ShowCollections)
175                } else {
176                    Err(E::unknown_variant(value, &["ShowCollections"]))
177                }
178            }
179
180            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
181            where
182                A: MapAccess<'de>,
183            {
184                let key = map
185                    .next_key::<alloc::string::String>()?
186                    .ok_or_else(|| A::Error::custom("expected a statement tag"))?;
187                let stmt = match key.as_str() {
188                    "Query" => Stmt::Query(map.next_value()?),
189                    "Scroll" => Stmt::Scroll(map.next_value()?),
190                    "Upsert" => Stmt::Upsert(map.next_value()?),
191                    "CreateCollection" => Stmt::CreateCollection(map.next_value()?),
192                    "CreateIndex" => Stmt::CreateIndex(map.next_value()?),
193                    "DropIndex" => Stmt::DropIndex(map.next_value()?),
194                    "CreateShardKey" => Stmt::CreateShardKey(map.next_value()?),
195                    "DropShardKey" => Stmt::DropShardKey(map.next_value()?),
196                    "AlterCollection" => Stmt::AlterCollection(map.next_value()?),
197                    "DropCollection" => Stmt::DropCollection(map.next_value()?),
198                    // Canonical serialized form (`{"ShowCollections": {}}`);
199                    // the payload is ignored, mirroring the derived impl's
200                    // permissive unit-variant handling.
201                    "ShowCollections" => {
202                        map.next_value::<IgnoredAny>()?;
203                        Stmt::ShowCollections
204                    }
205                    "ShowQuotas" => {
206                        map.next_value::<IgnoredAny>()?;
207                        Stmt::ShowQuotas
208                    }
209                    "ShowCollection" => Stmt::ShowCollection(map.next_value()?),
210                    "ShowShardKeys" => Stmt::ShowShardKeys(map.next_value()?),
211                    "Delete" => Stmt::Delete(map.next_value()?),
212                    "ClearPayload" => Stmt::ClearPayload(map.next_value()?),
213                    "DeletePayload" => Stmt::DeletePayload(map.next_value()?),
214                    "DeleteVector" => Stmt::DeleteVector(map.next_value()?),
215                    "UpdateVector" => Stmt::UpdateVector(map.next_value()?),
216                    "UpdatePayload" => Stmt::UpdatePayload(map.next_value()?),
217                    "Count" => Stmt::Count(map.next_value()?),
218                    "Facet" => Stmt::Facet(map.next_value()?),
219                    "SetQuota" => Stmt::SetQuota(map.next_value()?),
220                    "Batch" => Stmt::Batch(map.next_value()?),
221                    _ => {
222                        return Err(A::Error::unknown_variant(
223                            &key,
224                            &[
225                                "Query",
226                                "Scroll",
227                                "Upsert",
228                                "CreateCollection",
229                                "CreateIndex",
230                                "DropIndex",
231                                "CreateShardKey",
232                                "DropShardKey",
233                                "AlterCollection",
234                                "DropCollection",
235                                "ShowCollections",
236                                "ShowCollection",
237                                "ShowShardKeys",
238                                "Delete",
239                                "ClearPayload",
240                                "DeletePayload",
241                                "DeleteVector",
242                                "UpdateVector",
243                                "UpdatePayload",
244                                "Count",
245                                "Facet",
246                                "ShowQuotas",
247                                "SetQuota",
248                                "Batch",
249                            ],
250                        ));
251                    }
252                };
253                if map.next_key::<IgnoredAny>()?.is_some() {
254                    return Err(A::Error::custom("duplicate statement tag"));
255                }
256                Ok(stmt)
257            }
258        }
259
260        deserializer.deserialize_any(StmtVisitor)
261    }
262}
263
264impl Stmt {
265    /// Return the canonical keyword name for this statement variant (e.g. "QUERY", "CREATE COLLECTION").
266    pub fn stmt_kind(&self) -> &'static str {
267        match self {
268            Self::Query(_) => "QUERY",
269            Self::Scroll(_) => "SCROLL",
270            Self::Count(_) => "COUNT",
271            Self::Facet(_) => "FACET",
272            Self::Upsert(_) => "UPSERT",
273            Self::Delete(_) => "DELETE",
274            Self::ClearPayload(_) => "CLEAR PAYLOAD",
275            Self::DeletePayload(_) => "DELETE PAYLOAD",
276            Self::DeleteVector(_) => "DELETE VECTOR",
277            Self::UpdateVector(_) => "UPDATE VECTOR",
278            Self::UpdatePayload(_) => "UPDATE PAYLOAD",
279            Self::CreateCollection(_) => "CREATE COLLECTION",
280            Self::AlterCollection(_) => "ALTER COLLECTION",
281            Self::DropCollection(_) => "DROP COLLECTION",
282            Self::CreateIndex(_) => "CREATE INDEX",
283            Self::DropIndex(_) => "DROP INDEX",
284            Self::CreateShardKey(_) => "CREATE SHARD KEY",
285            Self::DropShardKey(_) => "DROP SHARD KEY",
286            Self::ShowCollections => "SHOW COLLECTIONS",
287            Self::ShowCollection(_) => "SHOW COLLECTION",
288            Self::ShowShardKeys(_) => "SHOW SHARD KEYS",
289            Self::ShowQuotas => "SHOW QUOTAS",
290            Self::SetQuota(_) => "SET QUOTA",
291            Self::Batch(_) => "BATCH",
292        }
293    }
294}
295
296impl core::fmt::Display for Stmt {
297    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
298        write!(f, "{}", crate::fmt::format_stmt(self))
299    }
300}