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