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