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 => ev.get_uuid().map(|uuid| {
1506 let idxkref = IdxKeyRef::new(Attribute::Uuid.as_ref(), &IndexType::Equality);
1507 let idx = idxmeta
1508 .get(&idxkref as &dyn IdxKeyToRef)
1509 .copied()
1510 .and_then(NonZeroU8::new);
1511 FilterResolved::Eq(Attribute::Uuid, PartialValue::Uuid(uuid), idx)
1512 }),
1513 FilterComp::Cnt(a, v) => {
1514 let idxkref = IdxKeyRef::new(&a, &IndexType::SubString);
1515 let idx = idxmeta
1516 .get(&idxkref as &dyn IdxKeyToRef)
1517 .copied()
1518 .and_then(NonZeroU8::new);
1519 Some(FilterResolved::Cnt(a, v, idx))
1520 }
1521 FilterComp::Stw(a, v) => {
1522 let idxkref = IdxKeyRef::new(&a, &IndexType::SubString);
1523 let idx = idxmeta
1524 .get(&idxkref as &dyn IdxKeyToRef)
1525 .copied()
1526 .and_then(NonZeroU8::new);
1527 Some(FilterResolved::Stw(a, v, idx))
1528 }
1529 FilterComp::Enw(a, v) => {
1530 let idxkref = IdxKeyRef::new(&a, &IndexType::SubString);
1531 let idx = idxmeta
1532 .get(&idxkref as &dyn IdxKeyToRef)
1533 .copied()
1534 .and_then(NonZeroU8::new);
1535 Some(FilterResolved::Enw(a, v, idx))
1536 }
1537 FilterComp::Pres(a) => {
1538 let idxkref = IdxKeyRef::new(&a, &IndexType::Presence);
1539 let idx = idxmeta
1540 .get(&idxkref as &dyn IdxKeyToRef)
1541 .copied()
1542 .and_then(NonZeroU8::new);
1543 Some(FilterResolved::Pres(a, idx))
1544 }
1545 FilterComp::LessThan(a, v) => {
1546 let idxkref = IdxKeyRef::new(&a, &IndexType::Ordering);
1547 let idx = idxmeta
1548 .get(&idxkref as &dyn IdxKeyToRef)
1549 .copied()
1550 .and_then(NonZeroU8::new);
1551 Some(FilterResolved::LessThan(a, v, idx))
1552 }
1553 FilterComp::Or(vs) => {
1557 let fi: Option<Vec<_>> = vs
1558 .into_iter()
1559 .map(|f| FilterResolved::resolve_idx(f, ev, idxmeta))
1560 .collect();
1561 fi.map(|fi| FilterResolved::Or(fi, None))
1562 }
1563 FilterComp::And(vs) => {
1564 let fi: Option<Vec<_>> = vs
1565 .into_iter()
1566 .map(|f| FilterResolved::resolve_idx(f, ev, idxmeta))
1567 .collect();
1568 fi.map(|fi| FilterResolved::And(fi, None))
1569 }
1570 FilterComp::Inclusion(vs) => {
1571 let fi: Option<Vec<_>> = vs
1572 .into_iter()
1573 .map(|f| FilterResolved::resolve_idx(f, ev, idxmeta))
1574 .collect();
1575 fi.map(|fi| FilterResolved::Inclusion(fi, None))
1576 }
1577 FilterComp::AndNot(f) => {
1578 FilterResolved::resolve_idx((*f).clone(), ev, idxmeta)
1584 .map(|fi| FilterResolved::AndNot(Box::new(fi), None))
1585 }
1586 FilterComp::Invalid(attr) => Some(FilterResolved::Invalid(attr)),
1587 }
1588 }
1589
1590 fn resolve_no_idx(fc: FilterComp, ev: &Identity) -> Option<Self> {
1591 match fc {
1595 FilterComp::Eq(a, v) => {
1596 let idx = matches!(a.as_str(), ATTR_NAME | ATTR_UUID);
1600 let idx = NonZeroU8::new(idx as u8);
1601 Some(FilterResolved::Eq(a, v, idx))
1602 }
1603 FilterComp::SelfUuid => ev.get_uuid().map(|uuid| {
1604 FilterResolved::Eq(
1605 Attribute::Uuid,
1606 PartialValue::Uuid(uuid),
1607 NonZeroU8::new(true as u8),
1608 )
1609 }),
1610 FilterComp::Cnt(a, v) => Some(FilterResolved::Cnt(a, v, None)),
1611 FilterComp::Stw(a, v) => Some(FilterResolved::Stw(a, v, None)),
1612 FilterComp::Enw(a, v) => Some(FilterResolved::Enw(a, v, None)),
1613 FilterComp::Pres(a) => Some(FilterResolved::Pres(a, None)),
1614 FilterComp::LessThan(a, v) => Some(FilterResolved::LessThan(a, v, None)),
1615 FilterComp::Or(vs) => {
1616 let fi: Option<Vec<_>> = vs
1617 .into_iter()
1618 .map(|f| FilterResolved::resolve_no_idx(f, ev))
1619 .collect();
1620 fi.map(|fi| FilterResolved::Or(fi, None))
1621 }
1622 FilterComp::And(vs) => {
1623 let fi: Option<Vec<_>> = vs
1624 .into_iter()
1625 .map(|f| FilterResolved::resolve_no_idx(f, ev))
1626 .collect();
1627 fi.map(|fi| FilterResolved::And(fi, None))
1628 }
1629 FilterComp::Inclusion(vs) => {
1630 let fi: Option<Vec<_>> = vs
1631 .into_iter()
1632 .map(|f| FilterResolved::resolve_no_idx(f, ev))
1633 .collect();
1634 fi.map(|fi| FilterResolved::Inclusion(fi, None))
1635 }
1636 FilterComp::AndNot(f) => {
1637 FilterResolved::resolve_no_idx((*f).clone(), ev)
1643 .map(|fi| FilterResolved::AndNot(Box::new(fi), None))
1644 }
1645 FilterComp::Invalid(attr) => Some(FilterResolved::Invalid(attr)),
1646 }
1647 }
1648
1649 fn fast_optimise(self) -> Self {
1651 match self {
1652 FilterResolved::Inclusion(mut f_list, _) => {
1653 f_list.sort_unstable();
1654 f_list.dedup();
1655 let sf = f_list.last().and_then(|f| f.get_slopeyness_factor());
1656 FilterResolved::Inclusion(f_list, sf)
1657 }
1658 FilterResolved::And(mut f_list, _) => {
1659 f_list.sort_unstable();
1660 f_list.dedup();
1661 let sf = f_list.first().and_then(|f| f.get_slopeyness_factor());
1662 FilterResolved::And(f_list, sf)
1663 }
1664 v => v,
1665 }
1666 }
1667
1668 fn optimise(&self) -> Self {
1669 match self {
1671 FilterResolved::Inclusion(f_list, _) => {
1672 let (f_list_inc, mut f_list_new): (Vec<_>, Vec<_>) = f_list
1674 .iter()
1675 .map(|f_ref| f_ref.optimise())
1676 .partition(|f| matches!(f, FilterResolved::Inclusion(_, _)));
1677
1678 f_list_inc.into_iter().for_each(|fc| {
1679 if let FilterResolved::Inclusion(mut l, _) = fc {
1680 f_list_new.append(&mut l)
1681 }
1682 });
1683 f_list_new.sort_unstable();
1685 f_list_new.dedup();
1686 let sf = f_list_new.last().and_then(|f| f.get_slopeyness_factor());
1688 FilterResolved::Inclusion(f_list_new, sf)
1689 }
1690 FilterResolved::And(f_list, _) => {
1691 let (f_list_and, mut f_list_new): (Vec<_>, Vec<_>) = f_list
1693 .iter()
1694 .map(|f_ref| f_ref.optimise())
1695 .partition(|f| matches!(f, FilterResolved::And(_, _)));
1696
1697 f_list_and.into_iter().for_each(|fc| {
1710 if let FilterResolved::And(mut l, _) = fc {
1711 f_list_new.append(&mut l)
1712 }
1713 });
1714
1715 if f_list_new.len() == 1 {
1717 f_list_new.remove(0)
1718 } else {
1719 f_list_new.sort_unstable();
1721 f_list_new.dedup();
1722 let sf = f_list_new.first().and_then(|f| f.get_slopeyness_factor());
1726 FilterResolved::And(f_list_new, sf)
1729 }
1730 }
1731 FilterResolved::Or(f_list, _) => {
1732 let (f_list_or, mut f_list_new): (Vec<_>, Vec<_>) = f_list
1733 .iter()
1734 .map(|f_ref| f_ref.optimise())
1736 .partition(|f| matches!(f, FilterResolved::Or(_, _)));
1738
1739 f_list_or.into_iter().for_each(|fc| {
1741 if let FilterResolved::Or(mut l, _) = fc {
1742 f_list_new.append(&mut l)
1743 }
1744 });
1745
1746 if f_list_new.len() == 1 {
1748 f_list_new.remove(0)
1749 } else {
1750 #[allow(clippy::unnecessary_sort_by)]
1757 f_list_new.sort_unstable_by(|a, b| b.cmp(a));
1758 f_list_new.dedup();
1759 let sf = f_list_new.last().and_then(|f| f.get_slopeyness_factor());
1761 FilterResolved::Or(f_list_new, sf)
1762 }
1763 }
1764 f => f.clone(),
1765 }
1766 }
1767
1768 pub fn is_andnot(&self) -> bool {
1769 matches!(self, FilterResolved::AndNot(_, _))
1770 }
1771
1772 #[inline(always)]
1773 fn get_slopeyness_factor(&self) -> Option<NonZeroU8> {
1774 match self {
1775 FilterResolved::Eq(_, _, sf)
1776 | FilterResolved::Cnt(_, _, sf)
1777 | FilterResolved::Stw(_, _, sf)
1778 | FilterResolved::Enw(_, _, sf)
1779 | FilterResolved::Pres(_, sf)
1780 | FilterResolved::LessThan(_, _, sf)
1781 | FilterResolved::Or(_, sf)
1782 | FilterResolved::And(_, sf)
1783 | FilterResolved::Inclusion(_, sf)
1784 | FilterResolved::AndNot(_, sf) => *sf,
1785 FilterResolved::Invalid(_) => NonZeroU8::new(1),
1787 }
1788 }
1789}
1790
1791#[cfg(test)]
1792mod tests {
1793 use std::cmp::{Ordering, PartialOrd};
1794 use std::collections::BTreeSet;
1795 use std::time::Duration;
1796
1797 use kanidm_proto::internal::Filter as ProtoFilter;
1798 use ldap3_proto::simple::LdapFilter;
1799
1800 use crate::event::{CreateEvent, DeleteEvent};
1801 use crate::filter::{Filter, FilterInvalid, DEFAULT_LIMIT_FILTER_DEPTH_MAX};
1802 use crate::prelude::*;
1803
1804 #[test]
1805 fn test_filter_simple() {
1806 let _filt: Filter<FilterInvalid> = filter!(f_eq(Attribute::Class, EntryClass::User.into()));
1808
1809 let _complex_filt: Filter<FilterInvalid> = filter!(f_and!([
1811 f_or!([
1812 f_eq(Attribute::UserId, PartialValue::new_iutf8("test_a")),
1813 f_eq(Attribute::UserId, PartialValue::new_iutf8("test_b")),
1814 ]),
1815 f_sub(Attribute::Class, EntryClass::User.into()),
1816 ]));
1817 }
1818
1819 macro_rules! filter_optimise_assert {
1820 (
1821 $init:expr,
1822 $expect:expr
1823 ) => {{
1824 #[allow(unused_imports)]
1825 use crate::filter::{f_and, f_andnot, f_eq, f_or, f_pres, f_sub};
1826 use crate::filter::{Filter, FilterInvalid};
1827 let f_init: Filter<FilterInvalid> = Filter::new($init);
1828 let f_expect: Filter<FilterInvalid> = Filter::new($expect);
1829 let f_init_r = f_init.into_valid_resolved();
1831 let f_init_o = f_init_r.optimise();
1832 let f_init_e = f_expect.into_valid_resolved();
1833 debug!("--");
1834 debug!("init --> {:?}", f_init_r);
1835 debug!("opt --> {:?}", f_init_o);
1836 debug!("expect --> {:?}", f_init_e);
1837 assert_eq!(f_init_o, f_init_e);
1838 }};
1839 }
1840
1841 #[test]
1842 fn test_filter_optimise() {
1843 sketching::test_init();
1844 filter_optimise_assert!(
1846 f_and(vec![f_and(vec![f_eq(
1847 Attribute::Class,
1848 EntryClass::TestClass.into()
1849 )])]),
1850 f_eq(Attribute::Class, EntryClass::TestClass.into())
1851 );
1852
1853 filter_optimise_assert!(
1854 f_or(vec![f_or(vec![f_eq(
1855 Attribute::Class,
1856 EntryClass::TestClass.into()
1857 )])]),
1858 f_eq(Attribute::Class, EntryClass::TestClass.into())
1859 );
1860
1861 filter_optimise_assert!(
1862 f_and(vec![f_or(vec![f_and(vec![f_eq(
1863 Attribute::Class,
1864 EntryClass::TestClass.to_partialvalue()
1865 )])])]),
1866 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue())
1867 );
1868
1869 filter_optimise_assert!(
1871 f_and(vec![
1872 f_and(vec![f_eq(
1873 Attribute::Class,
1874 EntryClass::TestClass.to_partialvalue()
1875 )]),
1876 f_sub(Attribute::Class, PartialValue::new_iutf8("te")),
1877 f_pres(Attribute::Class),
1878 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue())
1879 ]),
1880 f_and(vec![
1881 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue()),
1882 f_pres(Attribute::Class),
1883 f_sub(Attribute::Class, PartialValue::new_iutf8("te")),
1884 ])
1885 );
1886
1887 filter_optimise_assert!(
1889 f_and(vec![
1890 f_and(vec![
1891 f_eq(Attribute::Class, PartialValue::new_iutf8("foo")),
1892 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue()),
1893 f_eq(Attribute::Uid, PartialValue::new_iutf8("bar")),
1894 ]),
1895 f_sub(Attribute::Class, PartialValue::new_iutf8("te")),
1896 f_pres(Attribute::Class),
1897 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue())
1898 ]),
1899 f_and(vec![
1900 f_eq(Attribute::Class, PartialValue::new_iutf8("foo")),
1901 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue()),
1902 f_pres(Attribute::Class),
1903 f_eq(Attribute::Uid, PartialValue::new_iutf8("bar")),
1904 f_sub(Attribute::Class, PartialValue::new_iutf8("te")),
1905 ])
1906 );
1907
1908 filter_optimise_assert!(
1909 f_or(vec![
1910 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue()),
1911 f_pres(Attribute::Class),
1912 f_sub(Attribute::Class, PartialValue::new_iutf8("te")),
1913 f_or(vec![f_eq(
1914 Attribute::Class,
1915 EntryClass::TestClass.to_partialvalue()
1916 )]),
1917 ]),
1918 f_or(vec![
1919 f_sub(Attribute::Class, PartialValue::new_iutf8("te")),
1920 f_pres(Attribute::Class),
1921 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue())
1922 ])
1923 );
1924
1925 filter_optimise_assert!(
1927 f_or(vec![
1928 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue()),
1929 f_and(vec![
1930 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue()),
1931 f_eq(Attribute::Term, EntryClass::TestClass.to_partialvalue()),
1932 f_or(vec![f_eq(
1933 Attribute::Class,
1934 EntryClass::TestClass.to_partialvalue()
1935 )])
1936 ]),
1937 ]),
1938 f_or(vec![
1939 f_and(vec![
1940 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue()),
1941 f_eq(Attribute::Term, EntryClass::TestClass.to_partialvalue())
1942 ]),
1943 f_eq(Attribute::Class, EntryClass::TestClass.to_partialvalue()),
1944 ])
1945 );
1946 }
1947
1948 #[test]
1949 fn test_filter_eq() {
1950 let f_t1a = filter!(f_pres(Attribute::UserId));
1951 let f_t1b = filter!(f_pres(Attribute::UserId));
1952 let f_t1c = filter!(f_pres(Attribute::NonExist));
1953
1954 assert_eq!(f_t1a, f_t1b);
1955 assert!(f_t1a != f_t1c);
1956 assert!(f_t1b != f_t1c);
1957
1958 let f_t2a = filter!(f_and!([f_pres(Attribute::UserId)]));
1959 let f_t2b = filter!(f_and!([f_pres(Attribute::UserId)]));
1960 let f_t2c = filter!(f_and!([f_pres(Attribute::NonExist)]));
1961 assert_eq!(f_t2a, f_t2b);
1962 assert!(f_t2a != f_t2c);
1963 assert!(f_t2b != f_t2c);
1964
1965 assert!(f_t2c != f_t1a);
1966 assert!(f_t2c != f_t1c);
1967 }
1968
1969 #[test]
1970 fn test_filter_ord() {
1971 let f_t1a = filter_resolved!(f_pres(Attribute::UserId));
1975 let f_t1b = filter_resolved!(f_pres(Attribute::UserId));
1976
1977 assert_eq!(f_t1a.partial_cmp(&f_t1b), Some(Ordering::Equal));
1978 assert_eq!(f_t1b.partial_cmp(&f_t1a), Some(Ordering::Equal));
1979
1980 let f_t2a = filter_resolved!(f_and!([]));
1981 let f_t2b = filter_resolved!(f_and!([]));
1982 assert_eq!(f_t2a.partial_cmp(&f_t2b), Some(Ordering::Equal));
1983 assert_eq!(f_t2b.partial_cmp(&f_t2a), Some(Ordering::Equal));
1984
1985 let f_t3b = filter_resolved!(f_eq(Attribute::UserId, PartialValue::new_iutf8("")));
1988 assert_eq!(f_t1a.partial_cmp(&f_t3b), Some(Ordering::Greater));
1989 assert_eq!(f_t3b.partial_cmp(&f_t1a), Some(Ordering::Less));
1990
1991 let f_t4b = filter_resolved!(f_sub(Attribute::UserId, PartialValue::new_iutf8("")));
1993 assert_eq!(f_t1a.partial_cmp(&f_t4b), Some(Ordering::Less));
1994 assert_eq!(f_t3b.partial_cmp(&f_t4b), Some(Ordering::Less));
1995
1996 assert_eq!(f_t4b.partial_cmp(&f_t1a), Some(Ordering::Greater));
1997 assert_eq!(f_t4b.partial_cmp(&f_t3b), Some(Ordering::Greater));
1998 }
1999
2000 #[test]
2001 fn test_filter_clone() {
2002 let f_t1a = filter_resolved!(f_pres(Attribute::UserId));
2005 let f_t1b = f_t1a.clone();
2006 let f_t1c = filter_resolved!(f_pres(Attribute::NonExist));
2007
2008 assert_eq!(f_t1a, f_t1b);
2009 assert!(f_t1a != f_t1c);
2010
2011 let f_t2a = filter_resolved!(f_and!([f_pres(Attribute::UserId)]));
2012 let f_t2b = f_t2a.clone();
2013 let f_t2c = filter_resolved!(f_and!([f_pres(Attribute::NonExist)]));
2014
2015 assert_eq!(f_t2a, f_t2b);
2016 assert!(f_t2a != f_t2c);
2017 }
2018
2019 #[test]
2020 fn test_lessthan_entry_filter() {
2021 let e = entry_init!(
2022 (Attribute::UserId, Value::new_iutf8("william")),
2023 (
2024 Attribute::Uuid,
2025 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2026 ),
2027 (Attribute::GidNumber, Value::Uint32(1000))
2028 )
2029 .into_sealed_new();
2030
2031 let f_t1a = filter_resolved!(f_lt(Attribute::GidNumber, PartialValue::new_uint32(500)));
2032 assert!(!e.entry_match_no_index(&f_t1a));
2033
2034 let f_t1b = filter_resolved!(f_lt(Attribute::GidNumber, PartialValue::new_uint32(1000)));
2035 assert!(!e.entry_match_no_index(&f_t1b));
2036
2037 let f_t1c = filter_resolved!(f_lt(Attribute::GidNumber, PartialValue::new_uint32(1001)));
2038 assert!(e.entry_match_no_index(&f_t1c));
2039 }
2040
2041 #[test]
2042 fn test_or_entry_filter() {
2043 let e = entry_init!(
2044 (Attribute::UserId, Value::new_iutf8("william")),
2045 (
2046 Attribute::Uuid,
2047 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2048 ),
2049 (Attribute::GidNumber, Value::Uint32(1000))
2050 )
2051 .into_sealed_new();
2052
2053 let f_t1a = filter_resolved!(f_or!([
2054 f_eq(Attribute::UserId, PartialValue::new_iutf8("william")),
2055 f_eq(Attribute::GidNumber, PartialValue::Uint32(1000)),
2056 ]));
2057 assert!(e.entry_match_no_index(&f_t1a));
2058
2059 let f_t2a = 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_t2a));
2064
2065 let f_t3a = filter_resolved!(f_or!([
2066 f_eq(Attribute::UserId, PartialValue::new_iutf8("alice")),
2067 f_eq(Attribute::GidNumber, PartialValue::Uint32(1000)),
2068 ]));
2069 assert!(e.entry_match_no_index(&f_t3a));
2070
2071 let f_t4a = filter_resolved!(f_or!([
2072 f_eq(Attribute::UserId, PartialValue::new_iutf8("alice")),
2073 f_eq(Attribute::GidNumber, PartialValue::Uint32(1001)),
2074 ]));
2075 assert!(!e.entry_match_no_index(&f_t4a));
2076 }
2077
2078 #[test]
2079 fn test_and_entry_filter() {
2080 let e = entry_init!(
2081 (Attribute::UserId, Value::new_iutf8("william")),
2082 (
2083 Attribute::Uuid,
2084 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2085 ),
2086 (Attribute::GidNumber, Value::Uint32(1000))
2087 )
2088 .into_sealed_new();
2089
2090 let f_t1a = filter_resolved!(f_and!([
2091 f_eq(Attribute::UserId, PartialValue::new_iutf8("william")),
2092 f_eq(Attribute::GidNumber, PartialValue::Uint32(1000)),
2093 ]));
2094 assert!(e.entry_match_no_index(&f_t1a));
2095
2096 let f_t2a = filter_resolved!(f_and!([
2097 f_eq(Attribute::UserId, PartialValue::new_iutf8("william")),
2098 f_eq(Attribute::GidNumber, PartialValue::Uint32(1001)),
2099 ]));
2100 assert!(!e.entry_match_no_index(&f_t2a));
2101
2102 let f_t3a = filter_resolved!(f_and!([
2103 f_eq(Attribute::UserId, PartialValue::new_iutf8("alice")),
2104 f_eq(Attribute::GidNumber, PartialValue::Uint32(1000)),
2105 ]));
2106 assert!(!e.entry_match_no_index(&f_t3a));
2107
2108 let f_t4a = filter_resolved!(f_and!([
2109 f_eq(Attribute::UserId, PartialValue::new_iutf8("alice")),
2110 f_eq(Attribute::GidNumber, PartialValue::Uint32(1001)),
2111 ]));
2112 assert!(!e.entry_match_no_index(&f_t4a));
2113 }
2114
2115 #[test]
2116 fn test_not_entry_filter() {
2117 let e1 = entry_init!(
2118 (Attribute::UserId, Value::new_iutf8("william")),
2119 (
2120 Attribute::Uuid,
2121 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2122 ),
2123 (Attribute::GidNumber, Value::Uint32(1000))
2124 )
2125 .into_sealed_new();
2126
2127 let f_t1a = filter_resolved!(f_andnot(f_eq(
2128 Attribute::UserId,
2129 PartialValue::new_iutf8("alice")
2130 )));
2131 assert!(e1.entry_match_no_index(&f_t1a));
2132
2133 let f_t2a = filter_resolved!(f_andnot(f_eq(
2134 Attribute::UserId,
2135 PartialValue::new_iutf8("william")
2136 )));
2137 assert!(!e1.entry_match_no_index(&f_t2a));
2138 }
2139
2140 #[test]
2141 fn test_nested_entry_filter() {
2142 let e1 = entry_init!(
2143 (Attribute::Class, EntryClass::Person.to_value().clone()),
2144 (
2145 Attribute::Uuid,
2146 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2147 ),
2148 (Attribute::GidNumber, Value::Uint32(1000))
2149 )
2150 .into_sealed_new();
2151
2152 let e2 = entry_init!(
2153 (Attribute::Class, EntryClass::Person.to_value().clone()),
2154 (
2155 Attribute::Uuid,
2156 Value::Uuid(uuid::uuid!("4b6228ab-1dbe-42a4-a9f5-f6368222438e"))
2157 ),
2158 (Attribute::GidNumber, Value::Uint32(1001))
2159 )
2160 .into_sealed_new();
2161
2162 let e3 = entry_init!(
2163 (Attribute::Class, EntryClass::Person.to_value()),
2164 (
2165 Attribute::Uuid,
2166 Value::Uuid(uuid::uuid!("7b23c99d-c06b-4a9a-a958-3afa56383e1d"))
2167 ),
2168 (Attribute::GidNumber, Value::Uint32(1002))
2169 )
2170 .into_sealed_new();
2171
2172 let e4 = entry_init!(
2173 (Attribute::Class, EntryClass::Group.to_value()),
2174 (
2175 Attribute::Uuid,
2176 Value::Uuid(uuid::uuid!("21d816b5-1f6a-4696-b7c1-6ed06d22ed81"))
2177 ),
2178 (Attribute::GidNumber, Value::Uint32(1000))
2179 )
2180 .into_sealed_new();
2181
2182 let f_t1a = filter_resolved!(f_and!([
2183 f_eq(Attribute::Class, EntryClass::Person.into()),
2184 f_or!([
2185 f_eq(Attribute::GidNumber, PartialValue::Uint32(1001)),
2186 f_eq(Attribute::GidNumber, PartialValue::Uint32(1000))
2187 ])
2188 ]));
2189
2190 assert!(e1.entry_match_no_index(&f_t1a));
2191 assert!(e2.entry_match_no_index(&f_t1a));
2192 assert!(!e3.entry_match_no_index(&f_t1a));
2193 assert!(!e4.entry_match_no_index(&f_t1a));
2194 }
2195
2196 #[test]
2197 fn test_attr_set_filter() {
2198 let mut f_expect = BTreeSet::new();
2199 f_expect.insert(Attribute::from("userid"));
2200 f_expect.insert(Attribute::Class);
2201 let f_t1a = filter_valid!(f_and!([
2204 f_eq(Attribute::UserId, PartialValue::new_iutf8("alice")),
2205 f_eq(Attribute::Class, PartialValue::new_iutf8("1001")),
2206 ]));
2207
2208 assert_eq!(f_t1a.get_attr_set(), f_expect);
2209
2210 let f_t2a = filter_valid!(f_and!([
2211 f_eq(Attribute::UserId, PartialValue::new_iutf8("alice")),
2212 f_eq(Attribute::Class, PartialValue::new_iutf8("1001")),
2213 f_eq(Attribute::UserId, PartialValue::new_iutf8("claire")),
2214 ]));
2215
2216 assert_eq!(f_t2a.get_attr_set(), f_expect);
2217 }
2218
2219 #[qs_test]
2220 async fn test_filter_resolve_value(server: &QueryServer) {
2221 let time_p1 = duration_from_epoch_now();
2222 let time_p2 = time_p1 + Duration::from_secs(CHANGELOG_MAX_AGE * 2);
2223 let time_p3 = time_p2 + Duration::from_secs(CHANGELOG_MAX_AGE * 2);
2224
2225 let mut server_txn = server.write(time_p1).await.expect("txn");
2226
2227 let e1 = entry_init!(
2228 (Attribute::Class, EntryClass::Object.to_value()),
2229 (Attribute::Class, EntryClass::Account.to_value()),
2230 (Attribute::Class, EntryClass::Person.to_value()),
2231 (Attribute::Name, Value::new_iname("testperson1")),
2232 (
2233 Attribute::Uuid,
2234 Value::Uuid(uuid::uuid!("cc8e95b4-c24f-4d68-ba54-8bed76f63930"))
2235 ),
2236 (Attribute::Description, Value::new_utf8s("testperson1")),
2237 (Attribute::DisplayName, Value::new_utf8s("testperson1"))
2238 );
2239
2240 let e2 = entry_init!(
2241 (Attribute::Class, EntryClass::Object.to_value()),
2242 (Attribute::Class, EntryClass::Account.to_value()),
2243 (Attribute::Class, EntryClass::Person.to_value()),
2244 (Attribute::Name, Value::new_iname("testperson2")),
2245 (
2246 Attribute::Uuid,
2247 Value::Uuid(uuid::uuid!("a67c0c71-0b35-4218-a6b0-22d23d131d27"))
2248 ),
2249 (Attribute::Description, Value::new_utf8s("testperson2")),
2250 (Attribute::DisplayName, Value::new_utf8s("testperson2"))
2251 );
2252
2253 let e_ts = entry_init!(
2255 (Attribute::Class, EntryClass::Object.to_value()),
2256 (Attribute::Class, EntryClass::Account.to_value()),
2257 (Attribute::Class, EntryClass::Person.to_value()),
2258 (Attribute::Name, Value::new_iname("testperson3")),
2259 (
2260 Attribute::Uuid,
2261 Value::Uuid(uuid!("9557f49c-97a5-4277-a9a5-097d17eb8317"))
2262 ),
2263 (Attribute::Description, Value::new_utf8s("testperson3")),
2264 (Attribute::DisplayName, Value::new_utf8s("testperson3"))
2265 );
2266
2267 let ce = CreateEvent::new_internal(vec![e1, e2, e_ts]);
2268 let cr = server_txn.create(&ce);
2269 assert!(cr.is_ok());
2270
2271 let de_sin = DeleteEvent::new_internal_invalid(filter!(f_or!([f_eq(
2272 Attribute::Name,
2273 PartialValue::new_iname("testperson3")
2274 )])));
2275 assert!(server_txn.delete(&de_sin).is_ok());
2276
2277 assert!(server_txn.commit().is_ok());
2279
2280 let mut server_txn = server.write(time_p2).await.expect("txn");
2282 assert!(server_txn.purge_recycled().is_ok());
2283 assert!(server_txn.commit().is_ok());
2284
2285 let mut server_txn = server.write(time_p3).await.expect("txn");
2286 assert!(server_txn.purge_tombstones().is_ok());
2287
2288 let t1 = vs_utf8!["teststring".to_string()] as _;
2292 let r1 = server_txn.resolve_valueset(&t1);
2293 assert_eq!(r1, Ok(vec!["teststring".to_string()]));
2294
2295 let t_uuid = vs_refer![uuid!("cc8e95b4-c24f-4d68-ba54-8bed76f63930")] as _;
2297 let r_uuid = server_txn.resolve_valueset(&t_uuid);
2298 debug!("{:?}", r_uuid);
2299 assert_eq!(r_uuid, Ok(vec!["testperson1@example.com".to_string()]));
2300
2301 let t_uuid = vs_refer![uuid!("a67c0c71-0b35-4218-a6b0-22d23d131d27")] as _;
2303 let r_uuid = server_txn.resolve_valueset(&t_uuid);
2304 debug!("{:?}", r_uuid);
2305 assert_eq!(r_uuid, Ok(vec!["testperson2@example.com".to_string()]));
2306
2307 let t_uuid_non = vs_refer![uuid!("b83e98f0-3d2e-41d2-9796-d8d993289c86")] as _;
2309 let r_uuid_non = server_txn.resolve_valueset(&t_uuid_non);
2310 debug!("{:?}", r_uuid_non);
2311 assert_eq!(
2312 r_uuid_non,
2313 Ok(vec!["b83e98f0-3d2e-41d2-9796-d8d993289c86".to_string()])
2314 );
2315
2316 let t_uuid_ts = vs_refer![uuid!("9557f49c-97a5-4277-a9a5-097d17eb8317")] as _;
2318 let r_uuid_ts = server_txn.resolve_valueset(&t_uuid_ts);
2319 debug!("{:?}", r_uuid_ts);
2320 assert_eq!(
2321 r_uuid_ts,
2322 Ok(vec!["9557f49c-97a5-4277-a9a5-097d17eb8317".to_string()])
2323 );
2324 }
2325
2326 #[qs_test]
2327 async fn test_filter_depth_limits(server: &QueryServer) {
2328 let mut r_txn = server.read().await.unwrap();
2329
2330 let mut inv_proto = ProtoFilter::Pres(Attribute::Class.to_string());
2331 for _i in 0..(DEFAULT_LIMIT_FILTER_DEPTH_MAX + 1) {
2332 inv_proto = ProtoFilter::And(vec![inv_proto]);
2333 }
2334
2335 let mut inv_ldap = LdapFilter::Present(Attribute::Class.to_string());
2336 for _i in 0..(DEFAULT_LIMIT_FILTER_DEPTH_MAX + 1) {
2337 inv_ldap = LdapFilter::And(vec![inv_ldap]);
2338 }
2339
2340 let ev = Identity::from_internal();
2341
2342 let res = Filter::from_ro(&ev, &inv_proto, &mut r_txn);
2344 assert_eq!(res, Err(OperationError::ResourceLimit));
2345
2346 let res = Filter::from_ldap_ro(&ev, &inv_ldap, &mut r_txn);
2348 assert_eq!(res, Err(OperationError::ResourceLimit));
2349
2350 std::mem::drop(r_txn);
2352
2353 let mut wr_txn = server.write(duration_from_epoch_now()).await.expect("txn");
2355 let res = Filter::from_rw(&ev, &inv_proto, &mut wr_txn);
2356 assert_eq!(res, Err(OperationError::ResourceLimit));
2357 }
2358
2359 #[qs_test]
2360 async fn test_filter_max_element_limits(server: &QueryServer) {
2361 const LIMIT: usize = 4;
2362 let mut r_txn = server.read().await.unwrap();
2363
2364 let inv_proto = ProtoFilter::And(
2365 (0..(LIMIT * 2))
2366 .map(|_| ProtoFilter::Pres(Attribute::Class.to_string()))
2367 .collect(),
2368 );
2369
2370 let inv_ldap = LdapFilter::And(
2371 (0..(LIMIT * 2))
2372 .map(|_| LdapFilter::Present(Attribute::Class.to_string()))
2373 .collect(),
2374 );
2375
2376 let mut ev = Identity::from_internal();
2377 ev.limits_mut().filter_max_elements = LIMIT;
2378
2379 let res = Filter::from_ro(&ev, &inv_proto, &mut r_txn);
2381 assert_eq!(res, Err(OperationError::ResourceLimit));
2382
2383 let res = Filter::from_ldap_ro(&ev, &inv_ldap, &mut r_txn);
2385 assert_eq!(res, Err(OperationError::ResourceLimit));
2386
2387 std::mem::drop(r_txn);
2389
2390 let mut wr_txn = server.write(duration_from_epoch_now()).await.expect("txn");
2392 let res = Filter::from_rw(&ev, &inv_proto, &mut wr_txn);
2393 assert_eq!(res, Err(OperationError::ResourceLimit));
2394 }
2395}