Skip to main content

icydb_core/db/query/predicate/
ast.rs

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