Skip to main content

qql_core/ast/
statement.rs

1use super::{FilterExpr, FormulaExpr, Value};
2use alloc::boxed::Box;
3use alloc::string::String;
4use alloc::vec::Vec;
5
6#[derive(Debug, Clone, PartialEq, Eq)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8pub enum PointId {
9    Number(u64),
10    String(String),
11}
12
13#[derive(Debug, Clone, PartialEq)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15pub enum VectorValue {
16    Dense(Vec<f32>),
17    Sparse { indices: Vec<u32>, values: Vec<f32> },
18    MultiDense(Vec<Vec<f32>>),
19}
20
21#[derive(Debug, Clone, PartialEq)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23pub enum PointVectors {
24    Unnamed(VectorValue),
25    Named(Vec<(String, VectorValue)>),
26}
27
28#[derive(Debug, Clone, PartialEq)]
29#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
30pub enum QueryInput {
31    Text {
32        text: String,
33        model: Option<String>,
34    },
35    /// Image path or URL for dense embedding (CLIP vision, etc.).
36    /// Resolved to [`VectorValue::Dense`] before plan/dispatch.
37    Image {
38        source: String,
39        model: Option<String>,
40    },
41    Vector(VectorValue),
42    Point(PointId),
43}
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
47pub enum VectorKind {
48    Dense,
49    Sparse,
50}
51
52#[derive(Debug, Clone, PartialEq, Eq)]
53#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
54pub struct VectorTarget {
55    pub name: String,
56    pub kind: Option<VectorKind>,
57    /// Multivector (ColBERT-style) dense target. Filled at parse only via
58    /// `AS MULTI`, or at execution prep from collection schema
59    /// (`multivector_config`). Not a third `VectorKind` — still dense.
60    #[cfg_attr(feature = "serde", serde(default))]
61    pub multi: bool,
62}
63
64#[derive(Debug, Clone, PartialEq)]
65#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
66pub struct MmrConfig {
67    pub diversity: f64,
68    pub candidates: u64,
69}
70
71#[derive(Debug, Clone, PartialEq)]
72#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
73pub struct ContextPair {
74    pub positive: QueryInput,
75    pub negative: QueryInput,
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
80pub enum RecommendStrategy {
81    AverageVector,
82    BestScore,
83    SumScores,
84}
85
86#[derive(Debug, Clone, PartialEq)]
87#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
88pub struct FeedbackItem {
89    pub example: QueryInput,
90    pub score: f64,
91}
92
93#[derive(Debug, Clone, Copy, PartialEq)]
94#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
95pub struct FeedbackStrategy {
96    pub a: f64,
97    pub b: f64,
98    pub c: f64,
99}
100
101#[derive(Debug, Clone, Copy, PartialEq, Eq)]
102#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
103pub enum OrderDirection {
104    Asc,
105    Desc,
106}
107
108#[derive(Debug, Clone, Copy, PartialEq, Eq)]
109#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
110pub enum FusionMethod {
111    Rrf,
112    Dbsf,
113}
114
115#[derive(Debug, Clone, PartialEq)]
116#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
117pub enum QueryCollection {
118    Explicit(String),
119    Inherited,
120}
121
122#[derive(Debug, Clone, PartialEq)]
123#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
124pub enum PrefetchSource {
125    Cte(String),
126    Query(Box<QueryStmt>),
127}
128
129#[derive(Debug, Clone, PartialEq)]
130#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
131pub struct LookupSpec {
132    pub collection: String,
133    pub vector: Option<String>,
134}
135
136#[derive(Debug, Clone, PartialEq)]
137#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
138pub struct Prefetch {
139    pub source: PrefetchSource,
140    pub filter: Option<Box<FilterExpr>>,
141    pub score_threshold: Option<f64>,
142    pub lookup: Option<LookupSpec>,
143}
144
145#[derive(Debug, Clone, PartialEq)]
146#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
147pub enum QueryExpr {
148    Points {
149        ids: Vec<PointId>,
150    },
151    Nearest {
152        input: QueryInput,
153        using: Option<VectorTarget>,
154        prefetch: Vec<Prefetch>,
155        mmr: Option<Box<MmrConfig>>,
156    },
157    Recommend {
158        positive: Vec<QueryInput>,
159        negative: Vec<QueryInput>,
160        strategy: Option<RecommendStrategy>,
161        using: Option<VectorTarget>,
162        prefetch: Vec<Prefetch>,
163    },
164    Context {
165        pairs: Vec<ContextPair>,
166        using: Option<VectorTarget>,
167        prefetch: Vec<Prefetch>,
168    },
169    Discover {
170        target: QueryInput,
171        context: Vec<ContextPair>,
172        using: Option<VectorTarget>,
173        prefetch: Vec<Prefetch>,
174    },
175    OrderBy {
176        field: String,
177        direction: OrderDirection,
178    },
179    SampleRandom,
180    Fusion {
181        method: FusionMethod,
182        prefetch: Vec<Prefetch>,
183    },
184    Formula {
185        expression: Box<FormulaExpr>,
186        defaults: Vec<(String, Value)>,
187        prefetch: Vec<Prefetch>,
188    },
189    RelevanceFeedback {
190        target: QueryInput,
191        feedback: Vec<FeedbackItem>,
192        strategy: FeedbackStrategy,
193        using: Option<VectorTarget>,
194        prefetch: Vec<Prefetch>,
195    },
196    Hybrid {
197        text: String,
198        model: Option<String>,
199        dense_vector: Option<String>,
200        sparse_vector: Option<String>,
201        fusion: FusionMethod,
202    },
203    Rerank {
204        input: QueryInput,
205        model: String,
206        using: Option<VectorTarget>,
207        prefetch: Vec<Prefetch>,
208    },
209    /// Cross-encoder pair rerank: score query against PREFETCH document texts.
210    /// Not sent to Qdrant as MaxSim — executor scores client-side then reorders.
211    CrossRerank {
212        /// Query string scored against each document.
213        query: String,
214        /// Cross-encoder model id (e.g. bge-reranker-base).
215        model: String,
216        /// Payload field holding document text (default `"text"` at resolve time).
217        field: Option<String>,
218        prefetch: Vec<Prefetch>,
219    },
220}
221
222#[derive(Debug, Clone, PartialEq, Default)]
223#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
224pub struct QuantizationSearchParams {
225    pub ignore: Option<bool>,
226    pub rescore: Option<bool>,
227    pub oversampling: Option<f64>,
228}
229
230/// Read consistency for Qdrant point reads.
231///
232/// OpenAPI `ReadConsistency` / proto `ReadConsistency`: either a replica
233/// **factor** `N`, or a named mode (`majority` / `quorum` / `all`).
234/// REST: query param on `/points/query` etc. gRPC: `read_consistency` field.
235#[derive(Debug, Clone, PartialEq)]
236#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
237pub enum ReadConsistency {
238    /// Send requests to N nodes; keep points present on all of them.
239    Factor(u64),
240    /// N/2+1 random requests; points present on all of them.
241    Majority,
242    /// All nodes; points present on a majority.
243    Quorum,
244    /// All nodes; points present on all of them.
245    All,
246}
247
248#[derive(Debug, Clone, PartialEq, Default)]
249#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
250pub struct SearchParams {
251    pub hnsw_ef: Option<u64>,
252    pub exact: Option<bool>,
253    pub acorn: Option<bool>,
254    /// ACORN selectivity ceiling in (0, 1]. Only valid with `acorn = true`.
255    pub max_selectivity: Option<f64>,
256    pub indexed_only: Option<bool>,
257    pub quantization: Option<QuantizationSearchParams>,
258    pub rrf_k: Option<u64>,
259    pub rrf_weights: Option<Vec<f64>>,
260    /// Request-level timeout in **seconds** (OpenAPI query param / proto field).
261    /// Not part of body `SearchParams`.
262    pub timeout: Option<u64>,
263    /// Request-level read consistency (OpenAPI query param / proto field).
264    pub consistency: Option<ReadConsistency>,
265}
266
267#[derive(Debug, Clone, PartialEq)]
268#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
269pub enum PayloadSelector {
270    All,
271    None,
272    Include(Vec<String>),
273    Exclude(Vec<String>),
274}
275
276#[derive(Debug, Clone, PartialEq)]
277#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
278pub enum VectorSelector {
279    All,
280    None,
281    Names(Vec<String>),
282}
283
284#[derive(Debug, Clone, PartialEq, Default)]
285#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
286pub struct QueryOutput {
287    pub payload: Option<PayloadSelector>,
288    pub vectors: Option<VectorSelector>,
289}
290
291#[derive(Debug, Clone, PartialEq)]
292#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
293pub struct GroupSpec {
294    pub field: String,
295    pub size: Option<u64>,
296    pub lookup: Option<String>,
297}
298
299#[derive(Debug, Clone, PartialEq, Default)]
300#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
301pub struct PageSpec {
302    pub limit: Option<u64>,
303    pub offset: Option<u64>,
304}
305
306#[derive(Debug, Clone, PartialEq)]
307#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
308pub struct Cte {
309    pub name: String,
310    pub query: Box<QueryStmt>,
311}
312
313#[derive(Debug, Clone, PartialEq)]
314#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
315pub struct QueryStmt {
316    pub ctes: Vec<Cte>,
317    pub collection: QueryCollection,
318    pub expression: QueryExpr,
319    pub filter: Option<Box<FilterExpr>>,
320    pub params: Option<SearchParams>,
321    pub score_threshold: Option<f64>,
322    pub group: Option<GroupSpec>,
323    pub output: QueryOutput,
324    pub page: PageSpec,
325    pub shard_key: Option<String>,
326}
327
328#[derive(Debug, Clone, PartialEq)]
329#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
330pub struct ScrollStmt {
331    pub collection: String,
332    pub limit: u64,
333    pub filter: Option<Box<FilterExpr>>,
334    pub after: Option<PointId>,
335    pub shard_key: Option<String>,
336    /// Optional `WITH VECTOR` selector. Defaults to no vectors when `None`.
337    pub with_vector: Option<VectorSelector>,
338}
339
340#[derive(Debug, Clone, PartialEq)]
341#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
342pub enum EmbedKind {
343    Dense {
344        model: Option<String>,
345    },
346    Sparse {
347        model: Option<String>,
348    },
349    /// Multivector / ColBERT bag (`embed_multi` → MultiDense).
350    Multi {
351        model: Option<String>,
352    },
353    /// Image / CLIP vision path or URL → dense vector (`embed_image`).
354    Image {
355        model: Option<String>,
356    },
357}
358
359#[derive(Debug, Clone, PartialEq)]
360#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
361pub struct EmbedDirective {
362    pub source_field: String,
363    pub target_vector: String,
364    pub kind: EmbedKind,
365}
366
367#[derive(Debug, Clone, PartialEq)]
368#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
369pub enum EmbeddingSpec {
370    Dense {
371        model: Option<String>,
372        vector: Option<String>,
373        field: Option<String>,
374    },
375    Sparse {
376        model: Option<String>,
377        vector: Option<String>,
378        field: Option<String>,
379    },
380    Hybrid {
381        dense_model: Option<String>,
382        dense_vector: Option<String>,
383        dense_field: Option<String>,
384        sparse_model: Option<String>,
385        sparse_vector: Option<String>,
386        sparse_field: Option<String>,
387    },
388    /// Multivector / ColBERT: text → bag of token vectors for a named multi slot.
389    MultiVector {
390        model: Option<String>,
391        vector: Option<String>,
392        field: Option<String>,
393    },
394    /// Image / CLIP vision: payload field holds a path or URL → dense vector.
395    Image {
396        model: Option<String>,
397        vector: Option<String>,
398        field: Option<String>,
399    },
400    /// Combined specs (e.g. DENSE + SPARSE + MULTI VECTOR colbert).
401    Multi(Vec<EmbeddingSpec>),
402}
403
404#[derive(Debug, Clone, PartialEq)]
405#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
406pub struct UpsertPoint {
407    pub id: PointId,
408    pub vectors: Option<PointVectors>,
409    pub payload: Vec<(String, Value)>,
410}
411
412#[derive(Debug, Clone, PartialEq)]
413#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
414pub struct UpsertStmt {
415    pub collection: String,
416    pub points: Vec<UpsertPoint>,
417    pub embedding: Option<EmbeddingSpec>,
418    pub embed: Vec<EmbedDirective>,
419    pub shard_key: Option<String>,
420}
421
422#[derive(Debug, Clone, Copy, PartialEq, Eq)]
423#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
424pub enum VectorDistance {
425    Cosine,
426    Dot,
427    Euclid,
428    Manhattan,
429}
430
431#[derive(Debug, Clone, Copy, PartialEq, Eq)]
432#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
433pub enum MultivectorComparator {
434    MaxSim,
435}
436
437#[derive(Debug, Clone, PartialEq)]
438#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
439pub struct MultivectorConfig {
440    pub comparator: MultivectorComparator,
441}
442
443#[derive(Debug, Clone, PartialEq)]
444#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
445pub struct VectorDef {
446    pub name: String,
447    pub size: u64,
448    pub distance: VectorDistance,
449    pub hnsw: Option<Box<HnswRuntimeConfig>>,
450    pub quantization: Option<Box<QuantizationConfig>>,
451    pub multivector: Option<MultivectorConfig>,
452    pub vectors: Option<Box<VectorsConfig>>,
453}
454
455#[derive(Debug, Clone, PartialEq)]
456#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
457pub struct SparseIndexConfig {
458    pub full_scan_threshold: Option<u64>,
459    pub on_disk: Option<bool>,
460    pub datatype: Option<String>,
461}
462
463#[derive(Debug, Clone, PartialEq)]
464#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
465pub struct SparseVectorDef {
466    pub name: String,
467    pub index: Option<Box<SparseIndexConfig>>,
468    pub modifier: Option<String>,
469}
470
471#[derive(Debug, Clone, Copy, PartialEq, Eq)]
472#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
473pub enum QuantizationType {
474    Scalar,
475    Binary,
476    Product,
477    Turbo,
478}
479
480#[derive(Debug, Clone, PartialEq)]
481#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
482pub struct QuantizationConfig {
483    pub qtype: QuantizationType,
484    pub always_ram: bool,
485    pub quantile: Option<f64>,
486    pub bits: Option<f64>,
487    pub compression: Option<String>,
488    pub encoding: Option<String>,
489    pub query_encoding: Option<String>,
490}
491
492#[derive(Debug, Clone, PartialEq)]
493#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
494pub struct QuantizationUpdate {
495    pub disabled: bool,
496    pub config: Option<Box<QuantizationConfig>>,
497}
498
499#[derive(Debug, Clone, PartialEq)]
500#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
501pub struct HnswRuntimeConfig {
502    pub m: Option<u64>,
503    pub ef_construct: Option<u64>,
504    pub full_scan_threshold: Option<u64>,
505    pub max_indexing_threads: Option<u64>,
506    pub on_disk: Option<bool>,
507    pub payload_m: Option<u64>,
508    pub inline_storage: Option<bool>,
509}
510
511#[derive(Debug, Clone, PartialEq)]
512#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
513pub struct VectorsConfig {
514    pub on_disk: Option<bool>,
515}
516
517#[derive(Debug, Clone, Copy, PartialEq)]
518#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
519pub struct OptimizationThreads {
520    pub auto_: bool,
521    pub value: u64,
522}
523
524#[derive(Debug, Clone, PartialEq)]
525#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
526pub struct OptimizersRuntimeConfig {
527    pub deleted_threshold: Option<f64>,
528    pub vacuum_min_vector_number: Option<u64>,
529    pub default_segment_number: Option<u64>,
530    pub max_segment_size: Option<u64>,
531    pub memmap_threshold: Option<u64>,
532    pub indexing_threshold: Option<u64>,
533    pub flush_interval_sec: Option<u64>,
534    pub max_optimization_threads: Option<OptimizationThreads>,
535    pub prevent_unoptimized: Option<bool>,
536}
537
538#[derive(Debug, Clone, PartialEq)]
539#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
540pub struct CollectionParamsConfig {
541    pub replication_factor: Option<u64>,
542    pub write_consistency_factor: Option<u64>,
543    pub read_fan_out_factor: Option<u64>,
544    pub read_fan_out_delay_ms: Option<u64>,
545    pub on_disk_payload: Option<bool>,
546    pub shard_number: Option<u64>,
547    pub sharding_method: Option<String>,
548    pub shard_keys: Option<Vec<String>>,
549}
550
551#[derive(Debug, Clone, PartialEq)]
552#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
553pub struct CollectionConfig {
554    pub vectors: Option<Box<VectorsConfig>>,
555    pub hnsw: Option<Box<HnswRuntimeConfig>>,
556    pub optimizers: Option<Box<OptimizersRuntimeConfig>>,
557    pub params: Option<Box<CollectionParamsConfig>>,
558    pub quantization: Option<Box<QuantizationConfig>>,
559    pub quantization_update: Option<Box<QuantizationUpdate>>,
560}
561
562#[derive(Debug, Clone, PartialEq)]
563#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
564pub enum CollectionMode {
565    Dense {
566        model: Option<String>,
567    },
568    Hybrid {
569        dense_vector: Option<String>,
570        sparse_vector: Option<String>,
571    },
572    Rerank,
573}
574
575#[derive(Debug, Clone, PartialEq)]
576#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
577pub struct ClearPayloadStmt {
578    pub collection: String,
579    pub selector: PointSelector,
580    pub shard_key: Option<String>,
581}
582
583#[derive(Debug, Clone, PartialEq)]
584#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
585pub struct DeleteVectorStmt {
586    pub collection: String,
587    pub selector: PointSelector,
588    pub vector_names: Vec<String>,
589    pub shard_key: Option<String>,
590}
591
592#[derive(Debug, Clone, PartialEq)]
593#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
594pub struct CreateCollectionStmt {
595    pub collection: String,
596    pub mode: CollectionMode,
597    pub vectors: Vec<VectorDef>,
598    pub sparse_vectors: Vec<SparseVectorDef>,
599    pub config: Option<Box<CollectionConfig>>,
600}
601
602#[derive(Debug, Clone, PartialEq)]
603#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
604pub struct AlterCollectionStmt {
605    pub collection: String,
606    pub config: Option<Box<CollectionConfig>>,
607}
608
609#[derive(Debug, Clone, PartialEq)]
610#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
611pub struct DropCollectionStmt {
612    pub collection: String,
613}
614
615#[derive(Debug, Clone, PartialEq)]
616#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
617pub struct CreateIndexStmt {
618    pub collection: String,
619    pub field: String,
620    pub field_type: String,
621    pub options: Vec<(String, Value)>,
622}
623
624#[derive(Debug, Clone, PartialEq)]
625#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
626pub struct DropIndexStmt {
627    pub collection: String,
628    pub field: String,
629}
630
631#[derive(Debug, Clone, PartialEq)]
632#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
633pub struct CountStmt {
634    pub collection: QueryCollection,
635    pub filter: Option<Box<FilterExpr>>,
636    pub shard_key: Option<String>,
637    pub exact: Option<bool>,
638}
639
640#[derive(Debug, Clone, PartialEq)]
641#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
642pub struct CreateShardKeyStmt {
643    pub collection: String,
644    pub shard_key: String,
645    pub shards_number: Option<u64>,
646    pub replication_factor: Option<u64>,
647}
648
649#[derive(Debug, Clone, PartialEq)]
650#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
651pub struct DropShardKeyStmt {
652    pub collection: String,
653    pub shard_key: String,
654}
655
656#[derive(Debug, Clone, PartialEq)]
657#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
658pub enum PointSelector {
659    Id(PointId),
660    Ids(Vec<PointId>),
661    Filter(Box<FilterExpr>),
662}
663
664#[derive(Debug, Clone, PartialEq)]
665#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
666pub struct DeleteStmt {
667    pub collection: String,
668    pub selector: PointSelector,
669    pub shard_key: Option<String>,
670}
671
672#[derive(Debug, Clone, PartialEq)]
673#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
674pub struct UpdateVectorStmt {
675    pub collection: String,
676    pub point_id: PointId,
677    pub vector: VectorValue,
678    pub vector_name: Option<String>,
679    pub shard_key: Option<String>,
680}
681
682#[derive(Debug, Clone, PartialEq)]
683#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
684pub struct DeletePayloadStmt {
685    pub collection: String,
686    pub keys: Vec<String>,
687    pub selector: PointSelector,
688    pub shard_key: Option<String>,
689}
690
691#[derive(Debug, Clone, PartialEq)]
692#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
693pub struct UpdatePayloadStmt {
694    pub collection: String,
695    pub selector: PointSelector,
696    pub payload: Vec<(String, Value)>,
697    pub shard_key: Option<String>,
698}
699
700#[derive(Debug, Clone, PartialEq)]
701pub enum Stmt {
702    Query(Box<QueryStmt>),
703    Scroll(Box<ScrollStmt>),
704    Upsert(Box<UpsertStmt>),
705    CreateCollection(Box<CreateCollectionStmt>),
706    CreateIndex(Box<CreateIndexStmt>),
707    DropIndex(Box<DropIndexStmt>),
708    CreateShardKey(Box<CreateShardKeyStmt>),
709    DropShardKey(Box<DropShardKeyStmt>),
710    AlterCollection(Box<AlterCollectionStmt>),
711    DropCollection(Box<DropCollectionStmt>),
712    ShowCollections,
713    ShowCollection(String),
714    ShowShardKeys(String),
715    Delete(Box<DeleteStmt>),
716    ClearPayload(Box<ClearPayloadStmt>),
717    DeletePayload(Box<DeletePayloadStmt>),
718    DeleteVector(Box<DeleteVectorStmt>),
719    UpdateVector(Box<UpdateVectorStmt>),
720    UpdatePayload(Box<UpdatePayloadStmt>),
721    Count(Box<CountStmt>),
722}
723
724#[cfg(feature = "serde")]
725impl serde::Serialize for Stmt {
726    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
727    where
728        S: serde::Serializer,
729    {
730        use serde::ser::SerializeMap;
731        match self {
732            Stmt::Query(s) => serializer.serialize_newtype_variant("Stmt", 0, "Query", s),
733            Stmt::Scroll(s) => serializer.serialize_newtype_variant("Stmt", 1, "Scroll", s),
734            Stmt::Upsert(s) => serializer.serialize_newtype_variant("Stmt", 2, "Upsert", s),
735            Stmt::CreateCollection(s) => {
736                serializer.serialize_newtype_variant("Stmt", 3, "CreateCollection", s)
737            }
738            Stmt::CreateIndex(s) => {
739                serializer.serialize_newtype_variant("Stmt", 4, "CreateIndex", s)
740            }
741            Stmt::DropIndex(s) => serializer.serialize_newtype_variant("Stmt", 5, "DropIndex", s),
742            Stmt::CreateShardKey(s) => {
743                serializer.serialize_newtype_variant("Stmt", 6, "CreateShardKey", s)
744            }
745            Stmt::DropShardKey(s) => {
746                serializer.serialize_newtype_variant("Stmt", 7, "DropShardKey", s)
747            }
748            Stmt::AlterCollection(s) => {
749                serializer.serialize_newtype_variant("Stmt", 8, "AlterCollection", s)
750            }
751            Stmt::DropCollection(s) => {
752                serializer.serialize_newtype_variant("Stmt", 9, "DropCollection", s)
753            }
754            // Unit variant. The serialized form is the empty-object tag
755            // `{"ShowCollections": {}}` (kept for backward compatibility with
756            // consumers that already emit that shape). The manual
757            // `Deserialize` accepts both this form and the derived string
758            // form `"ShowCollections"`, so serde round-trips.
759            Stmt::ShowCollections => {
760                let mut map = serializer.serialize_map(Some(1))?;
761                let empty = std::collections::BTreeMap::<String, String>::new();
762                map.serialize_entry("ShowCollections", &empty)?;
763                map.end()
764            }
765            Stmt::ShowCollection(s) => {
766                serializer.serialize_newtype_variant("Stmt", 11, "ShowCollection", s)
767            }
768            Stmt::ShowShardKeys(s) => {
769                serializer.serialize_newtype_variant("Stmt", 12, "ShowShardKeys", s)
770            }
771            Stmt::Delete(s) => serializer.serialize_newtype_variant("Stmt", 13, "Delete", s),
772            Stmt::ClearPayload(s) => {
773                serializer.serialize_newtype_variant("Stmt", 14, "ClearPayload", s)
774            }
775            Stmt::DeletePayload(s) => {
776                serializer.serialize_newtype_variant("Stmt", 15, "DeletePayload", s)
777            }
778            Stmt::DeleteVector(s) => {
779                serializer.serialize_newtype_variant("Stmt", 16, "DeleteVector", s)
780            }
781            Stmt::UpdateVector(s) => {
782                serializer.serialize_newtype_variant("Stmt", 17, "UpdateVector", s)
783            }
784            Stmt::UpdatePayload(s) => {
785                serializer.serialize_newtype_variant("Stmt", 18, "UpdatePayload", s)
786            }
787            Stmt::Count(s) => serializer.serialize_newtype_variant("Stmt", 19, "Count", s),
788        }
789    }
790}
791
792#[cfg(feature = "serde")]
793impl<'de> serde::Deserialize<'de> for Stmt {
794    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
795    where
796        D: serde::Deserializer<'de>,
797    {
798        use core::fmt;
799        use serde::de::{Error as _, IgnoredAny, MapAccess, Visitor};
800
801        struct StmtVisitor;
802
803        impl<'de> Visitor<'de> for StmtVisitor {
804            type Value = Stmt;
805
806            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
807                formatter.write_str("an externally tagged QQL statement")
808            }
809
810            /// Derived externally-tagged form of the unit variant.
811            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
812            where
813                E: serde::de::Error,
814            {
815                if value == "ShowCollections" {
816                    Ok(Stmt::ShowCollections)
817                } else {
818                    Err(E::unknown_variant(value, &["ShowCollections"]))
819                }
820            }
821
822            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
823            where
824                A: MapAccess<'de>,
825            {
826                let key = map
827                    .next_key::<alloc::string::String>()?
828                    .ok_or_else(|| A::Error::custom("expected a statement tag"))?;
829                let stmt = match key.as_str() {
830                    "Query" => Stmt::Query(map.next_value()?),
831                    "Scroll" => Stmt::Scroll(map.next_value()?),
832                    "Upsert" => Stmt::Upsert(map.next_value()?),
833                    "CreateCollection" => Stmt::CreateCollection(map.next_value()?),
834                    "CreateIndex" => Stmt::CreateIndex(map.next_value()?),
835                    "DropIndex" => Stmt::DropIndex(map.next_value()?),
836                    "CreateShardKey" => Stmt::CreateShardKey(map.next_value()?),
837                    "DropShardKey" => Stmt::DropShardKey(map.next_value()?),
838                    "AlterCollection" => Stmt::AlterCollection(map.next_value()?),
839                    "DropCollection" => Stmt::DropCollection(map.next_value()?),
840                    // Canonical serialized form (`{"ShowCollections": {}}`);
841                    // the payload is ignored, mirroring the derived impl's
842                    // permissive unit-variant handling.
843                    "ShowCollections" => {
844                        map.next_value::<IgnoredAny>()?;
845                        Stmt::ShowCollections
846                    }
847                    "ShowCollection" => Stmt::ShowCollection(map.next_value()?),
848                    "ShowShardKeys" => Stmt::ShowShardKeys(map.next_value()?),
849                    "Delete" => Stmt::Delete(map.next_value()?),
850                    "ClearPayload" => Stmt::ClearPayload(map.next_value()?),
851                    "DeletePayload" => Stmt::DeletePayload(map.next_value()?),
852                    "DeleteVector" => Stmt::DeleteVector(map.next_value()?),
853                    "UpdateVector" => Stmt::UpdateVector(map.next_value()?),
854                    "UpdatePayload" => Stmt::UpdatePayload(map.next_value()?),
855                    "Count" => Stmt::Count(map.next_value()?),
856                    _ => {
857                        return Err(A::Error::unknown_variant(
858                            &key,
859                            &[
860                                "Query",
861                                "Scroll",
862                                "Upsert",
863                                "CreateCollection",
864                                "CreateIndex",
865                                "DropIndex",
866                                "CreateShardKey",
867                                "DropShardKey",
868                                "AlterCollection",
869                                "DropCollection",
870                                "ShowCollections",
871                                "ShowCollection",
872                                "ShowShardKeys",
873                                "Delete",
874                                "ClearPayload",
875                                "DeletePayload",
876                                "DeleteVector",
877                                "UpdateVector",
878                                "UpdatePayload",
879                                "Count",
880                            ],
881                        ));
882                    }
883                };
884                if map.next_key::<IgnoredAny>()?.is_some() {
885                    return Err(A::Error::custom("duplicate statement tag"));
886                }
887                Ok(stmt)
888            }
889        }
890
891        deserializer.deserialize_any(StmtVisitor)
892    }
893}