Skip to main content

lora_ast/
ast.rs

1use smallvec::SmallVec;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
4pub struct Span {
5    pub start: usize,
6    pub end: usize,
7}
8
9impl Span {
10    #[must_use]
11    pub const fn new(start: usize, end: usize) -> Self {
12        Self { start, end }
13    }
14}
15
16#[derive(Debug, Clone)]
17pub struct Document {
18    pub statement: Statement,
19    pub span: Span,
20}
21
22#[derive(Debug, Clone)]
23pub enum Statement {
24    Query(Query),
25    Schema(SchemaCommand),
26}
27
28#[derive(Debug, Clone)]
29pub enum SchemaCommand {
30    CreateIndex(CreateIndex),
31    DropIndex(DropIndex),
32    ShowIndexes(ShowIndexes),
33    CreateConstraint(CreateConstraint),
34    DropConstraint(DropConstraint),
35    ShowConstraints(ShowConstraints),
36}
37
38#[derive(Debug, Clone)]
39pub struct CreateConstraint {
40    pub name: ConstraintNameSpec,
41    pub if_not_exists: bool,
42    pub entity: IndexEntityKind,
43    /// Pattern variable in the `FOR` clause (`n`, `r`).
44    pub variable: String,
45    /// Label / rel-type. Always present — constraints don't accept the
46    /// wildcard form that LOOKUP indexes do.
47    pub label: String,
48    pub properties: Vec<String>,
49    pub kind: ConstraintKind,
50    pub span: Span,
51}
52
53#[derive(Debug, Clone)]
54pub struct DropConstraint {
55    pub name: ConstraintNameSpec,
56    pub if_exists: bool,
57    pub span: Span,
58}
59
60#[derive(Debug, Clone)]
61pub struct ShowConstraints {
62    pub pipeline: Option<ShowPipeline>,
63    pub span: Span,
64}
65
66/// `SHOW INDEXES YIELD … [WHERE …] [RETURN …]` tail. Modelled after
67/// Cypher-style catalog syntax: YIELD is the anchor, optional WHERE filters the
68/// yielded rows, optional RETURN reprojects them. ORDER BY / SKIP /
69/// LIMIT can appear on either YIELD or RETURN — semantically applied
70/// to the rows at that stage.
71#[derive(Debug, Clone)]
72pub struct ShowPipeline {
73    pub yield_part: ShowYield,
74    pub where_: Option<Expr>,
75    pub return_part: Option<ShowReturn>,
76    pub span: Span,
77}
78
79#[derive(Debug, Clone)]
80pub struct ShowYield {
81    /// `YIELD *` — pass every catalog column through unchanged.
82    pub star: bool,
83    /// `YIELD a, b AS x` items (empty when `star` is true).
84    pub items: Vec<YieldItem>,
85    pub order: Vec<SortItem>,
86    pub skip: Option<Expr>,
87    pub limit: Option<Expr>,
88    pub span: Span,
89}
90
91#[derive(Debug, Clone)]
92pub struct ShowReturn {
93    pub items: Vec<ProjectionItem>,
94    pub order: Vec<SortItem>,
95    pub skip: Option<Expr>,
96    pub limit: Option<Expr>,
97    pub span: Span,
98}
99
100/// Type filter for `SHOW [TYPE] INDEXES`. `All` is the explicit
101/// unfiltered form; `Fulltext` and `Vector` parse but yield no rows
102/// because those index types aren't backed by anything in the catalog
103/// yet.
104#[derive(Debug, Clone, Copy, PartialEq, Eq)]
105pub enum IndexKindFilter {
106    All,
107    Range,
108    Text,
109    Point,
110    Lookup,
111    Fulltext,
112    Vector,
113}
114
115#[derive(Debug, Clone)]
116pub enum ConstraintNameSpec {
117    Literal(String),
118    Parameter(String),
119}
120
121#[derive(Debug, Clone, PartialEq)]
122pub enum ConstraintKind {
123    /// `IS UNIQUE` — single or composite.
124    Unique,
125    /// `IS NOT NULL` — single property only.
126    Existence,
127    /// `IS NODE KEY` — single or composite, node only.
128    NodeKey,
129    /// `IS RELATIONSHIP KEY` — single or composite, relationship only.
130    RelationshipKey,
131    /// `IS :: Type` — single property only.
132    PropertyType(PropertyTypeExpr),
133}
134
135impl ConstraintKind {
136    /// Human-readable tag for SHOW CONSTRAINTS and diagnostics.
137    #[must_use]
138    pub fn type_tag(&self, entity: IndexEntityKind) -> &'static str {
139        match (self, entity) {
140            (ConstraintKind::Unique, IndexEntityKind::Node) => "NODE_PROPERTY_UNIQUENESS",
141            (ConstraintKind::Unique, IndexEntityKind::Relationship) => {
142                "RELATIONSHIP_PROPERTY_UNIQUENESS"
143            }
144            (ConstraintKind::Existence, IndexEntityKind::Node) => "NODE_PROPERTY_EXISTENCE",
145            (ConstraintKind::Existence, IndexEntityKind::Relationship) => {
146                "RELATIONSHIP_PROPERTY_EXISTENCE"
147            }
148            (ConstraintKind::NodeKey, _) => "NODE_KEY",
149            (ConstraintKind::RelationshipKey, _) => "RELATIONSHIP_KEY",
150            (ConstraintKind::PropertyType(_), IndexEntityKind::Node) => "NODE_PROPERTY_TYPE",
151            (ConstraintKind::PropertyType(_), IndexEntityKind::Relationship) => {
152                "RELATIONSHIP_PROPERTY_TYPE"
153            }
154        }
155    }
156}
157
158/// A closed dynamic union of property types: `T1 | T2 | ...`. A single
159/// type is represented as a one-element union.
160#[derive(Debug, Clone, PartialEq)]
161pub struct PropertyTypeExpr {
162    pub alternatives: Vec<PropertyTypeTerm>,
163}
164
165#[derive(Debug, Clone, PartialEq)]
166pub enum PropertyTypeTerm {
167    Scalar(ScalarType),
168    List {
169        inner: Box<PropertyTypeTerm>,
170        /// `LIST<X NOT NULL>` is the only fully-supported list shape in
171        /// Cypher compatibility mode; we keep the flag for grammar fidelity
172        /// even though we reject `LIST<X>` (nullable elements) at the
173        /// catalog layer.
174        not_null: bool,
175    },
176    Vector {
177        coord: VectorCoordType,
178        dimension: u32,
179    },
180}
181
182#[derive(Debug, Clone, Copy, PartialEq, Eq)]
183pub enum ScalarType {
184    Boolean,
185    String,
186    Integer,
187    Float,
188    Date,
189    LocalTime,
190    ZonedTime,
191    LocalDateTime,
192    ZonedDateTime,
193    Duration,
194    Point,
195    Map,
196    Any,
197}
198
199impl ScalarType {
200    #[must_use]
201    pub const fn as_str(self) -> &'static str {
202        match self {
203            ScalarType::Boolean => "BOOLEAN",
204            ScalarType::String => "STRING",
205            ScalarType::Integer => "INTEGER",
206            ScalarType::Float => "FLOAT",
207            ScalarType::Date => "DATE",
208            ScalarType::LocalTime => "LOCAL TIME",
209            ScalarType::ZonedTime => "ZONED TIME",
210            ScalarType::LocalDateTime => "LOCAL DATETIME",
211            ScalarType::ZonedDateTime => "ZONED DATETIME",
212            ScalarType::Duration => "DURATION",
213            ScalarType::Point => "POINT",
214            ScalarType::Map => "MAP",
215            ScalarType::Any => "ANY",
216        }
217    }
218}
219
220#[derive(Debug, Clone, Copy, PartialEq, Eq)]
221pub enum VectorCoordType {
222    Int8,
223    Int16,
224    Int32,
225    Int64,
226    Float32,
227    Float64,
228}
229
230impl VectorCoordType {
231    #[must_use]
232    pub const fn as_str(self) -> &'static str {
233        match self {
234            VectorCoordType::Int8 => "INT8",
235            VectorCoordType::Int16 => "INT16",
236            VectorCoordType::Int32 => "INT32",
237            VectorCoordType::Int64 => "INT64",
238            VectorCoordType::Float32 => "FLOAT32",
239            VectorCoordType::Float64 => "FLOAT64",
240        }
241    }
242}
243
244#[derive(Debug, Clone)]
245pub struct DropIndex {
246    pub name: IndexNameSpec,
247    pub if_exists: bool,
248    pub span: Span,
249}
250
251#[derive(Debug, Clone)]
252pub struct CreateIndex {
253    pub kind: IndexKind,
254    pub name: Option<IndexNameSpec>,
255    pub if_not_exists: bool,
256    pub entity: IndexEntityKind,
257    /// Pattern variable in the FOR clause (`n` for `(n:Person)`, `r` for `()-[r:KNOWS]-()`).
258    pub variable: String,
259    /// `Some(label_or_type)` for property indexes; `None` for `LOOKUP` token indexes
260    /// where the label/type is the wildcard captured by `labels(n)` / `type(r)`.
261    /// For `FULLTEXT` (which accepts `:A|B|C`) this carries the first label; the
262    /// rest live in `additional_labels`.
263    pub label: Option<String>,
264    /// Extra labels beyond `label`. Only populated for `FULLTEXT` indexes
265    /// declared with the `(n:A|B|C)` pattern.
266    pub additional_labels: Vec<String>,
267    /// Property keys covered by the index. Empty for `LOOKUP` token indexes.
268    pub properties: Vec<String>,
269    pub options: Option<IndexOptions>,
270    pub span: Span,
271}
272
273#[derive(Debug, Clone, Copy, PartialEq, Eq)]
274pub enum IndexKind {
275    Range,
276    Text,
277    Point,
278    Lookup,
279    Vector,
280    Fulltext,
281}
282
283impl IndexKind {
284    #[must_use]
285    pub const fn as_str(self) -> &'static str {
286        match self {
287            IndexKind::Range => "RANGE",
288            IndexKind::Text => "TEXT",
289            IndexKind::Point => "POINT",
290            IndexKind::Lookup => "LOOKUP",
291            IndexKind::Vector => "VECTOR",
292            IndexKind::Fulltext => "FULLTEXT",
293        }
294    }
295}
296
297#[derive(Debug, Clone, Copy, PartialEq, Eq)]
298pub enum IndexEntityKind {
299    Node,
300    Relationship,
301}
302
303impl IndexEntityKind {
304    #[must_use]
305    pub const fn as_str(self) -> &'static str {
306        match self {
307            IndexEntityKind::Node => "NODE",
308            IndexEntityKind::Relationship => "RELATIONSHIP",
309        }
310    }
311}
312
313#[derive(Debug, Clone)]
314pub enum IndexNameSpec {
315    Literal(String),
316    Parameter(String),
317}
318
319#[derive(Debug, Clone)]
320pub struct IndexOptions {
321    pub config: Vec<(String, Expr)>,
322    pub span: Span,
323}
324
325#[derive(Debug, Clone)]
326pub struct ShowIndexes {
327    /// Optional index-type filter (e.g. `SHOW RANGE INDEXES`). `None`
328    /// means no filter clause was written; `Some(IndexKindFilter::All)`
329    /// is the explicit `SHOW ALL INDEXES` form (semantically the same).
330    pub filter: Option<IndexKindFilter>,
331    pub pipeline: Option<ShowPipeline>,
332    pub span: Span,
333}
334
335#[derive(Debug, Clone)]
336pub enum Query {
337    Regular(RegularQuery),
338    StandaloneCall(StandaloneCall),
339}
340
341#[derive(Debug, Clone)]
342pub struct RegularQuery {
343    pub head: SingleQuery,
344    pub unions: Vec<UnionPart>,
345    pub span: Span,
346}
347
348#[derive(Debug, Clone)]
349pub struct UnionPart {
350    pub all: bool,
351    pub query: SingleQuery,
352    pub span: Span,
353}
354
355#[derive(Debug, Clone)]
356pub enum SingleQuery {
357    SinglePart(SinglePartQuery),
358    MultiPart(MultiPartQuery),
359}
360
361#[derive(Debug, Clone)]
362pub struct SinglePartQuery {
363    pub reading_clauses: Vec<ReadingClause>,
364    pub updating_clauses: Vec<UpdatingClause>,
365    pub return_clause: Option<Return>,
366    pub span: Span,
367}
368
369#[derive(Debug, Clone)]
370pub struct MultiPartQuery {
371    pub parts: Vec<QueryPart>,
372    pub tail: Box<SinglePartQuery>,
373    pub span: Span,
374}
375
376#[derive(Debug, Clone)]
377pub struct QueryPart {
378    pub reading_clauses: Vec<ReadingClause>,
379    pub updating_clauses: Vec<UpdatingClause>,
380    pub with_clause: With,
381    pub span: Span,
382}
383
384#[derive(Debug, Clone)]
385pub enum ReadingClause {
386    Match(Match),
387    Unwind(Unwind),
388    InQueryCall(InQueryCall),
389    CallSubquery(CallSubquery),
390}
391
392#[derive(Debug, Clone)]
393pub struct CallSubquery {
394    pub body: Box<RegularQuery>,
395    pub span: Span,
396}
397
398#[derive(Debug, Clone)]
399pub enum UpdatingClause {
400    Create(Create),
401    Merge(Merge),
402    Delete(Delete),
403    Set(Set),
404    Remove(Remove),
405}
406
407#[derive(Debug, Clone)]
408pub struct Match {
409    pub optional: bool,
410    pub pattern: Pattern,
411    pub where_: Option<Expr>,
412    pub span: Span,
413}
414
415#[derive(Debug, Clone)]
416pub struct Unwind {
417    pub expr: Expr,
418    pub alias: Variable,
419    pub span: Span,
420}
421
422#[derive(Debug, Clone)]
423pub struct Create {
424    pub pattern: Pattern,
425    pub span: Span,
426}
427
428#[derive(Debug, Clone)]
429pub struct Merge {
430    pub pattern_part: PatternPart,
431    pub actions: Vec<MergeAction>,
432    pub span: Span,
433}
434
435#[derive(Debug, Clone)]
436pub struct MergeAction {
437    pub on_match: bool,
438    pub set: Set,
439    pub span: Span,
440}
441
442#[derive(Debug, Clone)]
443pub struct Delete {
444    pub detach: bool,
445    pub expressions: Vec<Expr>,
446    pub span: Span,
447}
448
449#[derive(Debug, Clone)]
450pub struct Set {
451    pub items: Vec<SetItem>,
452    pub span: Span,
453}
454
455#[derive(Debug, Clone)]
456pub enum SetItem {
457    SetProperty {
458        target: Expr,
459        value: Expr,
460        span: Span,
461    },
462    SetVariable {
463        variable: Variable,
464        value: Expr,
465        span: Span,
466    },
467    MutateVariable {
468        variable: Variable,
469        value: Expr,
470        span: Span,
471    },
472    SetLabels {
473        variable: Variable,
474        labels: Vec<String>,
475        span: Span,
476    },
477}
478
479#[derive(Debug, Clone)]
480pub struct Remove {
481    pub items: Vec<RemoveItem>,
482    pub span: Span,
483}
484
485#[derive(Debug, Clone)]
486pub enum RemoveItem {
487    Labels {
488        variable: Variable,
489        labels: Vec<String>,
490        span: Span,
491    },
492    Property {
493        expr: Expr,
494        span: Span,
495    },
496}
497
498#[derive(Debug, Clone)]
499pub struct InQueryCall {
500    pub procedure: ProcedureInvocation,
501    pub yield_items: Vec<YieldItem>,
502    pub where_: Option<Expr>,
503    pub span: Span,
504}
505
506#[derive(Debug, Clone)]
507pub struct StandaloneCall {
508    pub procedure: ProcedureInvocationKind,
509    pub yield_items: Vec<YieldItem>,
510    pub yield_all: bool,
511    pub span: Span,
512}
513
514#[derive(Debug, Clone)]
515pub enum ProcedureInvocationKind {
516    Explicit(ProcedureInvocation),
517    Implicit(ProcedureName),
518}
519
520#[derive(Debug, Clone)]
521pub struct ProcedureInvocation {
522    pub name: ProcedureName,
523    pub args: Vec<Expr>,
524    pub span: Span,
525}
526
527#[derive(Debug, Clone)]
528pub struct YieldItem {
529    pub field: Option<String>,
530    pub alias: Variable,
531    pub span: Span,
532}
533
534#[derive(Debug, Clone)]
535pub struct With {
536    pub body: ProjectionBody,
537    pub where_: Option<Expr>,
538    pub span: Span,
539}
540
541#[derive(Debug, Clone)]
542pub struct Return {
543    pub body: ProjectionBody,
544    pub span: Span,
545}
546
547#[derive(Debug, Clone)]
548pub struct ProjectionBody {
549    pub distinct: bool,
550    pub items: Vec<ProjectionItem>,
551    pub order: Vec<SortItem>,
552    pub skip: Option<Expr>,
553    pub limit: Option<Expr>,
554    pub span: Span,
555}
556
557#[derive(Debug, Clone)]
558pub enum ProjectionItem {
559    Expr {
560        expr: Expr,
561        alias: Option<Variable>,
562        span: Span,
563    },
564    Star {
565        span: Span,
566    },
567}
568
569#[derive(Debug, Clone)]
570pub struct SortItem {
571    pub expr: Expr,
572    pub direction: SortDirection,
573    pub span: Span,
574}
575
576#[derive(Debug, Clone, Copy, PartialEq, Eq)]
577pub enum SortDirection {
578    Asc,
579    Desc,
580}
581
582#[derive(Debug, Clone)]
583pub struct Pattern {
584    pub parts: Vec<PatternPart>,
585    pub span: Span,
586}
587
588#[derive(Debug, Clone)]
589pub struct PatternPart {
590    pub binding: Option<Variable>,
591    pub element: PatternElement,
592    pub span: Span,
593}
594
595#[derive(Debug, Clone)]
596pub enum PatternElement {
597    NodeChain {
598        head: NodePattern,
599        chain: Vec<PatternElementChain>,
600        span: Span,
601    },
602    Parenthesized(Box<PatternElement>, Span),
603    ShortestPath {
604        all: bool,
605        element: Box<PatternElement>,
606        span: Span,
607    },
608}
609
610#[derive(Debug, Clone)]
611pub struct PatternElementChain {
612    pub relationship: RelationshipPattern,
613    pub node: NodePattern,
614    pub span: Span,
615}
616
617#[derive(Debug, Clone)]
618pub struct NodePattern {
619    pub variable: Option<Variable>,
620    /// Each inner `Vec` is a disjunctive group (OR).
621    /// The outer `SmallVec` is conjunctive (AND across groups).
622    /// `:A:B` → `[[A], [B]]`;  `:A|B` → `[[A, B]]`.
623    pub labels: SmallVec<SmallVec<String, 2>, 2>,
624    pub properties: Option<Expr>,
625    pub span: Span,
626}
627
628#[derive(Debug, Clone)]
629pub struct RelationshipPattern {
630    pub direction: Direction,
631    pub detail: Option<RelationshipDetail>,
632    pub span: Span,
633}
634
635#[derive(Debug, Clone)]
636pub struct RelationshipDetail {
637    pub variable: Option<Variable>,
638    pub types: SmallVec<String, 2>,
639    pub range: Option<RangeLiteral>,
640    pub properties: Option<Expr>,
641    pub span: Span,
642}
643
644#[derive(Debug, Clone, Copy, PartialEq, Eq)]
645pub enum Direction {
646    Left,
647    Right,
648    Undirected,
649}
650
651#[derive(Debug, Clone)]
652pub struct RangeLiteral {
653    pub start: Option<u64>,
654    pub end: Option<u64>,
655    pub span: Span,
656}
657
658#[derive(Debug, Clone)]
659pub struct Variable {
660    pub name: String,
661    pub span: Span,
662}
663
664#[derive(Debug, Clone)]
665pub struct ProcedureName {
666    pub parts: Vec<String>,
667    pub span: Span,
668}
669
670#[derive(Debug, Clone)]
671pub enum Expr {
672    Variable(Variable),
673    Integer(i64, Span),
674    Float(f64, Span),
675    String(String, Span),
676    Bool(bool, Span),
677    Null(Span),
678    Parameter(String, Span),
679    List(Vec<Expr>, Span),
680    Map(Vec<(String, Expr)>, Span),
681    Property {
682        expr: Box<Expr>,
683        key: String,
684        span: Span,
685    },
686    Binary {
687        lhs: Box<Expr>,
688        op: BinaryOp,
689        rhs: Box<Expr>,
690        span: Span,
691    },
692    Unary {
693        op: UnaryOp,
694        expr: Box<Expr>,
695        span: Span,
696    },
697    FunctionCall {
698        name: Vec<String>,
699        distinct: bool,
700        args: Vec<Expr>,
701        span: Span,
702    },
703    TypeCast {
704        expr: Box<Expr>,
705        target: LiteralTypeExpr,
706        try_cast: bool,
707        span: Span,
708    },
709    Case {
710        input: Option<Box<Expr>>,
711        alternatives: Vec<(Expr, Expr)>,
712        else_expr: Option<Box<Expr>>,
713        span: Span,
714    },
715    ListPredicate {
716        kind: ListPredicateKind,
717        variable: Variable,
718        list: Box<Expr>,
719        predicate: Box<Expr>,
720        span: Span,
721    },
722    ListComprehension {
723        variable: Variable,
724        list: Box<Expr>,
725        filter: Option<Box<Expr>>,
726        map_expr: Option<Box<Expr>>,
727        span: Span,
728    },
729    Reduce {
730        accumulator: Variable,
731        init: Box<Expr>,
732        variable: Variable,
733        list: Box<Expr>,
734        expr: Box<Expr>,
735        span: Span,
736    },
737    MapProjection {
738        base: Box<Expr>,
739        selectors: Vec<MapProjectionSelector>,
740        span: Span,
741    },
742    Index {
743        expr: Box<Expr>,
744        index: Box<Expr>,
745        span: Span,
746    },
747    Slice {
748        expr: Box<Expr>,
749        from: Option<Box<Expr>>,
750        to: Option<Box<Expr>>,
751        span: Span,
752    },
753    ExistsSubquery {
754        pattern: Pattern,
755        where_: Option<Box<Expr>>,
756        span: Span,
757    },
758    PatternComprehension {
759        pattern: Box<PatternElement>,
760        where_: Option<Box<Expr>>,
761        map_expr: Box<Expr>,
762        span: Span,
763    },
764}
765
766#[derive(Debug, Clone, PartialEq)]
767pub enum LiteralTypeExpr {
768    Named {
769        name: String,
770        span: Span,
771    },
772    List {
773        inner: Box<LiteralTypeExpr>,
774        span: Span,
775    },
776    Vector {
777        coordinate: String,
778        dimension: u32,
779        span: Span,
780    },
781}
782
783impl LiteralTypeExpr {
784    #[must_use]
785    pub fn span(&self) -> Span {
786        match self {
787            LiteralTypeExpr::Named { span, .. }
788            | LiteralTypeExpr::List { span, .. }
789            | LiteralTypeExpr::Vector { span, .. } => *span,
790        }
791    }
792}
793
794#[derive(Debug, Clone)]
795pub enum MapProjectionSelector {
796    /// `.propertyName` — include a specific property
797    Property(String),
798    /// `.*` — include all properties
799    AllProperties,
800    /// `key: expr` — include a computed entry
801    Literal(String, Expr),
802}
803
804#[derive(Debug, Clone, Copy, PartialEq, Eq)]
805pub enum ListPredicateKind {
806    Any,
807    All,
808    None,
809    Single,
810}
811
812impl Expr {
813    #[must_use]
814    pub fn span(&self) -> Span {
815        match self {
816            Expr::Variable(v) => v.span,
817            Expr::Integer(_, s)
818            | Expr::Float(_, s)
819            | Expr::String(_, s)
820            | Expr::Bool(_, s)
821            | Expr::Null(s)
822            | Expr::Parameter(_, s)
823            | Expr::List(_, s)
824            | Expr::Map(_, s)
825            | Expr::Property { span: s, .. }
826            | Expr::Binary { span: s, .. }
827            | Expr::Unary { span: s, .. }
828            | Expr::FunctionCall { span: s, .. }
829            | Expr::TypeCast { span: s, .. }
830            | Expr::Case { span: s, .. }
831            | Expr::ListPredicate { span: s, .. }
832            | Expr::ListComprehension { span: s, .. }
833            | Expr::Reduce { span: s, .. }
834            | Expr::MapProjection { span: s, .. }
835            | Expr::Index { span: s, .. }
836            | Expr::Slice { span: s, .. }
837            | Expr::ExistsSubquery { span: s, .. }
838            | Expr::PatternComprehension { span: s, .. } => *s,
839        }
840    }
841}
842
843#[derive(Debug, Clone, Copy, PartialEq, Eq)]
844pub enum BinaryOp {
845    Or,
846    Xor,
847    And,
848    Eq,
849    Ne,
850    Lt,
851    Gt,
852    Le,
853    Ge,
854    Add,
855    Sub,
856    Mul,
857    Div,
858    Mod,
859    Pow,
860    In,
861    StartsWith,
862    EndsWith,
863    Contains,
864    IsNull,
865    IsNotNull,
866    RegexMatch,
867}
868
869#[derive(Debug, Clone, Copy, PartialEq, Eq)]
870pub enum UnaryOp {
871    Not,
872    Pos,
873    Neg,
874}