1use serde::{Deserialize, Serialize};
2use serde_with::skip_serializing_none;
3
4use crate::models::SourceReference;
5
6mod query_value;
7pub use query_value::*;
8mod aggregate;
9pub use aggregate::*;
10
11#[derive(Serialize, Deserialize, Clone, Debug)]
12#[serde(rename_all = "camelCase", rename_all_fields = "camelCase")]
13#[skip_serializing_none]
14pub enum AdvancedFilter {
29 Equals {
31 property: Vec<String>,
33 value: QueryValue,
35 },
36 In {
38 property: Vec<String>,
40 values: QueryValue,
42 },
43 Range {
46 property: Vec<String>,
48 #[serde(skip_serializing_if = "Option::is_none")]
50 gte: Option<QueryValue>,
51 #[serde(skip_serializing_if = "Option::is_none")]
53 gt: Option<QueryValue>,
54 #[serde(skip_serializing_if = "Option::is_none")]
56 lte: Option<QueryValue>,
57 #[serde(skip_serializing_if = "Option::is_none")]
59 lt: Option<QueryValue>,
60 },
61 Prefix {
63 property: Vec<String>,
65 value: String,
67 },
68 Exists {
70 property: Vec<String>,
72 },
73 ContainsAny {
76 property: Vec<String>,
78 values: QueryValue,
80 },
81 ContainsAll {
84 property: Vec<String>,
86 values: QueryValue,
88 },
89 MatchAll {},
91 Nested {
94 scope: Vec<String>,
96 filter: Box<AdvancedFilter>,
98 },
99 Overlaps {
101 start_property: Vec<String>,
103 end_property: Vec<String>,
105 #[serde(skip_serializing_if = "Option::is_none")]
107 gte: Option<QueryValue>,
108 #[serde(skip_serializing_if = "Option::is_none")]
110 gt: Option<QueryValue>,
111 #[serde(skip_serializing_if = "Option::is_none")]
113 lte: Option<QueryValue>,
114 #[serde(skip_serializing_if = "Option::is_none")]
116 lt: Option<QueryValue>,
117 },
118 HasData(Vec<SourceReference>),
120 And(Vec<AdvancedFilter>),
122 Or(Vec<AdvancedFilter>),
124 Not(Box<AdvancedFilter>),
126}
127
128impl Default for AdvancedFilter {
129 fn default() -> Self {
130 Self::MatchAll {}
131 }
132}
133
134pub trait PropertyIdentifier {
136 fn into_identifier(self) -> Vec<String>;
138}
139
140impl PropertyIdentifier for Vec<String> {
141 fn into_identifier(self) -> Vec<String> {
142 self
143 }
144}
145
146impl PropertyIdentifier for &[String] {
147 fn into_identifier(self) -> Vec<String> {
148 self.to_owned()
149 }
150}
151
152impl PropertyIdentifier for &[&str] {
153 fn into_identifier(self) -> Vec<String> {
154 self.iter().map(|&s| s.to_owned()).collect()
155 }
156}
157
158impl<const N: usize> PropertyIdentifier for &[String; N] {
159 fn into_identifier(self) -> Vec<String> {
160 self.to_vec()
161 }
162}
163
164impl<const N: usize> PropertyIdentifier for &[&str; N] {
165 fn into_identifier(self) -> Vec<String> {
166 self.iter().map(|&s| s.to_owned()).collect()
167 }
168}
169
170impl<const N: usize> PropertyIdentifier for [String; N] {
171 fn into_identifier(self) -> Vec<String> {
172 self.to_vec()
173 }
174}
175
176impl<const N: usize> PropertyIdentifier for [&str; N] {
177 fn into_identifier(self) -> Vec<String> {
178 self.iter().map(|&s| s.to_owned()).collect()
179 }
180}
181
182pub enum RangeItem<T> {
184 Inclusive(T),
186 Exclusive(T),
188 Empty,
190}
191
192impl<T> RangeItem<T> {
193 pub fn map<R>(self, map: impl FnOnce(T) -> R) -> RangeItem<R> {
195 match self {
196 RangeItem::Inclusive(r) => RangeItem::Inclusive(map(r)),
197 RangeItem::Exclusive(r) => RangeItem::Exclusive(map(r)),
198 RangeItem::Empty => RangeItem::Empty,
199 }
200 }
201}
202
203pub trait IntoQueryRange {
205 fn into_query_range(self) -> (RangeItem<QueryValue>, RangeItem<QueryValue>);
207}
208
209impl<T> IntoQueryRange for std::ops::Range<T>
210where
211 T: Into<QueryValue>,
212{
213 fn into_query_range(self) -> (RangeItem<QueryValue>, RangeItem<QueryValue>) {
214 (
215 RangeItem::Inclusive(self.start.into()),
216 RangeItem::Exclusive(self.end.into()),
217 )
218 }
219}
220
221impl<T> IntoQueryRange for std::ops::RangeFrom<T>
222where
223 T: Into<QueryValue>,
224{
225 fn into_query_range(self) -> (RangeItem<QueryValue>, RangeItem<QueryValue>) {
226 (RangeItem::Inclusive(self.start.into()), RangeItem::Empty)
227 }
228}
229
230impl IntoQueryRange for std::ops::RangeFull {
231 fn into_query_range(self) -> (RangeItem<QueryValue>, RangeItem<QueryValue>) {
232 (RangeItem::Empty, RangeItem::Empty)
233 }
234}
235
236impl<T> IntoQueryRange for std::ops::RangeInclusive<T>
237where
238 T: Into<QueryValue> + Clone,
239{
240 fn into_query_range(self) -> (RangeItem<QueryValue>, RangeItem<QueryValue>) {
241 (
242 RangeItem::Inclusive(self.start().clone().into()),
243 RangeItem::Inclusive(self.end().clone().into()),
244 )
245 }
246}
247
248impl<T> IntoQueryRange for std::ops::RangeTo<T>
249where
250 T: Into<QueryValue>,
251{
252 fn into_query_range(self) -> (RangeItem<QueryValue>, RangeItem<QueryValue>) {
253 (RangeItem::Empty, RangeItem::Exclusive(self.end.into()))
254 }
255}
256
257impl<T> IntoQueryRange for std::ops::RangeToInclusive<T>
258where
259 T: Into<QueryValue>,
260{
261 fn into_query_range(self) -> (RangeItem<QueryValue>, RangeItem<QueryValue>) {
262 (RangeItem::Empty, RangeItem::Exclusive(self.end.into()))
263 }
264}
265
266impl<T: Into<QueryValue>> IntoQueryRange for (T, T) {
267 fn into_query_range(self) -> (RangeItem<QueryValue>, RangeItem<QueryValue>) {
268 (
269 RangeItem::Inclusive(self.0.into()),
270 RangeItem::Exclusive(self.1.into()),
271 )
272 }
273}
274
275impl<T> IntoQueryRange for (RangeItem<T>, RangeItem<T>)
276where
277 T: Into<QueryValue>,
278{
279 fn into_query_range(self) -> (RangeItem<QueryValue>, RangeItem<QueryValue>) {
280 (self.0.map(Into::into), self.1.map(Into::into))
281 }
282}
283
284pub(crate) mod filter_methods {
286 use super::*;
287 pub fn equals(
294 property: impl PropertyIdentifier,
295 value: impl Into<QueryValue>,
296 ) -> AdvancedFilter {
297 AdvancedFilter::Equals {
298 property: property.into_identifier(),
299 value: value.into(),
300 }
301 }
302 pub fn is_in(
309 property: impl PropertyIdentifier,
310 values: impl Into<QueryValue>,
311 ) -> AdvancedFilter {
312 AdvancedFilter::In {
313 property: property.into_identifier(),
314 values: values.into(),
315 }
316 }
317
318 pub fn range(property: impl PropertyIdentifier, range: impl IntoQueryRange) -> AdvancedFilter {
330 let (start, end) = range.into_query_range();
331 let mut lte = None;
332 let mut gte = None;
333 let mut lt = None;
334 let mut gt = None;
335 match start {
336 RangeItem::Inclusive(i) => gte = Some(i),
337 RangeItem::Exclusive(i) => gt = Some(i),
338 RangeItem::Empty => (),
339 }
340 match end {
341 RangeItem::Inclusive(i) => lte = Some(i),
342 RangeItem::Exclusive(i) => lt = Some(i),
343 RangeItem::Empty => (),
344 }
345
346 AdvancedFilter::Range {
347 property: property.into_identifier(),
348 gte,
349 gt,
350 lte,
351 lt,
352 }
353 }
354
355 pub fn prefix(property: impl PropertyIdentifier, value: impl Into<String>) -> AdvancedFilter {
362 AdvancedFilter::Prefix {
363 property: property.into_identifier(),
364 value: value.into(),
365 }
366 }
367
368 pub fn exists(property: impl PropertyIdentifier) -> AdvancedFilter {
374 AdvancedFilter::Exists {
375 property: property.into_identifier(),
376 }
377 }
378
379 pub fn contains_any(
386 property: impl PropertyIdentifier,
387 values: impl Into<QueryValue>,
388 ) -> AdvancedFilter {
389 AdvancedFilter::ContainsAny {
390 property: property.into_identifier(),
391 values: values.into(),
392 }
393 }
394
395 pub fn contains_all(
402 property: impl PropertyIdentifier,
403 values: impl Into<QueryValue>,
404 ) -> AdvancedFilter {
405 AdvancedFilter::ContainsAll {
406 property: property.into_identifier(),
407 values: values.into(),
408 }
409 }
410
411 pub fn match_all() -> AdvancedFilter {
413 AdvancedFilter::MatchAll {}
414 }
415
416 pub fn nested(scope: impl PropertyIdentifier, filter: AdvancedFilter) -> AdvancedFilter {
423 AdvancedFilter::Nested {
424 scope: scope.into_identifier(),
425 filter: Box::new(filter),
426 }
427 }
428
429 pub fn overlaps(
442 start_property: impl PropertyIdentifier,
443 end_property: impl PropertyIdentifier,
444 range: impl IntoQueryRange,
445 ) -> AdvancedFilter {
446 let (start, end) = range.into_query_range();
447 let mut lte = None;
448 let mut gte = None;
449 let mut lt = None;
450 let mut gt = None;
451 match start {
452 RangeItem::Inclusive(i) => gte = Some(i),
453 RangeItem::Exclusive(i) => gt = Some(i),
454 RangeItem::Empty => (),
455 }
456 match end {
457 RangeItem::Inclusive(i) => lte = Some(i),
458 RangeItem::Exclusive(i) => lt = Some(i),
459 RangeItem::Empty => (),
460 }
461 AdvancedFilter::Overlaps {
462 start_property: start_property.into_identifier(),
463 end_property: end_property.into_identifier(),
464 gte,
465 gt,
466 lte,
467 lt,
468 }
469 }
470
471 pub fn has_data(references: Vec<SourceReference>) -> AdvancedFilter {
477 AdvancedFilter::HasData(references)
478 }
479
480 pub fn not(filter: AdvancedFilter) -> AdvancedFilter {
486 filter.not()
487 }
488
489 pub fn and(filters: Vec<AdvancedFilter>) -> AdvancedFilter {
495 AdvancedFilter::And(filters)
496 }
497
498 pub fn or(filters: Vec<AdvancedFilter>) -> AdvancedFilter {
504 AdvancedFilter::Or(filters)
505 }
506}
507
508impl AdvancedFilter {
509 #[allow(clippy::should_implement_trait)]
510 pub fn not(self) -> Self {
516 match self {
517 Self::Not(n) => *n,
518 _ => Self::Not(Box::new(self)),
519 }
520 }
521 pub fn and(mut self, filter: AdvancedFilter) -> Self {
527 match &mut self {
528 Self::And(a) => {
529 a.push(filter);
530 self
531 }
532 _ => Self::And(vec![self, filter]),
533 }
534 }
535 pub fn or(mut self, filter: AdvancedFilter) -> Self {
541 match &mut self {
542 Self::Or(a) => {
543 a.push(filter);
544 self
545 }
546 _ => Self::Or(vec![self, filter]),
547 }
548 }
549}