Skip to main content

icydb_core/db/query/predicate/
ast.rs

1use crate::{db::query::predicate::coercion::CoercionSpec, value::Value};
2use std::ops::BitAnd;
3
4///
5/// Predicate AST
6///
7/// Pure, schema-agnostic representation of query predicates.
8/// This layer contains no type validation, index logic, or execution
9/// semantics. All interpretation occurs in later passes:
10///
11/// - normalization
12/// - validation (schema-aware)
13/// - planning
14/// - execution
15///
16
17///
18/// CompareOp
19///
20
21#[derive(Clone, Copy, Debug, Eq, PartialEq)]
22pub enum CompareOp {
23    Eq,
24    Ne,
25    Lt,
26    Lte,
27    Gt,
28    Gte,
29    In,
30    NotIn,
31    AnyIn,
32    AllIn,
33    Contains,
34    StartsWith,
35    EndsWith,
36}
37
38///
39/// ComparePredicate
40///
41
42#[derive(Clone, Debug, Eq, PartialEq)]
43pub struct ComparePredicate {
44    pub field: String,
45    pub op: CompareOp,
46    pub value: Value,
47    pub coercion: CoercionSpec,
48}
49
50impl ComparePredicate {
51    fn new(field: String, op: CompareOp, value: Value) -> Self {
52        Self {
53            field,
54            op,
55            value,
56            coercion: CoercionSpec::default(),
57        }
58    }
59
60    #[must_use]
61    pub fn eq(field: String, value: Value) -> Self {
62        Self::new(field, CompareOp::Eq, value)
63    }
64
65    #[must_use]
66    pub fn ne(field: String, value: Value) -> Self {
67        Self::new(field, CompareOp::Ne, value)
68    }
69
70    #[must_use]
71    pub fn lt(field: String, value: Value) -> Self {
72        Self::new(field, CompareOp::Lt, value)
73    }
74
75    #[must_use]
76    pub fn lte(field: String, value: Value) -> Self {
77        Self::new(field, CompareOp::Lte, value)
78    }
79
80    #[must_use]
81    pub fn gt(field: String, value: Value) -> Self {
82        Self::new(field, CompareOp::Gt, value)
83    }
84
85    #[must_use]
86    pub fn gte(field: String, value: Value) -> Self {
87        Self::new(field, CompareOp::Gte, value)
88    }
89
90    #[must_use]
91    pub fn in_(field: String, values: Vec<Value>) -> Self {
92        Self::new(field, CompareOp::In, Value::List(values))
93    }
94
95    #[must_use]
96    pub fn not_in(field: String, values: Vec<Value>) -> Self {
97        Self::new(field, CompareOp::NotIn, Value::List(values))
98    }
99}
100
101///
102/// Predicate
103///
104
105#[derive(Clone, Debug, Eq, PartialEq)]
106pub enum Predicate {
107    True,
108    False,
109    And(Vec<Self>),
110    Or(Vec<Self>),
111    Not(Box<Self>),
112    Compare(ComparePredicate),
113    IsNull {
114        field: String,
115    },
116    IsMissing {
117        field: String,
118    },
119    IsEmpty {
120        field: String,
121    },
122    IsNotEmpty {
123        field: String,
124    },
125    MapContainsKey {
126        field: String,
127        key: Value,
128        coercion: CoercionSpec,
129    },
130    MapContainsValue {
131        field: String,
132        value: Value,
133        coercion: CoercionSpec,
134    },
135    MapContainsEntry {
136        field: String,
137        key: Value,
138        value: Value,
139        coercion: CoercionSpec,
140    },
141    TextContains {
142        field: String,
143        value: Value,
144    },
145    TextContainsCi {
146        field: String,
147        value: Value,
148    },
149}
150
151impl Predicate {
152    #[must_use]
153    pub const fn and(preds: Vec<Self>) -> Self {
154        Self::And(preds)
155    }
156
157    #[must_use]
158    pub const fn or(preds: Vec<Self>) -> Self {
159        Self::Or(preds)
160    }
161
162    #[allow(clippy::should_implement_trait)]
163    #[must_use]
164    pub fn not(pred: Self) -> Self {
165        Self::Not(Box::new(pred))
166    }
167
168    #[must_use]
169    pub fn eq(field: String, value: Value) -> Self {
170        Self::Compare(ComparePredicate::eq(field, value))
171    }
172
173    #[must_use]
174    pub fn ne(field: String, value: Value) -> Self {
175        Self::Compare(ComparePredicate::ne(field, value))
176    }
177
178    #[must_use]
179    pub fn lt(field: String, value: Value) -> Self {
180        Self::Compare(ComparePredicate::lt(field, value))
181    }
182
183    #[must_use]
184    pub fn lte(field: String, value: Value) -> Self {
185        Self::Compare(ComparePredicate::lte(field, value))
186    }
187
188    #[must_use]
189    pub fn gt(field: String, value: Value) -> Self {
190        Self::Compare(ComparePredicate::gt(field, value))
191    }
192
193    #[must_use]
194    pub fn gte(field: String, value: Value) -> Self {
195        Self::Compare(ComparePredicate::gte(field, value))
196    }
197
198    #[must_use]
199    pub fn in_(field: String, values: Vec<Value>) -> Self {
200        Self::Compare(ComparePredicate::in_(field, values))
201    }
202
203    #[must_use]
204    pub fn not_in(field: String, values: Vec<Value>) -> Self {
205        Self::Compare(ComparePredicate::not_in(field, values))
206    }
207}
208
209impl BitAnd for Predicate {
210    type Output = Self;
211
212    fn bitand(self, rhs: Self) -> Self::Output {
213        Self::And(vec![self, rhs])
214    }
215}
216
217impl BitAnd for &Predicate {
218    type Output = Predicate;
219
220    fn bitand(self, rhs: Self) -> Self::Output {
221        Predicate::And(vec![self.clone(), rhs.clone()])
222    }
223}