Skip to main content

holocron/query/
filter.rs

1use crate::catalog::CatalogType;
2
3/// A filter expression tree: logical AND/OR combinators around comparison leaves.
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub enum Filter {
6    And(Vec<Filter>),
7    Or(Vec<Filter>),
8    Leaf(Comparison),
9}
10
11/// A single comparison against a column. The shape of the value is fixed by
12/// the variant — illegal states (e.g. `In` with one value) are unrepresentable.
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub enum Comparison {
15    /// A column-to-value comparison: equality, ordering, or text pattern.
16    Compare {
17        column: String,
18        op: CompareOp,
19        value: String,
20    },
21    /// Membership in a set of values.
22    Set {
23        column: String,
24        op: SetOp,
25        values: Vec<String>,
26    },
27    /// A null check: `true` for IS NULL, `false` for IS NOT NULL.
28    NullCheck { column: String, is_null: bool },
29}
30
31/// Column-to-value comparison operators.
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub enum CompareOp {
34    Eq,
35    NotEq,
36    Gt,
37    Gte,
38    Lt,
39    Lte,
40    Like,
41    StartsWith,
42    EndsWith,
43}
44
45/// Set-membership operators.
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47pub enum SetOp {
48    In,
49    NotIn,
50}
51
52impl CompareOp {
53    /// Whether this operator is valid for the given column type.
54    pub fn supported_by(&self, data_type: &CatalogType) -> bool {
55        match self {
56            Self::Eq | Self::NotEq => data_type.supports_equality(),
57            Self::Gt | Self::Gte | Self::Lt | Self::Lte => data_type.supports_ordering(),
58            Self::Like | Self::StartsWith | Self::EndsWith => data_type.supports_text_pattern(),
59        }
60    }
61
62    /// Surface-syntax name, used in diagnostics.
63    pub fn name(&self) -> &'static str {
64        match self {
65            Self::Eq => "==",
66            Self::NotEq => "!=",
67            Self::Gt => "=gt=",
68            Self::Gte => "=ge=",
69            Self::Lt => "=lt=",
70            Self::Lte => "=le=",
71            Self::Like => "=like=",
72            Self::StartsWith => "=starts=",
73            Self::EndsWith => "=ends=",
74        }
75    }
76}
77
78impl SetOp {
79    /// Whether this operator is valid for the given column type.
80    pub fn supported_by(&self, data_type: &CatalogType) -> bool {
81        data_type.supports_set()
82    }
83
84    /// Surface-syntax name, used in diagnostics.
85    pub fn name(&self) -> &'static str {
86        match self {
87            Self::In => "=in=",
88            Self::NotIn => "=out=",
89        }
90    }
91}