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::client::{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_or(vs: Vec<FC>) -> FC {
68 FC::Or(vs)
69}
70
71pub fn f_and(vs: Vec<FC>) -> FC {
72 FC::And(vs)
73}
74
75pub fn f_inc(vs: Vec<FC>) -> FC {
76 FC::Inclusion(vs)
77}
78
79pub fn f_andnot(fc: FC) -> FC {
80 FC::AndNot(Box::new(fc))
81}
82
83pub fn f_self() -> FC {
84 FC::SelfUuid
85}
86
87pub fn f_invalid(a: Attribute) -> FC {
88 FC::Invalid(a)
89}
90
91pub fn f_id(uuid: &str) -> FC {
92 let uf = Uuid::parse_str(uuid)
93 .ok()
94 .map(|u| FC::Eq(Attribute::Uuid, PartialValue::Uuid(u)));
95 let spnf = PartialValue::new_spn_s(uuid).map(|spn| FC::Eq(Attribute::Spn, spn));
96 let nf = FC::Eq(Attribute::Name, PartialValue::new_iname(uuid));
97 let f: Vec<_> = iter::once(uf)
98 .chain(iter::once(spnf))
99 .flatten()
100 .chain(iter::once(nf))
101 .collect();
102 FC::Or(f)
103}
104
105pub fn f_spn_name(id: &str) -> FC {
106 let spnf = PartialValue::new_spn_s(id).map(|spn| FC::Eq(Attribute::Spn, spn));
107 let nf = FC::Eq(Attribute::Name, PartialValue::new_iname(id));
108 let f: Vec<_> = iter::once(spnf).flatten().chain(iter::once(nf)).collect();
109 FC::Or(f)
110}
111
112#[derive(Clone, Debug, Deserialize)]
115pub enum FC {
116 Eq(Attribute, PartialValue),
117 Cnt(Attribute, PartialValue),
118 Pres(Attribute),
119 LessThan(Attribute, PartialValue),
120 Or(Vec<FC>),
121 And(Vec<FC>),
122 Inclusion(Vec<FC>),
123 AndNot(Box<FC>),
124 SelfUuid,
125 Invalid(Attribute),
126 }
128
129#[derive(Clone, Hash, PartialEq, PartialOrd, Ord, Eq)]
131enum FilterComp {
132 Eq(Attribute, PartialValue),
134 Cnt(Attribute, PartialValue),
135 Stw(Attribute, PartialValue),
136 Enw(Attribute, PartialValue),
137 Pres(Attribute),
138 LessThan(Attribute, PartialValue),
139 Or(Vec<FilterComp>),
140 And(Vec<FilterComp>),
141 Inclusion(Vec<FilterComp>),
142 AndNot(Box<FilterComp>),
143 SelfUuid,
144 Invalid(Attribute),
145 }
148
149impl fmt::Debug for FilterComp {
150 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151 match self {
152 FilterComp::Eq(attr, pv) => {
153 write!(f, "{} eq {:?}", attr, pv)
154 }
155 FilterComp::Cnt(attr, pv) => {
156 write!(f, "{} cnt {:?}", attr, pv)
157 }
158 FilterComp::Stw(attr, pv) => {
159 write!(f, "{} stw {:?}", attr, pv)
160 }
161 FilterComp::Enw(attr, pv) => {
162 write!(f, "{} enw {:?}", attr, pv)
163 }
164 FilterComp::Pres(attr) => {
165 write!(f, "{} pres", attr)
166 }
167 FilterComp::LessThan(attr, pv) => {
168 write!(f, "{} lt {:?}", attr, pv)
169 }
170 FilterComp::And(list) => {
171 write!(f, "(")?;
172 for (i, fc) in list.iter().enumerate() {
173 write!(f, "{:?}", fc)?;
174 if i != list.len() - 1 {
175 write!(f, " and ")?;
176 }
177 }
178 write!(f, ")")
179 }
180 FilterComp::Or(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, " or ")?;
186 }
187 }
188 write!(f, ")")
189 }
190 FilterComp::Inclusion(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, " inc ")?;
196 }
197 }
198 write!(f, ")")
199 }
200 FilterComp::AndNot(inner) => {
201 write!(f, "not ( {:?} )", inner)
202 }
203 FilterComp::SelfUuid => {
204 write!(f, "uuid eq self")
205 }
206 FilterComp::Invalid(attr) => {
207 write!(f, "invalid ( {:?} )", attr)
208 }
209 }
210 }
211}
212
213#[derive(Clone, Eq)]
224pub enum FilterResolved {
225 Eq(Attribute, PartialValue, Option<NonZeroU8>),
227 Cnt(Attribute, PartialValue, Option<NonZeroU8>),
228 Stw(Attribute, PartialValue, Option<NonZeroU8>),
229 Enw(Attribute, PartialValue, Option<NonZeroU8>),
230 Pres(Attribute, Option<NonZeroU8>),
231 LessThan(Attribute, PartialValue, Option<NonZeroU8>),
232 Or(Vec<FilterResolved>, Option<NonZeroU8>),
233 And(Vec<FilterResolved>, Option<NonZeroU8>),
234 Invalid(Attribute),
235 Inclusion(Vec<FilterResolved>, Option<NonZeroU8>),
237 AndNot(Box<FilterResolved>, Option<NonZeroU8>),
238}
239
240impl fmt::Debug for FilterResolved {
241 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242 match self {
243 FilterResolved::Eq(attr, pv, idx) => {
244 write!(
245 f,
246 "(s{} {} eq {:?})",
247 idx.unwrap_or(NonZeroU8::MAX),
248 attr,
249 pv
250 )
251 }
252 FilterResolved::Cnt(attr, pv, idx) => {
253 write!(
254 f,
255 "(s{} {} cnt {:?})",
256 idx.unwrap_or(NonZeroU8::MAX),
257 attr,
258 pv
259 )
260 }
261 FilterResolved::Stw(attr, pv, idx) => {
262 write!(
263 f,
264 "(s{} {} stw {:?})",
265 idx.unwrap_or(NonZeroU8::MAX),
266 attr,
267 pv
268 )
269 }
270 FilterResolved::Enw(attr, pv, idx) => {
271 write!(
272 f,
273 "(s{} {} enw {:?})",
274 idx.unwrap_or(NonZeroU8::MAX),
275 attr,
276 pv
277 )
278 }
279 FilterResolved::Pres(attr, idx) => {
280 write!(f, "(s{} {} pres)", idx.unwrap_or(NonZeroU8::MAX), attr)
281 }
282 FilterResolved::LessThan(attr, pv, idx) => {
283 write!(
284 f,
285 "(s{} {} lt {:?})",
286 idx.unwrap_or(NonZeroU8::MAX),
287 attr,
288 pv
289 )
290 }
291 FilterResolved::And(list, idx) => {
292 write!(f, "(s{} ", idx.unwrap_or(NonZeroU8::MAX))?;
293 for (i, fc) in list.iter().enumerate() {
294 write!(f, "{:?}", fc)?;
295 if i != list.len() - 1 {
296 write!(f, " and ")?;
297 }
298 }
299 write!(f, ")")
300 }
301 FilterResolved::Or(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, " or ")?;
307 }
308 }
309 write!(f, ")")
310 }
311 FilterResolved::Inclusion(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, " inc ")?;
317 }
318 }
319 write!(f, ")")
320 }
321 FilterResolved::AndNot(inner, idx) => {
322 write!(f, "not (s{} {:?})", idx.unwrap_or(NonZeroU8::MAX), inner)
323 }
324 FilterResolved::Invalid(attr) => {
325 write!(f, "{} inv", attr)
326 }
327 }
328 }
329}
330
331#[derive(Debug, Clone, PartialEq, Eq)]
332pub struct FilterInvalid {
334 inner: FilterComp,
335}
336
337#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
338pub struct FilterValid {
340 inner: FilterComp,
341}
342
343#[derive(Clone, PartialEq, Eq)]
344pub struct FilterValidResolved {
345 inner: FilterResolved,
346}
347
348#[derive(Debug)]
349pub enum FilterPlan {
350 Invalid,
351 EqIndexed(Attribute, String),
352 EqUnindexed(Attribute),
353 EqCorrupt(Attribute),
354 SubIndexed(Attribute, String),
355 SubUnindexed(Attribute),
356 SubCorrupt(Attribute),
357 PresIndexed(Attribute),
358 PresUnindexed(Attribute),
359 PresCorrupt(Attribute),
360 LessThanUnindexed(Attribute),
361 OrUnindexed(Vec<FilterPlan>),
362 OrIndexed(Vec<FilterPlan>),
363 OrPartial(Vec<FilterPlan>),
364 OrPartialThreshold(Vec<FilterPlan>),
365 AndEmptyCand(Vec<FilterPlan>),
366 AndIndexed(Vec<FilterPlan>),
367 AndUnindexed(Vec<FilterPlan>),
368 AndPartial(Vec<FilterPlan>),
369 AndPartialThreshold(Vec<FilterPlan>),
370 AndNot(Box<FilterPlan>),
371 InclusionInvalid(Vec<FilterPlan>),
372 InclusionIndexed(Vec<FilterPlan>),
373}
374
375fn fmt_filterplan_set(f: &mut fmt::Formatter<'_>, name: &str, plan: &[FilterPlan]) -> fmt::Result {
379 write!(f, "{name}(")?;
380 for item in plan {
381 write!(f, "{}, ", item)?;
382 }
383 write!(f, ")")
384}
385
386impl fmt::Display for FilterPlan {
387 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
388 match self {
389 Self::Invalid => write!(f, "Invalid"),
390 Self::EqIndexed(attr, _) => write!(f, "EqIndexed({attr})"),
391 Self::EqCorrupt(attr) => write!(f, "EqCorrupt({attr})"),
392 Self::EqUnindexed(attr) => write!(f, "EqUnindexed({attr})"),
393
394 Self::SubIndexed(attr, _) => write!(f, "SubIndexed({attr})"),
395 Self::SubCorrupt(attr) => write!(f, "SubCorrupt({attr})"),
396 Self::SubUnindexed(attr) => write!(f, "SubUnindexed({attr})"),
397
398 Self::PresIndexed(attr) => write!(f, "PresIndexed({attr})"),
399 Self::PresCorrupt(attr) => write!(f, "PresCorrupt({attr})"),
400 Self::PresUnindexed(attr) => write!(f, "PresUnindexed({attr})"),
401
402 Self::LessThanUnindexed(attr) => write!(f, "LessThanUnindexed({attr})"),
403
404 Self::OrUnindexed(plan) => fmt_filterplan_set(f, "OrUnindexed", plan),
405 Self::OrIndexed(plan) => write!(f, "OrIndexed(len={})", plan.len()),
406 Self::OrPartial(plan) => fmt_filterplan_set(f, "OrPartial", plan),
407 Self::OrPartialThreshold(plan) => fmt_filterplan_set(f, "OrPartialThreshold", plan),
408
409 Self::AndEmptyCand(plan) => write!(f, "AndEmptyCand(len={})", plan.len()),
410 Self::AndUnindexed(plan) => fmt_filterplan_set(f, "AndUnindexed", plan),
411 Self::AndIndexed(plan) => write!(f, "AndIndexed(len={})", plan.len()),
412 Self::AndPartial(plan) => fmt_filterplan_set(f, "AndPartial", plan),
413 Self::AndPartialThreshold(plan) => fmt_filterplan_set(f, "AndPartialThreshold", plan),
414
415 Self::AndNot(plan) => write!(f, "AndNot({plan})"),
416
417 Self::InclusionInvalid(plan) => fmt_filterplan_set(f, "InclusionInvalid", plan),
418 Self::InclusionIndexed(plan) => write!(f, "InclusionIndexed(len={})", plan.len()),
419 }
420 }
421}
422
423#[derive(Clone, Hash, Ord, Eq, PartialOrd, PartialEq)]
445pub struct Filter<STATE> {
446 state: STATE,
447}
448
449impl fmt::Debug for Filter<FilterValidResolved> {
450 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
451 writeln!(f, "Filter(Valid) {:?}", self.state.inner)
452 }
453}
454
455impl fmt::Debug for Filter<FilterValid> {
456 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
457 writeln!(f, "Filter(Valid) {:?}", self.state.inner)
458 }
459}
460
461impl fmt::Debug for Filter<FilterInvalid> {
462 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
463 writeln!(f, "Filter(Invalid) {:?}", self.state.inner)
464 }
465}
466
467impl Filter<FilterValidResolved> {
468 #[cfg(test)]
472 fn optimise(&self) -> Self {
473 Filter {
487 state: FilterValidResolved {
488 inner: self.state.inner.optimise(),
489 },
490 }
491 }
492
493 pub fn to_inner(&self) -> &FilterResolved {
503 &self.state.inner
504 }
505}
506
507impl Filter<FilterValid> {
508 pub fn invalidate(self) -> Filter<FilterInvalid> {
509 Filter {
511 state: FilterInvalid {
512 inner: self.state.inner,
513 },
514 }
515 }
516
517 pub fn resolve(
518 &self,
519 ev: &Identity,
520 idxmeta: Option<&IdxMeta>,
521 mut rsv_cache: Option<&mut ResolveFilterCacheReadTxn<'_>>,
522 ) -> Result<Filter<FilterValidResolved>, OperationError> {
523 let cacheable = idxmeta.is_some() && FilterResolved::resolve_cacheable(&self.state.inner);
532
533 let cache_key = if cacheable {
534 if let Some(rcache) = rsv_cache.as_mut() {
536 let cache_key = (ev.get_event_origin_id(), Arc::new(self.clone()));
538 if let Some(f) = rcache.get(&cache_key) {
539 trace!("shortcut: a resolved filter already exists.");
541 return Ok(f.as_ref().clone());
542 };
543 Some(cache_key)
545 } else {
546 None
547 }
548 } else {
549 None
551 };
552
553 let resolved_filt = Filter {
556 state: FilterValidResolved {
557 inner: match idxmeta {
558 Some(idx) => {
559 FilterResolved::resolve_idx(self.state.inner.clone(), ev, &idx.idxkeys)
560 }
561 None => FilterResolved::resolve_no_idx(self.state.inner.clone(), ev),
562 }
563 .map(|f| {
564 match idxmeta {
565 Some(_) => f.optimise(),
567 None => f.fast_optimise(),
569 }
570 })
571 .ok_or(OperationError::FilterUuidResolution)?,
572 },
573 };
574
575 if let Some(cache_key) = cache_key {
578 if let Some(rcache) = rsv_cache.as_mut() {
579 trace!(?resolved_filt, "inserting filter to resolved cache");
580 rcache.insert(cache_key, Arc::new(resolved_filt.clone()));
581 }
582 }
583
584 Ok(resolved_filt)
585 }
586
587 pub fn get_attr_set(&self) -> BTreeSet<Attribute> {
588 let mut r_set = BTreeSet::new();
590 self.state.inner.get_attr_set(&mut r_set);
591 r_set
592 }
593
594 pub fn into_ignore_hidden(self) -> Self {
601 Filter {
603 state: FilterValid {
604 inner: FilterComp::new_ignore_hidden(self.state.inner),
605 },
606 }
607 }
608
609 pub fn into_recycled(self) -> Self {
610 Filter {
612 state: FilterValid {
613 inner: FilterComp::new_recycled(self.state.inner),
614 },
615 }
616 }
617}
618
619impl Filter<FilterInvalid> {
620 pub fn new(inner: FC) -> Self {
621 let fc = FilterComp::new(inner);
622 Filter {
623 state: FilterInvalid { inner: fc },
624 }
625 }
626
627 pub fn new_ignore_hidden(inner: FC) -> Self {
628 let fc = FilterComp::new(inner);
629 Filter {
630 state: FilterInvalid {
631 inner: FilterComp::new_ignore_hidden(fc),
632 },
633 }
634 }
635
636 pub fn new_recycled(inner: FC) -> Self {
637 let fc = FilterComp::new(inner);
639 Filter {
640 state: FilterInvalid {
641 inner: FilterComp::new_recycled(fc),
642 },
643 }
644 }
645
646 pub fn join_parts_and(a: Self, b: Self) -> Self {
647 Filter {
649 state: FilterInvalid {
650 inner: FilterComp::And(vec![a.state.inner, b.state.inner]),
651 },
652 }
653 }
654
655 #[cfg(test)]
658 pub fn into_valid_resolved(self) -> Filter<FilterValidResolved> {
659 let idxmeta = vec![
670 (Attribute::Uuid, IndexType::Equality),
671 (Attribute::Uuid, IndexType::Presence),
672 (Attribute::Name, IndexType::Equality),
673 (Attribute::Name, IndexType::SubString),
674 (Attribute::Name, IndexType::Presence),
675 (Attribute::Class, IndexType::Equality),
676 (Attribute::Class, IndexType::Presence),
677 (Attribute::Member, IndexType::Equality),
678 (Attribute::Member, IndexType::Presence),
679 (Attribute::MemberOf, IndexType::Equality),
680 (Attribute::MemberOf, IndexType::Presence),
681 (Attribute::DirectMemberOf, IndexType::Equality),
682 (Attribute::DirectMemberOf, IndexType::Presence),
683 ];
684
685 let idxmeta_ref = idxmeta.iter().map(|(attr, itype)| (attr, itype)).collect();
686
687 Filter {
688 state: FilterValidResolved {
689 inner: FilterResolved::from_invalid(self.state.inner, &idxmeta_ref),
690 },
691 }
692 }
693
694 #[cfg(test)]
697 pub fn into_valid(self) -> Filter<FilterValid> {
698 Filter {
705 state: FilterValid {
706 inner: self.state.inner,
707 },
708 }
709 }
710
711 pub fn validate(
712 &self,
713 schema: &dyn SchemaTransaction,
714 ) -> Result<Filter<FilterValid>, SchemaError> {
715 Ok(Filter {
718 state: FilterValid {
719 inner: self.state.inner.validate(schema)?,
720 },
721 })
722 }
723
724 #[instrument(name = "filter::from_ro", level = "trace", skip_all)]
728 pub fn from_ro(
729 ev: &Identity,
730 f: &ProtoFilter,
731 qs: &mut QueryServerReadTransaction,
732 ) -> Result<Self, OperationError> {
733 let depth = DEFAULT_LIMIT_FILTER_DEPTH_MAX as usize;
734 let mut elems = ev.limits().filter_max_elements;
735 Ok(Filter {
736 state: FilterInvalid {
737 inner: FilterComp::from_ro(f, qs, depth, &mut elems)?,
738 },
739 })
740 }
741
742 #[instrument(name = "filter::from_rw", level = "trace", skip_all)]
743 pub fn from_rw(
744 ev: &Identity,
745 f: &ProtoFilter,
746 qs: &mut QueryServerWriteTransaction,
747 ) -> Result<Self, OperationError> {
748 let depth = DEFAULT_LIMIT_FILTER_DEPTH_MAX as usize;
749 let mut elems = ev.limits().filter_max_elements;
750 Ok(Filter {
751 state: FilterInvalid {
752 inner: FilterComp::from_rw(f, qs, depth, &mut elems)?,
753 },
754 })
755 }
756
757 #[instrument(name = "filter::from_ldap_ro", level = "trace", skip_all)]
758 pub fn from_ldap_ro(
759 ev: &Identity,
760 f: &LdapFilter,
761 qs: &mut QueryServerReadTransaction,
762 ) -> Result<Self, OperationError> {
763 let depth = DEFAULT_LIMIT_FILTER_DEPTH_MAX as usize;
764 let mut elems = ev.limits().filter_max_elements;
765 Ok(Filter {
766 state: FilterInvalid {
767 inner: FilterComp::from_ldap_ro(f, qs, depth, &mut elems)?,
768 },
769 })
770 }
771
772 #[instrument(name = "filter::from_scim_ro", level = "trace", skip_all)]
773 pub fn from_scim_ro(
774 ev: &Identity,
775 f: &ScimFilter,
776 qs: &mut QueryServerReadTransaction,
777 ) -> Result<Self, OperationError> {
778 let depth = DEFAULT_LIMIT_FILTER_DEPTH_MAX as usize;
779 let mut elems = ev.limits().filter_max_elements;
780 Ok(Filter {
781 state: FilterInvalid {
782 inner: FilterComp::from_scim_ro(f, qs, depth, &mut elems)?,
783 },
784 })
785 }
786}
787
788impl FromStr for Filter<FilterInvalid> {
789 type Err = OperationError;
790 fn from_str(s: &str) -> Result<Self, Self::Err> {
791 let f: FC = serde_json::from_str(s).map_err(|_| OperationError::FilterParseError)?;
792 Ok(Filter {
793 state: FilterInvalid {
794 inner: FilterComp::new(f),
795 },
796 })
797 }
798}
799
800impl FilterComp {
801 fn new(fc: FC) -> Self {
802 match fc {
803 FC::Eq(a, v) => FilterComp::Eq(a, v),
804 FC::Cnt(a, v) => FilterComp::Cnt(a, v),
805 FC::Pres(a) => FilterComp::Pres(a),
806 FC::LessThan(a, v) => FilterComp::LessThan(a, v),
807 FC::Or(v) => FilterComp::Or(v.into_iter().map(FilterComp::new).collect()),
808 FC::And(v) => FilterComp::And(v.into_iter().map(FilterComp::new).collect()),
809 FC::Inclusion(v) => FilterComp::Inclusion(v.into_iter().map(FilterComp::new).collect()),
810 FC::AndNot(b) => FilterComp::AndNot(Box::new(FilterComp::new(*b))),
811 FC::SelfUuid => FilterComp::SelfUuid,
812 FC::Invalid(a) => FilterComp::Invalid(a),
813 }
814 }
815
816 fn new_ignore_hidden(fc: FilterComp) -> Self {
817 FilterComp::And(vec![
818 FilterComp::AndNot(Box::new(FilterComp::Or(vec![
819 FilterComp::Eq(Attribute::Class, EntryClass::Tombstone.into()),
820 FilterComp::Eq(Attribute::Class, EntryClass::Recycled.into()),
821 ]))),
822 fc,
823 ])
824 }
825
826 fn new_recycled(fc: FilterComp) -> Self {
827 FilterComp::And(vec![
828 FilterComp::Eq(Attribute::Class, EntryClass::Recycled.into()),
829 fc,
830 ])
831 }
832
833 fn get_attr_set(&self, r_set: &mut BTreeSet<Attribute>) {
834 match self {
835 FilterComp::Eq(attr, _)
836 | FilterComp::Cnt(attr, _)
837 | FilterComp::Stw(attr, _)
838 | FilterComp::Enw(attr, _)
839 | FilterComp::Pres(attr)
840 | FilterComp::LessThan(attr, _)
841 | FilterComp::Invalid(attr) => {
842 r_set.insert(attr.clone());
843 }
844 FilterComp::Or(vs) => vs.iter().for_each(|f| f.get_attr_set(r_set)),
845 FilterComp::And(vs) => vs.iter().for_each(|f| f.get_attr_set(r_set)),
846 FilterComp::Inclusion(vs) => vs.iter().for_each(|f| f.get_attr_set(r_set)),
847 FilterComp::AndNot(f) => f.get_attr_set(r_set),
848 FilterComp::SelfUuid => {
849 r_set.insert(Attribute::Uuid);
850 }
851 }
852 }
853
854 fn validate(&self, schema: &dyn SchemaTransaction) -> Result<FilterComp, SchemaError> {
855 let schema_attributes = schema.get_attributes();
862 match self {
867 FilterComp::Eq(attr, value) => {
868 match schema_attributes.get(attr) {
871 Some(schema_a) => {
872 schema_a
873 .validate_partialvalue(attr, value)
874 .map(|_| FilterComp::Eq(attr.clone(), value.clone()))
876 }
878 None => Err(SchemaError::InvalidAttribute(attr.to_string())),
879 }
880 }
881 FilterComp::Cnt(attr, value) => {
882 match schema_attributes.get(attr) {
883 Some(schema_a) => {
884 schema_a
885 .validate_partialvalue(attr, value)
886 .map(|_| FilterComp::Cnt(attr.clone(), value.clone()))
888 }
890 None => Err(SchemaError::InvalidAttribute(attr.to_string())),
891 }
892 }
893 FilterComp::Stw(attr, value) => {
894 match schema_attributes.get(attr) {
895 Some(schema_a) => {
896 schema_a
897 .validate_partialvalue(attr, value)
898 .map(|_| FilterComp::Stw(attr.clone(), value.clone()))
900 }
902 None => Err(SchemaError::InvalidAttribute(attr.to_string())),
903 }
904 }
905 FilterComp::Enw(attr, value) => {
906 match schema_attributes.get(attr) {
907 Some(schema_a) => {
908 schema_a
909 .validate_partialvalue(attr, value)
910 .map(|_| FilterComp::Enw(attr.clone(), value.clone()))
912 }
914 None => Err(SchemaError::InvalidAttribute(attr.to_string())),
915 }
916 }
917 FilterComp::Pres(attr) => {
918 match schema_attributes.get(attr) {
919 Some(_attr_name) => {
920 Ok(FilterComp::Pres(attr.clone()))
922 }
923 None => Err(SchemaError::InvalidAttribute(attr.to_string())),
924 }
925 }
926 FilterComp::LessThan(attr, value) => {
927 match schema_attributes.get(attr) {
928 Some(schema_a) => {
929 schema_a
930 .validate_partialvalue(attr, value)
931 .map(|_| FilterComp::LessThan(attr.clone(), value.clone()))
933 }
935 None => Err(SchemaError::InvalidAttribute(attr.to_string())),
936 }
937 }
938 FilterComp::Or(filters) => {
939 if filters.is_empty() {
944 return Err(SchemaError::EmptyFilter);
945 };
946 let x: Result<Vec<_>, _> = filters
947 .iter()
948 .map(|filter| filter.validate(schema))
949 .collect();
950 x.map(FilterComp::Or)
952 }
953 FilterComp::And(filters) => {
954 if filters.is_empty() {
959 return Err(SchemaError::EmptyFilter);
960 };
961 let x: Result<Vec<_>, _> = filters
962 .iter()
963 .map(|filter| filter.validate(schema))
964 .collect();
965 x.map(FilterComp::And)
967 }
968 FilterComp::Inclusion(filters) => {
969 if filters.is_empty() {
970 return Err(SchemaError::EmptyFilter);
971 };
972 let x: Result<Vec<_>, _> = filters
973 .iter()
974 .map(|filter| filter.validate(schema))
975 .collect();
976 x.map(FilterComp::Inclusion)
978 }
979 FilterComp::AndNot(filter) => {
980 filter
982 .validate(schema)
983 .map(|r_filter| FilterComp::AndNot(Box::new(r_filter)))
984 }
985 FilterComp::SelfUuid => {
986 Ok(FilterComp::SelfUuid)
988 }
989 FilterComp::Invalid(attr) => {
990 Ok(FilterComp::Invalid(attr.clone()))
993 }
994 }
995 }
996
997 fn from_ro(
998 f: &ProtoFilter,
999 qs: &mut QueryServerReadTransaction,
1000 depth: usize,
1001 elems: &mut usize,
1002 ) -> Result<Self, OperationError> {
1003 let ndepth = depth.checked_sub(1).ok_or(OperationError::ResourceLimit)?;
1004 Ok(match f {
1005 ProtoFilter::Eq(a, v) => {
1006 let nk = Attribute::from(a.as_str());
1007 let v = qs.clone_partialvalue(&nk, v)?;
1008 FilterComp::Eq(nk, v)
1009 }
1010 ProtoFilter::Cnt(a, v) => {
1011 let nk = Attribute::from(a.as_str());
1012 let v = qs.clone_partialvalue(&nk, v)?;
1013 FilterComp::Cnt(nk, v)
1014 }
1015 ProtoFilter::Pres(a) => {
1016 let nk = Attribute::from(a.as_str());
1017 FilterComp::Pres(nk)
1018 }
1019 ProtoFilter::Or(l) => {
1020 *elems = (*elems)
1021 .checked_sub(l.len())
1022 .ok_or(OperationError::ResourceLimit)?;
1023 FilterComp::Or(
1024 l.iter()
1025 .map(|f| Self::from_ro(f, qs, ndepth, elems))
1026 .collect::<Result<Vec<_>, _>>()?,
1027 )
1028 }
1029 ProtoFilter::And(l) => {
1030 *elems = (*elems)
1031 .checked_sub(l.len())
1032 .ok_or(OperationError::ResourceLimit)?;
1033 FilterComp::And(
1034 l.iter()
1035 .map(|f| Self::from_ro(f, qs, ndepth, elems))
1036 .collect::<Result<Vec<_>, _>>()?,
1037 )
1038 }
1039 ProtoFilter::AndNot(l) => {
1040 *elems = (*elems)
1041 .checked_sub(1)
1042 .ok_or(OperationError::ResourceLimit)?;
1043 FilterComp::AndNot(Box::new(Self::from_ro(l, qs, ndepth, elems)?))
1044 }
1045 ProtoFilter::SelfUuid => FilterComp::SelfUuid,
1046 })
1047 }
1048
1049 fn from_rw(
1050 f: &ProtoFilter,
1051 qs: &mut QueryServerWriteTransaction,
1052 depth: usize,
1053 elems: &mut usize,
1054 ) -> Result<Self, OperationError> {
1055 let ndepth = depth.checked_sub(1).ok_or(OperationError::ResourceLimit)?;
1056 Ok(match f {
1057 ProtoFilter::Eq(a, v) => {
1058 let nk = Attribute::from(a.as_str());
1059 let v = qs.clone_partialvalue(&nk, v)?;
1060 FilterComp::Eq(nk, v)
1061 }
1062 ProtoFilter::Cnt(a, v) => {
1063 let nk = Attribute::from(a.as_str());
1064 let v = qs.clone_partialvalue(&nk, v)?;
1065 FilterComp::Cnt(nk, v)
1066 }
1067 ProtoFilter::Pres(a) => {
1068 let nk = Attribute::from(a.as_str());
1069 FilterComp::Pres(nk)
1070 }
1071 ProtoFilter::Or(l) => {
1072 *elems = (*elems)
1073 .checked_sub(l.len())
1074 .ok_or(OperationError::ResourceLimit)?;
1075 FilterComp::Or(
1076 l.iter()
1077 .map(|f| Self::from_rw(f, qs, ndepth, elems))
1078 .collect::<Result<Vec<_>, _>>()?,
1079 )
1080 }
1081 ProtoFilter::And(l) => {
1082 *elems = (*elems)
1083 .checked_sub(l.len())
1084 .ok_or(OperationError::ResourceLimit)?;
1085 FilterComp::And(
1086 l.iter()
1087 .map(|f| Self::from_rw(f, qs, ndepth, elems))
1088 .collect::<Result<Vec<_>, _>>()?,
1089 )
1090 }
1091 ProtoFilter::AndNot(l) => {
1092 *elems = (*elems)
1093 .checked_sub(1)
1094 .ok_or(OperationError::ResourceLimit)?;
1095
1096 FilterComp::AndNot(Box::new(Self::from_rw(l, qs, ndepth, elems)?))
1097 }
1098 ProtoFilter::SelfUuid => FilterComp::SelfUuid,
1099 })
1100 }
1101
1102 fn from_ldap_ro(
1103 f: &LdapFilter,
1104 qs: &mut QueryServerReadTransaction,
1105 depth: usize,
1106 elems: &mut usize,
1107 ) -> Result<Self, OperationError> {
1108 let ndepth = depth.checked_sub(1).ok_or(OperationError::ResourceLimit)?;
1109 *elems = (*elems)
1110 .checked_sub(1)
1111 .ok_or(OperationError::ResourceLimit)?;
1112 Ok(match f {
1113 LdapFilter::And(l) => FilterComp::And(
1114 l.iter()
1115 .map(|f| Self::from_ldap_ro(f, qs, ndepth, elems))
1116 .collect::<Result<Vec<_>, _>>()?,
1117 ),
1118 LdapFilter::Or(l) => FilterComp::Or(
1119 l.iter()
1120 .map(|f| Self::from_ldap_ro(f, qs, ndepth, elems))
1121 .collect::<Result<Vec<_>, _>>()?,
1122 ),
1123 LdapFilter::Not(l) => {
1124 FilterComp::AndNot(Box::new(Self::from_ldap_ro(l, qs, ndepth, elems)?))
1125 }
1126 LdapFilter::Equality(a, v) => {
1127 let a = ldap_attr_filter_map(a);
1128 let pv = qs.clone_partialvalue(&a, v);
1129
1130 match pv {
1131 Ok(pv) => FilterComp::Eq(a, pv),
1132 Err(_) if a == Attribute::Spn => FilterComp::Invalid(a),
1133 Err(err) => return Err(err),
1134 }
1135 }
1136 LdapFilter::Present(a) => FilterComp::Pres(ldap_attr_filter_map(a)),
1137 LdapFilter::Substring(
1138 a,
1139 LdapSubstringFilter {
1140 initial,
1141 any,
1142 final_,
1143 },
1144 ) => {
1145 let a = ldap_attr_filter_map(a);
1146
1147 let mut terms = Vec::with_capacity(any.len() + 2);
1148 if let Some(ini) = initial {
1149 let v = qs.clone_partialvalue(&a, ini)?;
1150 terms.push(FilterComp::Stw(a.clone(), v));
1151 }
1152
1153 for term in any.iter() {
1154 let v = qs.clone_partialvalue(&a, term)?;
1155 terms.push(FilterComp::Cnt(a.clone(), v));
1156 }
1157
1158 if let Some(fin) = final_ {
1159 let v = qs.clone_partialvalue(&a, fin)?;
1160 terms.push(FilterComp::Enw(a.clone(), v));
1161 }
1162
1163 FilterComp::And(terms)
1164 }
1165 LdapFilter::GreaterOrEqual(_, _) => {
1166 admin_error!("Unsupported filter operation - greater or equal");
1167 return Err(OperationError::FilterGeneration);
1168 }
1169 LdapFilter::LessOrEqual(_, _) => {
1170 admin_error!("Unsupported filter operation - less or equal");
1171 return Err(OperationError::FilterGeneration);
1172 }
1173 LdapFilter::Approx(_, _) => {
1174 admin_error!("Unsupported filter operation - approximate");
1175 return Err(OperationError::FilterGeneration);
1176 }
1177 LdapFilter::Extensible(_) => {
1178 admin_error!("Unsupported filter operation - extensible");
1179 return Err(OperationError::FilterGeneration);
1180 }
1181 })
1182 }
1183
1184 fn from_scim_ro(
1185 f: &ScimFilter,
1186 qs: &mut QueryServerReadTransaction,
1187 depth: usize,
1188 elems: &mut usize,
1189 ) -> Result<Self, OperationError> {
1190 let ndepth = depth.checked_sub(1).ok_or(OperationError::ResourceLimit)?;
1191 *elems = (*elems)
1192 .checked_sub(1)
1193 .ok_or(OperationError::ResourceLimit)?;
1194 Ok(match f {
1195 ScimFilter::Present(ScimAttrPath { a, s: None }) => FilterComp::Pres(a.clone()),
1196 ScimFilter::Equal(ScimAttrPath { a, s: None }, json_value) => {
1197 let pv = qs.resolve_scim_json_get(a, json_value)?;
1198 FilterComp::Eq(a.clone(), pv)
1199 }
1200
1201 ScimFilter::Contains(ScimAttrPath { a, s: None }, json_value) => {
1202 let pv = qs.resolve_scim_json_get(a, json_value)?;
1203 FilterComp::Cnt(a.clone(), pv)
1204 }
1205 ScimFilter::StartsWith(ScimAttrPath { a, s: None }, json_value) => {
1206 let pv = qs.resolve_scim_json_get(a, json_value)?;
1207 FilterComp::Stw(a.clone(), pv)
1208 }
1209 ScimFilter::EndsWith(ScimAttrPath { a, s: None }, json_value) => {
1210 let pv = qs.resolve_scim_json_get(a, json_value)?;
1211 FilterComp::Enw(a.clone(), pv)
1212 }
1213 ScimFilter::Greater(ScimAttrPath { a, s: None }, json_value) => {
1214 let pv = qs.resolve_scim_json_get(a, json_value)?;
1215 FilterComp::And(vec![
1217 FilterComp::Pres(a.clone()),
1218 FilterComp::AndNot(Box::new(FilterComp::Or(vec![
1219 FilterComp::LessThan(a.clone(), pv.clone()),
1220 FilterComp::Eq(a.clone(), pv),
1221 ]))),
1222 ])
1223 }
1224 ScimFilter::Less(ScimAttrPath { a, s: None }, json_value) => {
1225 let pv = qs.resolve_scim_json_get(a, json_value)?;
1226 FilterComp::LessThan(a.clone(), pv)
1227 }
1228 ScimFilter::GreaterOrEqual(ScimAttrPath { a, s: None }, json_value) => {
1229 let pv = qs.resolve_scim_json_get(a, json_value)?;
1230 FilterComp::And(vec![
1232 FilterComp::Pres(a.clone()),
1233 FilterComp::AndNot(Box::new(FilterComp::LessThan(a.clone(), pv.clone()))),
1234 ])
1235 }
1236 ScimFilter::LessOrEqual(ScimAttrPath { a, s: None }, json_value) => {
1237 let pv = qs.resolve_scim_json_get(a, json_value)?;
1238 FilterComp::Or(vec![
1239 FilterComp::LessThan(a.clone(), pv.clone()),
1240 FilterComp::Eq(a.clone(), pv),
1241 ])
1242 }
1243 ScimFilter::Not(f) => {
1244 let f = Self::from_scim_ro(f, qs, ndepth, elems)?;
1245 FilterComp::AndNot(Box::new(f))
1246 }
1247 ScimFilter::Or(left, right) => {
1248 let left = Self::from_scim_ro(left, qs, ndepth, elems)?;
1249 let right = Self::from_scim_ro(right, qs, ndepth, elems)?;
1250 FilterComp::Or(vec![left, right])
1251 }
1252 ScimFilter::And(left, right) => {
1253 let left = Self::from_scim_ro(left, qs, ndepth, elems)?;
1254 let right = Self::from_scim_ro(right, qs, ndepth, elems)?;
1255 FilterComp::And(vec![left, right])
1256 }
1257 ScimFilter::NotEqual(ScimAttrPath { s: None, .. }, _) => {
1258 error!("Unsupported filter operation - not-equal");
1259 return Err(OperationError::FilterGeneration);
1260 }
1261 ScimFilter::Present(ScimAttrPath { s: Some(_), .. })
1262 | ScimFilter::Equal(ScimAttrPath { s: Some(_), .. }, _)
1263 | ScimFilter::NotEqual(ScimAttrPath { s: Some(_), .. }, _)
1264 | ScimFilter::Contains(ScimAttrPath { s: Some(_), .. }, _)
1265 | ScimFilter::StartsWith(ScimAttrPath { s: Some(_), .. }, _)
1266 | ScimFilter::EndsWith(ScimAttrPath { s: Some(_), .. }, _)
1267 | ScimFilter::Greater(ScimAttrPath { s: Some(_), .. }, _)
1268 | ScimFilter::Less(ScimAttrPath { s: Some(_), .. }, _)
1269 | ScimFilter::GreaterOrEqual(ScimAttrPath { s: Some(_), .. }, _)
1270 | ScimFilter::LessOrEqual(ScimAttrPath { s: Some(_), .. }, _) => {
1271 error!("Unsupported filter operation - sub-attribute");
1272 return Err(OperationError::FilterGeneration);
1273 }
1274 ScimFilter::Complex(..) => {
1275 error!("Unsupported filter operation - complex");
1276 return Err(OperationError::FilterGeneration);
1277 }
1278 })
1279 }
1280}
1281
1282#[cfg(test)]
1308impl PartialOrd for Filter<FilterValidResolved> {
1309 fn partial_cmp(&self, rhs: &Filter<FilterValidResolved>) -> Option<Ordering> {
1310 self.state.inner.partial_cmp(&rhs.state.inner)
1311 }
1312}
1313
1314impl PartialEq for FilterResolved {
1315 fn eq(&self, rhs: &FilterResolved) -> bool {
1316 match (self, rhs) {
1317 (FilterResolved::Eq(a1, v1, _), FilterResolved::Eq(a2, v2, _)) => a1 == a2 && v1 == v2,
1318 (FilterResolved::Cnt(a1, v1, _), FilterResolved::Cnt(a2, v2, _)) => {
1319 a1 == a2 && v1 == v2
1320 }
1321 (FilterResolved::Pres(a1, _), FilterResolved::Pres(a2, _)) => a1 == a2,
1322 (FilterResolved::LessThan(a1, v1, _), FilterResolved::LessThan(a2, v2, _)) => {
1323 a1 == a2 && v1 == v2
1324 }
1325 (FilterResolved::And(vs1, _), FilterResolved::And(vs2, _)) => vs1 == vs2,
1326 (FilterResolved::Or(vs1, _), FilterResolved::Or(vs2, _)) => vs1 == vs2,
1327 (FilterResolved::Inclusion(vs1, _), FilterResolved::Inclusion(vs2, _)) => vs1 == vs2,
1328 (FilterResolved::AndNot(f1, _), FilterResolved::AndNot(f2, _)) => f1 == f2,
1329 (_, _) => false,
1330 }
1331 }
1332}
1333
1334impl PartialOrd for FilterResolved {
1335 fn partial_cmp(&self, rhs: &FilterResolved) -> Option<Ordering> {
1336 Some(self.cmp(rhs))
1337 }
1338}
1339
1340impl Ord for FilterResolved {
1341 fn cmp(&self, rhs: &FilterResolved) -> Ordering {
1343 let left_slopey = self.get_slopeyness_factor();
1344 let right_slopey = rhs.get_slopeyness_factor();
1345
1346 let r = match (left_slopey, right_slopey) {
1347 (Some(sfl), Some(sfr)) => sfl.cmp(&sfr),
1348 (Some(_), None) => Ordering::Less,
1349 (None, Some(_)) => Ordering::Greater,
1350 (None, None) => Ordering::Equal,
1351 };
1352
1353 if r == Ordering::Equal {
1360 match (self, rhs) {
1361 (FilterResolved::Eq(a1, v1, _), FilterResolved::Eq(a2, v2, _))
1362 | (FilterResolved::Cnt(a1, v1, _), FilterResolved::Cnt(a2, v2, _))
1363 | (FilterResolved::LessThan(a1, v1, _), FilterResolved::LessThan(a2, v2, _)) => {
1364 match a1.cmp(a2) {
1365 Ordering::Equal => v1.cmp(v2),
1366 o => o,
1367 }
1368 }
1369 (FilterResolved::Pres(a1, _), FilterResolved::Pres(a2, _)) => a1.cmp(a2),
1370 (FilterResolved::Eq(_, _, _), _) => Ordering::Less,
1372 (_, FilterResolved::Eq(_, _, _)) => Ordering::Greater,
1373 (FilterResolved::Pres(_, _), _) => Ordering::Less,
1374 (_, FilterResolved::Pres(_, _)) => Ordering::Greater,
1375 (FilterResolved::LessThan(_, _, _), _) => Ordering::Less,
1376 (_, FilterResolved::LessThan(_, _, _)) => Ordering::Greater,
1377 (FilterResolved::Cnt(_, _, _), _) => Ordering::Less,
1378 (_, FilterResolved::Cnt(_, _, _)) => Ordering::Greater,
1379 (_, _) => Ordering::Equal,
1381 }
1382 } else {
1383 r
1384 }
1385 }
1386}
1387
1388impl FilterResolved {
1389 #[cfg(test)]
1392 fn from_invalid(fc: FilterComp, idxmeta: &HashSet<(&Attribute, &IndexType)>) -> Self {
1393 match fc {
1394 FilterComp::Eq(a, v) => {
1395 let idx = idxmeta.contains(&(&a, &IndexType::Equality));
1396 let idx = NonZeroU8::new(idx as u8);
1397 FilterResolved::Eq(a, v, idx)
1398 }
1399 FilterComp::SelfUuid => panic!("Not possible to resolve SelfUuid in from_invalid!"),
1400 FilterComp::Invalid(attr) => FilterResolved::Invalid(attr),
1401 FilterComp::Cnt(a, v) => {
1402 let idx = idxmeta.contains(&(&a, &IndexType::SubString));
1403 let idx = NonZeroU8::new(idx as u8);
1404 FilterResolved::Cnt(a, v, idx)
1405 }
1406 FilterComp::Stw(a, v) => {
1407 let idx = idxmeta.contains(&(&a, &IndexType::SubString));
1408 let idx = NonZeroU8::new(idx as u8);
1409 FilterResolved::Stw(a, v, idx)
1410 }
1411 FilterComp::Enw(a, v) => {
1412 let idx = idxmeta.contains(&(&a, &IndexType::SubString));
1413 let idx = NonZeroU8::new(idx as u8);
1414 FilterResolved::Enw(a, v, idx)
1415 }
1416 FilterComp::Pres(a) => {
1417 let idx = idxmeta.contains(&(&a, &IndexType::Presence));
1418 FilterResolved::Pres(a, NonZeroU8::new(idx as u8))
1419 }
1420 FilterComp::LessThan(a, v) => {
1421 FilterResolved::LessThan(a, v, None)
1424 }
1425 FilterComp::Or(vs) => FilterResolved::Or(
1426 vs.into_iter()
1427 .map(|v| FilterResolved::from_invalid(v, idxmeta))
1428 .collect(),
1429 None,
1430 ),
1431 FilterComp::And(vs) => FilterResolved::And(
1432 vs.into_iter()
1433 .map(|v| FilterResolved::from_invalid(v, idxmeta))
1434 .collect(),
1435 None,
1436 ),
1437 FilterComp::Inclusion(vs) => FilterResolved::Inclusion(
1438 vs.into_iter()
1439 .map(|v| FilterResolved::from_invalid(v, idxmeta))
1440 .collect(),
1441 None,
1442 ),
1443 FilterComp::AndNot(f) => {
1444 FilterResolved::AndNot(
1450 Box::new(FilterResolved::from_invalid((*f).clone(), idxmeta)),
1451 None,
1452 )
1453 }
1454 }
1455 }
1456
1457 fn resolve_cacheable(fc: &FilterComp) -> bool {
1458 match fc {
1459 FilterComp::Or(vs) | FilterComp::And(vs) | FilterComp::Inclusion(vs) => {
1460 if vs.len() < 8 {
1461 vs.iter().all(FilterResolved::resolve_cacheable)
1462 } else {
1463 false
1465 }
1466 }
1467 FilterComp::AndNot(f) => FilterResolved::resolve_cacheable(f.as_ref()),
1468 FilterComp::Eq(..)
1469 | FilterComp::SelfUuid
1470 | FilterComp::Cnt(..)
1471 | FilterComp::Stw(..)
1472 | FilterComp::Enw(..)
1473 | FilterComp::Pres(_)
1474 | FilterComp::Invalid(_)
1475 | FilterComp::LessThan(..) => true,
1476 }
1477 }
1478
1479 fn resolve_idx(
1480 fc: FilterComp,
1481 ev: &Identity,
1482 idxmeta: &HashMap<IdxKey, IdxSlope>,
1483 ) -> Option<Self> {
1484 match fc {
1485 FilterComp::Eq(a, v) => {
1486 let idxkref = IdxKeyRef::new(&a, &IndexType::Equality);
1487 let idx = idxmeta
1488 .get(&idxkref as &dyn IdxKeyToRef)
1489 .copied()
1490 .and_then(NonZeroU8::new);
1491 Some(FilterResolved::Eq(a, v, idx))
1492 }
1493 FilterComp::SelfUuid => ev.get_uuid().map(|uuid| {
1494 let idxkref = IdxKeyRef::new(Attribute::Uuid.as_ref(), &IndexType::Equality);
1495 let idx = idxmeta
1496 .get(&idxkref as &dyn IdxKeyToRef)
1497 .copied()
1498 .and_then(NonZeroU8::new);
1499 FilterResolved::Eq(Attribute::Uuid, PartialValue::Uuid(uuid), idx)
1500 }),
1501 FilterComp::Cnt(a, v) => {
1502 let idxkref = IdxKeyRef::new(&a, &IndexType::SubString);
1503 let idx = idxmeta
1504 .get(&idxkref as &dyn IdxKeyToRef)
1505 .copied()
1506 .and_then(NonZeroU8::new);
1507 Some(FilterResolved::Cnt(a, v, idx))
1508 }
1509 FilterComp::Stw(a, v) => {
1510 let idxkref = IdxKeyRef::new(&a, &IndexType::SubString);
1511 let idx = idxmeta
1512 .get(&idxkref as &dyn IdxKeyToRef)
1513 .copied()
1514 .and_then(NonZeroU8::new);
1515 Some(FilterResolved::Stw(a, v, idx))
1516 }
1517 FilterComp::Enw(a, v) => {
1518 let idxkref = IdxKeyRef::new(&a, &IndexType::SubString);
1519 let idx = idxmeta
1520 .get(&idxkref as &dyn IdxKeyToRef)
1521 .copied()
1522 .and_then(NonZeroU8::new);
1523 Some(FilterResolved::Enw(a, v, idx))
1524 }
1525 FilterComp::Pres(a) => {
1526 let idxkref = IdxKeyRef::new(&a, &IndexType::Presence);
1527 let idx = idxmeta
1528 .get(&idxkref as &dyn IdxKeyToRef)
1529 .copied()
1530 .and_then(NonZeroU8::new);
1531 Some(FilterResolved::Pres(a, idx))
1532 }
1533 FilterComp::LessThan(a, v) => {
1534 Some(FilterResolved::LessThan(a, v, None))
1536 }
1537 FilterComp::Or(vs) => {
1541 let fi: Option<Vec<_>> = vs
1542 .into_iter()
1543 .map(|f| FilterResolved::resolve_idx(f, ev, idxmeta))
1544 .collect();
1545 fi.map(|fi| FilterResolved::Or(fi, None))
1546 }
1547 FilterComp::And(vs) => {
1548 let fi: Option<Vec<_>> = vs
1549 .into_iter()
1550 .map(|f| FilterResolved::resolve_idx(f, ev, idxmeta))
1551 .collect();
1552 fi.map(|fi| FilterResolved::And(fi, None))
1553 }
1554 FilterComp::Inclusion(vs) => {
1555 let fi: Option<Vec<_>> = vs
1556 .into_iter()
1557 .map(|f| FilterResolved::resolve_idx(f, ev, idxmeta))
1558 .collect();
1559 fi.map(|fi| FilterResolved::Inclusion(fi, None))
1560 }
1561 FilterComp::AndNot(f) => {
1562 FilterResolved::resolve_idx((*f).clone(), ev, idxmeta)
1568 .map(|fi| FilterResolved::AndNot(Box::new(fi), None))
1569 }
1570 FilterComp::Invalid(attr) => Some(FilterResolved::Invalid(attr)),
1571 }
1572 }
1573
1574 fn resolve_no_idx(fc: FilterComp, ev: &Identity) -> Option<Self> {
1575 match fc {
1579 FilterComp::Eq(a, v) => {
1580 let idx = matches!(a.as_str(), ATTR_NAME | ATTR_UUID);
1584 let idx = NonZeroU8::new(idx as u8);
1585 Some(FilterResolved::Eq(a, v, idx))
1586 }
1587 FilterComp::SelfUuid => ev.get_uuid().map(|uuid| {
1588 FilterResolved::Eq(
1589 Attribute::Uuid,
1590 PartialValue::Uuid(uuid),
1591 NonZeroU8::new(true as u8),
1592 )
1593 }),
1594 FilterComp::Cnt(a, v) => Some(FilterResolved::Cnt(a, v, None)),
1595 FilterComp::Stw(a, v) => Some(FilterResolved::Stw(a, v, None)),
1596 FilterComp::Enw(a, v) => Some(FilterResolved::Enw(a, v, None)),
1597 FilterComp::Pres(a) => Some(FilterResolved::Pres(a, None)),
1598 FilterComp::LessThan(a, v) => Some(FilterResolved::LessThan(a, v, None)),
1599 FilterComp::Or(vs) => {
1600 let fi: Option<Vec<_>> = vs
1601 .into_iter()
1602 .map(|f| FilterResolved::resolve_no_idx(f, ev))
1603 .collect();
1604 fi.map(|fi| FilterResolved::Or(fi, None))
1605 }
1606 FilterComp::And(vs) => {
1607 let fi: Option<Vec<_>> = vs
1608 .into_iter()
1609 .map(|f| FilterResolved::resolve_no_idx(f, ev))
1610 .collect();
1611 fi.map(|fi| FilterResolved::And(fi, None))
1612 }
1613 FilterComp::Inclusion(vs) => {
1614 let fi: Option<Vec<_>> = vs
1615 .into_iter()
1616 .map(|f| FilterResolved::resolve_no_idx(f, ev))
1617 .collect();
1618 fi.map(|fi| FilterResolved::Inclusion(fi, None))
1619 }
1620 FilterComp::AndNot(f) => {
1621 FilterResolved::resolve_no_idx((*f).clone(), ev)
1627 .map(|fi| FilterResolved::AndNot(Box::new(fi), None))
1628 }
1629 FilterComp::Invalid(attr) => Some(FilterResolved::Invalid(attr)),
1630 }
1631 }
1632
1633 fn fast_optimise(self) -> Self {
1635 match self {
1636 FilterResolved::Inclusion(mut f_list, _) => {
1637 f_list.sort_unstable();
1638 f_list.dedup();
1639 let sf = f_list.last().and_then(|f| f.get_slopeyness_factor());
1640 FilterResolved::Inclusion(f_list, sf)
1641 }
1642 FilterResolved::And(mut f_list, _) => {
1643 f_list.sort_unstable();
1644 f_list.dedup();
1645 let sf = f_list.first().and_then(|f| f.get_slopeyness_factor());
1646 FilterResolved::And(f_list, sf)
1647 }
1648 v => v,
1649 }
1650 }
1651
1652 fn optimise(&self) -> Self {
1653 match self {
1655 FilterResolved::Inclusion(f_list, _) => {
1656 let (f_list_inc, mut f_list_new): (Vec<_>, Vec<_>) = f_list
1658 .iter()
1659 .map(|f_ref| f_ref.optimise())
1660 .partition(|f| matches!(f, FilterResolved::Inclusion(_, _)));
1661
1662 f_list_inc.into_iter().for_each(|fc| {
1663 if let FilterResolved::Inclusion(mut l, _) = fc {
1664 f_list_new.append(&mut l)
1665 }
1666 });
1667 f_list_new.sort_unstable();
1669 f_list_new.dedup();
1670 let sf = f_list_new.last().and_then(|f| f.get_slopeyness_factor());
1672 FilterResolved::Inclusion(f_list_new, sf)
1673 }
1674 FilterResolved::And(f_list, _) => {
1675 let (f_list_and, mut f_list_new): (Vec<_>, Vec<_>) = f_list
1677 .iter()
1678 .map(|f_ref| f_ref.optimise())
1679 .partition(|f| matches!(f, FilterResolved::And(_, _)));
1680
1681 f_list_and.into_iter().for_each(|fc| {
1694 if let FilterResolved::And(mut l, _) = fc {
1695 f_list_new.append(&mut l)
1696 }
1697 });
1698
1699 if f_list_new.len() == 1 {
1701 f_list_new.remove(0)
1702 } else {
1703 f_list_new.sort_unstable();
1705 f_list_new.dedup();
1706 let sf = f_list_new.first().and_then(|f| f.get_slopeyness_factor());
1710 FilterResolved::And(f_list_new, sf)
1713 }
1714 }
1715 FilterResolved::Or(f_list, _) => {
1716 let (f_list_or, mut f_list_new): (Vec<_>, Vec<_>) = f_list
1717 .iter()
1718 .map(|f_ref| f_ref.optimise())
1720 .partition(|f| matches!(f, FilterResolved::Or(_, _)));
1722
1723 f_list_or.into_iter().for_each(|fc| {
1725 if let FilterResolved::Or(mut l, _) = fc {
1726 f_list_new.append(&mut l)
1727 }
1728 });
1729
1730 if f_list_new.len() == 1 {
1732 f_list_new.remove(0)
1733 } else {
1734 #[allow(clippy::unnecessary_sort_by)]
1741 f_list_new.sort_unstable_by(|a, b| b.cmp(a));
1742 f_list_new.dedup();
1743 let sf = f_list_new.last().and_then(|f| f.get_slopeyness_factor());
1745 FilterResolved::Or(f_list_new, sf)
1746 }
1747 }
1748 f => f.clone(),
1749 }
1750 }
1751
1752 pub fn is_andnot(&self) -> bool {
1753 matches!(self, FilterResolved::AndNot(_, _))
1754 }
1755
1756 #[inline(always)]
1757 fn get_slopeyness_factor(&self) -> Option<NonZeroU8> {
1758 match self {
1759 FilterResolved::Eq(_, _, sf)
1760 | FilterResolved::Cnt(_, _, sf)
1761 | FilterResolved::Stw(_, _, sf)
1762 | FilterResolved::Enw(_, _, sf)
1763 | FilterResolved::Pres(_, sf)
1764 | FilterResolved::LessThan(_, _, sf)
1765 | FilterResolved::Or(_, sf)
1766 | FilterResolved::And(_, sf)
1767 | FilterResolved::Inclusion(_, sf)
1768 | FilterResolved::AndNot(_, sf) => *sf,
1769 FilterResolved::Invalid(_) => NonZeroU8::new(1),
1771 }
1772 }
1773}
1774
1775#[cfg(test)]
1776mod tests {
1777 use std::cmp::{Ordering, PartialOrd};
1778 use std::collections::BTreeSet;
1779 use std::time::Duration;
1780
1781 use kanidm_proto::internal::Filter as ProtoFilter;
1782 use ldap3_proto::simple::LdapFilter;
1783
1784 use crate::event::{CreateEvent, DeleteEvent};
1785 use crate::filter::{Filter, FilterInvalid, DEFAULT_LIMIT_FILTER_DEPTH_MAX};
1786 use crate::prelude::*;
1787
1788 #[test]
1789 fn test_filter_simple() {
1790 let _filt: Filter<FilterInvalid> = filter!(f_eq(Attribute::Class, EntryClass::User.into()));
1792
1793 let _complex_filt: Filter<FilterInvalid> = filter!(f_and!([
1795 f_or!([
1796 f_eq(Attribute::UserId, PartialValue::new_iutf8("test_a")),
1797 f_eq(Attribute::UserId, PartialValue::new_iutf8("test_b")),
1798 ]),
1799 f_sub(Attribute::Class, EntryClass::User.into()),
1800 ]));
1801 }
1802
1803 macro_rules! filter_optimise_assert {
1804 (
1805 $init:expr,
1806 $expect:expr
1807 ) => {{
1808 #[allow(unused_imports)]
1809 use crate::filter::{f_and, f_andnot, f_eq, f_or, f_pres, f_sub};
1810 use crate::filter::{Filter, FilterInvalid};
1811 let f_init: Filter<FilterInvalid> = Filter::new($init);
1812 let f_expect: Filter<FilterInvalid> = Filter::new($expect);
1813 let f_init_r = f_init.into_valid_resolved();
1815 let f_init_o = f_init_r.optimise();
1816 let f_init_e = f_expect.into_valid_resolved();
1817 debug!("--");
1818 debug!("init --> {:?}", f_init_r);
1819 debug!("opt --> {:?}", f_init_o);
1820 debug!("expect --> {:?}", f_init_e);
1821 assert_eq!(f_init_o, f_init_e);
1822 }};
1823 }
1824
1825 #[test]
1826 fn test_filter_optimise() {
1827 sketching::test_init();
1828 filter_optimise_assert!(
1830 f_and(vec![f_and(vec![f_eq(
1831 Attribute::Class,
1832 EntryClass::TestClass.into()
1833 )])]),
1834 f_eq(Attribute::Class, EntryClass::TestClass.into())
1835 );
1836
1837 filter_optimise_assert!(
1838 f_or(vec![f_or(vec![f_eq(
1839 Attribute::Class,
1840 EntryClass::TestClass.into()
1841 )])]),
1842 f_eq(Attribute::Class, EntryClass::TestClass.into())
1843 );
1844
1845 filter_optimise_assert!(
1846 f_and(vec![f_or(vec![f_and(vec![f_eq(
1847 Attribute::Class,
1848 EntryClass::TestClass.to_partialvalue()
1849 )])])]),
1850 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue())
1851 );
1852
1853 filter_optimise_assert!(
1855 f_and(vec![
1856 f_and(vec![f_eq(
1857 Attribute::Class,
1858 EntryClass::TestClass.to_partialvalue()
1859 )]),
1860 f_sub(Attribute::Class, PartialValue::new_class("te")),
1861 f_pres(Attribute::Class),
1862 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue())
1863 ]),
1864 f_and(vec![
1865 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue()),
1866 f_pres(Attribute::Class),
1867 f_sub(Attribute::Class, PartialValue::new_class("te")),
1868 ])
1869 );
1870
1871 filter_optimise_assert!(
1873 f_and(vec![
1874 f_and(vec![
1875 f_eq(Attribute::Class, PartialValue::new_class("foo")),
1876 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue()),
1877 f_eq(Attribute::Uid, PartialValue::new_class("bar")),
1878 ]),
1879 f_sub(Attribute::Class, PartialValue::new_class("te")),
1880 f_pres(Attribute::Class),
1881 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue())
1882 ]),
1883 f_and(vec![
1884 f_eq(Attribute::Class, PartialValue::new_class("foo")),
1885 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue()),
1886 f_pres(Attribute::Class),
1887 f_eq(Attribute::Uid, PartialValue::new_class("bar")),
1888 f_sub(Attribute::Class, PartialValue::new_class("te")),
1889 ])
1890 );
1891
1892 filter_optimise_assert!(
1893 f_or(vec![
1894 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue()),
1895 f_pres(Attribute::Class),
1896 f_sub(Attribute::Class, PartialValue::new_class("te")),
1897 f_or(vec![f_eq(
1898 Attribute::Class,
1899 EntryClass::TestClass.to_partialvalue()
1900 )]),
1901 ]),
1902 f_or(vec![
1903 f_sub(Attribute::Class, PartialValue::new_class("te")),
1904 f_pres(Attribute::Class),
1905 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue())
1906 ])
1907 );
1908
1909 filter_optimise_assert!(
1911 f_or(vec![
1912 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue()),
1913 f_and(vec![
1914 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue()),
1915 f_eq(Attribute::Term, EntryClass::TestClass.to_partialvalue()),
1916 f_or(vec![f_eq(
1917 Attribute::Class,
1918 EntryClass::TestClass.to_partialvalue()
1919 )])
1920 ]),
1921 ]),
1922 f_or(vec![
1923 f_and(vec![
1924 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue()),
1925 f_eq(Attribute::Term, EntryClass::TestClass.to_partialvalue())
1926 ]),
1927 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue()),
1928 ])
1929 );
1930 }
1931
1932 #[test]
1933 fn test_filter_eq() {
1934 let f_t1a = filter!(f_pres(Attribute::UserId));
1935 let f_t1b = filter!(f_pres(Attribute::UserId));
1936 let f_t1c = filter!(f_pres(Attribute::NonExist));
1937
1938 assert_eq!(f_t1a, f_t1b);
1939 assert!(f_t1a != f_t1c);
1940 assert!(f_t1b != f_t1c);
1941
1942 let f_t2a = filter!(f_and!([f_pres(Attribute::UserId)]));
1943 let f_t2b = filter!(f_and!([f_pres(Attribute::UserId)]));
1944 let f_t2c = filter!(f_and!([f_pres(Attribute::NonExist)]));
1945 assert_eq!(f_t2a, f_t2b);
1946 assert!(f_t2a != f_t2c);
1947 assert!(f_t2b != f_t2c);
1948
1949 assert!(f_t2c != f_t1a);
1950 assert!(f_t2c != f_t1c);
1951 }
1952
1953 #[test]
1954 fn test_filter_ord() {
1955 let f_t1a = filter_resolved!(f_pres(Attribute::UserId));
1959 let f_t1b = filter_resolved!(f_pres(Attribute::UserId));
1960
1961 assert_eq!(f_t1a.partial_cmp(&f_t1b), Some(Ordering::Equal));
1962 assert_eq!(f_t1b.partial_cmp(&f_t1a), Some(Ordering::Equal));
1963
1964 let f_t2a = filter_resolved!(f_and!([]));
1965 let f_t2b = filter_resolved!(f_and!([]));
1966 assert_eq!(f_t2a.partial_cmp(&f_t2b), Some(Ordering::Equal));
1967 assert_eq!(f_t2b.partial_cmp(&f_t2a), Some(Ordering::Equal));
1968
1969 let f_t3b = filter_resolved!(f_eq(Attribute::UserId, PartialValue::new_iutf8("")));
1972 assert_eq!(f_t1a.partial_cmp(&f_t3b), Some(Ordering::Greater));
1973 assert_eq!(f_t3b.partial_cmp(&f_t1a), Some(Ordering::Less));
1974
1975 let f_t4b = filter_resolved!(f_sub(Attribute::UserId, PartialValue::new_iutf8("")));
1977 assert_eq!(f_t1a.partial_cmp(&f_t4b), Some(Ordering::Less));
1978 assert_eq!(f_t3b.partial_cmp(&f_t4b), Some(Ordering::Less));
1979
1980 assert_eq!(f_t4b.partial_cmp(&f_t1a), Some(Ordering::Greater));
1981 assert_eq!(f_t4b.partial_cmp(&f_t3b), Some(Ordering::Greater));
1982 }
1983
1984 #[test]
1985 fn test_filter_clone() {
1986 let f_t1a = filter_resolved!(f_pres(Attribute::UserId));
1989 let f_t1b = f_t1a.clone();
1990 let f_t1c = filter_resolved!(f_pres(Attribute::NonExist));
1991
1992 assert_eq!(f_t1a, f_t1b);
1993 assert!(f_t1a != f_t1c);
1994
1995 let f_t2a = filter_resolved!(f_and!([f_pres(Attribute::UserId)]));
1996 let f_t2b = f_t2a.clone();
1997 let f_t2c = filter_resolved!(f_and!([f_pres(Attribute::NonExist)]));
1998
1999 assert_eq!(f_t2a, f_t2b);
2000 assert!(f_t2a != f_t2c);
2001 }
2002
2003 #[test]
2004 fn test_lessthan_entry_filter() {
2005 let e = entry_init!(
2006 (Attribute::UserId, Value::new_iutf8("william")),
2007 (
2008 Attribute::Uuid,
2009 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2010 ),
2011 (Attribute::GidNumber, Value::Uint32(1000))
2012 )
2013 .into_sealed_new();
2014
2015 let f_t1a = filter_resolved!(f_lt(Attribute::GidNumber, PartialValue::new_uint32(500)));
2016 assert!(!e.entry_match_no_index(&f_t1a));
2017
2018 let f_t1b = filter_resolved!(f_lt(Attribute::GidNumber, PartialValue::new_uint32(1000)));
2019 assert!(!e.entry_match_no_index(&f_t1b));
2020
2021 let f_t1c = filter_resolved!(f_lt(Attribute::GidNumber, PartialValue::new_uint32(1001)));
2022 assert!(e.entry_match_no_index(&f_t1c));
2023 }
2024
2025 #[test]
2026 fn test_or_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_or!([
2038 f_eq(Attribute::UserId, PartialValue::new_iutf8("william")),
2039 f_eq(Attribute::GidNumber, PartialValue::Uint32(1000)),
2040 ]));
2041 assert!(e.entry_match_no_index(&f_t1a));
2042
2043 let f_t2a = filter_resolved!(f_or!([
2044 f_eq(Attribute::UserId, PartialValue::new_iutf8("william")),
2045 f_eq(Attribute::GidNumber, PartialValue::Uint32(1000)),
2046 ]));
2047 assert!(e.entry_match_no_index(&f_t2a));
2048
2049 let f_t3a = filter_resolved!(f_or!([
2050 f_eq(Attribute::UserId, PartialValue::new_iutf8("alice")),
2051 f_eq(Attribute::GidNumber, PartialValue::Uint32(1000)),
2052 ]));
2053 assert!(e.entry_match_no_index(&f_t3a));
2054
2055 let f_t4a = filter_resolved!(f_or!([
2056 f_eq(Attribute::UserId, PartialValue::new_iutf8("alice")),
2057 f_eq(Attribute::GidNumber, PartialValue::Uint32(1001)),
2058 ]));
2059 assert!(!e.entry_match_no_index(&f_t4a));
2060 }
2061
2062 #[test]
2063 fn test_and_entry_filter() {
2064 let e = entry_init!(
2065 (Attribute::UserId, Value::new_iutf8("william")),
2066 (
2067 Attribute::Uuid,
2068 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2069 ),
2070 (Attribute::GidNumber, Value::Uint32(1000))
2071 )
2072 .into_sealed_new();
2073
2074 let f_t1a = filter_resolved!(f_and!([
2075 f_eq(Attribute::UserId, PartialValue::new_iutf8("william")),
2076 f_eq(Attribute::GidNumber, PartialValue::Uint32(1000)),
2077 ]));
2078 assert!(e.entry_match_no_index(&f_t1a));
2079
2080 let f_t2a = filter_resolved!(f_and!([
2081 f_eq(Attribute::UserId, PartialValue::new_iutf8("william")),
2082 f_eq(Attribute::GidNumber, PartialValue::Uint32(1001)),
2083 ]));
2084 assert!(!e.entry_match_no_index(&f_t2a));
2085
2086 let f_t3a = filter_resolved!(f_and!([
2087 f_eq(Attribute::UserId, PartialValue::new_iutf8("alice")),
2088 f_eq(Attribute::GidNumber, PartialValue::Uint32(1000)),
2089 ]));
2090 assert!(!e.entry_match_no_index(&f_t3a));
2091
2092 let f_t4a = filter_resolved!(f_and!([
2093 f_eq(Attribute::UserId, PartialValue::new_iutf8("alice")),
2094 f_eq(Attribute::GidNumber, PartialValue::Uint32(1001)),
2095 ]));
2096 assert!(!e.entry_match_no_index(&f_t4a));
2097 }
2098
2099 #[test]
2100 fn test_not_entry_filter() {
2101 let e1 = entry_init!(
2102 (Attribute::UserId, Value::new_iutf8("william")),
2103 (
2104 Attribute::Uuid,
2105 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2106 ),
2107 (Attribute::GidNumber, Value::Uint32(1000))
2108 )
2109 .into_sealed_new();
2110
2111 let f_t1a = filter_resolved!(f_andnot(f_eq(
2112 Attribute::UserId,
2113 PartialValue::new_iutf8("alice")
2114 )));
2115 assert!(e1.entry_match_no_index(&f_t1a));
2116
2117 let f_t2a = filter_resolved!(f_andnot(f_eq(
2118 Attribute::UserId,
2119 PartialValue::new_iutf8("william")
2120 )));
2121 assert!(!e1.entry_match_no_index(&f_t2a));
2122 }
2123
2124 #[test]
2125 fn test_nested_entry_filter() {
2126 let e1 = entry_init!(
2127 (Attribute::Class, EntryClass::Person.to_value().clone()),
2128 (
2129 Attribute::Uuid,
2130 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2131 ),
2132 (Attribute::GidNumber, Value::Uint32(1000))
2133 )
2134 .into_sealed_new();
2135
2136 let e2 = entry_init!(
2137 (Attribute::Class, EntryClass::Person.to_value().clone()),
2138 (
2139 Attribute::Uuid,
2140 Value::Uuid(uuid::uuid!("4b6228ab-1dbe-42a4-a9f5-f6368222438e"))
2141 ),
2142 (Attribute::GidNumber, Value::Uint32(1001))
2143 )
2144 .into_sealed_new();
2145
2146 let e3 = entry_init!(
2147 (Attribute::Class, EntryClass::Person.to_value()),
2148 (
2149 Attribute::Uuid,
2150 Value::Uuid(uuid::uuid!("7b23c99d-c06b-4a9a-a958-3afa56383e1d"))
2151 ),
2152 (Attribute::GidNumber, Value::Uint32(1002))
2153 )
2154 .into_sealed_new();
2155
2156 let e4 = entry_init!(
2157 (Attribute::Class, EntryClass::Group.to_value()),
2158 (
2159 Attribute::Uuid,
2160 Value::Uuid(uuid::uuid!("21d816b5-1f6a-4696-b7c1-6ed06d22ed81"))
2161 ),
2162 (Attribute::GidNumber, Value::Uint32(1000))
2163 )
2164 .into_sealed_new();
2165
2166 let f_t1a = filter_resolved!(f_and!([
2167 f_eq(Attribute::Class, EntryClass::Person.into()),
2168 f_or!([
2169 f_eq(Attribute::GidNumber, PartialValue::Uint32(1001)),
2170 f_eq(Attribute::GidNumber, PartialValue::Uint32(1000))
2171 ])
2172 ]));
2173
2174 assert!(e1.entry_match_no_index(&f_t1a));
2175 assert!(e2.entry_match_no_index(&f_t1a));
2176 assert!(!e3.entry_match_no_index(&f_t1a));
2177 assert!(!e4.entry_match_no_index(&f_t1a));
2178 }
2179
2180 #[test]
2181 fn test_attr_set_filter() {
2182 let mut f_expect = BTreeSet::new();
2183 f_expect.insert(Attribute::from("userid"));
2184 f_expect.insert(Attribute::Class);
2185 let f_t1a = filter_valid!(f_and!([
2188 f_eq(Attribute::UserId, PartialValue::new_iutf8("alice")),
2189 f_eq(Attribute::Class, PartialValue::new_iutf8("1001")),
2190 ]));
2191
2192 assert_eq!(f_t1a.get_attr_set(), f_expect);
2193
2194 let f_t2a = filter_valid!(f_and!([
2195 f_eq(Attribute::UserId, PartialValue::new_iutf8("alice")),
2196 f_eq(Attribute::Class, PartialValue::new_iutf8("1001")),
2197 f_eq(Attribute::UserId, PartialValue::new_iutf8("claire")),
2198 ]));
2199
2200 assert_eq!(f_t2a.get_attr_set(), f_expect);
2201 }
2202
2203 #[qs_test]
2204 async fn test_filter_resolve_value(server: &QueryServer) {
2205 let time_p1 = duration_from_epoch_now();
2206 let time_p2 = time_p1 + Duration::from_secs(CHANGELOG_MAX_AGE * 2);
2207 let time_p3 = time_p2 + Duration::from_secs(CHANGELOG_MAX_AGE * 2);
2208
2209 let mut server_txn = server.write(time_p1).await.expect("txn");
2210
2211 let e1 = entry_init!(
2212 (Attribute::Class, EntryClass::Object.to_value()),
2213 (Attribute::Class, EntryClass::Account.to_value()),
2214 (Attribute::Class, EntryClass::Person.to_value()),
2215 (Attribute::Name, Value::new_iname("testperson1")),
2216 (
2217 Attribute::Uuid,
2218 Value::Uuid(uuid::uuid!("cc8e95b4-c24f-4d68-ba54-8bed76f63930"))
2219 ),
2220 (Attribute::Description, Value::new_utf8s("testperson1")),
2221 (Attribute::DisplayName, Value::new_utf8s("testperson1"))
2222 );
2223
2224 let e2 = entry_init!(
2225 (Attribute::Class, EntryClass::Object.to_value()),
2226 (Attribute::Class, EntryClass::Account.to_value()),
2227 (Attribute::Class, EntryClass::Person.to_value()),
2228 (Attribute::Name, Value::new_iname("testperson2")),
2229 (
2230 Attribute::Uuid,
2231 Value::Uuid(uuid::uuid!("a67c0c71-0b35-4218-a6b0-22d23d131d27"))
2232 ),
2233 (Attribute::Description, Value::new_utf8s("testperson2")),
2234 (Attribute::DisplayName, Value::new_utf8s("testperson2"))
2235 );
2236
2237 let e_ts = entry_init!(
2239 (Attribute::Class, EntryClass::Object.to_value()),
2240 (Attribute::Class, EntryClass::Account.to_value()),
2241 (Attribute::Class, EntryClass::Person.to_value()),
2242 (Attribute::Name, Value::new_iname("testperson3")),
2243 (
2244 Attribute::Uuid,
2245 Value::Uuid(uuid!("9557f49c-97a5-4277-a9a5-097d17eb8317"))
2246 ),
2247 (Attribute::Description, Value::new_utf8s("testperson3")),
2248 (Attribute::DisplayName, Value::new_utf8s("testperson3"))
2249 );
2250
2251 let ce = CreateEvent::new_internal(vec![e1, e2, e_ts]);
2252 let cr = server_txn.create(&ce);
2253 assert!(cr.is_ok());
2254
2255 let de_sin = DeleteEvent::new_internal_invalid(filter!(f_or!([f_eq(
2256 Attribute::Name,
2257 PartialValue::new_iname("testperson3")
2258 )])));
2259 assert!(server_txn.delete(&de_sin).is_ok());
2260
2261 assert!(server_txn.commit().is_ok());
2263
2264 let mut server_txn = server.write(time_p2).await.expect("txn");
2266 assert!(server_txn.purge_recycled().is_ok());
2267 assert!(server_txn.commit().is_ok());
2268
2269 let mut server_txn = server.write(time_p3).await.expect("txn");
2270 assert!(server_txn.purge_tombstones().is_ok());
2271
2272 let t1 = vs_utf8!["teststring".to_string()] as _;
2276 let r1 = server_txn.resolve_valueset(&t1);
2277 assert_eq!(r1, Ok(vec!["teststring".to_string()]));
2278
2279 let t_uuid = vs_refer![uuid!("cc8e95b4-c24f-4d68-ba54-8bed76f63930")] as _;
2281 let r_uuid = server_txn.resolve_valueset(&t_uuid);
2282 debug!("{:?}", r_uuid);
2283 assert_eq!(r_uuid, Ok(vec!["testperson1@example.com".to_string()]));
2284
2285 let t_uuid = vs_refer![uuid!("a67c0c71-0b35-4218-a6b0-22d23d131d27")] as _;
2287 let r_uuid = server_txn.resolve_valueset(&t_uuid);
2288 debug!("{:?}", r_uuid);
2289 assert_eq!(r_uuid, Ok(vec!["testperson2@example.com".to_string()]));
2290
2291 let t_uuid_non = vs_refer![uuid!("b83e98f0-3d2e-41d2-9796-d8d993289c86")] as _;
2293 let r_uuid_non = server_txn.resolve_valueset(&t_uuid_non);
2294 debug!("{:?}", r_uuid_non);
2295 assert_eq!(
2296 r_uuid_non,
2297 Ok(vec!["b83e98f0-3d2e-41d2-9796-d8d993289c86".to_string()])
2298 );
2299
2300 let t_uuid_ts = vs_refer![uuid!("9557f49c-97a5-4277-a9a5-097d17eb8317")] as _;
2302 let r_uuid_ts = server_txn.resolve_valueset(&t_uuid_ts);
2303 debug!("{:?}", r_uuid_ts);
2304 assert_eq!(
2305 r_uuid_ts,
2306 Ok(vec!["9557f49c-97a5-4277-a9a5-097d17eb8317".to_string()])
2307 );
2308 }
2309
2310 #[qs_test]
2311 async fn test_filter_depth_limits(server: &QueryServer) {
2312 let mut r_txn = server.read().await.unwrap();
2313
2314 let mut inv_proto = ProtoFilter::Pres(Attribute::Class.to_string());
2315 for _i in 0..(DEFAULT_LIMIT_FILTER_DEPTH_MAX + 1) {
2316 inv_proto = ProtoFilter::And(vec![inv_proto]);
2317 }
2318
2319 let mut inv_ldap = LdapFilter::Present(Attribute::Class.to_string());
2320 for _i in 0..(DEFAULT_LIMIT_FILTER_DEPTH_MAX + 1) {
2321 inv_ldap = LdapFilter::And(vec![inv_ldap]);
2322 }
2323
2324 let ev = Identity::from_internal();
2325
2326 let res = Filter::from_ro(&ev, &inv_proto, &mut r_txn);
2328 assert_eq!(res, Err(OperationError::ResourceLimit));
2329
2330 let res = Filter::from_ldap_ro(&ev, &inv_ldap, &mut r_txn);
2332 assert_eq!(res, Err(OperationError::ResourceLimit));
2333
2334 std::mem::drop(r_txn);
2336
2337 let mut wr_txn = server.write(duration_from_epoch_now()).await.expect("txn");
2339 let res = Filter::from_rw(&ev, &inv_proto, &mut wr_txn);
2340 assert_eq!(res, Err(OperationError::ResourceLimit));
2341 }
2342
2343 #[qs_test]
2344 async fn test_filter_max_element_limits(server: &QueryServer) {
2345 const LIMIT: usize = 4;
2346 let mut r_txn = server.read().await.unwrap();
2347
2348 let inv_proto = ProtoFilter::And(
2349 (0..(LIMIT * 2))
2350 .map(|_| ProtoFilter::Pres(Attribute::Class.to_string()))
2351 .collect(),
2352 );
2353
2354 let inv_ldap = LdapFilter::And(
2355 (0..(LIMIT * 2))
2356 .map(|_| LdapFilter::Present(Attribute::Class.to_string()))
2357 .collect(),
2358 );
2359
2360 let mut ev = Identity::from_internal();
2361 ev.limits_mut().filter_max_elements = LIMIT;
2362
2363 let res = Filter::from_ro(&ev, &inv_proto, &mut r_txn);
2365 assert_eq!(res, Err(OperationError::ResourceLimit));
2366
2367 let res = Filter::from_ldap_ro(&ev, &inv_ldap, &mut r_txn);
2369 assert_eq!(res, Err(OperationError::ResourceLimit));
2370
2371 std::mem::drop(r_txn);
2373
2374 let mut wr_txn = server.write(duration_from_epoch_now()).await.expect("txn");
2376 let res = Filter::from_rw(&ev, &inv_proto, &mut wr_txn);
2377 assert_eq!(res, Err(OperationError::ResourceLimit));
2378 }
2379}