1use std::cmp::{Ordering, PartialOrd};
12use std::collections::BTreeSet;
13use std::fmt;
14use std::hash::Hash;
15use std::iter;
16use std::num::NonZeroU8;
17use std::str::FromStr;
18use std::sync::Arc;
19
20use concread::arcache::{ARCache, ARCacheReadTxn};
21use hashbrown::HashMap;
22#[cfg(test)]
23use hashbrown::HashSet;
24use kanidm_proto::constants::ATTR_UUID;
25use kanidm_proto::internal::{Filter as ProtoFilter, OperationError, SchemaError};
26use kanidm_proto::scim_v1::{AttrPath as ScimAttrPath, ScimFilter};
27use ldap3_proto::proto::{LdapFilter, LdapSubstringFilter};
28use serde::Deserialize;
29use uuid::Uuid;
30
31use crate::be::{IdxKey, IdxKeyRef, IdxKeyToRef, IdxMeta, IdxSlope};
32use crate::idm::ldap::ldap_attr_filter_map;
33use crate::prelude::*;
34use crate::schema::SchemaTransaction;
35use crate::value::{IndexType, PartialValue};
36
37pub type ResolveFilterCache =
38 ARCache<(IdentityId, Arc<Filter<FilterValid>>), Arc<Filter<FilterValidResolved>>>;
39
40pub type ResolveFilterCacheReadTxn<'a> = ARCacheReadTxn<
41 'a,
42 (IdentityId, Arc<Filter<FilterValid>>),
43 Arc<Filter<FilterValidResolved>>,
44 (),
45>;
46
47pub fn f_eq(a: Attribute, v: PartialValue) -> FC {
52 FC::Eq(a, v)
53}
54
55pub fn f_sub(a: Attribute, v: PartialValue) -> FC {
56 FC::Cnt(a, v)
57}
58
59pub fn f_pres(a: Attribute) -> FC {
60 FC::Pres(a)
61}
62
63pub fn f_lt(a: Attribute, v: PartialValue) -> FC {
64 FC::LessThan(a, v)
65}
66
67pub fn f_gt(a: Attribute, v: PartialValue) -> FC {
68 FC::And(vec![
69 FC::Pres(a.clone()),
70 FC::AndNot(Box::new(FC::Or(vec![
71 FC::Eq(a.clone(), v.clone()),
72 FC::LessThan(a, v),
73 ]))),
74 ])
75}
76
77pub fn f_or(vs: Vec<FC>) -> FC {
78 FC::Or(vs)
79}
80
81pub fn f_and(vs: Vec<FC>) -> FC {
82 FC::And(vs)
83}
84
85pub fn f_inc(vs: Vec<FC>) -> FC {
86 FC::Inclusion(vs)
87}
88
89pub fn f_andnot(fc: FC) -> FC {
90 FC::AndNot(Box::new(fc))
91}
92
93pub fn f_self() -> FC {
94 FC::SelfUuid
95}
96
97pub fn f_invalid(a: Attribute) -> FC {
98 FC::Invalid(a)
99}
100
101pub fn f_id(uuid: &str) -> FC {
102 let uf = Uuid::parse_str(uuid)
103 .ok()
104 .map(|u| FC::Eq(Attribute::Uuid, PartialValue::Uuid(u)));
105 let spnf = PartialValue::new_spn_s(uuid).map(|spn| FC::Eq(Attribute::Spn, spn));
106 let nf = FC::Eq(Attribute::Name, PartialValue::new_iname(uuid));
107 let f: Vec<_> = iter::once(uf)
108 .chain(iter::once(spnf))
109 .flatten()
110 .chain(iter::once(nf))
111 .collect();
112 FC::Or(f)
113}
114
115pub fn f_spn_name(id: &str) -> FC {
116 let spnf = PartialValue::new_spn_s(id).map(|spn| FC::Eq(Attribute::Spn, spn));
117 let nf = FC::Eq(Attribute::Name, PartialValue::new_iname(id));
118 let f: Vec<_> = iter::once(spnf).flatten().chain(iter::once(nf)).collect();
119 FC::Or(f)
120}
121
122#[derive(Clone, Debug, Deserialize)]
125pub enum FC {
126 Eq(Attribute, PartialValue),
127 Cnt(Attribute, PartialValue),
128 Pres(Attribute),
129 LessThan(Attribute, PartialValue),
130 Or(Vec<FC>),
131 And(Vec<FC>),
132 Inclusion(Vec<FC>),
133 AndNot(Box<FC>),
134 SelfUuid,
135 Invalid(Attribute),
136 }
138
139#[derive(Clone, Hash, PartialEq, PartialOrd, Ord, Eq)]
141enum FilterComp {
142 Eq(Attribute, PartialValue),
144 Cnt(Attribute, PartialValue),
145 Stw(Attribute, PartialValue),
146 Enw(Attribute, PartialValue),
147 Pres(Attribute),
148 LessThan(Attribute, PartialValue),
149 Or(Vec<FilterComp>),
150 And(Vec<FilterComp>),
151 Inclusion(Vec<FilterComp>),
152 AndNot(Box<FilterComp>),
153 SelfUuid,
154 Invalid(Attribute),
155 }
158
159impl fmt::Debug for FilterComp {
160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161 match self {
162 FilterComp::Eq(attr, pv) => {
163 write!(f, "{attr} eq {pv:?}")
164 }
165 FilterComp::Cnt(attr, pv) => {
166 write!(f, "{attr} cnt {pv:?}")
167 }
168 FilterComp::Stw(attr, pv) => {
169 write!(f, "{attr} stw {pv:?}")
170 }
171 FilterComp::Enw(attr, pv) => {
172 write!(f, "{attr} enw {pv:?}")
173 }
174 FilterComp::Pres(attr) => {
175 write!(f, "{attr} pres")
176 }
177 FilterComp::LessThan(attr, pv) => {
178 write!(f, "{attr} lt {pv:?}")
179 }
180 FilterComp::And(list) => {
181 write!(f, "(")?;
182 for (i, fc) in list.iter().enumerate() {
183 write!(f, "{fc:?}")?;
184 if i != list.len() - 1 {
185 write!(f, " and ")?;
186 }
187 }
188 write!(f, ")")
189 }
190 FilterComp::Or(list) => {
191 write!(f, "(")?;
192 for (i, fc) in list.iter().enumerate() {
193 write!(f, "{fc:?}")?;
194 if i != list.len() - 1 {
195 write!(f, " or ")?;
196 }
197 }
198 write!(f, ")")
199 }
200 FilterComp::Inclusion(list) => {
201 write!(f, "(")?;
202 for (i, fc) in list.iter().enumerate() {
203 write!(f, "{fc:?}")?;
204 if i != list.len() - 1 {
205 write!(f, " inc ")?;
206 }
207 }
208 write!(f, ")")
209 }
210 FilterComp::AndNot(inner) => {
211 write!(f, "not ( {inner:?} )")
212 }
213 FilterComp::SelfUuid => {
214 write!(f, "uuid eq self")
215 }
216 FilterComp::Invalid(attr) => {
217 write!(f, "invalid ( {attr:?} )")
218 }
219 }
220 }
221}
222
223#[derive(Clone, Eq)]
234pub enum FilterResolved {
235 Eq(Attribute, PartialValue, Option<NonZeroU8>),
237 Cnt(Attribute, PartialValue, Option<NonZeroU8>),
238 Stw(Attribute, PartialValue, Option<NonZeroU8>),
239 Enw(Attribute, PartialValue, Option<NonZeroU8>),
240 Pres(Attribute, Option<NonZeroU8>),
241 LessThan(Attribute, PartialValue, Option<NonZeroU8>),
242 Or(Vec<FilterResolved>, Option<NonZeroU8>),
243 And(Vec<FilterResolved>, Option<NonZeroU8>),
244 Invalid(Attribute),
245 Inclusion(Vec<FilterResolved>, Option<NonZeroU8>),
247 AndNot(Box<FilterResolved>, Option<NonZeroU8>),
248}
249
250impl fmt::Debug for FilterResolved {
251 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
252 match self {
253 FilterResolved::Eq(attr, pv, idx) => {
254 write!(
255 f,
256 "(s{} {} eq {:?})",
257 idx.unwrap_or(NonZeroU8::MAX),
258 attr,
259 pv
260 )
261 }
262 FilterResolved::Cnt(attr, pv, idx) => {
263 write!(
264 f,
265 "(s{} {} cnt {:?})",
266 idx.unwrap_or(NonZeroU8::MAX),
267 attr,
268 pv
269 )
270 }
271 FilterResolved::Stw(attr, pv, idx) => {
272 write!(
273 f,
274 "(s{} {} stw {:?})",
275 idx.unwrap_or(NonZeroU8::MAX),
276 attr,
277 pv
278 )
279 }
280 FilterResolved::Enw(attr, pv, idx) => {
281 write!(
282 f,
283 "(s{} {} enw {:?})",
284 idx.unwrap_or(NonZeroU8::MAX),
285 attr,
286 pv
287 )
288 }
289 FilterResolved::Pres(attr, idx) => {
290 write!(f, "(s{} {} pres)", idx.unwrap_or(NonZeroU8::MAX), attr)
291 }
292 FilterResolved::LessThan(attr, pv, idx) => {
293 write!(
294 f,
295 "(s{} {} lt {:?})",
296 idx.unwrap_or(NonZeroU8::MAX),
297 attr,
298 pv
299 )
300 }
301 FilterResolved::And(list, idx) => {
302 write!(f, "(s{} ", idx.unwrap_or(NonZeroU8::MAX))?;
303 for (i, fc) in list.iter().enumerate() {
304 write!(f, "{fc:?}")?;
305 if i != list.len() - 1 {
306 write!(f, " and ")?;
307 }
308 }
309 write!(f, ")")
310 }
311 FilterResolved::Or(list, idx) => {
312 write!(f, "(s{} ", idx.unwrap_or(NonZeroU8::MAX))?;
313 for (i, fc) in list.iter().enumerate() {
314 write!(f, "{fc:?}")?;
315 if i != list.len() - 1 {
316 write!(f, " or ")?;
317 }
318 }
319 write!(f, ")")
320 }
321 FilterResolved::Inclusion(list, idx) => {
322 write!(f, "(s{} ", idx.unwrap_or(NonZeroU8::MAX))?;
323 for (i, fc) in list.iter().enumerate() {
324 write!(f, "{fc:?}")?;
325 if i != list.len() - 1 {
326 write!(f, " inc ")?;
327 }
328 }
329 write!(f, ")")
330 }
331 FilterResolved::AndNot(inner, idx) => {
332 write!(f, "not (s{} {:?})", idx.unwrap_or(NonZeroU8::MAX), inner)
333 }
334 FilterResolved::Invalid(attr) => {
335 write!(f, "{attr} inv")
336 }
337 }
338 }
339}
340
341#[derive(Debug, Clone, PartialEq, Eq)]
342pub struct FilterInvalid {
344 inner: FilterComp,
345}
346
347#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
348pub struct FilterValid {
350 inner: FilterComp,
351}
352
353#[derive(Clone, PartialEq, Eq)]
354pub struct FilterValidResolved {
355 inner: FilterResolved,
356}
357
358#[derive(Debug)]
359pub enum FilterPlan {
360 Invalid,
361 EqIndexed(Attribute, String),
362 EqUnindexed(Attribute),
363 EqCorrupt(Attribute),
364 SubIndexed(Attribute, String),
365 SubUnindexed(Attribute),
366 SubCorrupt(Attribute),
367 PresIndexed(Attribute),
368 PresUnindexed(Attribute),
369 PresCorrupt(Attribute),
370 LessThanUnindexed(Attribute),
371 LessThanIndexed(Attribute),
372 LessThanCorrupt(Attribute),
373 OrUnindexed(Vec<FilterPlan>),
374 OrIndexed(Vec<FilterPlan>),
375 OrPartial(Vec<FilterPlan>),
376 OrPartialThreshold(Vec<FilterPlan>),
377 AndEmptyCand(Vec<FilterPlan>),
378 AndIndexed(Vec<FilterPlan>),
379 AndUnindexed(Vec<FilterPlan>),
380 AndPartial(Vec<FilterPlan>),
381 AndPartialThreshold(Vec<FilterPlan>),
382 AndNot(Box<FilterPlan>),
383 InclusionInvalid(Vec<FilterPlan>),
384 InclusionIndexed(Vec<FilterPlan>),
385}
386
387fn fmt_filterplan_set(f: &mut fmt::Formatter<'_>, name: &str, plan: &[FilterPlan]) -> fmt::Result {
391 write!(f, "{name}(")?;
392 for item in plan {
393 write!(f, "{item}, ")?;
394 }
395 write!(f, ")")
396}
397
398impl fmt::Display for FilterPlan {
399 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
400 match self {
401 Self::Invalid => write!(f, "Invalid"),
402 Self::EqIndexed(attr, _) => write!(f, "EqIndexed({attr})"),
403 Self::EqCorrupt(attr) => write!(f, "EqCorrupt({attr})"),
404 Self::EqUnindexed(attr) => write!(f, "EqUnindexed({attr})"),
405
406 Self::SubIndexed(attr, _) => write!(f, "SubIndexed({attr})"),
407 Self::SubCorrupt(attr) => write!(f, "SubCorrupt({attr})"),
408 Self::SubUnindexed(attr) => write!(f, "SubUnindexed({attr})"),
409
410 Self::PresIndexed(attr) => write!(f, "PresIndexed({attr})"),
411 Self::PresCorrupt(attr) => write!(f, "PresCorrupt({attr})"),
412 Self::PresUnindexed(attr) => write!(f, "PresUnindexed({attr})"),
413
414 Self::LessThanUnindexed(attr) => write!(f, "LessThanUnindexed({attr})"),
415 Self::LessThanIndexed(attr) => write!(f, "LessThanIndexed({attr})"),
416 Self::LessThanCorrupt(attr) => write!(f, "LessThanCorrupt({attr})"),
417
418 Self::OrUnindexed(plan) => fmt_filterplan_set(f, "OrUnindexed", plan),
419 Self::OrIndexed(plan) => write!(f, "OrIndexed(len={})", plan.len()),
420 Self::OrPartial(plan) => fmt_filterplan_set(f, "OrPartial", plan),
421 Self::OrPartialThreshold(plan) => fmt_filterplan_set(f, "OrPartialThreshold", plan),
422
423 Self::AndEmptyCand(plan) => write!(f, "AndEmptyCand(len={})", plan.len()),
424 Self::AndUnindexed(plan) => fmt_filterplan_set(f, "AndUnindexed", plan),
425 Self::AndIndexed(plan) => write!(f, "AndIndexed(len={})", plan.len()),
426 Self::AndPartial(plan) => fmt_filterplan_set(f, "AndPartial", plan),
427 Self::AndPartialThreshold(plan) => fmt_filterplan_set(f, "AndPartialThreshold", plan),
428
429 Self::AndNot(plan) => write!(f, "AndNot({plan})"),
430
431 Self::InclusionInvalid(plan) => fmt_filterplan_set(f, "InclusionInvalid", plan),
432 Self::InclusionIndexed(plan) => write!(f, "InclusionIndexed(len={})", plan.len()),
433 }
434 }
435}
436
437#[derive(Clone, Hash, Ord, Eq, PartialOrd, PartialEq)]
459pub struct Filter<STATE> {
460 state: STATE,
461}
462
463impl fmt::Debug for Filter<FilterValidResolved> {
464 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
465 writeln!(f, "Filter(Valid) {:?}", self.state.inner)
466 }
467}
468
469impl fmt::Debug for Filter<FilterValid> {
470 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
471 writeln!(f, "Filter(Valid) {:?}", self.state.inner)
472 }
473}
474
475impl fmt::Debug for Filter<FilterInvalid> {
476 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
477 writeln!(f, "Filter(Invalid) {:?}", self.state.inner)
478 }
479}
480
481impl Filter<FilterValidResolved> {
482 #[cfg(test)]
486 fn optimise(&self) -> Self {
487 Filter {
501 state: FilterValidResolved {
502 inner: self.state.inner.optimise(),
503 },
504 }
505 }
506
507 pub fn to_inner(&self) -> &FilterResolved {
517 &self.state.inner
518 }
519}
520
521impl Filter<FilterValid> {
522 pub fn invalidate(self) -> Filter<FilterInvalid> {
523 Filter {
525 state: FilterInvalid {
526 inner: self.state.inner,
527 },
528 }
529 }
530
531 pub fn resolve(
532 &self,
533 ev: &Identity,
534 idxmeta: Option<&IdxMeta>,
535 mut rsv_cache: Option<&mut ResolveFilterCacheReadTxn<'_>>,
536 ) -> Result<Filter<FilterValidResolved>, OperationError> {
537 let cacheable = idxmeta.is_some() && FilterResolved::resolve_cacheable(&self.state.inner);
546
547 let cache_key = if cacheable {
548 if let Some(rcache) = rsv_cache.as_mut() {
550 let cache_key = (ev.get_event_origin_id(), Arc::new(self.clone()));
552 if let Some(f) = rcache.get(&cache_key) {
553 trace!("shortcut: a resolved filter already exists.");
555 return Ok(f.as_ref().clone());
556 };
557 Some(cache_key)
559 } else {
560 None
561 }
562 } else {
563 None
565 };
566
567 let resolved_filt = Filter {
570 state: FilterValidResolved {
571 inner: match idxmeta {
572 Some(idx) => {
573 FilterResolved::resolve_idx(self.state.inner.clone(), ev, &idx.idxkeys)
574 }
575 None => FilterResolved::resolve_no_idx(self.state.inner.clone(), ev),
576 }
577 .map(|f| {
578 match idxmeta {
579 Some(_) => f.optimise(),
581 None => f.fast_optimise(),
583 }
584 })
585 .ok_or(OperationError::FilterUuidResolution)?,
586 },
587 };
588
589 if let Some(cache_key) = cache_key {
592 if let Some(rcache) = rsv_cache.as_mut() {
593 trace!(?resolved_filt, "inserting filter to resolved cache");
594 rcache.insert(cache_key, Arc::new(resolved_filt.clone()));
595 }
596 }
597
598 Ok(resolved_filt)
599 }
600
601 pub fn get_attr_set(&self) -> BTreeSet<Attribute> {
602 let mut r_set = BTreeSet::new();
604 self.state.inner.get_attr_set(&mut r_set);
605 r_set
606 }
607
608 pub fn into_ignore_hidden(self) -> Self {
615 Filter {
617 state: FilterValid {
618 inner: FilterComp::new_ignore_hidden(self.state.inner),
619 },
620 }
621 }
622
623 pub fn into_recycled(self) -> Self {
624 Filter {
626 state: FilterValid {
627 inner: FilterComp::new_recycled(self.state.inner),
628 },
629 }
630 }
631}
632
633impl Filter<FilterInvalid> {
634 pub fn new(inner: FC) -> Self {
635 let fc = FilterComp::new(inner);
636 Filter {
637 state: FilterInvalid { inner: fc },
638 }
639 }
640
641 pub fn new_ignore_hidden(inner: FC) -> Self {
642 let fc = FilterComp::new(inner);
643 Filter {
644 state: FilterInvalid {
645 inner: FilterComp::new_ignore_hidden(fc),
646 },
647 }
648 }
649
650 pub fn new_recycled(inner: FC) -> Self {
651 let fc = FilterComp::new(inner);
653 Filter {
654 state: FilterInvalid {
655 inner: FilterComp::new_recycled(fc),
656 },
657 }
658 }
659
660 pub fn join_parts_and(a: Self, b: Self) -> Self {
661 Filter {
663 state: FilterInvalid {
664 inner: FilterComp::And(vec![a.state.inner, b.state.inner]),
665 },
666 }
667 }
668
669 #[cfg(test)]
672 pub fn into_valid_resolved(self) -> Filter<FilterValidResolved> {
673 let idxmeta = vec![
684 (Attribute::Uuid, IndexType::Equality),
685 (Attribute::Uuid, IndexType::Presence),
686 (Attribute::Name, IndexType::Equality),
687 (Attribute::Name, IndexType::SubString),
688 (Attribute::Name, IndexType::Presence),
689 (Attribute::Class, IndexType::Equality),
690 (Attribute::Class, IndexType::Presence),
691 (Attribute::Member, IndexType::Equality),
692 (Attribute::Member, IndexType::Presence),
693 (Attribute::MemberOf, IndexType::Equality),
694 (Attribute::MemberOf, IndexType::Presence),
695 (Attribute::DirectMemberOf, IndexType::Equality),
696 (Attribute::DirectMemberOf, IndexType::Presence),
697 ];
698
699 let idxmeta_ref = idxmeta.iter().map(|(attr, itype)| (attr, itype)).collect();
700
701 Filter {
702 state: FilterValidResolved {
703 inner: FilterResolved::from_invalid(self.state.inner, &idxmeta_ref),
704 },
705 }
706 }
707
708 #[cfg(test)]
711 pub fn into_valid(self) -> Filter<FilterValid> {
712 Filter {
719 state: FilterValid {
720 inner: self.state.inner,
721 },
722 }
723 }
724
725 pub fn validate(
726 &self,
727 schema: &dyn SchemaTransaction,
728 ) -> Result<Filter<FilterValid>, SchemaError> {
729 Ok(Filter {
732 state: FilterValid {
733 inner: self.state.inner.validate(schema)?,
734 },
735 })
736 }
737
738 #[instrument(name = "filter::from_ro", level = "trace", skip_all)]
742 pub fn from_ro(
743 ev: &Identity,
744 f: &ProtoFilter,
745 qs: &mut QueryServerReadTransaction,
746 ) -> Result<Self, OperationError> {
747 let depth = DEFAULT_LIMIT_FILTER_DEPTH_MAX as usize;
748 let mut elems = ev.limits().filter_max_elements;
749 Ok(Filter {
750 state: FilterInvalid {
751 inner: FilterComp::from_ro(f, qs, depth, &mut elems)?,
752 },
753 })
754 }
755
756 #[instrument(name = "filter::from_rw", level = "trace", skip_all)]
757 pub fn from_rw(
758 ev: &Identity,
759 f: &ProtoFilter,
760 qs: &mut QueryServerWriteTransaction,
761 ) -> Result<Self, OperationError> {
762 let depth = DEFAULT_LIMIT_FILTER_DEPTH_MAX as usize;
763 let mut elems = ev.limits().filter_max_elements;
764 Ok(Filter {
765 state: FilterInvalid {
766 inner: FilterComp::from_rw(f, qs, depth, &mut elems)?,
767 },
768 })
769 }
770
771 #[instrument(name = "filter::from_ldap_ro", level = "trace", skip_all)]
772 pub fn from_ldap_ro(
773 ev: &Identity,
774 f: &LdapFilter,
775 qs: &mut QueryServerReadTransaction,
776 ) -> Result<Self, OperationError> {
777 let depth = DEFAULT_LIMIT_FILTER_DEPTH_MAX as usize;
778 let mut elems = ev.limits().filter_max_elements;
779 Ok(Filter {
780 state: FilterInvalid {
781 inner: FilterComp::from_ldap_ro(f, qs, depth, &mut elems)?,
782 },
783 })
784 }
785
786 #[instrument(name = "filter::from_scim_ro", level = "trace", skip_all)]
787 pub fn from_scim_ro(
788 ev: &Identity,
789 f: &ScimFilter,
790 qs: &mut QueryServerReadTransaction,
791 ) -> Result<Self, OperationError> {
792 let depth = DEFAULT_LIMIT_FILTER_DEPTH_MAX as usize;
793 let mut elems = ev.limits().filter_max_elements;
794 Ok(Filter {
795 state: FilterInvalid {
796 inner: FilterComp::from_scim_ro(f, qs, depth, &mut elems)?,
797 },
798 })
799 }
800}
801
802impl FromStr for Filter<FilterInvalid> {
803 type Err = OperationError;
804 fn from_str(s: &str) -> Result<Self, Self::Err> {
805 let f: FC = serde_json::from_str(s).map_err(|_| OperationError::FilterParseError)?;
806 Ok(Filter {
807 state: FilterInvalid {
808 inner: FilterComp::new(f),
809 },
810 })
811 }
812}
813
814impl FilterComp {
815 fn new(fc: FC) -> Self {
816 match fc {
817 FC::Eq(a, v) => FilterComp::Eq(a, v),
818 FC::Cnt(a, v) => FilterComp::Cnt(a, v),
819 FC::Pres(a) => FilterComp::Pres(a),
820 FC::LessThan(a, v) => FilterComp::LessThan(a, v),
821 FC::Or(v) => FilterComp::Or(v.into_iter().map(FilterComp::new).collect()),
822 FC::And(v) => FilterComp::And(v.into_iter().map(FilterComp::new).collect()),
823 FC::Inclusion(v) => FilterComp::Inclusion(v.into_iter().map(FilterComp::new).collect()),
824 FC::AndNot(b) => FilterComp::AndNot(Box::new(FilterComp::new(*b))),
825 FC::SelfUuid => FilterComp::SelfUuid,
826 FC::Invalid(a) => FilterComp::Invalid(a),
827 }
828 }
829
830 fn new_ignore_hidden(fc: FilterComp) -> Self {
831 FilterComp::And(vec![
832 FilterComp::AndNot(Box::new(FilterComp::Or(vec![
833 FilterComp::Eq(Attribute::Class, EntryClass::Tombstone.into()),
834 FilterComp::Eq(Attribute::Class, EntryClass::Recycled.into()),
835 ]))),
836 fc,
837 ])
838 }
839
840 fn new_recycled(fc: FilterComp) -> Self {
841 FilterComp::And(vec![
842 FilterComp::Eq(Attribute::Class, EntryClass::Recycled.into()),
843 fc,
844 ])
845 }
846
847 fn get_attr_set(&self, r_set: &mut BTreeSet<Attribute>) {
848 match self {
849 FilterComp::Eq(attr, _)
850 | FilterComp::Cnt(attr, _)
851 | FilterComp::Stw(attr, _)
852 | FilterComp::Enw(attr, _)
853 | FilterComp::Pres(attr)
854 | FilterComp::LessThan(attr, _)
855 | FilterComp::Invalid(attr) => {
856 r_set.insert(attr.clone());
857 }
858 FilterComp::Or(vs) => vs.iter().for_each(|f| f.get_attr_set(r_set)),
859 FilterComp::And(vs) => vs.iter().for_each(|f| f.get_attr_set(r_set)),
860 FilterComp::Inclusion(vs) => vs.iter().for_each(|f| f.get_attr_set(r_set)),
861 FilterComp::AndNot(f) => f.get_attr_set(r_set),
862 FilterComp::SelfUuid => {
863 r_set.insert(Attribute::Uuid);
864 }
865 }
866 }
867
868 fn validate(&self, schema: &dyn SchemaTransaction) -> Result<FilterComp, SchemaError> {
869 let schema_attributes = schema.get_attributes();
876 match self {
881 FilterComp::Eq(attr, value) => {
882 match schema_attributes.get(attr) {
885 Some(schema_a) => {
886 schema_a
887 .validate_partialvalue(attr, value)
888 .map(|_| FilterComp::Eq(attr.clone(), value.clone()))
890 }
892 None => Err(SchemaError::InvalidAttribute(attr.to_string())),
893 }
894 }
895 FilterComp::Cnt(attr, value) => {
896 match schema_attributes.get(attr) {
897 Some(schema_a) => {
898 schema_a
899 .validate_partialvalue(attr, value)
900 .map(|_| FilterComp::Cnt(attr.clone(), value.clone()))
902 }
904 None => Err(SchemaError::InvalidAttribute(attr.to_string())),
905 }
906 }
907 FilterComp::Stw(attr, value) => {
908 match schema_attributes.get(attr) {
909 Some(schema_a) => {
910 schema_a
911 .validate_partialvalue(attr, value)
912 .map(|_| FilterComp::Stw(attr.clone(), value.clone()))
914 }
916 None => Err(SchemaError::InvalidAttribute(attr.to_string())),
917 }
918 }
919 FilterComp::Enw(attr, value) => {
920 match schema_attributes.get(attr) {
921 Some(schema_a) => {
922 schema_a
923 .validate_partialvalue(attr, value)
924 .map(|_| FilterComp::Enw(attr.clone(), value.clone()))
926 }
928 None => Err(SchemaError::InvalidAttribute(attr.to_string())),
929 }
930 }
931 FilterComp::Pres(attr) => {
932 match schema_attributes.get(attr) {
933 Some(_attr_name) => {
934 Ok(FilterComp::Pres(attr.clone()))
936 }
937 None => Err(SchemaError::InvalidAttribute(attr.to_string())),
938 }
939 }
940 FilterComp::LessThan(attr, value) => {
941 match schema_attributes.get(attr) {
942 Some(schema_a) => {
943 schema_a
944 .validate_partialvalue(attr, value)
945 .map(|_| FilterComp::LessThan(attr.clone(), value.clone()))
947 }
949 None => Err(SchemaError::InvalidAttribute(attr.to_string())),
950 }
951 }
952 FilterComp::Or(filters) => {
953 if filters.is_empty() {
958 return Err(SchemaError::EmptyFilter);
959 };
960 let x: Result<Vec<_>, _> = filters
961 .iter()
962 .map(|filter| filter.validate(schema))
963 .collect();
964 x.map(FilterComp::Or)
966 }
967 FilterComp::And(filters) => {
968 if filters.is_empty() {
973 return Err(SchemaError::EmptyFilter);
974 };
975 let x: Result<Vec<_>, _> = filters
976 .iter()
977 .map(|filter| filter.validate(schema))
978 .collect();
979 x.map(FilterComp::And)
981 }
982 FilterComp::Inclusion(filters) => {
983 if filters.is_empty() {
984 return Err(SchemaError::EmptyFilter);
985 };
986 let x: Result<Vec<_>, _> = filters
987 .iter()
988 .map(|filter| filter.validate(schema))
989 .collect();
990 x.map(FilterComp::Inclusion)
992 }
993 FilterComp::AndNot(filter) => {
994 filter
996 .validate(schema)
997 .map(|r_filter| FilterComp::AndNot(Box::new(r_filter)))
998 }
999 FilterComp::SelfUuid => {
1000 Ok(FilterComp::SelfUuid)
1002 }
1003 FilterComp::Invalid(attr) => {
1004 Ok(FilterComp::Invalid(attr.clone()))
1007 }
1008 }
1009 }
1010
1011 fn from_ro(
1012 f: &ProtoFilter,
1013 qs: &mut QueryServerReadTransaction,
1014 depth: usize,
1015 elems: &mut usize,
1016 ) -> Result<Self, OperationError> {
1017 let ndepth = depth.checked_sub(1).ok_or(OperationError::ResourceLimit)?;
1018 Ok(match f {
1019 ProtoFilter::Eq(a, v) => {
1020 let nk = Attribute::from(a.as_str());
1021 let v = qs.clone_partialvalue(&nk, v)?;
1022 FilterComp::Eq(nk, v)
1023 }
1024 ProtoFilter::Cnt(a, v) => {
1025 let nk = Attribute::from(a.as_str());
1026 let v = qs.clone_partialvalue(&nk, v)?;
1027 FilterComp::Cnt(nk, v)
1028 }
1029 ProtoFilter::Pres(a) => {
1030 let nk = Attribute::from(a.as_str());
1031 FilterComp::Pres(nk)
1032 }
1033 ProtoFilter::Or(l) => {
1034 *elems = (*elems)
1035 .checked_sub(l.len())
1036 .ok_or(OperationError::ResourceLimit)?;
1037 FilterComp::Or(
1038 l.iter()
1039 .map(|f| Self::from_ro(f, qs, ndepth, elems))
1040 .collect::<Result<Vec<_>, _>>()?,
1041 )
1042 }
1043 ProtoFilter::And(l) => {
1044 *elems = (*elems)
1045 .checked_sub(l.len())
1046 .ok_or(OperationError::ResourceLimit)?;
1047 FilterComp::And(
1048 l.iter()
1049 .map(|f| Self::from_ro(f, qs, ndepth, elems))
1050 .collect::<Result<Vec<_>, _>>()?,
1051 )
1052 }
1053 ProtoFilter::AndNot(l) => {
1054 *elems = (*elems)
1055 .checked_sub(1)
1056 .ok_or(OperationError::ResourceLimit)?;
1057 FilterComp::AndNot(Box::new(Self::from_ro(l, qs, ndepth, elems)?))
1058 }
1059 ProtoFilter::SelfUuid => FilterComp::SelfUuid,
1060 })
1061 }
1062
1063 fn from_rw(
1064 f: &ProtoFilter,
1065 qs: &mut QueryServerWriteTransaction,
1066 depth: usize,
1067 elems: &mut usize,
1068 ) -> Result<Self, OperationError> {
1069 let ndepth = depth.checked_sub(1).ok_or(OperationError::ResourceLimit)?;
1070 Ok(match f {
1071 ProtoFilter::Eq(a, v) => {
1072 let nk = Attribute::from(a.as_str());
1073 let v = qs.clone_partialvalue(&nk, v)?;
1074 FilterComp::Eq(nk, v)
1075 }
1076 ProtoFilter::Cnt(a, v) => {
1077 let nk = Attribute::from(a.as_str());
1078 let v = qs.clone_partialvalue(&nk, v)?;
1079 FilterComp::Cnt(nk, v)
1080 }
1081 ProtoFilter::Pres(a) => {
1082 let nk = Attribute::from(a.as_str());
1083 FilterComp::Pres(nk)
1084 }
1085 ProtoFilter::Or(l) => {
1086 *elems = (*elems)
1087 .checked_sub(l.len())
1088 .ok_or(OperationError::ResourceLimit)?;
1089 FilterComp::Or(
1090 l.iter()
1091 .map(|f| Self::from_rw(f, qs, ndepth, elems))
1092 .collect::<Result<Vec<_>, _>>()?,
1093 )
1094 }
1095 ProtoFilter::And(l) => {
1096 *elems = (*elems)
1097 .checked_sub(l.len())
1098 .ok_or(OperationError::ResourceLimit)?;
1099 FilterComp::And(
1100 l.iter()
1101 .map(|f| Self::from_rw(f, qs, ndepth, elems))
1102 .collect::<Result<Vec<_>, _>>()?,
1103 )
1104 }
1105 ProtoFilter::AndNot(l) => {
1106 *elems = (*elems)
1107 .checked_sub(1)
1108 .ok_or(OperationError::ResourceLimit)?;
1109
1110 FilterComp::AndNot(Box::new(Self::from_rw(l, qs, ndepth, elems)?))
1111 }
1112 ProtoFilter::SelfUuid => FilterComp::SelfUuid,
1113 })
1114 }
1115
1116 fn from_ldap_ro(
1117 f: &LdapFilter,
1118 qs: &mut QueryServerReadTransaction,
1119 depth: usize,
1120 elems: &mut usize,
1121 ) -> Result<Self, OperationError> {
1122 let ndepth = depth.checked_sub(1).ok_or(OperationError::ResourceLimit)?;
1123 *elems = (*elems)
1124 .checked_sub(1)
1125 .ok_or(OperationError::ResourceLimit)?;
1126 Ok(match f {
1127 LdapFilter::And(l) => FilterComp::And(
1128 l.iter()
1129 .map(|f| Self::from_ldap_ro(f, qs, ndepth, elems))
1130 .collect::<Result<Vec<_>, _>>()?,
1131 ),
1132 LdapFilter::Or(l) => FilterComp::Or(
1133 l.iter()
1134 .map(|f| Self::from_ldap_ro(f, qs, ndepth, elems))
1135 .collect::<Result<Vec<_>, _>>()?,
1136 ),
1137 LdapFilter::Not(l) => {
1138 FilterComp::AndNot(Box::new(Self::from_ldap_ro(l, qs, ndepth, elems)?))
1139 }
1140 LdapFilter::Equality(a, v) => {
1141 let a = ldap_attr_filter_map(a);
1142 let pv = qs.clone_partialvalue(&a, v);
1143
1144 match pv {
1145 Ok(pv) => FilterComp::Eq(a, pv),
1146 Err(_) if a == Attribute::Spn => FilterComp::Invalid(a),
1147 Err(err) => return Err(err),
1148 }
1149 }
1150 LdapFilter::Present(a) => FilterComp::Pres(ldap_attr_filter_map(a)),
1151 LdapFilter::Substring(
1152 a,
1153 LdapSubstringFilter {
1154 initial,
1155 any,
1156 final_,
1157 },
1158 ) => {
1159 let a = ldap_attr_filter_map(a);
1160
1161 let mut terms = Vec::with_capacity(any.len() + 2);
1162 if let Some(ini) = initial {
1163 let v = qs.clone_partialvalue(&a, ini)?;
1164 terms.push(FilterComp::Stw(a.clone(), v));
1165 }
1166
1167 for term in any.iter() {
1168 let v = qs.clone_partialvalue(&a, term)?;
1169 terms.push(FilterComp::Cnt(a.clone(), v));
1170 }
1171
1172 if let Some(fin) = final_ {
1173 let v = qs.clone_partialvalue(&a, fin)?;
1174 terms.push(FilterComp::Enw(a.clone(), v));
1175 }
1176
1177 FilterComp::And(terms)
1178 }
1179 LdapFilter::GreaterOrEqual(_, _) => {
1180 admin_error!("Unsupported filter operation - greater or equal");
1181 return Err(OperationError::FilterGeneration);
1182 }
1183 LdapFilter::LessOrEqual(_, _) => {
1184 admin_error!("Unsupported filter operation - less or equal");
1185 return Err(OperationError::FilterGeneration);
1186 }
1187 LdapFilter::Approx(_, _) => {
1188 admin_error!("Unsupported filter operation - approximate");
1189 return Err(OperationError::FilterGeneration);
1190 }
1191 LdapFilter::Extensible(_) => {
1192 admin_error!("Unsupported filter operation - extensible");
1193 return Err(OperationError::FilterGeneration);
1194 }
1195 })
1196 }
1197
1198 fn from_scim_ro(
1199 f: &ScimFilter,
1200 qs: &mut QueryServerReadTransaction,
1201 depth: usize,
1202 elems: &mut usize,
1203 ) -> Result<Self, OperationError> {
1204 let ndepth = depth.checked_sub(1).ok_or(OperationError::ResourceLimit)?;
1205 *elems = (*elems)
1206 .checked_sub(1)
1207 .ok_or(OperationError::ResourceLimit)?;
1208 Ok(match f {
1209 ScimFilter::Present(ScimAttrPath { a, s: None }) => FilterComp::Pres(a.clone()),
1210 ScimFilter::Equal(ScimAttrPath { a, s: None }, json_value) => {
1211 let pv = qs.resolve_scim_json_get(a, json_value)?;
1212 FilterComp::Eq(a.clone(), pv)
1213 }
1214 ScimFilter::Contains(ScimAttrPath { a, s: None }, json_value) => {
1215 let pv = qs.resolve_scim_json_get(a, json_value)?;
1216 FilterComp::Cnt(a.clone(), pv)
1217 }
1218 ScimFilter::StartsWith(ScimAttrPath { a, s: None }, json_value) => {
1219 let pv = qs.resolve_scim_json_get(a, json_value)?;
1220 FilterComp::Stw(a.clone(), pv)
1221 }
1222 ScimFilter::EndsWith(ScimAttrPath { a, s: None }, json_value) => {
1223 let pv = qs.resolve_scim_json_get(a, json_value)?;
1224 FilterComp::Enw(a.clone(), pv)
1225 }
1226 ScimFilter::Greater(ScimAttrPath { a, s: None }, json_value) => {
1227 let pv = qs.resolve_scim_json_get(a, json_value)?;
1228 FilterComp::And(vec![
1230 FilterComp::Pres(a.clone()),
1231 FilterComp::AndNot(Box::new(FilterComp::Or(vec![
1232 FilterComp::LessThan(a.clone(), pv.clone()),
1233 FilterComp::Eq(a.clone(), pv),
1234 ]))),
1235 ])
1236 }
1237 ScimFilter::Less(ScimAttrPath { a, s: None }, json_value) => {
1238 let pv = qs.resolve_scim_json_get(a, json_value)?;
1239 FilterComp::LessThan(a.clone(), pv)
1240 }
1241 ScimFilter::GreaterOrEqual(ScimAttrPath { a, s: None }, json_value) => {
1242 let pv = qs.resolve_scim_json_get(a, json_value)?;
1243 FilterComp::And(vec![
1245 FilterComp::Pres(a.clone()),
1246 FilterComp::AndNot(Box::new(FilterComp::LessThan(a.clone(), pv.clone()))),
1247 ])
1248 }
1249 ScimFilter::LessOrEqual(ScimAttrPath { a, s: None }, json_value) => {
1250 let pv = qs.resolve_scim_json_get(a, json_value)?;
1251 FilterComp::Or(vec![
1252 FilterComp::LessThan(a.clone(), pv.clone()),
1253 FilterComp::Eq(a.clone(), pv),
1254 ])
1255 }
1256 ScimFilter::Not(f) => {
1257 let f = Self::from_scim_ro(f, qs, ndepth, elems)?;
1258 FilterComp::AndNot(Box::new(f))
1259 }
1260 ScimFilter::Or(left, right) => {
1261 let left = Self::from_scim_ro(left, qs, ndepth, elems)?;
1262 let right = Self::from_scim_ro(right, qs, ndepth, elems)?;
1263 FilterComp::Or(vec![left, right])
1264 }
1265 ScimFilter::And(left, right) => {
1266 let left = Self::from_scim_ro(left, qs, ndepth, elems)?;
1267 let right = Self::from_scim_ro(right, qs, ndepth, elems)?;
1268 FilterComp::And(vec![left, right])
1269 }
1270 ScimFilter::NotEqual(ScimAttrPath { s: None, .. }, _) => {
1271 error!("Unsupported filter operation - not-equal");
1272 return Err(OperationError::FilterGeneration);
1273 }
1274 ScimFilter::Present(ScimAttrPath { s: Some(_), .. })
1275 | ScimFilter::Equal(ScimAttrPath { s: Some(_), .. }, _)
1276 | ScimFilter::NotEqual(ScimAttrPath { s: Some(_), .. }, _)
1277 | ScimFilter::Contains(ScimAttrPath { s: Some(_), .. }, _)
1278 | ScimFilter::StartsWith(ScimAttrPath { s: Some(_), .. }, _)
1279 | ScimFilter::EndsWith(ScimAttrPath { s: Some(_), .. }, _)
1280 | ScimFilter::Greater(ScimAttrPath { s: Some(_), .. }, _)
1281 | ScimFilter::Less(ScimAttrPath { s: Some(_), .. }, _)
1282 | ScimFilter::GreaterOrEqual(ScimAttrPath { s: Some(_), .. }, _)
1283 | ScimFilter::LessOrEqual(ScimAttrPath { s: Some(_), .. }, _) => {
1284 error!("Unsupported filter operation - sub-attribute");
1285 return Err(OperationError::FilterGeneration);
1286 }
1287 ScimFilter::Complex(..) => {
1288 error!("Unsupported filter operation - complex");
1289 return Err(OperationError::FilterGeneration);
1290 }
1291 })
1292 }
1293}
1294
1295#[cfg(test)]
1321impl PartialOrd for Filter<FilterValidResolved> {
1322 fn partial_cmp(&self, rhs: &Filter<FilterValidResolved>) -> Option<Ordering> {
1323 self.state.inner.partial_cmp(&rhs.state.inner)
1324 }
1325}
1326
1327impl PartialEq for FilterResolved {
1328 fn eq(&self, rhs: &FilterResolved) -> bool {
1329 match (self, rhs) {
1330 (FilterResolved::Eq(a1, v1, _), FilterResolved::Eq(a2, v2, _)) => a1 == a2 && v1 == v2,
1331 (FilterResolved::Cnt(a1, v1, _), FilterResolved::Cnt(a2, v2, _)) => {
1332 a1 == a2 && v1 == v2
1333 }
1334 (FilterResolved::Pres(a1, _), FilterResolved::Pres(a2, _)) => a1 == a2,
1335 (FilterResolved::LessThan(a1, v1, _), FilterResolved::LessThan(a2, v2, _)) => {
1336 a1 == a2 && v1 == v2
1337 }
1338 (FilterResolved::And(vs1, _), FilterResolved::And(vs2, _)) => vs1 == vs2,
1339 (FilterResolved::Or(vs1, _), FilterResolved::Or(vs2, _)) => vs1 == vs2,
1340 (FilterResolved::Inclusion(vs1, _), FilterResolved::Inclusion(vs2, _)) => vs1 == vs2,
1341 (FilterResolved::AndNot(f1, _), FilterResolved::AndNot(f2, _)) => f1 == f2,
1342 (_, _) => false,
1343 }
1344 }
1345}
1346
1347impl PartialOrd for FilterResolved {
1348 fn partial_cmp(&self, rhs: &FilterResolved) -> Option<Ordering> {
1349 Some(self.cmp(rhs))
1350 }
1351}
1352
1353impl Ord for FilterResolved {
1354 fn cmp(&self, rhs: &FilterResolved) -> Ordering {
1356 let left_slopey = self.get_slopeyness_factor();
1357 let right_slopey = rhs.get_slopeyness_factor();
1358
1359 let r = match (left_slopey, right_slopey) {
1360 (Some(sfl), Some(sfr)) => sfl.cmp(&sfr),
1361 (Some(_), None) => Ordering::Less,
1362 (None, Some(_)) => Ordering::Greater,
1363 (None, None) => Ordering::Equal,
1364 };
1365
1366 if r == Ordering::Equal {
1373 match (self, rhs) {
1374 (FilterResolved::Eq(a1, v1, _), FilterResolved::Eq(a2, v2, _))
1375 | (FilterResolved::Cnt(a1, v1, _), FilterResolved::Cnt(a2, v2, _))
1376 | (FilterResolved::LessThan(a1, v1, _), FilterResolved::LessThan(a2, v2, _)) => {
1377 match a1.cmp(a2) {
1378 Ordering::Equal => v1.cmp(v2),
1379 o => o,
1380 }
1381 }
1382 (FilterResolved::Pres(a1, _), FilterResolved::Pres(a2, _)) => a1.cmp(a2),
1383 (FilterResolved::Eq(_, _, _), _) => Ordering::Less,
1385 (_, FilterResolved::Eq(_, _, _)) => Ordering::Greater,
1386 (FilterResolved::Pres(_, _), _) => Ordering::Less,
1387 (_, FilterResolved::Pres(_, _)) => Ordering::Greater,
1388 (FilterResolved::LessThan(_, _, _), _) => Ordering::Less,
1389 (_, FilterResolved::LessThan(_, _, _)) => Ordering::Greater,
1390 (FilterResolved::Cnt(_, _, _), _) => Ordering::Less,
1391 (_, FilterResolved::Cnt(_, _, _)) => Ordering::Greater,
1392 (_, _) => Ordering::Equal,
1394 }
1395 } else {
1396 r
1397 }
1398 }
1399}
1400
1401impl FilterResolved {
1402 #[cfg(test)]
1405 fn from_invalid(fc: FilterComp, idxmeta: &HashSet<(&Attribute, &IndexType)>) -> Self {
1406 match fc {
1407 FilterComp::Eq(a, v) => {
1408 let idx = idxmeta.contains(&(&a, &IndexType::Equality));
1409 let idx = NonZeroU8::new(idx as u8);
1410 FilterResolved::Eq(a, v, idx)
1411 }
1412 FilterComp::SelfUuid => panic!("Not possible to resolve SelfUuid in from_invalid!"),
1413 FilterComp::Invalid(attr) => FilterResolved::Invalid(attr),
1414 FilterComp::Cnt(a, v) => {
1415 let idx = idxmeta.contains(&(&a, &IndexType::SubString));
1416 let idx = NonZeroU8::new(idx as u8);
1417 FilterResolved::Cnt(a, v, idx)
1418 }
1419 FilterComp::Stw(a, v) => {
1420 let idx = idxmeta.contains(&(&a, &IndexType::SubString));
1421 let idx = NonZeroU8::new(idx as u8);
1422 FilterResolved::Stw(a, v, idx)
1423 }
1424 FilterComp::Enw(a, v) => {
1425 let idx = idxmeta.contains(&(&a, &IndexType::SubString));
1426 let idx = NonZeroU8::new(idx as u8);
1427 FilterResolved::Enw(a, v, idx)
1428 }
1429 FilterComp::Pres(a) => {
1430 let idx = idxmeta.contains(&(&a, &IndexType::Presence));
1431 FilterResolved::Pres(a, NonZeroU8::new(idx as u8))
1432 }
1433 FilterComp::LessThan(a, v) => {
1434 let idx = idxmeta.contains(&(&a, &IndexType::Ordering));
1435 FilterResolved::LessThan(a, v, NonZeroU8::new(idx as u8))
1436 }
1437 FilterComp::Or(vs) => FilterResolved::Or(
1438 vs.into_iter()
1439 .map(|v| FilterResolved::from_invalid(v, idxmeta))
1440 .collect(),
1441 None,
1442 ),
1443 FilterComp::And(vs) => FilterResolved::And(
1444 vs.into_iter()
1445 .map(|v| FilterResolved::from_invalid(v, idxmeta))
1446 .collect(),
1447 None,
1448 ),
1449 FilterComp::Inclusion(vs) => FilterResolved::Inclusion(
1450 vs.into_iter()
1451 .map(|v| FilterResolved::from_invalid(v, idxmeta))
1452 .collect(),
1453 None,
1454 ),
1455 FilterComp::AndNot(f) => {
1456 FilterResolved::AndNot(
1462 Box::new(FilterResolved::from_invalid((*f).clone(), idxmeta)),
1463 None,
1464 )
1465 }
1466 }
1467 }
1468
1469 fn resolve_cacheable(fc: &FilterComp) -> bool {
1470 match fc {
1471 FilterComp::Or(vs) | FilterComp::And(vs) | FilterComp::Inclusion(vs) => {
1472 if vs.len() < 8 {
1473 vs.iter().all(FilterResolved::resolve_cacheable)
1474 } else {
1475 false
1477 }
1478 }
1479 FilterComp::AndNot(f) => FilterResolved::resolve_cacheable(f.as_ref()),
1480 FilterComp::Eq(..)
1481 | FilterComp::SelfUuid
1482 | FilterComp::Cnt(..)
1483 | FilterComp::Stw(..)
1484 | FilterComp::Enw(..)
1485 | FilterComp::Pres(_)
1486 | FilterComp::Invalid(_)
1487 | FilterComp::LessThan(..) => true,
1488 }
1489 }
1490
1491 fn resolve_idx(
1492 fc: FilterComp,
1493 ev: &Identity,
1494 idxmeta: &HashMap<IdxKey, IdxSlope>,
1495 ) -> Option<Self> {
1496 match fc {
1497 FilterComp::Eq(a, v) => {
1498 let idxkref = IdxKeyRef::new(&a, &IndexType::Equality);
1499 let idx = idxmeta
1500 .get(&idxkref as &dyn IdxKeyToRef)
1501 .copied()
1502 .and_then(NonZeroU8::new);
1503 Some(FilterResolved::Eq(a, v, idx))
1504 }
1505 FilterComp::SelfUuid => {
1506 let uuid = ev.get_uuid();
1507 let idxkref = IdxKeyRef::new(Attribute::Uuid.as_ref(), &IndexType::Equality);
1508 let idx = idxmeta
1509 .get(&idxkref as &dyn IdxKeyToRef)
1510 .copied()
1511 .and_then(NonZeroU8::new);
1512 Some(FilterResolved::Eq(
1513 Attribute::Uuid,
1514 PartialValue::Uuid(uuid),
1515 idx,
1516 ))
1517 }
1518 FilterComp::Cnt(a, v) => {
1519 let idxkref = IdxKeyRef::new(&a, &IndexType::SubString);
1520 let idx = idxmeta
1521 .get(&idxkref as &dyn IdxKeyToRef)
1522 .copied()
1523 .and_then(NonZeroU8::new);
1524 Some(FilterResolved::Cnt(a, v, idx))
1525 }
1526 FilterComp::Stw(a, v) => {
1527 let idxkref = IdxKeyRef::new(&a, &IndexType::SubString);
1528 let idx = idxmeta
1529 .get(&idxkref as &dyn IdxKeyToRef)
1530 .copied()
1531 .and_then(NonZeroU8::new);
1532 Some(FilterResolved::Stw(a, v, idx))
1533 }
1534 FilterComp::Enw(a, v) => {
1535 let idxkref = IdxKeyRef::new(&a, &IndexType::SubString);
1536 let idx = idxmeta
1537 .get(&idxkref as &dyn IdxKeyToRef)
1538 .copied()
1539 .and_then(NonZeroU8::new);
1540 Some(FilterResolved::Enw(a, v, idx))
1541 }
1542 FilterComp::Pres(a) => {
1543 let idxkref = IdxKeyRef::new(&a, &IndexType::Presence);
1544 let idx = idxmeta
1545 .get(&idxkref as &dyn IdxKeyToRef)
1546 .copied()
1547 .and_then(NonZeroU8::new);
1548 Some(FilterResolved::Pres(a, idx))
1549 }
1550 FilterComp::LessThan(a, v) => {
1551 let idxkref = IdxKeyRef::new(&a, &IndexType::Ordering);
1552 let idx = idxmeta
1553 .get(&idxkref as &dyn IdxKeyToRef)
1554 .copied()
1555 .and_then(NonZeroU8::new);
1556 Some(FilterResolved::LessThan(a, v, idx))
1557 }
1558 FilterComp::Or(vs) => {
1562 let fi: Option<Vec<_>> = vs
1563 .into_iter()
1564 .map(|f| FilterResolved::resolve_idx(f, ev, idxmeta))
1565 .collect();
1566 fi.map(|fi| FilterResolved::Or(fi, None))
1567 }
1568 FilterComp::And(vs) => {
1569 let fi: Option<Vec<_>> = vs
1570 .into_iter()
1571 .map(|f| FilterResolved::resolve_idx(f, ev, idxmeta))
1572 .collect();
1573 fi.map(|fi| FilterResolved::And(fi, None))
1574 }
1575 FilterComp::Inclusion(vs) => {
1576 let fi: Option<Vec<_>> = vs
1577 .into_iter()
1578 .map(|f| FilterResolved::resolve_idx(f, ev, idxmeta))
1579 .collect();
1580 fi.map(|fi| FilterResolved::Inclusion(fi, None))
1581 }
1582 FilterComp::AndNot(f) => {
1583 FilterResolved::resolve_idx((*f).clone(), ev, idxmeta)
1589 .map(|fi| FilterResolved::AndNot(Box::new(fi), None))
1590 }
1591 FilterComp::Invalid(attr) => Some(FilterResolved::Invalid(attr)),
1592 }
1593 }
1594
1595 fn resolve_no_idx(fc: FilterComp, ev: &Identity) -> Option<Self> {
1596 match fc {
1600 FilterComp::Eq(a, v) => {
1601 let idx = matches!(a.as_str(), ATTR_NAME | ATTR_UUID);
1605 let idx = NonZeroU8::new(idx as u8);
1606 Some(FilterResolved::Eq(a, v, idx))
1607 }
1608 FilterComp::SelfUuid => {
1609 let uuid = ev.get_uuid();
1610 Some(FilterResolved::Eq(
1611 Attribute::Uuid,
1612 PartialValue::Uuid(uuid),
1613 NonZeroU8::new(true as u8),
1614 ))
1615 }
1616 FilterComp::Cnt(a, v) => Some(FilterResolved::Cnt(a, v, None)),
1617 FilterComp::Stw(a, v) => Some(FilterResolved::Stw(a, v, None)),
1618 FilterComp::Enw(a, v) => Some(FilterResolved::Enw(a, v, None)),
1619 FilterComp::Pres(a) => Some(FilterResolved::Pres(a, None)),
1620 FilterComp::LessThan(a, v) => Some(FilterResolved::LessThan(a, v, None)),
1621 FilterComp::Or(vs) => {
1622 let fi: Option<Vec<_>> = vs
1623 .into_iter()
1624 .map(|f| FilterResolved::resolve_no_idx(f, ev))
1625 .collect();
1626 fi.map(|fi| FilterResolved::Or(fi, None))
1627 }
1628 FilterComp::And(vs) => {
1629 let fi: Option<Vec<_>> = vs
1630 .into_iter()
1631 .map(|f| FilterResolved::resolve_no_idx(f, ev))
1632 .collect();
1633 fi.map(|fi| FilterResolved::And(fi, None))
1634 }
1635 FilterComp::Inclusion(vs) => {
1636 let fi: Option<Vec<_>> = vs
1637 .into_iter()
1638 .map(|f| FilterResolved::resolve_no_idx(f, ev))
1639 .collect();
1640 fi.map(|fi| FilterResolved::Inclusion(fi, None))
1641 }
1642 FilterComp::AndNot(f) => {
1643 FilterResolved::resolve_no_idx((*f).clone(), ev)
1649 .map(|fi| FilterResolved::AndNot(Box::new(fi), None))
1650 }
1651 FilterComp::Invalid(attr) => Some(FilterResolved::Invalid(attr)),
1652 }
1653 }
1654
1655 fn fast_optimise(self) -> Self {
1657 match self {
1658 FilterResolved::Inclusion(mut f_list, _) => {
1659 f_list.sort_unstable();
1660 f_list.dedup();
1661 let sf = f_list.last().and_then(|f| f.get_slopeyness_factor());
1662 FilterResolved::Inclusion(f_list, sf)
1663 }
1664 FilterResolved::And(mut f_list, _) => {
1665 f_list.sort_unstable();
1666 f_list.dedup();
1667 let sf = f_list.first().and_then(|f| f.get_slopeyness_factor());
1668 FilterResolved::And(f_list, sf)
1669 }
1670 v => v,
1671 }
1672 }
1673
1674 fn optimise(&self) -> Self {
1675 match self {
1677 FilterResolved::Inclusion(f_list, _) => {
1678 let (f_list_inc, mut f_list_new): (Vec<_>, Vec<_>) = f_list
1680 .iter()
1681 .map(|f_ref| f_ref.optimise())
1682 .partition(|f| matches!(f, FilterResolved::Inclusion(_, _)));
1683
1684 f_list_inc.into_iter().for_each(|fc| {
1685 if let FilterResolved::Inclusion(mut l, _) = fc {
1686 f_list_new.append(&mut l)
1687 }
1688 });
1689 f_list_new.sort_unstable();
1691 f_list_new.dedup();
1692 let sf = f_list_new.last().and_then(|f| f.get_slopeyness_factor());
1694 FilterResolved::Inclusion(f_list_new, sf)
1695 }
1696 FilterResolved::And(f_list, _) => {
1697 let (f_list_and, mut f_list_new): (Vec<_>, Vec<_>) = f_list
1699 .iter()
1700 .map(|f_ref| f_ref.optimise())
1701 .partition(|f| matches!(f, FilterResolved::And(_, _)));
1702
1703 f_list_and.into_iter().for_each(|fc| {
1716 if let FilterResolved::And(mut l, _) = fc {
1717 f_list_new.append(&mut l)
1718 }
1719 });
1720
1721 if f_list_new.len() == 1 {
1723 f_list_new.remove(0)
1724 } else {
1725 f_list_new.sort_unstable();
1727 f_list_new.dedup();
1728 let sf = f_list_new.first().and_then(|f| f.get_slopeyness_factor());
1732 FilterResolved::And(f_list_new, sf)
1735 }
1736 }
1737 FilterResolved::Or(f_list, _) => {
1738 let (f_list_or, mut f_list_new): (Vec<_>, Vec<_>) = f_list
1739 .iter()
1740 .map(|f_ref| f_ref.optimise())
1742 .partition(|f| matches!(f, FilterResolved::Or(_, _)));
1744
1745 f_list_or.into_iter().for_each(|fc| {
1747 if let FilterResolved::Or(mut l, _) = fc {
1748 f_list_new.append(&mut l)
1749 }
1750 });
1751
1752 if f_list_new.len() == 1 {
1754 f_list_new.remove(0)
1755 } else {
1756 #[allow(clippy::unnecessary_sort_by)]
1763 f_list_new.sort_unstable_by(|a, b| b.cmp(a));
1764 f_list_new.dedup();
1765 let sf = f_list_new.last().and_then(|f| f.get_slopeyness_factor());
1767 FilterResolved::Or(f_list_new, sf)
1768 }
1769 }
1770 f => f.clone(),
1771 }
1772 }
1773
1774 pub fn is_andnot(&self) -> bool {
1775 matches!(self, FilterResolved::AndNot(_, _))
1776 }
1777
1778 #[inline(always)]
1779 fn get_slopeyness_factor(&self) -> Option<NonZeroU8> {
1780 match self {
1781 FilterResolved::Eq(_, _, sf)
1782 | FilterResolved::Cnt(_, _, sf)
1783 | FilterResolved::Stw(_, _, sf)
1784 | FilterResolved::Enw(_, _, sf)
1785 | FilterResolved::Pres(_, sf)
1786 | FilterResolved::LessThan(_, _, sf)
1787 | FilterResolved::Or(_, sf)
1788 | FilterResolved::And(_, sf)
1789 | FilterResolved::Inclusion(_, sf)
1790 | FilterResolved::AndNot(_, sf) => *sf,
1791 FilterResolved::Invalid(_) => NonZeroU8::new(1),
1793 }
1794 }
1795}
1796
1797#[cfg(test)]
1798mod tests {
1799 use std::cmp::{Ordering, PartialOrd};
1800 use std::collections::BTreeSet;
1801 use std::time::Duration;
1802
1803 use kanidm_proto::internal::Filter as ProtoFilter;
1804 use ldap3_proto::simple::LdapFilter;
1805
1806 use crate::event::{CreateEvent, DeleteEvent};
1807 use crate::filter::{Filter, FilterInvalid, DEFAULT_LIMIT_FILTER_DEPTH_MAX};
1808 use crate::prelude::*;
1809
1810 #[test]
1811 fn test_filter_simple() {
1812 let _filt: Filter<FilterInvalid> = filter!(f_eq(Attribute::Class, EntryClass::User.into()));
1814
1815 let _complex_filt: Filter<FilterInvalid> = filter!(f_and!([
1817 f_or!([
1818 f_eq(Attribute::UserId, PartialValue::new_iutf8("test_a")),
1819 f_eq(Attribute::UserId, PartialValue::new_iutf8("test_b")),
1820 ]),
1821 f_sub(Attribute::Class, EntryClass::User.into()),
1822 ]));
1823 }
1824
1825 macro_rules! filter_optimise_assert {
1826 (
1827 $init:expr,
1828 $expect:expr
1829 ) => {{
1830 #[allow(unused_imports)]
1831 use crate::filter::{f_and, f_andnot, f_eq, f_or, f_pres, f_sub};
1832 use crate::filter::{Filter, FilterInvalid};
1833 let f_init: Filter<FilterInvalid> = Filter::new($init);
1834 let f_expect: Filter<FilterInvalid> = Filter::new($expect);
1835 let f_init_r = f_init.into_valid_resolved();
1837 let f_init_o = f_init_r.optimise();
1838 let f_init_e = f_expect.into_valid_resolved();
1839 debug!("--");
1840 debug!("init --> {:?}", f_init_r);
1841 debug!("opt --> {:?}", f_init_o);
1842 debug!("expect --> {:?}", f_init_e);
1843 assert_eq!(f_init_o, f_init_e);
1844 }};
1845 }
1846
1847 #[test]
1848 fn test_filter_optimise() {
1849 sketching::test_init();
1850 filter_optimise_assert!(
1852 f_and(vec![f_and(vec![f_eq(
1853 Attribute::Class,
1854 EntryClass::TestClass.into()
1855 )])]),
1856 f_eq(Attribute::Class, EntryClass::TestClass.into())
1857 );
1858
1859 filter_optimise_assert!(
1860 f_or(vec![f_or(vec![f_eq(
1861 Attribute::Class,
1862 EntryClass::TestClass.into()
1863 )])]),
1864 f_eq(Attribute::Class, EntryClass::TestClass.into())
1865 );
1866
1867 filter_optimise_assert!(
1868 f_and(vec![f_or(vec![f_and(vec![f_eq(
1869 Attribute::Class,
1870 EntryClass::TestClass.to_partialvalue()
1871 )])])]),
1872 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue())
1873 );
1874
1875 filter_optimise_assert!(
1877 f_and(vec![
1878 f_and(vec![f_eq(
1879 Attribute::Class,
1880 EntryClass::TestClass.to_partialvalue()
1881 )]),
1882 f_sub(Attribute::Class, PartialValue::new_iutf8("te")),
1883 f_pres(Attribute::Class),
1884 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue())
1885 ]),
1886 f_and(vec![
1887 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue()),
1888 f_pres(Attribute::Class),
1889 f_sub(Attribute::Class, PartialValue::new_iutf8("te")),
1890 ])
1891 );
1892
1893 filter_optimise_assert!(
1895 f_and(vec![
1896 f_and(vec![
1897 f_eq(Attribute::Class, PartialValue::new_iutf8("foo")),
1898 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue()),
1899 f_eq(Attribute::Uid, PartialValue::new_iutf8("bar")),
1900 ]),
1901 f_sub(Attribute::Class, PartialValue::new_iutf8("te")),
1902 f_pres(Attribute::Class),
1903 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue())
1904 ]),
1905 f_and(vec![
1906 f_eq(Attribute::Class, PartialValue::new_iutf8("foo")),
1907 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue()),
1908 f_pres(Attribute::Class),
1909 f_eq(Attribute::Uid, PartialValue::new_iutf8("bar")),
1910 f_sub(Attribute::Class, PartialValue::new_iutf8("te")),
1911 ])
1912 );
1913
1914 filter_optimise_assert!(
1915 f_or(vec![
1916 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue()),
1917 f_pres(Attribute::Class),
1918 f_sub(Attribute::Class, PartialValue::new_iutf8("te")),
1919 f_or(vec![f_eq(
1920 Attribute::Class,
1921 EntryClass::TestClass.to_partialvalue()
1922 )]),
1923 ]),
1924 f_or(vec![
1925 f_sub(Attribute::Class, PartialValue::new_iutf8("te")),
1926 f_pres(Attribute::Class),
1927 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue())
1928 ])
1929 );
1930
1931 filter_optimise_assert!(
1933 f_or(vec![
1934 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue()),
1935 f_and(vec![
1936 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue()),
1937 f_eq(Attribute::Term, EntryClass::TestClass.to_partialvalue()),
1938 f_or(vec![f_eq(
1939 Attribute::Class,
1940 EntryClass::TestClass.to_partialvalue()
1941 )])
1942 ]),
1943 ]),
1944 f_or(vec![
1945 f_and(vec![
1946 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue()),
1947 f_eq(Attribute::Term, EntryClass::TestClass.to_partialvalue())
1948 ]),
1949 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue()),
1950 ])
1951 );
1952 }
1953
1954 #[test]
1955 fn test_filter_eq() {
1956 let f_t1a = filter!(f_pres(Attribute::UserId));
1957 let f_t1b = filter!(f_pres(Attribute::UserId));
1958 let f_t1c = filter!(f_pres(Attribute::NonExist));
1959
1960 assert_eq!(f_t1a, f_t1b);
1961 assert!(f_t1a != f_t1c);
1962 assert!(f_t1b != f_t1c);
1963
1964 let f_t2a = filter!(f_and!([f_pres(Attribute::UserId)]));
1965 let f_t2b = filter!(f_and!([f_pres(Attribute::UserId)]));
1966 let f_t2c = filter!(f_and!([f_pres(Attribute::NonExist)]));
1967 assert_eq!(f_t2a, f_t2b);
1968 assert!(f_t2a != f_t2c);
1969 assert!(f_t2b != f_t2c);
1970
1971 assert!(f_t2c != f_t1a);
1972 assert!(f_t2c != f_t1c);
1973 }
1974
1975 #[test]
1976 fn test_filter_ord() {
1977 let f_t1a = filter_resolved!(f_pres(Attribute::UserId));
1981 let f_t1b = filter_resolved!(f_pres(Attribute::UserId));
1982
1983 assert_eq!(f_t1a.partial_cmp(&f_t1b), Some(Ordering::Equal));
1984 assert_eq!(f_t1b.partial_cmp(&f_t1a), Some(Ordering::Equal));
1985
1986 let f_t2a = filter_resolved!(f_and!([]));
1987 let f_t2b = filter_resolved!(f_and!([]));
1988 assert_eq!(f_t2a.partial_cmp(&f_t2b), Some(Ordering::Equal));
1989 assert_eq!(f_t2b.partial_cmp(&f_t2a), Some(Ordering::Equal));
1990
1991 let f_t3b = filter_resolved!(f_eq(Attribute::UserId, PartialValue::new_iutf8("")));
1994 assert_eq!(f_t1a.partial_cmp(&f_t3b), Some(Ordering::Greater));
1995 assert_eq!(f_t3b.partial_cmp(&f_t1a), Some(Ordering::Less));
1996
1997 let f_t4b = filter_resolved!(f_sub(Attribute::UserId, PartialValue::new_iutf8("")));
1999 assert_eq!(f_t1a.partial_cmp(&f_t4b), Some(Ordering::Less));
2000 assert_eq!(f_t3b.partial_cmp(&f_t4b), Some(Ordering::Less));
2001
2002 assert_eq!(f_t4b.partial_cmp(&f_t1a), Some(Ordering::Greater));
2003 assert_eq!(f_t4b.partial_cmp(&f_t3b), Some(Ordering::Greater));
2004 }
2005
2006 #[test]
2007 fn test_filter_clone() {
2008 let f_t1a = filter_resolved!(f_pres(Attribute::UserId));
2011 let f_t1b = f_t1a.clone();
2012 let f_t1c = filter_resolved!(f_pres(Attribute::NonExist));
2013
2014 assert_eq!(f_t1a, f_t1b);
2015 assert!(f_t1a != f_t1c);
2016
2017 let f_t2a = filter_resolved!(f_and!([f_pres(Attribute::UserId)]));
2018 let f_t2b = f_t2a.clone();
2019 let f_t2c = filter_resolved!(f_and!([f_pres(Attribute::NonExist)]));
2020
2021 assert_eq!(f_t2a, f_t2b);
2022 assert!(f_t2a != f_t2c);
2023 }
2024
2025 #[test]
2026 fn test_lessthan_entry_filter() {
2027 let e = entry_init!(
2028 (Attribute::UserId, Value::new_iutf8("william")),
2029 (
2030 Attribute::Uuid,
2031 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2032 ),
2033 (Attribute::GidNumber, Value::Uint32(1000))
2034 )
2035 .into_sealed_new();
2036
2037 let f_t1a = filter_resolved!(f_lt(Attribute::GidNumber, PartialValue::new_uint32(500)));
2038 assert!(!e.entry_match_no_index(&f_t1a));
2039
2040 let f_t1b = filter_resolved!(f_lt(Attribute::GidNumber, PartialValue::new_uint32(1000)));
2041 assert!(!e.entry_match_no_index(&f_t1b));
2042
2043 let f_t1c = filter_resolved!(f_lt(Attribute::GidNumber, PartialValue::new_uint32(1001)));
2044 assert!(e.entry_match_no_index(&f_t1c));
2045 }
2046
2047 #[test]
2048 fn test_or_entry_filter() {
2049 let e = entry_init!(
2050 (Attribute::UserId, Value::new_iutf8("william")),
2051 (
2052 Attribute::Uuid,
2053 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2054 ),
2055 (Attribute::GidNumber, Value::Uint32(1000))
2056 )
2057 .into_sealed_new();
2058
2059 let f_t1a = filter_resolved!(f_or!([
2060 f_eq(Attribute::UserId, PartialValue::new_iutf8("william")),
2061 f_eq(Attribute::GidNumber, PartialValue::Uint32(1000)),
2062 ]));
2063 assert!(e.entry_match_no_index(&f_t1a));
2064
2065 let f_t2a = filter_resolved!(f_or!([
2066 f_eq(Attribute::UserId, PartialValue::new_iutf8("william")),
2067 f_eq(Attribute::GidNumber, PartialValue::Uint32(1000)),
2068 ]));
2069 assert!(e.entry_match_no_index(&f_t2a));
2070
2071 let f_t3a = filter_resolved!(f_or!([
2072 f_eq(Attribute::UserId, PartialValue::new_iutf8("alice")),
2073 f_eq(Attribute::GidNumber, PartialValue::Uint32(1000)),
2074 ]));
2075 assert!(e.entry_match_no_index(&f_t3a));
2076
2077 let f_t4a = filter_resolved!(f_or!([
2078 f_eq(Attribute::UserId, PartialValue::new_iutf8("alice")),
2079 f_eq(Attribute::GidNumber, PartialValue::Uint32(1001)),
2080 ]));
2081 assert!(!e.entry_match_no_index(&f_t4a));
2082 }
2083
2084 #[test]
2085 fn test_and_entry_filter() {
2086 let e = entry_init!(
2087 (Attribute::UserId, Value::new_iutf8("william")),
2088 (
2089 Attribute::Uuid,
2090 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2091 ),
2092 (Attribute::GidNumber, Value::Uint32(1000))
2093 )
2094 .into_sealed_new();
2095
2096 let f_t1a = filter_resolved!(f_and!([
2097 f_eq(Attribute::UserId, PartialValue::new_iutf8("william")),
2098 f_eq(Attribute::GidNumber, PartialValue::Uint32(1000)),
2099 ]));
2100 assert!(e.entry_match_no_index(&f_t1a));
2101
2102 let f_t2a = filter_resolved!(f_and!([
2103 f_eq(Attribute::UserId, PartialValue::new_iutf8("william")),
2104 f_eq(Attribute::GidNumber, PartialValue::Uint32(1001)),
2105 ]));
2106 assert!(!e.entry_match_no_index(&f_t2a));
2107
2108 let f_t3a = filter_resolved!(f_and!([
2109 f_eq(Attribute::UserId, PartialValue::new_iutf8("alice")),
2110 f_eq(Attribute::GidNumber, PartialValue::Uint32(1000)),
2111 ]));
2112 assert!(!e.entry_match_no_index(&f_t3a));
2113
2114 let f_t4a = filter_resolved!(f_and!([
2115 f_eq(Attribute::UserId, PartialValue::new_iutf8("alice")),
2116 f_eq(Attribute::GidNumber, PartialValue::Uint32(1001)),
2117 ]));
2118 assert!(!e.entry_match_no_index(&f_t4a));
2119 }
2120
2121 #[test]
2122 fn test_not_entry_filter() {
2123 let e1 = entry_init!(
2124 (Attribute::UserId, Value::new_iutf8("william")),
2125 (
2126 Attribute::Uuid,
2127 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2128 ),
2129 (Attribute::GidNumber, Value::Uint32(1000))
2130 )
2131 .into_sealed_new();
2132
2133 let f_t1a = filter_resolved!(f_andnot(f_eq(
2134 Attribute::UserId,
2135 PartialValue::new_iutf8("alice")
2136 )));
2137 assert!(e1.entry_match_no_index(&f_t1a));
2138
2139 let f_t2a = filter_resolved!(f_andnot(f_eq(
2140 Attribute::UserId,
2141 PartialValue::new_iutf8("william")
2142 )));
2143 assert!(!e1.entry_match_no_index(&f_t2a));
2144 }
2145
2146 #[test]
2147 fn test_nested_entry_filter() {
2148 let e1 = entry_init!(
2149 (Attribute::Class, EntryClass::Person.to_value().clone()),
2150 (
2151 Attribute::Uuid,
2152 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2153 ),
2154 (Attribute::GidNumber, Value::Uint32(1000))
2155 )
2156 .into_sealed_new();
2157
2158 let e2 = entry_init!(
2159 (Attribute::Class, EntryClass::Person.to_value().clone()),
2160 (
2161 Attribute::Uuid,
2162 Value::Uuid(uuid::uuid!("4b6228ab-1dbe-42a4-a9f5-f6368222438e"))
2163 ),
2164 (Attribute::GidNumber, Value::Uint32(1001))
2165 )
2166 .into_sealed_new();
2167
2168 let e3 = entry_init!(
2169 (Attribute::Class, EntryClass::Person.to_value()),
2170 (
2171 Attribute::Uuid,
2172 Value::Uuid(uuid::uuid!("7b23c99d-c06b-4a9a-a958-3afa56383e1d"))
2173 ),
2174 (Attribute::GidNumber, Value::Uint32(1002))
2175 )
2176 .into_sealed_new();
2177
2178 let e4 = entry_init!(
2179 (Attribute::Class, EntryClass::Group.to_value()),
2180 (
2181 Attribute::Uuid,
2182 Value::Uuid(uuid::uuid!("21d816b5-1f6a-4696-b7c1-6ed06d22ed81"))
2183 ),
2184 (Attribute::GidNumber, Value::Uint32(1000))
2185 )
2186 .into_sealed_new();
2187
2188 let f_t1a = filter_resolved!(f_and!([
2189 f_eq(Attribute::Class, EntryClass::Person.into()),
2190 f_or!([
2191 f_eq(Attribute::GidNumber, PartialValue::Uint32(1001)),
2192 f_eq(Attribute::GidNumber, PartialValue::Uint32(1000))
2193 ])
2194 ]));
2195
2196 assert!(e1.entry_match_no_index(&f_t1a));
2197 assert!(e2.entry_match_no_index(&f_t1a));
2198 assert!(!e3.entry_match_no_index(&f_t1a));
2199 assert!(!e4.entry_match_no_index(&f_t1a));
2200 }
2201
2202 #[test]
2203 fn test_attr_set_filter() {
2204 let mut f_expect = BTreeSet::new();
2205 f_expect.insert(Attribute::from("userid"));
2206 f_expect.insert(Attribute::Class);
2207 let f_t1a = filter_valid!(f_and!([
2210 f_eq(Attribute::UserId, PartialValue::new_iutf8("alice")),
2211 f_eq(Attribute::Class, PartialValue::new_iutf8("1001")),
2212 ]));
2213
2214 assert_eq!(f_t1a.get_attr_set(), f_expect);
2215
2216 let f_t2a = filter_valid!(f_and!([
2217 f_eq(Attribute::UserId, PartialValue::new_iutf8("alice")),
2218 f_eq(Attribute::Class, PartialValue::new_iutf8("1001")),
2219 f_eq(Attribute::UserId, PartialValue::new_iutf8("claire")),
2220 ]));
2221
2222 assert_eq!(f_t2a.get_attr_set(), f_expect);
2223 }
2224
2225 #[qs_test]
2226 async fn test_filter_resolve_value(server: &QueryServer) {
2227 let time_p1 = duration_from_epoch_now();
2228 let time_p2 = time_p1 + Duration::from_secs(CHANGELOG_MAX_AGE * 2);
2229 let time_p3 = time_p2 + Duration::from_secs(CHANGELOG_MAX_AGE * 2);
2230
2231 let mut server_txn = server.write(time_p1).await.expect("txn");
2232
2233 let e1 = entry_init!(
2234 (Attribute::Class, EntryClass::Object.to_value()),
2235 (Attribute::Class, EntryClass::Account.to_value()),
2236 (Attribute::Class, EntryClass::Person.to_value()),
2237 (Attribute::Name, Value::new_iname("testperson1")),
2238 (
2239 Attribute::Uuid,
2240 Value::Uuid(uuid::uuid!("cc8e95b4-c24f-4d68-ba54-8bed76f63930"))
2241 ),
2242 (Attribute::Description, Value::new_utf8s("testperson1")),
2243 (Attribute::DisplayName, Value::new_utf8s("testperson1"))
2244 );
2245
2246 let e2 = entry_init!(
2247 (Attribute::Class, EntryClass::Object.to_value()),
2248 (Attribute::Class, EntryClass::Account.to_value()),
2249 (Attribute::Class, EntryClass::Person.to_value()),
2250 (Attribute::Name, Value::new_iname("testperson2")),
2251 (
2252 Attribute::Uuid,
2253 Value::Uuid(uuid::uuid!("a67c0c71-0b35-4218-a6b0-22d23d131d27"))
2254 ),
2255 (Attribute::Description, Value::new_utf8s("testperson2")),
2256 (Attribute::DisplayName, Value::new_utf8s("testperson2"))
2257 );
2258
2259 let e_ts = entry_init!(
2261 (Attribute::Class, EntryClass::Object.to_value()),
2262 (Attribute::Class, EntryClass::Account.to_value()),
2263 (Attribute::Class, EntryClass::Person.to_value()),
2264 (Attribute::Name, Value::new_iname("testperson3")),
2265 (
2266 Attribute::Uuid,
2267 Value::Uuid(uuid!("9557f49c-97a5-4277-a9a5-097d17eb8317"))
2268 ),
2269 (Attribute::Description, Value::new_utf8s("testperson3")),
2270 (Attribute::DisplayName, Value::new_utf8s("testperson3"))
2271 );
2272
2273 let ce = CreateEvent::new_internal(vec![e1, e2, e_ts]);
2274 let cr = server_txn.create(&ce);
2275 assert!(cr.is_ok());
2276
2277 let de_sin = DeleteEvent::new_internal_invalid(filter!(f_or!([f_eq(
2278 Attribute::Name,
2279 PartialValue::new_iname("testperson3")
2280 )])));
2281 assert!(server_txn.delete(&de_sin).is_ok());
2282
2283 assert!(server_txn.commit().is_ok());
2285
2286 let mut server_txn = server.write(time_p2).await.expect("txn");
2288 assert!(server_txn.purge_recycled().is_ok());
2289 assert!(server_txn.commit().is_ok());
2290
2291 let mut server_txn = server.write(time_p3).await.expect("txn");
2292 assert!(server_txn.purge_tombstones().is_ok());
2293
2294 let t1 = vs_utf8!["teststring".to_string()] as _;
2298 let r1 = server_txn.resolve_valueset(&t1);
2299 assert_eq!(r1, Ok(vec!["teststring".to_string()]));
2300
2301 let t_uuid = vs_refer![uuid!("cc8e95b4-c24f-4d68-ba54-8bed76f63930")] as _;
2303 let r_uuid = server_txn.resolve_valueset(&t_uuid);
2304 debug!("{:?}", r_uuid);
2305 assert_eq!(r_uuid, Ok(vec!["testperson1@example.com".to_string()]));
2306
2307 let t_uuid = vs_refer![uuid!("a67c0c71-0b35-4218-a6b0-22d23d131d27")] as _;
2309 let r_uuid = server_txn.resolve_valueset(&t_uuid);
2310 debug!("{:?}", r_uuid);
2311 assert_eq!(r_uuid, Ok(vec!["testperson2@example.com".to_string()]));
2312
2313 let t_uuid_non = vs_refer![uuid!("b83e98f0-3d2e-41d2-9796-d8d993289c86")] as _;
2315 let r_uuid_non = server_txn.resolve_valueset(&t_uuid_non);
2316 debug!("{:?}", r_uuid_non);
2317 assert_eq!(
2318 r_uuid_non,
2319 Ok(vec!["b83e98f0-3d2e-41d2-9796-d8d993289c86".to_string()])
2320 );
2321
2322 let t_uuid_ts = vs_refer![uuid!("9557f49c-97a5-4277-a9a5-097d17eb8317")] as _;
2324 let r_uuid_ts = server_txn.resolve_valueset(&t_uuid_ts);
2325 debug!("{:?}", r_uuid_ts);
2326 assert_eq!(
2327 r_uuid_ts,
2328 Ok(vec!["9557f49c-97a5-4277-a9a5-097d17eb8317".to_string()])
2329 );
2330 }
2331
2332 #[qs_test]
2333 async fn test_filter_depth_limits(server: &QueryServer) {
2334 let mut r_txn = server.read().await.unwrap();
2335
2336 let mut inv_proto = ProtoFilter::Pres(Attribute::Class.to_string());
2337 for _i in 0..(DEFAULT_LIMIT_FILTER_DEPTH_MAX + 1) {
2338 inv_proto = ProtoFilter::And(vec![inv_proto]);
2339 }
2340
2341 let mut inv_ldap = LdapFilter::Present(Attribute::Class.to_string());
2342 for _i in 0..(DEFAULT_LIMIT_FILTER_DEPTH_MAX + 1) {
2343 inv_ldap = LdapFilter::And(vec![inv_ldap]);
2344 }
2345
2346 let ev = Identity::from_internal();
2347
2348 let res = Filter::from_ro(&ev, &inv_proto, &mut r_txn);
2350 assert_eq!(res, Err(OperationError::ResourceLimit));
2351
2352 let res = Filter::from_ldap_ro(&ev, &inv_ldap, &mut r_txn);
2354 assert_eq!(res, Err(OperationError::ResourceLimit));
2355
2356 std::mem::drop(r_txn);
2358
2359 let mut wr_txn = server.write(duration_from_epoch_now()).await.expect("txn");
2361 let res = Filter::from_rw(&ev, &inv_proto, &mut wr_txn);
2362 assert_eq!(res, Err(OperationError::ResourceLimit));
2363 }
2364
2365 #[qs_test]
2366 async fn test_filter_max_element_limits(server: &QueryServer) {
2367 const LIMIT: usize = 4;
2368 let mut r_txn = server.read().await.unwrap();
2369
2370 let inv_proto = ProtoFilter::And(
2371 (0..(LIMIT * 2))
2372 .map(|_| ProtoFilter::Pres(Attribute::Class.to_string()))
2373 .collect(),
2374 );
2375
2376 let inv_ldap = LdapFilter::And(
2377 (0..(LIMIT * 2))
2378 .map(|_| LdapFilter::Present(Attribute::Class.to_string()))
2379 .collect(),
2380 );
2381
2382 let mut ev = Identity::from_internal();
2383 ev.limits_mut().filter_max_elements = LIMIT;
2384
2385 let res = Filter::from_ro(&ev, &inv_proto, &mut r_txn);
2387 assert_eq!(res, Err(OperationError::ResourceLimit));
2388
2389 let res = Filter::from_ldap_ro(&ev, &inv_ldap, &mut r_txn);
2391 assert_eq!(res, Err(OperationError::ResourceLimit));
2392
2393 std::mem::drop(r_txn);
2395
2396 let mut wr_txn = server.write(duration_from_epoch_now()).await.expect("txn");
2398 let res = Filter::from_rw(&ev, &inv_proto, &mut wr_txn);
2399 assert_eq!(res, Err(OperationError::ResourceLimit));
2400 }
2401}