1use serde::{
32 Deserialize,
33 Serialize,
34};
35use std::cmp::Ordering;
36
37use serde_json::{
38 Number,
39 Value,
40};
41
42use crate::Metadata;
43
44#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
46pub enum Condition {
47 Eq {
49 key: String,
51 value: Value,
53 },
54 Ne {
56 key: String,
58 value: Value,
60 },
61 Gt {
63 key: String,
65 value: Value,
67 },
68 Gte {
70 key: String,
72 value: Value,
74 },
75 Lt {
77 key: String,
79 value: Value,
81 },
82 Lte {
84 key: String,
86 value: Value,
88 },
89 Exists {
91 key: String,
93 },
94 NotExists {
96 key: String,
98 },
99 In {
101 key: String,
103 values: Vec<Value>,
105 },
106 NotIn {
108 key: String,
110 values: Vec<Value>,
112 },
113}
114
115impl Condition {
116 fn matches(&self, meta: &Metadata) -> bool {
117 match self {
118 Condition::Eq { key, value } => meta.get_raw(key) == Some(value),
119 Condition::Ne { key, value } => meta.get_raw(key) != Some(value),
120 Condition::Gt { key, value } => meta
121 .get_raw(key)
122 .is_some_and(|v| compare_values(v, value) == Some(Ordering::Greater)),
123 Condition::Gte { key, value } => meta.get_raw(key).is_some_and(|v| {
124 matches!(
125 compare_values(v, value),
126 Some(Ordering::Greater) | Some(Ordering::Equal)
127 )
128 }),
129 Condition::Lt { key, value } => meta
130 .get_raw(key)
131 .is_some_and(|v| compare_values(v, value) == Some(Ordering::Less)),
132 Condition::Lte { key, value } => meta.get_raw(key).is_some_and(|v| {
133 matches!(
134 compare_values(v, value),
135 Some(Ordering::Less) | Some(Ordering::Equal)
136 )
137 }),
138 Condition::Exists { key } => meta.contains_key(key),
139 Condition::NotExists { key } => !meta.contains_key(key),
140 Condition::In { key, values } => meta.get_raw(key).is_some_and(|v| values.contains(v)),
141 Condition::NotIn { key, values } => {
142 meta.get_raw(key).map_or(true, |v| !values.contains(v))
143 }
144 }
145 }
146}
147
148fn compare_values(a: &Value, b: &Value) -> Option<Ordering> {
151 match (a, b) {
152 (Value::Number(x), Value::Number(y)) => compare_numbers(x, y),
153 (Value::String(x), Value::String(y)) => x.partial_cmp(y),
154 _ => None,
155 }
156}
157
158const MAX_SAFE_INTEGER_F64_U64: u64 = 9_007_199_254_740_992; const I64_MIN_F64: f64 = -9_223_372_036_854_775_808.0; const I64_EXCLUSIVE_MAX_F64: f64 = 9_223_372_036_854_775_808.0; const U64_EXCLUSIVE_MAX_F64: f64 = 18_446_744_073_709_551_616.0; fn compare_numbers(a: &Number, b: &Number) -> Option<Ordering> {
164 if let (Some(xi), Some(yi)) = (a.as_i64(), b.as_i64()) {
165 return Some(xi.cmp(&yi));
166 }
167 if let (Some(xi), Some(yu)) = (a.as_i64(), b.as_u64()) {
168 return Some(compare_i64_u64(xi, yu));
169 }
170 if let (Some(xu), Some(yi)) = (a.as_u64(), b.as_i64()) {
171 return Some(compare_i64_u64(yi, xu).reverse());
172 }
173 if let (Some(xu), Some(yu)) = (a.as_u64(), b.as_u64()) {
174 return Some(xu.cmp(&yu));
175 }
176 if let (Some(xi), Some(yf)) = (a.as_i64(), b.as_f64()) {
177 return compare_i64_f64(xi, yf);
178 }
179 if let (Some(xf), Some(yi)) = (a.as_f64(), b.as_i64()) {
180 return compare_i64_f64(yi, xf).map(Ordering::reverse);
181 }
182 if let (Some(xu), Some(yf)) = (a.as_u64(), b.as_f64()) {
183 return compare_u64_f64(xu, yf);
184 }
185 if let (Some(xf), Some(yu)) = (a.as_f64(), b.as_u64()) {
186 return compare_u64_f64(yu, xf).map(Ordering::reverse);
187 }
188 if let (Some(xf), Some(yf)) = (a.as_f64(), b.as_f64()) {
189 return xf.partial_cmp(&yf);
190 }
191
192 unreachable!("Number must be representable as i64/u64/f64")
194}
195
196#[inline]
197fn compare_i64_u64(x: i64, y: u64) -> Ordering {
198 if x < 0 {
199 Ordering::Less
200 } else {
201 (x as u64).cmp(&y)
202 }
203}
204
205#[inline]
206fn compare_i64_f64(x: i64, y: f64) -> Option<Ordering> {
207 if y.fract() == 0.0 && (I64_MIN_F64..I64_EXCLUSIVE_MAX_F64).contains(&y) {
208 return Some(x.cmp(&(y as i64)));
210 }
211
212 if x.unsigned_abs() <= MAX_SAFE_INTEGER_F64_U64 {
213 return (x as f64).partial_cmp(&y);
214 }
215
216 None
217}
218
219#[inline]
220fn compare_u64_f64(x: u64, y: f64) -> Option<Ordering> {
221 if y < 0.0 {
222 return Some(Ordering::Greater);
223 }
224
225 if y.fract() == 0.0 && (0.0..U64_EXCLUSIVE_MAX_F64).contains(&y) {
226 return Some(x.cmp(&(y as u64)));
228 }
229
230 None
231}
232
233#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
253pub enum MetadataFilter {
254 Condition(Condition),
256 And(Vec<MetadataFilter>),
258 Or(Vec<MetadataFilter>),
260 Not(Box<MetadataFilter>),
262}
263
264impl MetadataFilter {
265 pub fn eq<T: Serialize>(key: impl Into<String>, value: T) -> Self {
269 Self::Condition(Condition::Eq {
270 key: key.into(),
271 value: serde_json::to_value(value)
272 .expect("MetadataFilter::eq: value must be serializable"),
273 })
274 }
275
276 pub fn ne<T: Serialize>(key: impl Into<String>, value: T) -> Self {
278 Self::Condition(Condition::Ne {
279 key: key.into(),
280 value: serde_json::to_value(value)
281 .expect("MetadataFilter::ne: value must be serializable"),
282 })
283 }
284
285 pub fn gt<T: Serialize>(key: impl Into<String>, value: T) -> Self {
287 Self::Condition(Condition::Gt {
288 key: key.into(),
289 value: serde_json::to_value(value)
290 .expect("MetadataFilter::gt: value must be serializable"),
291 })
292 }
293
294 pub fn gte<T: Serialize>(key: impl Into<String>, value: T) -> Self {
296 Self::Condition(Condition::Gte {
297 key: key.into(),
298 value: serde_json::to_value(value)
299 .expect("MetadataFilter::gte: value must be serializable"),
300 })
301 }
302
303 pub fn lt<T: Serialize>(key: impl Into<String>, value: T) -> Self {
305 Self::Condition(Condition::Lt {
306 key: key.into(),
307 value: serde_json::to_value(value)
308 .expect("MetadataFilter::lt: value must be serializable"),
309 })
310 }
311
312 pub fn lte<T: Serialize>(key: impl Into<String>, value: T) -> Self {
314 Self::Condition(Condition::Lte {
315 key: key.into(),
316 value: serde_json::to_value(value)
317 .expect("MetadataFilter::lte: value must be serializable"),
318 })
319 }
320
321 pub fn exists(key: impl Into<String>) -> Self {
323 Self::Condition(Condition::Exists { key: key.into() })
324 }
325
326 pub fn not_exists(key: impl Into<String>) -> Self {
328 Self::Condition(Condition::NotExists { key: key.into() })
329 }
330
331 pub fn in_values<T, I>(key: impl Into<String>, values: I) -> Self
333 where
334 T: Serialize,
335 I: IntoIterator<Item = T>,
336 {
337 let values = values
338 .into_iter()
339 .map(|v| {
340 serde_json::to_value(v)
341 .expect("MetadataFilter::in_values: each value must be serializable")
342 })
343 .collect();
344 Self::Condition(Condition::In {
345 key: key.into(),
346 values,
347 })
348 }
349
350 pub fn not_in_values<T, I>(key: impl Into<String>, values: I) -> Self
352 where
353 T: Serialize,
354 I: IntoIterator<Item = T>,
355 {
356 let values = values
357 .into_iter()
358 .map(|v| {
359 serde_json::to_value(v)
360 .expect("MetadataFilter::not_in_values: each value must be serializable")
361 })
362 .collect();
363 Self::Condition(Condition::NotIn {
364 key: key.into(),
365 values,
366 })
367 }
368
369 #[must_use]
376 pub fn and(self, other: MetadataFilter) -> Self {
377 match self {
378 MetadataFilter::And(mut children) => {
379 children.push(other);
380 MetadataFilter::And(children)
381 }
382 _ => MetadataFilter::And(vec![self, other]),
383 }
384 }
385
386 #[must_use]
391 pub fn or(self, other: MetadataFilter) -> Self {
392 match self {
393 MetadataFilter::Or(mut children) => {
394 children.push(other);
395 MetadataFilter::Or(children)
396 }
397 _ => MetadataFilter::Or(vec![self, other]),
398 }
399 }
400
401 #[allow(clippy::should_implement_trait)]
403 #[must_use]
404 pub fn not(self) -> Self {
405 !self
406 }
407
408 pub fn matches(&self, meta: &Metadata) -> bool {
412 match self {
413 MetadataFilter::Condition(cond) => cond.matches(meta),
414 MetadataFilter::And(children) => children.iter().all(|f| f.matches(meta)),
415 MetadataFilter::Or(children) => children.iter().any(|f| f.matches(meta)),
416 MetadataFilter::Not(inner) => !inner.matches(meta),
417 }
418 }
419}
420
421impl std::ops::Not for MetadataFilter {
422 type Output = MetadataFilter;
423
424 fn not(self) -> Self::Output {
425 MetadataFilter::Not(Box::new(self))
426 }
427}