Skip to main content

icydb_core/db/query/predicate/
ast.rs

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