1use crate::be::dbentry::{DbEntry, DbEntryVers};
28use crate::be::dbvalue::DbValueSetV2;
29use crate::be::{IdxKey, IdxSlope};
30use crate::credential::apppwd::ApplicationPassword;
31use crate::credential::Credential;
32use crate::filter::{Filter, FilterInvalid, FilterResolved, FilterValidResolved};
33use crate::idm::ldap::ldap_vattr_map;
34use crate::modify::{Modify, ModifyInvalid, ModifyList, ModifyValid};
35use crate::prelude::*;
36use crate::repl::cid::Cid;
37use crate::repl::entry::EntryChangeState;
38use crate::repl::proto::{ReplEntryV1, ReplIncrementalEntryV1};
39use crate::schema::{SchemaAttribute, SchemaClass, SchemaTransaction};
40use crate::server::access::AccessEffectivePermission;
41use crate::value::{
42    ApiToken, CredentialType, IndexType, IntentTokenState, Oauth2Session, PartialValue, Session,
43    SyntaxType, Value,
44};
45use crate::valueset::{self, ScimResolveStatus, ValueSet};
46use compact_jwt::JwsEs256Signer;
47use hashbrown::{HashMap, HashSet};
48use kanidm_proto::internal::ImageValue;
49use kanidm_proto::internal::{
50    ConsistencyError, Filter as ProtoFilter, OperationError, SchemaError, UiHint,
51};
52use kanidm_proto::scim_v1::server::ScimEffectiveAccess;
53use kanidm_proto::v1::Entry as ProtoEntry;
54use ldap3_proto::simple::{LdapPartialAttribute, LdapSearchResultEntry};
55use openssl::ec::EcKey;
56use openssl::pkey::{Private, Public};
57use std::cmp::Ordering;
58pub use std::collections::BTreeSet as Set;
59use std::collections::{BTreeMap as Map, BTreeMap, BTreeSet};
60use std::sync::Arc;
61use time::OffsetDateTime;
62use tracing::trace;
63use uuid::Uuid;
64use webauthn_rs::prelude::{
65    AttestationCaList, AttestedPasskey as AttestedPasskeyV4, Passkey as PasskeyV4,
66};
67
68pub type EntryInitNew = Entry<EntryInit, EntryNew>;
69pub type EntryInvalidNew = Entry<EntryInvalid, EntryNew>;
70pub type EntryRefreshNew = Entry<EntryRefresh, EntryNew>;
71pub type EntrySealedNew = Entry<EntrySealed, EntryNew>;
72pub type EntryValidCommitted = Entry<EntryValid, EntryCommitted>;
73pub type EntrySealedCommitted = Entry<EntrySealed, EntryCommitted>;
74pub type EntryInvalidCommitted = Entry<EntryInvalid, EntryCommitted>;
75pub type EntryReducedCommitted = Entry<EntryReduced, EntryCommitted>;
76pub type EntryTuple = (Arc<EntrySealedCommitted>, EntryInvalidCommitted);
77
78pub type EntryIncrementalNew = Entry<EntryIncremental, EntryNew>;
79pub type EntryIncrementalCommitted = Entry<EntryIncremental, EntryCommitted>;
80
81#[derive(Clone, Debug)]
94pub struct EntryNew; #[derive(Clone, Debug)]
98pub struct EntryCommitted {
99    id: u64,
100}
101
102#[derive(Clone, Debug)]
103pub struct EntryInit;
104
105#[derive(Clone, Debug)]
112pub struct EntryInvalid {
113    cid: Cid,
114    ecstate: EntryChangeState,
115}
116
117#[derive(Clone, Debug)]
119pub struct EntryRefresh {
120    ecstate: EntryChangeState,
121}
122
123#[derive(Clone, Debug)]
125pub struct EntryIncremental {
126    uuid: Uuid,
128    ecstate: EntryChangeState,
129}
130
131#[derive(Clone, Debug)]
137pub struct EntryValid {
138    uuid: Uuid,
140    ecstate: EntryChangeState,
141}
142
143#[derive(Clone, Debug)]
150pub struct EntrySealed {
151    uuid: Uuid,
152    ecstate: EntryChangeState,
153}
154
155#[derive(Clone, Debug)]
161pub struct EntryReduced {
162    uuid: Uuid,
163    effective_access: Option<Box<AccessEffectivePermission>>,
164}
165
166pub type Eattrs = Map<Attribute, ValueSet>;
169
170pub trait GetUuid {
171    fn get_uuid(&self) -> Uuid;
172}
173
174pub trait Committed {}
175
176impl Committed for EntrySealed {}
177impl Committed for EntryReduced {}
178
179pub(crate) fn compare_attrs(left: &Eattrs, right: &Eattrs) -> bool {
180    let allkeys: Set<&Attribute> = left
183        .keys()
184        .chain(right.keys())
185        .filter(|k| *k != &Attribute::LastModifiedCid && *k != &Attribute::CreatedAtCid)
186        .collect();
187
188    allkeys.into_iter().all(|k| {
189        let left_vs = left.get(k);
191        let right_vs = right.get(k);
192        let r = match (left_vs, right_vs) {
193            (Some(l), Some(r)) => l.eq(r),
194            _ => false,
195        };
196        if !r {
197            trace!(?k, ?left_vs, ?right_vs, "compare_attrs_allkeys");
198        }
199        r
200    })
201}
202
203pub struct Entry<VALID, STATE> {
230    valid: VALID,
231    state: STATE,
232    attrs: Eattrs,
234}
235
236impl<VALID, STATE> std::fmt::Debug for Entry<VALID, STATE>
237where
238    STATE: std::fmt::Debug,
239    VALID: std::fmt::Debug,
240{
241    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
242        f.debug_struct("Entry<EntrySealed, _>")
243            .field("state", &self.state)
244            .field("valid", &self.valid)
245            .field("attrs", &self.attrs)
246            .finish()
247    }
248}
249
250impl<STATE> std::fmt::Display for Entry<EntrySealed, STATE>
251where
252    STATE: Clone,
253{
254    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
255        write!(f, "{}", self.get_uuid())
256    }
257}
258
259impl<STATE> std::fmt::Display for Entry<EntryInit, STATE>
260where
261    STATE: Clone,
262{
263    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
264        write!(f, "Entry in initial state")
265    }
266}
267
268impl<STATE> Entry<EntryInit, STATE>
269where
270    STATE: Clone,
271{
272    pub fn get_uuid(&self) -> Option<Uuid> {
274        self.attrs
275            .get(&Attribute::Uuid)
276            .and_then(|vs| vs.to_uuid_single())
277    }
278}
279
280impl Default for Entry<EntryInit, EntryNew> {
281    fn default() -> Self {
282        Self::new()
283    }
284}
285
286impl FromIterator<(Attribute, ValueSet)> for EntryInitNew {
287    fn from_iter<I: IntoIterator<Item = (Attribute, ValueSet)>>(iter: I) -> Self {
288        let attrs = Eattrs::from_iter(iter);
289
290        Entry {
291            valid: EntryInit,
292            state: EntryNew,
293            attrs,
294        }
295    }
296}
297
298impl Entry<EntryInit, EntryNew> {
299    pub fn new() -> Self {
300        Entry {
301            valid: EntryInit,
303            state: EntryNew,
304            attrs: Map::new(),
305        }
306    }
307
308    pub fn from_proto_entry(
311        e: &ProtoEntry,
312        qs: &mut QueryServerWriteTransaction,
313    ) -> Result<Self, OperationError> {
314        trace!("from_proto_entry");
315        let map2: Result<Eattrs, OperationError> = e
322            .attrs
323            .iter()
324            .filter(|(_, v)| !v.is_empty())
325            .map(|(k, v)| {
326                trace!(?k, ?v, "attribute");
327                let attr_nk = Attribute::from(k.as_str());
328                let nv = valueset::from_result_value_iter(
329                    v.iter().map(|vr| qs.clone_value(&attr_nk, vr)),
330                );
331                trace!(?nv, "new valueset transform");
332                match nv {
333                    Ok(nvi) => Ok((attr_nk, nvi)),
334                    Err(e) => Err(e),
335                }
336            })
337            .collect();
338
339        let x = map2?;
340
341        Ok(Entry {
342            state: EntryNew,
343            valid: EntryInit,
344            attrs: x,
345        })
346    }
347
348    #[instrument(level = "debug", skip_all)]
351    pub fn from_proto_entry_str(
352        es: &str,
353        qs: &mut QueryServerWriteTransaction,
354    ) -> Result<Self, OperationError> {
355        if cfg!(test) {
356            if es.len() > 256 {
357                let (dsp_es, _) = es.split_at(255);
358                trace!("Parsing -> {}...", dsp_es);
359            } else {
360                trace!("Parsing -> {}", es);
361            }
362        }
363        let pe: ProtoEntry = serde_json::from_str(es).map_err(|e| {
365            admin_error!(?e, "SerdeJson Failure");
368            OperationError::SerdeJsonError
369        })?;
370        Self::from_proto_entry(&pe, qs)
372    }
373
374    pub fn assign_cid(
377        mut self,
378        cid: Cid,
379        schema: &dyn SchemaTransaction,
380    ) -> Entry<EntryInvalid, EntryNew> {
381        let ecstate = EntryChangeState::new(&cid, &self.attrs, schema);
387
388        let cv = vs_cid![cid.clone()];
391        let _ = self.attrs.insert(Attribute::LastModifiedCid, cv);
392        let cv = vs_cid![cid.clone()];
393        let _ = self.attrs.insert(Attribute::CreatedAtCid, cv);
394
395        Entry {
396            valid: EntryInvalid { cid, ecstate },
397            state: EntryNew,
398            attrs: self.attrs,
399        }
400    }
401
402    pub fn compare(&self, rhs: &Entry<EntrySealed, EntryCommitted>) -> bool {
404        compare_attrs(&self.attrs, &rhs.attrs)
405    }
406
407    #[cfg(test)]
411    pub fn into_invalid_new(mut self) -> Entry<EntryInvalid, EntryNew> {
412        let cid = Cid::new_zero();
413        self.set_last_changed(cid.clone());
414
415        let ecstate = EntryChangeState::new_without_schema(&cid, &self.attrs);
416
417        Entry {
418            valid: EntryInvalid { cid, ecstate },
419            state: EntryNew,
420            attrs: self.attrs,
421        }
422    }
423
424    #[cfg(test)]
428    pub fn into_valid_new(mut self) -> Entry<EntryValid, EntryNew> {
429        let cid = Cid::new_zero();
430        self.set_last_changed(cid.clone());
431        let ecstate = EntryChangeState::new_without_schema(&cid, &self.attrs);
432
433        Entry {
434            valid: EntryValid {
435                ecstate,
436                uuid: self.get_uuid().expect("Invalid uuid"),
437            },
438            state: EntryNew,
439            attrs: self.attrs,
440        }
441    }
442
443    #[cfg(test)]
447    pub fn into_sealed_committed(mut self) -> Entry<EntrySealed, EntryCommitted> {
448        let cid = Cid::new_zero();
449        self.set_last_changed(cid.clone());
450        let ecstate = EntryChangeState::new_without_schema(&cid, &self.attrs);
451        let uuid = self.get_uuid().unwrap_or_else(Uuid::new_v4);
452        Entry {
453            valid: EntrySealed { uuid, ecstate },
454            state: EntryCommitted { id: 0 },
455            attrs: self.attrs,
456        }
457    }
458
459    #[cfg(test)]
463    pub fn into_sealed_new(mut self) -> Entry<EntrySealed, EntryNew> {
464        let cid = Cid::new_zero();
465        self.set_last_changed(cid.clone());
466        let ecstate = EntryChangeState::new_without_schema(&cid, &self.attrs);
467
468        Entry {
469            valid: EntrySealed {
470                uuid: self.get_uuid().expect("Invalid uuid"),
471                ecstate,
472            },
473            state: EntryNew,
474            attrs: self.attrs,
475        }
476    }
477
478    pub fn add_ava(&mut self, attr: Attribute, value: Value) {
484        self.add_ava_int(attr, value);
485    }
486
487    pub fn remove_ava(&mut self, attr: &Attribute) {
488        self.attrs.remove(attr);
489    }
490
491    pub fn set_ava_set(&mut self, attr: &Attribute, vs: ValueSet) {
493        self.attrs.insert(attr.clone(), vs);
494    }
495
496    pub fn set_ava<T>(&mut self, attr: Attribute, iter: T)
498    where
499        T: IntoIterator<Item = Value>,
500    {
501        self.set_ava_iter_int(attr, iter);
502    }
503
504    pub fn get_ava_mut<A: AsRef<Attribute>>(&mut self, attr: A) -> Option<&mut ValueSet> {
505        self.attrs.get_mut(attr.as_ref())
506    }
507}
508
509impl From<SchemaAttribute> for EntryInitNew {
510    fn from(value: SchemaAttribute) -> Self {
511        EntryInitNew::from(&value)
512    }
513}
514
515impl From<&SchemaAttribute> for EntryInitNew {
516    fn from(s: &SchemaAttribute) -> Self {
517        let mut attrs = Eattrs::new();
519        attrs.insert(Attribute::AttributeName, vs_iutf8![s.name.as_str()]);
520        attrs.insert(Attribute::Description, vs_utf8![s.description.to_owned()]);
521        attrs.insert(Attribute::Uuid, vs_uuid![s.uuid]);
522        attrs.insert(Attribute::MultiValue, vs_bool![s.multivalue]);
523        attrs.insert(Attribute::Phantom, vs_bool![s.phantom]);
524        attrs.insert(Attribute::SyncAllowed, vs_bool![s.sync_allowed]);
525        attrs.insert(Attribute::Replicated, vs_bool![s.replicated.into()]);
526        attrs.insert(Attribute::Unique, vs_bool![s.unique]);
527        attrs.insert(Attribute::Indexed, vs_bool![s.indexed]);
528        attrs.insert(Attribute::Syntax, vs_syntax![s.syntax]);
529        attrs.insert(
530            Attribute::Class,
531            vs_iutf8![
532                EntryClass::Object.into(),
533                EntryClass::System.into(),
534                EntryClass::AttributeType.into()
535            ],
536        );
537
538        Entry {
541            valid: EntryInit,
542            state: EntryNew,
543            attrs,
544        }
545    }
546}
547
548impl From<SchemaClass> for EntryInitNew {
549    fn from(value: SchemaClass) -> Self {
550        EntryInitNew::from(&value)
551    }
552}
553
554impl From<&SchemaClass> for EntryInitNew {
555    fn from(s: &SchemaClass) -> Self {
556        let mut attrs = Eattrs::new();
557        attrs.insert(Attribute::ClassName, vs_iutf8![s.name.as_str()]);
558        attrs.insert(Attribute::Description, vs_utf8![s.description.to_owned()]);
559        attrs.insert(Attribute::SyncAllowed, vs_bool![s.sync_allowed]);
560        attrs.insert(Attribute::Uuid, vs_uuid![s.uuid]);
561        attrs.insert(
562            Attribute::Class,
563            vs_iutf8![
564                EntryClass::Object.into(),
565                EntryClass::System.into(),
566                EntryClass::ClassType.into()
567            ],
568        );
569
570        let vs_systemmay = ValueSetIutf8::from_iter(s.systemmay.iter().map(|sm| sm.as_str()));
571        if let Some(vs) = vs_systemmay {
572            attrs.insert(Attribute::SystemMay, vs);
573        }
574
575        let vs_systemmust = ValueSetIutf8::from_iter(s.systemmust.iter().map(|sm| sm.as_str()));
576        if let Some(vs) = vs_systemmust {
577            attrs.insert(Attribute::SystemMust, vs);
578        }
579
580        let vs_systemexcludes =
581            ValueSetIutf8::from_iter(s.systemexcludes.iter().map(|sm| sm.as_str()));
582        if let Some(vs) = vs_systemexcludes {
583            attrs.insert(Attribute::SystemExcludes, vs);
584        }
585
586        let vs_systemsupplements =
587            ValueSetIutf8::from_iter(s.systemsupplements.iter().map(|sm| sm.as_str()));
588        if let Some(vs) = vs_systemsupplements {
589            attrs.insert(Attribute::SystemSupplements, vs);
590        }
591
592        Entry {
593            valid: EntryInit,
594            state: EntryNew,
595            attrs,
596        }
597    }
598}
599
600impl Entry<EntryRefresh, EntryNew> {
601    pub fn from_repl_entry_v1(repl_entry: ReplEntryV1) -> Result<Self, OperationError> {
602        let (ecstate, mut attrs) = repl_entry.rehydrate()?;
604
605        let last_mod_cid = ecstate.get_max_cid();
608        let cv = vs_cid![last_mod_cid.clone()];
609        let _ = attrs.insert(Attribute::LastModifiedCid, cv);
610
611        let create_at_cid = ecstate.at();
612        let cv = vs_cid![create_at_cid.clone()];
613        let _ = attrs.insert(Attribute::CreatedAtCid, cv);
614
615        Ok(Entry {
616            valid: EntryRefresh { ecstate },
617            state: EntryNew,
618            attrs,
619        })
620    }
621}
622
623impl<STATE> Entry<EntryRefresh, STATE> {
624    pub fn validate(
625        self,
626        schema: &dyn SchemaTransaction,
627    ) -> Result<Entry<EntryValid, STATE>, SchemaError> {
628        let uuid: Uuid = self
629            .attrs
630            .get(&Attribute::Uuid)
631            .ok_or_else(|| SchemaError::MissingMustAttribute(vec![Attribute::Uuid]))
632            .and_then(|vs| {
633                vs.to_uuid_single()
634                    .ok_or_else(|| SchemaError::MissingMustAttribute(vec![Attribute::Uuid]))
635            })?;
636
637        let ne = Entry {
639            valid: EntryValid {
640                uuid,
641                ecstate: self.valid.ecstate,
642            },
643            state: self.state,
644            attrs: self.attrs,
645        };
646
647        ne.validate(schema).map(|()| ne)
648    }
649}
650
651impl<STATE> Entry<EntryIncremental, STATE> {
652    pub fn get_uuid(&self) -> Uuid {
653        self.valid.uuid
654    }
655}
656
657impl Entry<EntryIncremental, EntryNew> {
658    fn stub_ecstate(&self) -> EntryChangeState {
659        self.valid.ecstate.stub()
660    }
661
662    pub fn rehydrate(repl_inc_entry: ReplIncrementalEntryV1) -> Result<Self, OperationError> {
663        let (uuid, ecstate, attrs) = repl_inc_entry.rehydrate()?;
664
665        Ok(Entry {
666            valid: EntryIncremental { uuid, ecstate },
667            state: EntryNew,
668            attrs,
669        })
670    }
671
672    pub(crate) fn is_add_conflict(&self, db_entry: &EntrySealedCommitted) -> bool {
673        use crate::repl::entry::State;
674        debug_assert_eq!(self.valid.uuid, db_entry.valid.uuid);
675        let self_cs = &self.valid.ecstate;
677        let db_cs = db_entry.get_changestate();
678
679        match (self_cs.current(), db_cs.current()) {
681            (State::Live { at: at_left, .. }, State::Live { at: at_right, .. }) => {
682                at_left != at_right
683            }
684            _ => false,
686        }
687    }
688
689    pub(crate) fn resolve_add_conflict(
690        &self,
691        cid: &Cid,
692        db_ent: &EntrySealedCommitted,
693    ) -> (Option<EntrySealedNew>, EntryIncrementalCommitted) {
694        use crate::repl::entry::State;
695        debug_assert_eq!(self.valid.uuid, db_ent.valid.uuid);
696        let self_cs = &self.valid.ecstate;
697        let db_cs = db_ent.get_changestate();
698
699        match (self_cs.current(), db_cs.current()) {
700            (
701                State::Live {
702                    at: at_left,
703                    changes: _changes_left,
704                },
705                State::Live {
706                    at: at_right,
707                    changes: _changes_right,
708                },
709            ) => {
710                debug_assert!(at_left != at_right);
711                if at_left > at_right {
722                    trace!("RI > DE, return DE");
723                    (
724                        None,
725                        Entry {
726                            valid: EntryIncremental {
727                                uuid: db_ent.valid.uuid,
728                                ecstate: db_cs.clone(),
729                            },
730                            state: EntryCommitted {
731                                id: db_ent.state.id,
732                            },
733                            attrs: db_ent.attrs.clone(),
734                        },
735                    )
736                }
737                else {
747                    trace!("RI < DE, return RI");
748                    let conflict = if at_right.s_uuid == cid.s_uuid {
750                        trace!("Origin process conflict entry");
751                        let mut cnf_ent = Entry {
754                            valid: EntryInvalid {
755                                cid: cid.clone(),
756                                ecstate: db_cs.clone(),
757                            },
758                            state: EntryNew,
759                            attrs: db_ent.attrs.clone(),
760                        };
761
762                        cnf_ent.add_ava(Attribute::SourceUuid, Value::Uuid(db_ent.valid.uuid));
764
765                        let new_uuid = Uuid::new_v4();
767                        cnf_ent.purge_ava(Attribute::Uuid);
768                        cnf_ent.add_ava(Attribute::Uuid, Value::Uuid(new_uuid));
769                        cnf_ent.add_ava(Attribute::Class, EntryClass::Recycled.into());
770                        cnf_ent.add_ava(Attribute::Class, EntryClass::Conflict.into());
771
772                        let cv = vs_cid![cid.clone()];
776                        let _ = cnf_ent.attrs.insert(Attribute::LastModifiedCid, cv);
777                        let cv = vs_cid![cid.clone()];
779                        let _ = cnf_ent.attrs.insert(Attribute::CreatedAtCid, cv);
780
781                        let Entry {
785                            valid: EntryInvalid { cid: _, ecstate },
786                            state,
787                            attrs,
788                        } = cnf_ent;
789
790                        let cnf_ent = Entry {
791                            valid: EntrySealed {
792                                uuid: new_uuid,
793                                ecstate,
794                            },
795                            state,
796                            attrs,
797                        };
798
799                        Some(cnf_ent)
800                    } else {
801                        None
802                    };
803
804                    let mut attrs = self.attrs.clone();
808                    let ecstate = self_cs.clone();
809
810                    let last_mod_cid = ecstate.get_max_cid();
811                    let cv = vs_cid![last_mod_cid.clone()];
812                    let _ = attrs.insert(Attribute::LastModifiedCid, cv);
813
814                    let create_at_cid = ecstate.at();
815                    let cv = vs_cid![create_at_cid.clone()];
816                    let _ = attrs.insert(Attribute::CreatedAtCid, cv);
817
818                    (
819                        conflict,
820                        Entry {
821                            valid: EntryIncremental {
822                                uuid: self.valid.uuid,
823                                ecstate,
824                            },
825                            state: EntryCommitted {
826                                id: db_ent.state.id,
827                            },
828                            attrs,
829                        },
830                    )
831                }
832            }
833            _ => unreachable!(),
835        }
836    }
837
838    pub(crate) fn merge_state(
839        &self,
840        db_ent: &EntrySealedCommitted,
841        schema: &dyn SchemaTransaction,
842        trim_cid: &Cid,
843    ) -> EntryIncrementalCommitted {
844        use crate::repl::entry::State;
845
846        debug_assert_eq!(self.valid.uuid, db_ent.valid.uuid);
848
849        let self_cs = &self.valid.ecstate;
852        let db_cs = db_ent.get_changestate();
853
854        match (self_cs.current(), db_cs.current()) {
855            (
856                State::Live {
857                    at: at_left,
858                    changes: changes_left,
859                },
860                State::Live {
861                    at: at_right,
862                    changes: changes_right,
863                },
864            ) => {
865                debug_assert_eq!(at_left, at_right);
866                let mut attr_set: Vec<_> =
871                    changes_left.keys().chain(changes_right.keys()).collect();
872                attr_set.shrink_to_fit();
873                attr_set.sort_unstable();
874                attr_set.dedup();
875
876                let mut changes = BTreeMap::default();
878                let mut eattrs = Eattrs::default();
879
880                for attr_name in attr_set.into_iter() {
882                    match (changes_left.get(attr_name), changes_right.get(attr_name)) {
883                        (Some(cid_left), Some(cid_right)) => {
884                            let take_left = cid_left > cid_right;
891
892                            match (self.attrs.get(attr_name), db_ent.attrs.get(attr_name)) {
893                                (Some(vs_left), Some(vs_right)) if take_left => {
894                                    changes.insert(attr_name.clone(), cid_left.clone());
895                                    #[allow(clippy::todo)]
896                                    if let Some(merged_attr_state) =
897                                        vs_left.repl_merge_valueset(vs_right, trim_cid)
898                                    {
899                                        eattrs.insert(attr_name.clone(), merged_attr_state);
902                                    } else {
903                                        eattrs.insert(attr_name.clone(), vs_left.clone());
904                                    }
905                                }
906                                (Some(vs_left), Some(vs_right)) => {
907                                    changes.insert(attr_name.clone(), cid_right.clone());
908                                    #[allow(clippy::todo)]
909                                    if let Some(merged_attr_state) =
910                                        vs_right.repl_merge_valueset(vs_left, trim_cid)
911                                    {
912                                        eattrs.insert(attr_name.clone(), merged_attr_state);
915                                    } else {
916                                        eattrs.insert(attr_name.clone(), vs_right.clone());
917                                    }
918                                }
919                                (Some(vs_left), None) if take_left => {
920                                    changes.insert(attr_name.clone(), cid_left.clone());
921                                    eattrs.insert(attr_name.clone(), vs_left.clone());
922                                }
923                                (Some(_vs_left), None) => {
924                                    changes.insert(attr_name.clone(), cid_right.clone());
925                                    }
927                                (None, Some(_vs_right)) if take_left => {
928                                    changes.insert(attr_name.clone(), cid_left.clone());
929                                    }
931                                (None, Some(vs_right)) => {
932                                    changes.insert(attr_name.clone(), cid_right.clone());
933                                    eattrs.insert(attr_name.clone(), vs_right.clone());
934                                }
935                                (None, None) if take_left => {
936                                    changes.insert(attr_name.clone(), cid_left.clone());
937                                    }
939                                (None, None) => {
940                                    changes.insert(attr_name.clone(), cid_right.clone());
941                                    }
943                            }
944                            }
946                        (Some(cid_left), None) => {
947                            changes.insert(attr_name.clone(), cid_left.clone());
949                            if let Some(valueset) = self.attrs.get(attr_name) {
950                                eattrs.insert(attr_name.clone(), valueset.clone());
951                            }
952                        }
953                        (None, Some(cid_right)) => {
954                            changes.insert(attr_name.clone(), cid_right.clone());
956                            if let Some(valueset) = db_ent.attrs.get(attr_name) {
957                                eattrs.insert(attr_name.clone(), valueset.clone());
958                            }
959                        }
960                        (None, None) => {
961                            debug_assert!(false);
963                        }
964                    }
965                }
966
967                let mut ecstate = EntryChangeState::build(State::Live {
968                    at: at_left.clone(),
969                    changes,
970                });
971
972                ecstate.retain(|k, _| schema.is_replicated(k));
976
977                let cv = vs_cid![ecstate.get_max_cid().clone()];
978                let _ = eattrs.insert(Attribute::LastModifiedCid, cv);
979
980                let cv = vs_cid![ecstate.at().clone()];
981                let _ = eattrs.insert(Attribute::CreatedAtCid, cv);
982
983                Entry {
984                    valid: EntryIncremental {
985                        uuid: self.valid.uuid,
986                        ecstate,
987                    },
988                    state: EntryCommitted {
989                        id: db_ent.state.id,
990                    },
991                    attrs: eattrs,
992                }
993            }
994            (State::Tombstone { at: left_at }, State::Live { .. }) => {
995                let mut attrs_new: Eattrs = Map::new();
999                let class_ava = vs_iutf8![EntryClass::Object.into(), EntryClass::Tombstone.into()];
1000                let last_mod_ava = vs_cid![left_at.clone()];
1001                let created_ava = vs_cid![left_at.clone()];
1002
1003                attrs_new.insert(Attribute::Uuid, vs_uuid![self.valid.uuid]);
1004                attrs_new.insert(Attribute::Class, class_ava);
1005                attrs_new.insert(Attribute::LastModifiedCid, last_mod_ava);
1006                attrs_new.insert(Attribute::CreatedAtCid, created_ava);
1007
1008                Entry {
1009                    valid: EntryIncremental {
1010                        uuid: self.valid.uuid,
1011                        ecstate: self.valid.ecstate.clone(),
1012                    },
1013                    state: EntryCommitted {
1014                        id: db_ent.state.id,
1015                    },
1016                    attrs: attrs_new,
1017                }
1018            }
1019            (State::Live { .. }, State::Tombstone { .. }) => {
1020                Entry {
1028                    valid: EntryIncremental {
1029                        uuid: db_ent.valid.uuid,
1030                        ecstate: db_ent.valid.ecstate.clone(),
1031                    },
1032                    state: EntryCommitted {
1033                        id: db_ent.state.id,
1034                    },
1035                    attrs: db_ent.attrs.clone(),
1036                }
1037            }
1038            (State::Tombstone { at: left_at }, State::Tombstone { at: right_at }) => {
1039                let (at, ecstate) = if left_at < right_at {
1044                    (left_at, self.valid.ecstate.clone())
1045                } else {
1046                    (right_at, db_ent.valid.ecstate.clone())
1047                };
1048
1049                let mut attrs_new: Eattrs = Map::new();
1050                let class_ava = vs_iutf8![EntryClass::Object.into(), EntryClass::Tombstone.into()];
1051                let last_mod_ava = vs_cid![at.clone()];
1052                let created_ava = vs_cid![at.clone()];
1053
1054                attrs_new.insert(Attribute::Uuid, vs_uuid![db_ent.valid.uuid]);
1055                attrs_new.insert(Attribute::Class, class_ava);
1056                attrs_new.insert(Attribute::LastModifiedCid, last_mod_ava);
1057                attrs_new.insert(Attribute::CreatedAtCid, created_ava);
1058
1059                Entry {
1060                    valid: EntryIncremental {
1061                        uuid: db_ent.valid.uuid,
1062                        ecstate,
1063                    },
1064                    state: EntryCommitted {
1065                        id: db_ent.state.id,
1066                    },
1067                    attrs: attrs_new,
1068                }
1069            }
1070        }
1071    }
1072}
1073
1074impl Entry<EntryIncremental, EntryCommitted> {
1075    pub(crate) fn validate_repl(self, schema: &dyn SchemaTransaction) -> EntryValidCommitted {
1076        let mut ne = Entry {
1081            valid: EntryValid {
1082                uuid: self.valid.uuid,
1083                ecstate: self.valid.ecstate,
1084            },
1085            state: self.state,
1086            attrs: self.attrs,
1087        };
1088
1089        if let Err(e) = ne.validate(schema) {
1090            warn!(uuid = ?self.valid.uuid, err = ?e, "Entry failed schema check, moving to a conflict state");
1091            ne.add_ava_int(Attribute::Class, EntryClass::Recycled.into());
1092            ne.add_ava_int(Attribute::Class, EntryClass::Conflict.into());
1093            ne.add_ava_int(Attribute::SourceUuid, Value::Uuid(self.valid.uuid));
1094        }
1095        ne
1096    }
1097}
1098
1099impl<STATE> Entry<EntryInvalid, STATE> {
1100    pub(crate) fn get_uuid(&self) -> Option<Uuid> {
1101        self.attrs
1102            .get(&Attribute::Uuid)
1103            .and_then(|vs| vs.to_uuid_single())
1104    }
1105
1106    pub fn validate(
1109        self,
1110        schema: &dyn SchemaTransaction,
1111    ) -> Result<Entry<EntryValid, STATE>, SchemaError> {
1112        let uuid: Uuid = self
1113            .attrs
1114            .get(&Attribute::Uuid)
1115            .ok_or_else(|| SchemaError::MissingMustAttribute(vec![Attribute::Uuid]))
1116            .and_then(|vs| {
1117                vs.to_uuid_single()
1118                    .ok_or_else(|| SchemaError::MissingMustAttribute(vec![Attribute::Uuid]))
1119            })?;
1120
1121        let ne = Entry {
1123            valid: EntryValid {
1124                uuid,
1125                ecstate: self.valid.ecstate,
1126            },
1127            state: self.state,
1128            attrs: self.attrs,
1129        };
1130
1131        ne.validate(schema).map(|()| ne)
1132    }
1133
1134    pub(crate) fn get_ava_refer_mut<A: AsRef<Attribute>>(
1138        &mut self,
1139        attr: A,
1140    ) -> Option<&mut BTreeSet<Uuid>> {
1141        self.attrs
1142            .get_mut(attr.as_ref())
1143            .and_then(|vs| vs.as_refer_set_mut())
1144    }
1145}
1146
1147impl<VALID, STATE> Clone for Entry<VALID, STATE>
1148where
1149    VALID: Clone,
1150    STATE: Clone,
1151{
1152    fn clone(&self) -> Entry<VALID, STATE> {
1154        Entry {
1155            valid: self.valid.clone(),
1156            state: self.state.clone(),
1157            attrs: self.attrs.clone(),
1158        }
1159    }
1160}
1161
1162impl Entry<EntryInvalid, EntryCommitted> {
1163    #[cfg(test)]
1167    pub fn into_valid_new(self) -> Entry<EntryValid, EntryNew> {
1168        let uuid = self.get_uuid().expect("Invalid uuid");
1169        Entry {
1170            valid: EntryValid {
1171                uuid,
1172                ecstate: self.valid.ecstate,
1173            },
1174            state: EntryNew,
1175            attrs: self.attrs,
1176        }
1177    }
1178
1179    pub fn to_recycled(mut self) -> Self {
1181        self.add_ava(Attribute::Class, EntryClass::Recycled.into());
1183
1184        Entry {
1188            valid: self.valid,
1189            state: self.state,
1190            attrs: self.attrs,
1191        }
1192    }
1193
1194    pub fn to_conflict<T>(&mut self, iter: T)
1196    where
1197        T: IntoIterator<Item = Uuid>,
1198    {
1199        self.add_ava(Attribute::Class, EntryClass::Recycled.into());
1200        self.add_ava(Attribute::Class, EntryClass::Conflict.into());
1201        for source_uuid in iter {
1203            self.add_ava(Attribute::SourceUuid, Value::Uuid(source_uuid));
1204        }
1205    }
1206
1207    pub fn to_revived(mut self) -> Self {
1209        self.remove_ava(Attribute::Class, &EntryClass::Recycled.into());
1211        self.remove_ava(Attribute::Class, &EntryClass::Conflict.into());
1212        self.purge_ava(Attribute::SourceUuid);
1213        self.purge_ava(Attribute::RecycledDirectMemberOf);
1214
1215        Entry {
1219            valid: self.valid,
1220            state: self.state,
1221            attrs: self.attrs,
1222        }
1223    }
1224}
1225impl Entry<EntryInvalid, EntryNew> {
1228    #[cfg(test)]
1231    pub fn into_init_new(self) -> Entry<EntryInit, EntryNew> {
1232        Entry {
1233            valid: EntryInit,
1234            state: EntryNew,
1235            attrs: self.attrs,
1236        }
1237    }
1238
1239    #[cfg(test)]
1243    pub fn into_valid_new(self) -> Entry<EntryValid, EntryNew> {
1244        let uuid = self.get_uuid().expect("Invalid uuid");
1245        Entry {
1246            valid: EntryValid {
1247                uuid,
1248                ecstate: self.valid.ecstate,
1249            },
1250            state: EntryNew,
1251            attrs: self.attrs,
1252        }
1253    }
1254
1255    #[cfg(test)]
1259    pub fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
1260        let uuid = self.get_uuid().unwrap_or_else(Uuid::new_v4);
1261        Entry {
1262            valid: EntrySealed {
1263                uuid,
1264                ecstate: self.valid.ecstate,
1265            },
1266            state: EntryCommitted { id: 0 },
1267            attrs: self.attrs,
1268        }
1269    }
1270
1271    #[cfg(test)]
1275    pub fn into_valid_committed(self) -> Entry<EntryValid, EntryCommitted> {
1276        let uuid = self.get_uuid().unwrap_or_else(Uuid::new_v4);
1277        Entry {
1278            valid: EntryValid {
1279                uuid,
1280                ecstate: self.valid.ecstate,
1281            },
1282            state: EntryCommitted { id: 0 },
1283            attrs: self.attrs,
1284        }
1285    }
1286}
1287
1288impl Entry<EntryInvalid, EntryCommitted> {
1289    #[cfg(test)]
1293    pub fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
1294        let uuid = self.get_uuid().unwrap_or_else(Uuid::new_v4);
1295        Entry {
1296            valid: EntrySealed {
1297                uuid,
1298                ecstate: self.valid.ecstate,
1299            },
1300            state: self.state,
1301            attrs: self.attrs,
1302        }
1303    }
1304}
1305
1306impl Entry<EntrySealed, EntryNew> {
1307    #[cfg(test)]
1311    pub fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
1312        Entry {
1313            valid: self.valid,
1314            state: EntryCommitted { id: 0 },
1315            attrs: self.attrs,
1316        }
1317    }
1318
1319    pub fn into_sealed_committed_id(self, id: u64) -> Entry<EntrySealed, EntryCommitted> {
1322        Entry {
1323            valid: self.valid,
1324            state: EntryCommitted { id },
1325            attrs: self.attrs,
1326        }
1327    }
1328
1329    pub fn compare(&self, rhs: &Entry<EntrySealed, EntryNew>) -> bool {
1330        compare_attrs(&self.attrs, &rhs.attrs)
1331    }
1332}
1333
1334type IdxDiff<'a> =
1335    Vec<Result<(&'a Attribute, IndexType, String), (&'a Attribute, IndexType, String)>>;
1336
1337impl<VALID> Entry<VALID, EntryCommitted> {
1338    pub fn get_id(&self) -> u64 {
1340        self.state.id
1341    }
1342}
1343
1344impl<STATE> Entry<EntrySealed, STATE> {
1345    pub fn into_init(self) -> Entry<EntryInit, STATE> {
1346        Entry {
1347            valid: EntryInit,
1348            state: self.state,
1349            attrs: self.attrs,
1350        }
1351    }
1352}
1353
1354impl Entry<EntrySealed, EntryCommitted> {
1355    #[cfg(test)]
1356    pub(crate) fn get_last_changed(&self) -> Cid {
1357        self.valid.ecstate.get_max_cid().clone()
1358    }
1359
1360    #[cfg(test)]
1362    pub fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
1363        self
1365    }
1366
1367    pub(crate) fn stub_sealed_committed_id(
1368        id: u64,
1369        ctx_ent: &EntryIncrementalNew,
1370    ) -> EntrySealedCommitted {
1371        let uuid = ctx_ent.get_uuid();
1372        let ecstate = ctx_ent.stub_ecstate();
1373
1374        Entry {
1375            valid: EntrySealed { uuid, ecstate },
1376            state: EntryCommitted { id },
1377            attrs: Default::default(),
1378        }
1379    }
1380
1381    pub fn insert_claim(&mut self, value: &str) {
1384        self.add_ava_int(Attribute::Claim, Value::new_iutf8(value));
1385    }
1386
1387    pub fn compare(&self, rhs: &Entry<EntrySealed, EntryCommitted>) -> bool {
1388        compare_attrs(&self.attrs, &rhs.attrs)
1389    }
1390
1391    pub fn to_dbentry(&self) -> DbEntry {
1393        DbEntry {
1396            ent: DbEntryVers::V3 {
1397                changestate: self.valid.ecstate.to_db_changestate(),
1398                attrs: self
1399                    .attrs
1400                    .iter()
1401                    .map(|(k, vs)| {
1402                        let dbvs: DbValueSetV2 = vs.to_db_valueset_v2();
1403                        (k.clone(), dbvs)
1404                    })
1405                    .collect(),
1406            },
1407        }
1408    }
1409
1410    #[inline]
1411    fn get_name2uuid_cands(&self) -> Set<String> {
1414        let cands = [Attribute::Spn, Attribute::Name, Attribute::GidNumber];
1420        cands
1421            .iter()
1422            .filter_map(|cand| {
1423                self.attrs
1424                    .get(cand)
1425                    .map(|vs| vs.to_proto_string_clone_iter())
1426            })
1427            .flatten()
1428            .collect()
1429    }
1430
1431    #[inline]
1432    fn get_externalid2uuid(&self) -> Option<String> {
1435        self.attrs
1436            .get(&Attribute::SyncExternalId)
1437            .and_then(|vs| vs.to_proto_string_single())
1438    }
1439
1440    #[inline]
1441    pub(crate) fn get_uuid2spn(&self) -> Value {
1444        self.attrs
1445            .get(&Attribute::Spn)
1446            .and_then(|vs| vs.to_value_single())
1447            .or_else(|| {
1448                self.attrs
1449                    .get(&Attribute::Name)
1450                    .and_then(|vs| vs.to_value_single())
1451            })
1452            .unwrap_or_else(|| Value::Uuid(self.get_uuid()))
1453    }
1454
1455    #[inline]
1456    pub(crate) fn get_uuid2rdn(&self) -> String {
1460        self.attrs
1461            .get(&Attribute::Spn)
1462            .and_then(|vs| vs.to_proto_string_single().map(|v| format!("spn={v}")))
1463            .or_else(|| {
1464                self.attrs
1465                    .get(&Attribute::Name)
1466                    .and_then(|vs| vs.to_proto_string_single().map(|v| format!("name={v}")))
1467            })
1468            .unwrap_or_else(|| format!("uuid={}", self.get_uuid().as_hyphenated()))
1469    }
1470
1471    pub(crate) fn idx_name2uuid_diff(
1474        pre: Option<&Self>,
1475        post: Option<&Self>,
1476    ) -> (
1477        Option<Set<String>>,
1479        Option<Set<String>>,
1481    ) {
1482        match (pre, post) {
1484            (None, None) => {
1485                (None, None)
1487            }
1488            (None, Some(b)) => {
1489                (Some(b.get_name2uuid_cands()), None)
1492            }
1493            (Some(a), None) => {
1494                (None, Some(a.get_name2uuid_cands()))
1496            }
1497            (Some(a), Some(b)) => {
1498                let pre_set = a.get_name2uuid_cands();
1499                let post_set = b.get_name2uuid_cands();
1500
1501                let add_set: Set<_> = post_set.difference(&pre_set).cloned().collect();
1503                let rem_set: Set<_> = pre_set.difference(&post_set).cloned().collect();
1505                (Some(add_set), Some(rem_set))
1506            }
1507        }
1508    }
1509
1510    pub(crate) fn idx_externalid2uuid_diff(
1512        pre: Option<&Self>,
1513        post: Option<&Self>,
1514    ) -> (Option<String>, Option<String>) {
1515        match (pre, post) {
1516            (None, None) => {
1517                (None, None)
1519            }
1520            (None, Some(b)) => {
1521                (b.get_externalid2uuid(), None)
1523            }
1524            (Some(a), None) => {
1525                (None, a.get_externalid2uuid())
1527            }
1528            (Some(a), Some(b)) => {
1529                let ia = a.get_externalid2uuid();
1530                let ib = b.get_externalid2uuid();
1531                if ia != ib {
1532                    (ib, ia)
1535                } else {
1536                    (None, None)
1538                }
1539            }
1540        }
1541    }
1542
1543    pub(crate) fn idx_uuid2spn_diff(
1546        pre: Option<&Self>,
1547        post: Option<&Self>,
1548    ) -> Option<Result<Value, ()>> {
1549        match (pre, post) {
1550            (None, None) => {
1551                None
1553            }
1554            (None, Some(b)) => {
1555                Some(Ok(b.get_uuid2spn()))
1557            }
1558            (Some(_a), None) => {
1559                Some(Err(()))
1561            }
1562            (Some(a), Some(b)) => {
1563                let ia = a.get_uuid2spn();
1564                let ib = b.get_uuid2spn();
1565                if ia != ib {
1566                    Some(Ok(ib))
1568                } else {
1569                    None
1571                }
1572            }
1573        }
1574    }
1575
1576    pub(crate) fn idx_uuid2rdn_diff(
1579        pre: Option<&Self>,
1580        post: Option<&Self>,
1581    ) -> Option<Result<String, ()>> {
1582        match (pre, post) {
1583            (None, None) => {
1584                None
1586            }
1587            (None, Some(b)) => {
1588                Some(Ok(b.get_uuid2rdn()))
1590            }
1591            (Some(_a), None) => {
1592                Some(Err(()))
1594            }
1595            (Some(a), Some(b)) => {
1596                let ia = a.get_uuid2rdn();
1597                let ib = b.get_uuid2rdn();
1598                if ia != ib {
1599                    Some(Ok(ib))
1601                } else {
1602                    None
1604                }
1605            }
1606        }
1607    }
1608
1609    pub(crate) fn idx_diff<'a>(
1612        idxmeta: &'a HashMap<IdxKey, IdxSlope>,
1613        pre: Option<&Self>,
1614        post: Option<&Self>,
1615    ) -> IdxDiff<'a> {
1616        match (pre, post) {
1621            (None, None) => {
1622                Vec::with_capacity(0)
1624            }
1625            (Some(pre_e), None) => {
1626                idxmeta
1628                    .keys()
1629                    .flat_map(|ikey| {
1630                        match pre_e.get_ava_set(&ikey.attr) {
1631                            None => Vec::with_capacity(0),
1632                            Some(vs) => {
1633                                let changes: Vec<Result<_, _>> = match ikey.itype {
1634                                    IndexType::Equality => {
1635                                        vs.generate_idx_eq_keys()
1637                                            .into_iter()
1638                                            .map(|idx_key| Err((&ikey.attr, ikey.itype, idx_key)))
1639                                            .collect()
1640                                    }
1641                                    IndexType::Presence => {
1642                                        vec![Err((&ikey.attr, ikey.itype, "_".to_string()))]
1643                                    }
1644                                    IndexType::SubString => vs
1645                                        .generate_idx_sub_keys()
1646                                        .into_iter()
1647                                        .map(|idx_key| Err((&ikey.attr, ikey.itype, idx_key)))
1648                                        .collect(),
1649                                };
1650                                changes
1651                            }
1652                        }
1653                    })
1654                    .collect()
1655            }
1656            (None, Some(post_e)) => {
1657                idxmeta
1659                    .keys()
1660                    .flat_map(|ikey| {
1661                        match post_e.get_ava_set(&ikey.attr) {
1662                            None => Vec::with_capacity(0),
1663                            Some(vs) => {
1664                                let changes: Vec<Result<_, _>> = match ikey.itype {
1665                                    IndexType::Equality => vs
1666                                        .generate_idx_eq_keys()
1667                                        .into_iter()
1668                                        .map(|idx_key| Ok((&ikey.attr, ikey.itype, idx_key)))
1669                                        .collect(),
1670                                    IndexType::Presence => {
1671                                        vec![Ok((&ikey.attr, ikey.itype, "_".to_string()))]
1672                                    }
1673                                    IndexType::SubString => vs
1674                                        .generate_idx_sub_keys()
1675                                        .into_iter()
1676                                        .map(|idx_key| Ok((&ikey.attr, ikey.itype, idx_key)))
1677                                        .collect(),
1678                                };
1679                                changes
1682                            }
1683                        }
1684                    })
1685                    .collect()
1686            }
1687            (Some(pre_e), Some(post_e)) => {
1688                assert_eq!(pre_e.state.id, post_e.state.id);
1689                idxmeta
1690                    .keys()
1691                    .flat_map(|ikey| {
1692                        match (
1693                            pre_e.get_ava_set(&ikey.attr),
1694                            post_e.get_ava_set(&ikey.attr),
1695                        ) {
1696                            (None, None) => {
1697                                Vec::with_capacity(0)
1699                            }
1700                            (Some(pre_vs), None) => {
1701                                let changes: Vec<Result<_, _>> = match ikey.itype {
1703                                    IndexType::Equality => {
1704                                        pre_vs
1707                                            .generate_idx_eq_keys()
1708                                            .into_iter()
1709                                            .map(|idx_key| Err((&ikey.attr, ikey.itype, idx_key)))
1710                                            .collect()
1711                                    }
1712                                    IndexType::Presence => {
1713                                        vec![Err((&ikey.attr, ikey.itype, "_".to_string()))]
1714                                    }
1715                                    IndexType::SubString => pre_vs
1716                                        .generate_idx_sub_keys()
1717                                        .into_iter()
1718                                        .map(|idx_key| Err((&ikey.attr, ikey.itype, idx_key)))
1719                                        .collect(),
1720                                };
1721                                changes
1722                            }
1723                            (None, Some(post_vs)) => {
1724                                let changes: Vec<Result<_, _>> = match ikey.itype {
1726                                    IndexType::Equality => {
1727                                        post_vs
1730                                            .generate_idx_eq_keys()
1731                                            .into_iter()
1732                                            .map(|idx_key| Ok((&ikey.attr, ikey.itype, idx_key)))
1733                                            .collect()
1734                                    }
1735                                    IndexType::Presence => {
1736                                        vec![Ok((&ikey.attr, ikey.itype, "_".to_string()))]
1737                                    }
1738                                    IndexType::SubString => post_vs
1739                                        .generate_idx_sub_keys()
1740                                        .into_iter()
1741                                        .map(|idx_key| Ok((&ikey.attr, ikey.itype, idx_key)))
1742                                        .collect(),
1743                                };
1744                                changes
1745                            }
1746                            (Some(pre_vs), Some(post_vs)) => {
1747                                let (mut pre_idx_keys, mut post_idx_keys) = match ikey.itype {
1749                                    IndexType::Equality => (
1750                                        pre_vs.generate_idx_eq_keys(),
1751                                        post_vs.generate_idx_eq_keys(),
1752                                    ),
1753                                    IndexType::Presence => {
1754                                        (Vec::with_capacity(0), Vec::with_capacity(0))
1756                                    }
1757                                    IndexType::SubString => (
1758                                        pre_vs.generate_idx_sub_keys(),
1759                                        post_vs.generate_idx_sub_keys(),
1760                                    ),
1761                                };
1762
1763                                let sz = if pre_idx_keys.len() > post_idx_keys.len() {
1764                                    pre_idx_keys.len()
1765                                } else {
1766                                    post_idx_keys.len()
1767                                };
1768
1769                                let mut added_vs = Vec::with_capacity(sz);
1770                                let mut removed_vs = Vec::with_capacity(sz);
1771
1772                                if sz > 0 {
1773                                    pre_idx_keys.sort_unstable();
1774                                    post_idx_keys.sort_unstable();
1775
1776                                    let mut pre_iter = pre_idx_keys.iter();
1777                                    let mut post_iter = post_idx_keys.iter();
1778
1779                                    let mut pre = pre_iter.next();
1780                                    let mut post = post_iter.next();
1781
1782                                    loop {
1783                                        match (pre, post) {
1784                                            (Some(a), Some(b)) => {
1785                                                match a.cmp(b) {
1786                                                    Ordering::Less => {
1787                                                        removed_vs.push(a.clone());
1788                                                        pre = pre_iter.next();
1789                                                    }
1790                                                    Ordering::Equal => {
1791                                                        pre = pre_iter.next();
1793                                                        post = post_iter.next();
1794                                                    }
1795                                                    Ordering::Greater => {
1796                                                        added_vs.push(b.clone());
1797                                                        post = post_iter.next();
1798                                                    }
1799                                                }
1800                                            }
1801                                            (Some(a), None) => {
1802                                                removed_vs.push(a.clone());
1803                                                pre = pre_iter.next();
1804                                            }
1805                                            (None, Some(b)) => {
1806                                                added_vs.push(b.clone());
1807                                                post = post_iter.next();
1808                                            }
1809                                            (None, None) => {
1810                                                break;
1811                                            }
1812                                        }
1813                                    }
1814                                } let mut diff =
1817                                    Vec::with_capacity(removed_vs.len() + added_vs.len());
1818
1819                                match ikey.itype {
1820                                    IndexType::SubString | IndexType::Equality => {
1821                                        removed_vs
1822                                            .into_iter()
1823                                            .map(|idx_key| Err((&ikey.attr, ikey.itype, idx_key)))
1824                                            .for_each(|v| diff.push(v));
1825                                        added_vs
1826                                            .into_iter()
1827                                            .map(|idx_key| Ok((&ikey.attr, ikey.itype, idx_key)))
1828                                            .for_each(|v| diff.push(v));
1829                                    }
1830                                    IndexType::Presence => {
1831                                        }
1833                                };
1834                                diff
1836                            }
1837                        }
1838                    })
1839                    .collect()
1840                }
1842        }
1843    }
1844
1845    pub fn from_dbentry(db_e: DbEntry, id: u64) -> Option<Self> {
1846        let (attrs, ecstate) = match db_e.ent {
1849            DbEntryVers::V3 { changestate, attrs } => {
1850                let ecstate = EntryChangeState::from_db_changestate(changestate);
1851
1852                let r_attrs = attrs
1853                    .into_iter()
1854                    .filter(|(_k, vs)| !vs.is_empty())
1856                    .map(|(k, dbvs)| {
1857                        valueset::from_db_valueset_v2(dbvs)
1858                            .map(|vs: ValueSet| (k, vs))
1859                            .map_err(|e| {
1860                                error!(?e, "from_dbentry failed");
1861                            })
1862                    })
1863                    .collect::<Result<Eattrs, ()>>()
1864                    .ok()?;
1865
1866                (r_attrs, ecstate)
1867            }
1868        };
1869
1870        let uuid = attrs
1871            .get(&Attribute::Uuid)
1872            .and_then(|vs| vs.to_uuid_single())?;
1873
1874        Some(Entry {
1875            valid: EntrySealed { uuid, ecstate },
1876            state: EntryCommitted { id },
1877            attrs,
1878        })
1879    }
1880
1881    #[cfg(test)]
1889    pub(crate) fn into_reduced(self) -> Entry<EntryReduced, EntryCommitted> {
1890        Entry {
1891            valid: EntryReduced {
1892                uuid: self.valid.uuid,
1893                effective_access: None,
1894            },
1895            state: self.state,
1896            attrs: self.attrs,
1897        }
1898    }
1899
1900    pub fn reduce_attributes(
1903        &self,
1904        allowed_attrs: &BTreeSet<Attribute>,
1905        effective_access: Option<Box<AccessEffectivePermission>>,
1906    ) -> Entry<EntryReduced, EntryCommitted> {
1907        let f_attrs: Map<_, _> = self
1909            .attrs
1910            .iter()
1911            .filter_map(|(k, v)| {
1912                if allowed_attrs.contains(k) {
1913                    Some((k.clone(), v.clone()))
1914                } else {
1915                    None
1916                }
1917            })
1918            .collect();
1919
1920        let valid = EntryReduced {
1921            uuid: self.valid.uuid,
1922            effective_access,
1923        };
1924        let state = self.state.clone();
1925
1926        Entry {
1927            valid,
1928            state,
1929            attrs: f_attrs,
1930        }
1931    }
1932
1933    pub fn to_tombstone(&self, cid: Cid) -> Entry<EntryInvalid, EntryCommitted> {
1935        let mut ecstate = self.valid.ecstate.clone();
1936        let mut attrs_new: Eattrs = Map::new();
1938
1939        let class_ava = vs_iutf8![EntryClass::Object.into(), EntryClass::Tombstone.into()];
1940        let last_mod_ava = vs_cid![cid.clone()];
1941        let created_ava = vs_cid![cid.clone()];
1942
1943        attrs_new.insert(Attribute::Uuid, vs_uuid![self.get_uuid()]);
1944        attrs_new.insert(Attribute::Class, class_ava);
1945        attrs_new.insert(Attribute::LastModifiedCid, last_mod_ava);
1946        attrs_new.insert(Attribute::CreatedAtCid, created_ava);
1947
1948        ecstate.tombstone(&cid);
1950
1951        Entry {
1952            valid: EntryInvalid { cid, ecstate },
1953            state: self.state.clone(),
1954            attrs: attrs_new,
1955        }
1956    }
1957
1958    pub fn into_valid(self, ecstate: EntryChangeState) -> Entry<EntryValid, EntryCommitted> {
1960        Entry {
1961            valid: EntryValid {
1962                uuid: self.valid.uuid,
1963                ecstate,
1964            },
1965            state: self.state,
1966            attrs: self.attrs,
1967        }
1968    }
1969
1970    pub fn verify(
1971        &self,
1972        schema: &dyn SchemaTransaction,
1973        results: &mut Vec<Result<(), ConsistencyError>>,
1974    ) {
1975        self.valid
1976            .ecstate
1977            .verify(schema, &self.attrs, self.state.id, results);
1978    }
1979}
1980
1981impl<STATE> Entry<EntryValid, STATE> {
1982    fn validate(&self, schema: &dyn SchemaTransaction) -> Result<(), SchemaError> {
1983        let schema_classes = schema.get_classes();
1984        let schema_attributes = schema.get_attributes();
1985
1986        trace!(?self.attrs, "Entry::validate -> target");
1988
1989        if !self.attribute_pres(Attribute::Class) {
1991            return Err(SchemaError::NoClassFound);
1993        }
1994
1995        if self.attribute_equality(Attribute::Class, &EntryClass::Conflict.into()) {
1996            trace!("Skipping schema validation on conflict entry");
1998            return Ok(());
1999        };
2000
2001        let recycled = self.attribute_equality(Attribute::Class, &EntryClass::Recycled.into());
2003
2004        let extensible =
2007            self.attribute_equality(Attribute::Class, &EntryClass::ExtensibleObject.into());
2008
2009        let entry_classes = self.get_ava_set(Attribute::Class).ok_or_else(|| {
2010            admin_debug!("Attribute '{}' missing from entry", Attribute::Class);
2011            SchemaError::NoClassFound
2012        })?;
2013        let mut invalid_classes = Vec::with_capacity(0);
2014
2015        let mut classes: Vec<&SchemaClass> = Vec::with_capacity(entry_classes.len());
2016
2017        let entry_classes = if let Some(ec) = entry_classes.as_iutf8_set() {
2020            ec.iter()
2021                .for_each(|s| match schema_classes.get(s.as_str()) {
2022                    Some(x) => classes.push(x),
2023                    None => {
2024                        admin_debug!("invalid class: {:?}", s);
2025                        invalid_classes.push(s.to_string())
2026                    }
2027                });
2028            ec
2029        } else {
2030            admin_debug!("corrupt class attribute");
2031            return Err(SchemaError::NoClassFound);
2032        };
2033
2034        if !invalid_classes.is_empty() {
2035            return Err(SchemaError::InvalidClass(invalid_classes));
2036        };
2037
2038        let supplements_classes: Vec<_> = classes
2042            .iter()
2043            .flat_map(|cls| cls.systemsupplements.iter().chain(cls.supplements.iter()))
2044            .collect();
2045
2046        let valid_supplements = if supplements_classes.is_empty() {
2048            true
2050        } else {
2051            supplements_classes
2052                .iter()
2053                .any(|class| entry_classes.contains(class.as_str()))
2054        };
2055
2056        if !valid_supplements {
2057            warn!(
2058                "Validation error, the following possible supplement classes are missing - {:?}",
2059                supplements_classes
2060            );
2061            let supplements_classes = supplements_classes.iter().map(|s| s.to_string()).collect();
2062            return Err(SchemaError::SupplementsNotSatisfied(supplements_classes));
2063        }
2064
2065        let excludes_classes: Vec<_> = classes
2066            .iter()
2067            .flat_map(|cls| cls.systemexcludes.iter().chain(cls.excludes.iter()))
2068            .collect();
2069
2070        let mut invalid_excludes = Vec::with_capacity(0);
2071
2072        excludes_classes.iter().for_each(|class| {
2073            if entry_classes.contains(class.as_str()) {
2074                invalid_excludes.push(class.to_string())
2075            }
2076        });
2077
2078        if !invalid_excludes.is_empty() {
2079            admin_warn!(
2080                "Validation error, the following excluded classes are present - {:?}",
2081                invalid_excludes
2082            );
2083            return Err(SchemaError::ExcludesNotSatisfied(invalid_excludes));
2084        }
2085
2086        let must: Result<Vec<&SchemaAttribute>, _> = classes
2099            .iter()
2100            .flat_map(|cls| cls.systemmust.iter().chain(cls.must.iter()))
2102            .map(|s| {
2103                schema_attributes.get(s).ok_or(SchemaError::Corrupted)
2106            })
2107            .collect();
2108
2109        let must = must?;
2110
2111        let mut missing_must = Vec::with_capacity(0);
2114        for attr in must.iter() {
2115            let avas = self.get_ava_set(&attr.name);
2116            if avas.is_none() {
2117                missing_must.push(attr.name.clone());
2118            }
2119        }
2120
2121        if !missing_must.is_empty() {
2122            admin_warn!(
2123                "Validation error, the following required ({}) (must) attributes are missing - {:?}",
2124                self.get_display_id(), missing_must
2125            );
2126            if !recycled {
2132                return Err(SchemaError::MissingMustAttribute(missing_must));
2133            }
2134        }
2135
2136        if extensible {
2137            self.attrs.iter().try_for_each(|(attr_name, avas)| {
2138                    match schema_attributes.get(attr_name) {
2139                        Some(a_schema) => {
2140                            if a_schema.phantom {
2143                                admin_warn!(
2144                                    "Rejecting attempt to add phantom attribute to extensible object: {}",
2145                                    attr_name
2146                                );
2147                                Err(SchemaError::PhantomAttribute(attr_name.to_string()))
2148                            } else {
2149                                a_schema.validate_ava(attr_name, avas)
2150                                }
2152                        }
2153                        None => {
2154                            admin_error!(
2155                                "Invalid Attribute {}, undefined in schema_attributes",
2156                                attr_name.to_string()
2157                            );
2158                            Err(SchemaError::InvalidAttribute(
2159                                attr_name.to_string()
2160                            ))
2161                        }
2162                    }
2163                })?;
2164        } else {
2165            let may: Result<Map<&Attribute, &SchemaAttribute>, _> = classes
2173                .iter()
2174                .flat_map(|cls| {
2176                    trace!(?cls);
2177                    cls.systemmust
2178                        .iter()
2179                        .chain(cls.must.iter())
2180                        .chain(cls.systemmay.iter())
2181                        .chain(cls.may.iter())
2182                })
2183                .map(|s| {
2184                    Ok((s, schema_attributes.get(s).ok_or(SchemaError::Corrupted)?))
2187                })
2188                .collect();
2189
2190            let may = may?;
2191
2192            self.attrs.iter().try_for_each(|(attr_name, avas)| {
2201                    match may.get(attr_name) {
2202                        Some(a_schema) => {
2203                            a_schema.validate_ava(attr_name, avas)
2206                            }
2208                        None => {
2209                            admin_error!(
2210                                "{} {} - not found in the list of valid attributes for this set of classes {:?} - valid attributes are {:?}",
2211
2212                                attr_name.as_str(),
2213                                self.get_display_id(),
2214                                entry_classes.iter().collect::<Vec<_>>(),
2215                                may.keys().collect::<Vec<_>>()
2216                            );
2217                            Err(SchemaError::AttributeNotValidForClass(
2218                                attr_name.to_string()
2219                            ))
2220                        }
2221                    }
2222                })?;
2223        }
2224
2225        Ok(())
2227    }
2228
2229    pub fn seal(mut self, schema: &dyn SchemaTransaction) -> Entry<EntrySealed, STATE> {
2230        let EntryValid { uuid, mut ecstate } = self.valid;
2231
2232        ecstate.retain(|k, _| schema.is_replicated(k));
2236
2237        let last_mod_cid = ecstate.get_max_cid();
2239        let cv = vs_cid![last_mod_cid.clone()];
2240        let _ = self.attrs.insert(Attribute::LastModifiedCid, cv);
2241
2242        let create_at_cid = ecstate.at();
2246        let cv = vs_cid![create_at_cid.clone()];
2247        let _ = self.attrs.insert(Attribute::CreatedAtCid, cv);
2248
2249        Entry {
2250            valid: EntrySealed { uuid, ecstate },
2251            state: self.state,
2252            attrs: self.attrs,
2253        }
2254    }
2255
2256    pub fn get_uuid(&self) -> Uuid {
2257        self.valid.uuid
2258    }
2259}
2260
2261impl<STATE> GetUuid for Entry<EntrySealed, STATE>
2262where
2263    STATE: Clone,
2264{
2265    fn get_uuid(&self) -> Uuid {
2266        self.valid.uuid
2267    }
2268}
2269
2270impl<STATE> Entry<EntrySealed, STATE>
2271where
2272    STATE: Clone,
2273{
2274    pub fn invalidate(mut self, cid: Cid, trim_cid: &Cid) -> Entry<EntryInvalid, STATE> {
2275        for vs in self.attrs.values_mut() {
2277            vs.trim(trim_cid);
2278        }
2279
2280        let last_mod_cid = self.valid.ecstate.get_max_cid();
2288        let cv = vs_cid![last_mod_cid.clone()];
2289        let _ = self.attrs.insert(Attribute::LastModifiedCid, cv);
2290
2291        let create_at_cid = self.valid.ecstate.at();
2292        let cv = vs_cid![create_at_cid.clone()];
2293        let _ = self.attrs.insert(Attribute::CreatedAtCid, cv);
2294
2295        Entry {
2296            valid: EntryInvalid {
2297                cid,
2298                ecstate: self.valid.ecstate,
2299            },
2300            state: self.state,
2301            attrs: self.attrs,
2302        }
2303    }
2304
2305    pub fn get_uuid(&self) -> Uuid {
2306        self.valid.uuid
2307    }
2308
2309    pub fn get_changestate(&self) -> &EntryChangeState {
2310        &self.valid.ecstate
2311    }
2312
2313    pub(crate) fn entry_changed_excluding_attribute<A: AsRef<Attribute>>(
2317        &self,
2318        attr: A,
2319        cid: &Cid,
2320    ) -> bool {
2321        let attr_ref = attr.as_ref();
2322
2323        use crate::repl::entry::State;
2324
2325        match self.get_changestate().current() {
2326            State::Live { at: _, changes } => {
2327                changes.iter().any(|(change_attr, change_id)| {
2328                    change_id >= cid &&
2329                    *change_attr != *attr_ref &&
2330                    *change_attr != Attribute::LastModifiedCid
2332                })
2333            }
2334            State::Tombstone { at } => at == cid,
2335        }
2336    }
2337
2338    #[cfg(test)]
2342    pub(crate) fn into_invalid(mut self) -> Entry<EntryInvalid, STATE> {
2343        let cid = Cid::new_zero();
2344        self.set_last_changed(cid.clone());
2345
2346        let ecstate = EntryChangeState::new_without_schema(&cid, &self.attrs);
2347
2348        Entry {
2349            valid: EntryInvalid { cid, ecstate },
2350            state: self.state,
2351            attrs: self.attrs,
2352        }
2353    }
2354}
2355
2356impl GetUuid for Entry<EntryReduced, EntryCommitted> {
2357    fn get_uuid(&self) -> Uuid {
2358        self.valid.uuid
2359    }
2360}
2361
2362impl Entry<EntryReduced, EntryCommitted> {
2363    pub fn get_uuid(&self) -> Uuid {
2364        self.valid.uuid
2365    }
2366
2367    pub fn to_pe(&self, qs: &mut QueryServerReadTransaction) -> Result<ProtoEntry, OperationError> {
2369        let attrs: Result<_, _> = self
2371            .attrs
2372            .iter()
2373            .map(|(k, vs)| qs.resolve_valueset(vs).map(|pvs| (k.to_string(), pvs)))
2374            .collect();
2375        Ok(ProtoEntry { attrs: attrs? })
2376    }
2377
2378    pub fn to_scim_kanidm<'a, TXN>(
2379        &self,
2380        read_txn: &mut TXN,
2381    ) -> Result<ScimEntryKanidm, OperationError>
2382    where
2383        TXN: QueryServerTransaction<'a>,
2384    {
2385        let result: Result<BTreeMap<Attribute, ScimValueKanidm>, OperationError> = self
2386            .attrs
2387            .iter()
2388            .filter(|(k, _vs)| **k != Attribute::Uuid)
2390            .filter_map(|(k, vs)| {
2391                let opt_resolve_status = vs.to_scim_value();
2392                let res_opt_scim_value = match opt_resolve_status {
2393                    None => Ok(None),
2394                    Some(ScimResolveStatus::Resolved(scim_value_kani)) => Ok(Some(scim_value_kani)),
2395                    Some(ScimResolveStatus::NeedsResolution(scim_value_interim)) => {
2396                        read_txn.resolve_scim_interim(scim_value_interim)
2397                    }
2398                };
2399                res_opt_scim_value
2400                    .transpose()
2401                    .map(|scim_res| scim_res.map(|scim_value| (k.clone(), scim_value)))
2402            })
2403            .collect();
2404
2405        let attrs = result?;
2406
2407        let ext_access_check = self.valid.effective_access.as_ref().map(|eff_acc| {
2408            let ident = eff_acc.ident;
2409            let delete = eff_acc.delete;
2410            let search = (&eff_acc.search).into();
2411            let modify_present = (&eff_acc.modify_pres).into();
2412            let modify_remove = (&eff_acc.modify_rem).into();
2413
2414            ScimEffectiveAccess {
2415                ident,
2416                delete,
2417                search,
2418                modify_present,
2419                modify_remove,
2420            }
2421        });
2422
2423        let id = self.get_uuid();
2424
2425        let schemas = Vec::with_capacity(0);
2428
2429        Ok(ScimEntryKanidm {
2430            header: ScimEntryHeader {
2431                schemas,
2432                id,
2433                external_id: None,
2435                meta: None,
2438            },
2439            ext_access_check,
2440            attrs,
2441        })
2442    }
2443
2444    pub fn to_ldap(
2446        &self,
2447        qs: &mut QueryServerReadTransaction,
2448        basedn: &str,
2449        all_attrs: bool,
2451        l_attrs: &[String],
2454    ) -> Result<LdapSearchResultEntry, OperationError> {
2455        let rdn = qs.uuid_to_rdn(self.get_uuid())?;
2456
2457        let dn = format!("{rdn},{basedn}");
2458
2459        let attr_map: Result<Map<&str, Vec<Vec<u8>>>, _> = self
2464            .attrs
2465            .iter()
2466            .map(|(k, vs)| {
2467                qs.resolve_valueset_ldap(vs, basedn)
2468                    .map(|pvs| (k.as_str(), pvs))
2469            })
2470            .collect();
2471        let attr_map = attr_map?;
2472
2473        let attr_names: Vec<(&str, &str)> = if all_attrs {
2476            self.attrs
2478                .keys()
2479                .map(|k| (k.as_str(), k.as_str()))
2480                .chain(
2481                    l_attrs
2482                        .iter()
2483                        .map(|k| (k.as_str(), ldap_vattr_map(k.as_str()).unwrap_or(k.as_str()))),
2484                )
2485                .collect()
2486        } else {
2487            l_attrs
2489                .iter()
2490                .map(|k| (k.as_str(), ldap_vattr_map(k.as_str()).unwrap_or(k.as_str())))
2491                .collect()
2492        };
2493
2494        let attributes: Vec<_> = attr_names
2496            .into_iter()
2497            .filter_map(|(ldap_a, kani_a)| {
2498                match ldap_a {
2500                    LDAP_ATTR_DN => Some(LdapPartialAttribute {
2501                        atype: LDAP_ATTR_DN.to_string(),
2502                        vals: vec![dn.as_bytes().to_vec()],
2503                    }),
2504                    LDAP_ATTR_ENTRYDN => Some(LdapPartialAttribute {
2505                        atype: LDAP_ATTR_ENTRYDN.to_string(),
2506                        vals: vec![dn.as_bytes().to_vec()],
2507                    }),
2508                    LDAP_ATTR_MAIL_PRIMARY | LDAP_ATTR_EMAIL_PRIMARY => {
2509                        attr_map.get(kani_a).map(|pvs| LdapPartialAttribute {
2510                            atype: ldap_a.to_string(),
2511                            vals: pvs
2512                                .first()
2513                                .map(|first| vec![first.clone()])
2514                                .unwrap_or_default(),
2515                        })
2516                    }
2517                    LDAP_ATTR_MAIL_ALTERNATIVE | LDAP_ATTR_EMAIL_ALTERNATIVE => {
2518                        attr_map.get(kani_a).map(|pvs| LdapPartialAttribute {
2519                            atype: ldap_a.to_string(),
2520                            vals: pvs
2521                                .split_first()
2522                                .map(|(_, rest)| rest.to_vec())
2523                                .unwrap_or_default(),
2524                        })
2525                    }
2526                    _ => attr_map.get(kani_a).map(|pvs| LdapPartialAttribute {
2527                        atype: ldap_a.to_string(),
2528                        vals: pvs.clone(),
2529                    }),
2530                }
2531            })
2532            .collect();
2533
2534        Ok(LdapSearchResultEntry { dn, attributes })
2535    }
2536}
2537
2538impl<VALID, STATE> Entry<VALID, STATE> {
2540    fn add_ava_int(&mut self, attr: Attribute, value: Value) -> bool {
2545        if let Some(vs) = self.attrs.get_mut(&attr) {
2546            let r = vs.insert_checked(value);
2547            debug_assert!(r.is_ok());
2548            r.unwrap_or(false)
2550        } else {
2551            #[allow(clippy::expect_used)]
2552            let vs = valueset::from_value_iter(std::iter::once(value))
2553                .expect("Unable to fail - non-zero iter, and single value type!");
2554            self.attrs.insert(attr, vs);
2555            true
2557        }
2558        }
2560
2561    fn set_ava_iter_int<T>(&mut self, attr: Attribute, iter: T)
2563    where
2564        T: IntoIterator<Item = Value>,
2565    {
2566        let Ok(vs) = valueset::from_value_iter(iter.into_iter()) else {
2567            trace!("set_ava_iter_int - empty from_value_iter, skipping");
2568            return;
2569        };
2570
2571        if let Some(existing_vs) = self.attrs.get_mut(&attr) {
2572            let _ = existing_vs.merge(&vs);
2574        } else {
2575            self.attrs.insert(attr, vs);
2577        }
2578    }
2579
2580    #[cfg(test)]
2582    fn set_last_changed(&mut self, cid: Cid) {
2583        let cv = vs_cid![cid.clone()];
2584        let _ = self.attrs.insert(Attribute::LastModifiedCid, cv);
2585        let cv = vs_cid![cid];
2586        let _ = self.attrs.insert(Attribute::CreatedAtCid, cv);
2587    }
2588
2589    pub(crate) fn get_display_id(&self) -> String {
2590        self.attrs
2591            .get(&Attribute::Spn)
2592            .and_then(|vs| vs.to_value_single())
2593            .or_else(|| {
2594                self.attrs
2595                    .get(&Attribute::Name)
2596                    .and_then(|vs| vs.to_value_single())
2597            })
2598            .or_else(|| {
2599                self.attrs
2600                    .get(&Attribute::Uuid)
2601                    .and_then(|vs| vs.to_value_single())
2602            })
2603            .map(|value| value.to_proto_string_clone())
2604            .unwrap_or_else(|| "no entry id available".to_string())
2605    }
2606
2607    pub fn get_ava_names(&self) -> impl Iterator<Item = &str> {
2609        self.attrs.keys().map(|a| a.as_str())
2611    }
2612
2613    pub fn get_ava(&self) -> &Eattrs {
2615        &self.attrs
2616    }
2617
2618    pub fn get_ava_iter(&self) -> impl Iterator<Item = (&Attribute, &ValueSet)> {
2619        self.attrs.iter()
2620    }
2621
2622    pub fn get_ava_set<A: AsRef<Attribute>>(&self, attr: A) -> Option<&ValueSet> {
2624        self.attrs.get(attr.as_ref())
2625    }
2626
2627    pub fn get_ava_refer<A: AsRef<Attribute>>(&self, attr: A) -> Option<&BTreeSet<Uuid>> {
2628        self.get_ava_set(attr).and_then(|vs| vs.as_refer_set())
2629    }
2630
2631    pub fn get_ava_as_iutf8_iter<A: AsRef<Attribute>>(
2632        &self,
2633        attr: A,
2634    ) -> Option<impl Iterator<Item = &str>> {
2635        self.get_ava_set(attr).and_then(|vs| vs.as_iutf8_iter())
2636    }
2637
2638    pub fn get_ava_as_iutf8<A: AsRef<Attribute>>(&self, attr: A) -> Option<&BTreeSet<String>> {
2639        self.get_ava_set(attr).and_then(|vs| vs.as_iutf8_set())
2640    }
2641
2642    pub fn get_ava_as_image<A: AsRef<Attribute>>(&self, attr: A) -> Option<&HashSet<ImageValue>> {
2643        self.get_ava_set(attr).and_then(|vs| vs.as_imageset())
2644    }
2645
2646    pub fn get_ava_single_image<A: AsRef<Attribute>>(&self, attr: A) -> Option<ImageValue> {
2647        let images = self.get_ava_set(attr).and_then(|vs| vs.as_imageset())?;
2648        images.iter().next().cloned()
2649    }
2650
2651    pub fn get_ava_single_credential_type<A: AsRef<Attribute>>(
2652        &self,
2653        attr: A,
2654    ) -> Option<CredentialType> {
2655        self.get_ava_set(attr)
2656            .and_then(|vs| vs.to_credentialtype_single())
2657    }
2658
2659    pub fn get_ava_as_oauthscopes<A: AsRef<Attribute>>(
2660        &self,
2661        attr: A,
2662    ) -> Option<impl Iterator<Item = &str>> {
2663        self.get_ava_set(attr)
2664            .and_then(|vs| vs.as_oauthscope_iter())
2665    }
2666
2667    pub fn get_ava_as_oauthscopemaps<A: AsRef<Attribute>>(
2668        &self,
2669        attr: A,
2670    ) -> Option<&std::collections::BTreeMap<Uuid, std::collections::BTreeSet<String>>> {
2671        self.get_ava_set(attr).and_then(|vs| vs.as_oauthscopemap())
2672    }
2673
2674    pub fn get_ava_as_intenttokens<A: AsRef<Attribute>>(
2675        &self,
2676        attr: A,
2677    ) -> Option<&std::collections::BTreeMap<String, IntentTokenState>> {
2678        self.get_ava_set(attr)
2679            .and_then(|vs| vs.as_intenttoken_map())
2680    }
2681
2682    pub fn get_ava_as_session_map<A: AsRef<Attribute>>(
2683        &self,
2684        attr: A,
2685    ) -> Option<&std::collections::BTreeMap<Uuid, Session>> {
2686        self.get_ava_set(attr).and_then(|vs| vs.as_session_map())
2687    }
2688
2689    pub fn get_ava_as_apitoken_map<A: AsRef<Attribute>>(
2690        &self,
2691        attr: A,
2692    ) -> Option<&std::collections::BTreeMap<Uuid, ApiToken>> {
2693        self.get_ava_set(attr).and_then(|vs| vs.as_apitoken_map())
2694    }
2695
2696    pub fn get_ava_as_oauth2session_map<A: AsRef<Attribute>>(
2697        &self,
2698        attr: A,
2699    ) -> Option<&std::collections::BTreeMap<Uuid, Oauth2Session>> {
2700        self.get_ava_set(attr)
2701            .and_then(|vs| vs.as_oauth2session_map())
2702    }
2703
2704    pub fn get_ava_iter_iname<A: AsRef<Attribute>>(
2706        &self,
2707        attr: A,
2708    ) -> Option<impl Iterator<Item = &str>> {
2709        self.get_ava_set(attr).and_then(|vs| vs.as_iname_iter())
2710    }
2711
2712    pub fn get_ava_iter_iutf8<A: AsRef<Attribute>>(
2714        &self,
2715        attr: A,
2716    ) -> Option<impl Iterator<Item = &str>> {
2717        self.get_ava_set(attr).and_then(|vs| vs.as_iutf8_iter())
2718    }
2719
2720    pub fn get_ava_as_refuuid<A: AsRef<Attribute>>(
2722        &self,
2723        attr: A,
2724    ) -> Option<Box<dyn Iterator<Item = Uuid> + '_>> {
2725        self.get_ava_set(attr).and_then(|vs| vs.as_ref_uuid_iter())
2727    }
2728
2729    pub fn get_ava_iter_sshpubkeys<A: AsRef<Attribute>>(
2731        &self,
2732        attr: A,
2733    ) -> Option<impl Iterator<Item = String> + '_> {
2734        self.get_ava_set(attr)
2735            .and_then(|vs| vs.as_sshpubkey_string_iter())
2736    }
2737
2738    pub fn get_ava_single<A: AsRef<Attribute>>(&self, attr: A) -> Option<Value> {
2744        self.get_ava_set(attr).and_then(|vs| vs.to_value_single())
2745    }
2746
2747    pub fn get_ava_single_proto_string<A: AsRef<Attribute>>(&self, attr: A) -> Option<String> {
2748        self.get_ava_set(attr)
2749            .and_then(|vs| vs.to_proto_string_single())
2750    }
2751
2752    pub fn get_ava_single_bool<A: AsRef<Attribute>>(&self, attr: A) -> Option<bool> {
2754        self.get_ava_set(attr).and_then(|vs| vs.to_bool_single())
2755    }
2756
2757    pub fn get_ava_single_uint32<A: AsRef<Attribute>>(&self, attr: A) -> Option<u32> {
2759        self.get_ava_set(attr).and_then(|vs| vs.to_uint32_single())
2760    }
2761
2762    pub fn get_ava_single_syntax<A: AsRef<Attribute>>(&self, attr: A) -> Option<SyntaxType> {
2764        self.get_ava_set(attr)
2765            .and_then(|vs| vs.to_syntaxtype_single())
2766    }
2767
2768    pub fn get_ava_single_credential<A: AsRef<Attribute>>(&self, attr: A) -> Option<&Credential> {
2770        self.get_ava_set(attr)
2771            .and_then(|vs| vs.to_credential_single())
2772    }
2773
2774    pub fn get_ava_passkeys<A: AsRef<Attribute>>(
2776        &self,
2777        attr: A,
2778    ) -> Option<&BTreeMap<Uuid, (String, PasskeyV4)>> {
2779        self.get_ava_set(attr).and_then(|vs| vs.as_passkey_map())
2780    }
2781
2782    pub fn get_ava_attestedpasskeys<A: AsRef<Attribute>>(
2784        &self,
2785        attr: A,
2786    ) -> Option<&BTreeMap<Uuid, (String, AttestedPasskeyV4)>> {
2787        self.get_ava_set(attr)
2788            .and_then(|vs| vs.as_attestedpasskey_map())
2789    }
2790
2791    pub fn get_ava_uihint<A: AsRef<Attribute>>(&self, attr: A) -> Option<&BTreeSet<UiHint>> {
2793        self.get_ava_set(attr).and_then(|vs| vs.as_uihint_set())
2794    }
2795
2796    pub fn get_ava_single_secret<A: AsRef<Attribute>>(&self, attr: A) -> Option<&str> {
2798        self.get_ava_set(attr).and_then(|vs| vs.to_secret_single())
2799    }
2800
2801    pub fn get_ava_single_datetime<A: AsRef<Attribute>>(&self, attr: A) -> Option<OffsetDateTime> {
2803        self.get_ava_set(attr)
2804            .and_then(|vs| vs.to_datetime_single())
2805    }
2806
2807    pub(crate) fn get_ava_single_utf8<A: AsRef<Attribute>>(&self, attr: A) -> Option<&str> {
2809        self.get_ava_set(attr).and_then(|vs| vs.to_utf8_single())
2810    }
2811
2812    pub(crate) fn get_ava_single_iutf8<A: AsRef<Attribute>>(&self, attr: A) -> Option<&str> {
2814        self.get_ava_set(attr).and_then(|vs| vs.to_iutf8_single())
2815    }
2816
2817    pub(crate) fn get_ava_single_iname<A: AsRef<Attribute>>(&self, attr: A) -> Option<&str> {
2819        self.get_ava_set(attr).and_then(|vs| vs.to_iname_single())
2820    }
2821
2822    pub fn get_ava_single_url<A: AsRef<Attribute>>(&self, attr: A) -> Option<&Url> {
2824        self.get_ava_set(attr).and_then(|vs| vs.to_url_single())
2825    }
2826
2827    pub fn get_ava_single_uuid<A: AsRef<Attribute>>(&self, attr: A) -> Option<Uuid> {
2828        self.get_ava_set(attr).and_then(|vs| vs.to_uuid_single())
2829    }
2830
2831    pub fn get_ava_single_refer<A: AsRef<Attribute>>(&self, attr: A) -> Option<Uuid> {
2832        self.get_ava_set(attr).and_then(|vs| vs.to_refer_single())
2833    }
2834
2835    pub fn get_ava_mail_primary<A: AsRef<Attribute>>(&self, attr: A) -> Option<&str> {
2836        self.get_ava_set(attr)
2837            .and_then(|vs| vs.to_email_address_primary_str())
2838    }
2839
2840    pub fn get_ava_iter_mail<A: AsRef<Attribute>>(
2841        &self,
2842        attr: A,
2843    ) -> Option<impl Iterator<Item = &str>> {
2844        self.get_ava_set(attr).and_then(|vs| vs.as_email_str_iter())
2845    }
2846
2847    pub fn get_ava_single_protofilter<A: AsRef<Attribute>>(&self, attr: A) -> Option<&ProtoFilter> {
2849        self.get_ava_set(attr)
2850            .and_then(|vs| vs.to_json_filter_single())
2851    }
2852
2853    pub fn get_ava_single_private_binary<A: AsRef<Attribute>>(&self, attr: A) -> Option<&[u8]> {
2854        self.get_ava_set(attr)
2855            .and_then(|vs| vs.to_private_binary_single())
2856    }
2857
2858    pub fn get_ava_single_jws_key_es256<A: AsRef<Attribute>>(
2859        &self,
2860        attr: A,
2861    ) -> Option<&JwsEs256Signer> {
2862        self.get_ava_set(attr)
2863            .and_then(|vs| vs.to_jws_key_es256_single())
2864    }
2865
2866    pub fn get_ava_single_eckey_private<A: AsRef<Attribute>>(
2867        &self,
2868        attr: A,
2869    ) -> Option<&EcKey<Private>> {
2870        self.get_ava_set(attr)
2871            .and_then(|vs| vs.to_eckey_private_single())
2872    }
2873
2874    pub fn get_ava_single_eckey_public<A: AsRef<Attribute>>(
2875        &self,
2876        attr: A,
2877    ) -> Option<&EcKey<Public>> {
2878        self.get_ava_set(attr)
2879            .and_then(|vs| vs.to_eckey_public_single())
2880    }
2881
2882    pub fn get_ava_webauthn_attestation_ca_list<A: AsRef<Attribute>>(
2883        &self,
2884        attr: A,
2885    ) -> Option<&AttestationCaList> {
2886        self.get_ava_set(attr)
2887            .and_then(|vs| vs.as_webauthn_attestation_ca_list())
2888    }
2889
2890    pub fn get_ava_application_password<A: AsRef<Attribute>>(
2891        &self,
2892        attr: A,
2893    ) -> Option<&BTreeMap<Uuid, Vec<ApplicationPassword>>> {
2894        self.get_ava_set(attr)
2895            .and_then(|vs| vs.as_application_password_map())
2896    }
2897
2898    pub(crate) fn generate_spn(&self, domain_name: &str) -> Option<Value> {
2900        self.get_ava_single_iname(Attribute::Name)
2901            .map(|name| Value::new_spn_str(name, domain_name))
2902    }
2903
2904    pub fn attribute_pres<A: AsRef<Attribute>>(&self, attr: A) -> bool {
2906        self.attrs.contains_key(attr.as_ref())
2907    }
2908
2909    pub fn attribute_equality<A: AsRef<Attribute>>(&self, attr: A, value: &PartialValue) -> bool {
2912        match self.attrs.get(attr.as_ref()) {
2917            Some(v_list) => v_list.contains(value),
2918            None => false,
2919        }
2920    }
2921
2922    pub fn attribute_substring<A: AsRef<Attribute>>(
2925        &self,
2926        attr: A,
2927        subvalue: &PartialValue,
2928    ) -> bool {
2929        self.get_ava_set(attr)
2930            .map(|vset| vset.substring(subvalue))
2931            .unwrap_or(false)
2932    }
2933
2934    pub fn attribute_startswith<A: AsRef<Attribute>>(
2937        &self,
2938        attr: A,
2939        subvalue: &PartialValue,
2940    ) -> bool {
2941        self.get_ava_set(attr)
2942            .map(|vset| vset.startswith(subvalue))
2943            .unwrap_or(false)
2944    }
2945
2946    pub fn attribute_endswith<A: AsRef<Attribute>>(
2949        &self,
2950        attr: A,
2951        subvalue: &PartialValue,
2952    ) -> bool {
2953        self.get_ava_set(attr)
2954            .map(|vset| vset.endswith(subvalue))
2955            .unwrap_or(false)
2956    }
2957
2958    pub fn attribute_lessthan<A: AsRef<Attribute>>(
2961        &self,
2962        attr: A,
2963        subvalue: &PartialValue,
2964    ) -> bool {
2965        self.get_ava_set(attr)
2966            .map(|vset| vset.lessthan(subvalue))
2967            .unwrap_or(false)
2968    }
2969
2970    #[inline(always)]
2975    #[instrument(level = "trace", name = "entry::entry_match_no_index", skip(self))]
2976    pub fn entry_match_no_index(&self, filter: &Filter<FilterValidResolved>) -> bool {
2978        self.entry_match_no_index_inner(filter.to_inner())
2979    }
2980
2981    fn entry_match_no_index_inner(&self, filter: &FilterResolved) -> bool {
2985        match filter {
2988            FilterResolved::Eq(attr, value, _) => self.attribute_equality(attr, value),
2989            FilterResolved::Cnt(attr, subvalue, _) => self.attribute_substring(attr, subvalue),
2990            FilterResolved::Stw(attr, subvalue, _) => self.attribute_startswith(attr, subvalue),
2991            FilterResolved::Enw(attr, subvalue, _) => self.attribute_endswith(attr, subvalue),
2992            FilterResolved::Pres(attr, _) => self.attribute_pres(attr),
2993            FilterResolved::LessThan(attr, subvalue, _) => self.attribute_lessthan(attr, subvalue),
2994            FilterResolved::Or(l, _) => l.iter().any(|f| self.entry_match_no_index_inner(f)),
2996            FilterResolved::And(l, _) => l.iter().all(|f| self.entry_match_no_index_inner(f)),
2998            FilterResolved::Inclusion(_, _) => {
2999                false
3003            }
3004            FilterResolved::AndNot(f, _) => !self.entry_match_no_index_inner(f),
3005            FilterResolved::Invalid(_) => false,
3006        }
3007    }
3008
3009    pub fn filter_from_attrs(&self, attrs: &[Attribute]) -> Option<Filter<FilterInvalid>> {
3012        let mut pairs: Vec<(Attribute, PartialValue)> = Vec::with_capacity(0);
3024
3025        for attr in attrs {
3026            match self.attrs.get(attr) {
3027                Some(values) => values
3028                    .to_partialvalue_iter()
3029                    .for_each(|pv| pairs.push((attr.clone(), pv))),
3030                None => return None,
3031            }
3032        }
3033
3034        let res: Vec<FC> = pairs
3035            .into_iter()
3036            .map(|(attr, pv)| FC::Eq(attr, pv))
3037            .collect();
3038        Some(filter_all!(f_and(res)))
3039    }
3040
3041    pub fn gen_modlist_assert(
3044        &self,
3045        schema: &dyn SchemaTransaction,
3046    ) -> Result<ModifyList<ModifyInvalid>, SchemaError> {
3047        let mut mods = ModifyList::new();
3051
3052        for (k, vs) in self.attrs.iter() {
3053            if *k == Attribute::Uuid {
3069                continue;
3070            }
3071            match schema.is_multivalue(k) {
3073                Ok(r) => {
3074                    if !r ||
3077                        *k == Attribute::AcpReceiverGroup ||
3080                        *k == Attribute::AcpCreateAttr ||
3081                        *k == Attribute::AcpCreateClass ||
3082                        *k == Attribute::AcpModifyPresentAttr ||
3083                        *k == Attribute::AcpModifyRemovedAttr ||
3084                        *k == Attribute::AcpModifyClass ||
3085                        *k == Attribute::SystemMust ||
3086                        *k == Attribute::SystemMay
3087                    {
3088                        mods.push_mod(Modify::Purged(k.clone()));
3089                    }
3090                }
3091                Err(e) => return Err(e),
3093            }
3094            for v in vs.to_value_iter() {
3095                mods.push_mod(Modify::Present(k.clone(), v.clone()));
3096            }
3097        }
3098
3099        Ok(mods)
3100    }
3101
3102    pub fn mask_recycled_ts(&self) -> Option<&Self> {
3105        match self.attrs.get(&Attribute::Class) {
3107            Some(cls) => {
3108                if cls.contains(&EntryClass::Tombstone.to_partialvalue())
3109                    || cls.contains(&EntryClass::Recycled.to_partialvalue())
3110                {
3111                    None
3112                } else {
3113                    Some(self)
3114                }
3115            }
3116            None => Some(self),
3117        }
3118    }
3119
3120    pub fn mask_recycled(&self) -> Option<&Self> {
3123        match self.attrs.get(&Attribute::Class) {
3125            Some(cls) => {
3126                if cls.contains(&EntryClass::Recycled.to_partialvalue()) {
3127                    None
3128                } else {
3129                    Some(self)
3130                }
3131            }
3132            None => Some(self),
3133        }
3134    }
3135
3136    pub fn mask_tombstone(&self) -> Option<&Self> {
3139        match self.attrs.get(&Attribute::Class) {
3141            Some(cls) => {
3142                if cls.contains(&EntryClass::Tombstone.to_partialvalue()) {
3143                    None
3144                } else {
3145                    Some(self)
3146                }
3147            }
3148            None => Some(self),
3149        }
3150    }
3151}
3152
3153impl<STATE> Entry<EntryInvalid, STATE>
3154where
3155    STATE: Clone,
3156{
3157    pub fn add_ava(&mut self, attr: Attribute, value: Value) {
3162        self.valid.ecstate.change_ava(&self.valid.cid, &attr);
3163        self.add_ava_int(attr, value);
3164    }
3165
3166    pub fn add_ava_if_not_exist<A: AsRef<Attribute>>(&mut self, attr: A, value: Value) {
3167        let attr_ref = attr.as_ref();
3168        if self.add_ava_int(attr_ref.clone(), value) {
3170            self.valid.ecstate.change_ava(&self.valid.cid, attr_ref);
3172        }
3173    }
3174
3175    fn assert_ava<A: AsRef<Attribute>>(
3176        &mut self,
3177        attr: A,
3178        value: &PartialValue,
3179    ) -> Result<(), OperationError> {
3180        self.valid
3181            .ecstate
3182            .change_ava(&self.valid.cid, attr.as_ref());
3183
3184        if self.attribute_equality(attr, value) {
3185            Ok(())
3186        } else {
3187            Err(OperationError::ModifyAssertionFailed)
3188        }
3189    }
3190
3191    pub(crate) fn remove_ava<A: AsRef<Attribute>>(&mut self, attr: A, value: &PartialValue) {
3194        let attr_ref = attr.as_ref();
3195        self.valid.ecstate.change_ava(&self.valid.cid, attr_ref);
3196
3197        let rm = if let Some(vs) = self.attrs.get_mut(attr_ref) {
3198            vs.remove(value, &self.valid.cid);
3199            vs.is_empty()
3200        } else {
3201            false
3202        };
3203        if rm {
3204            self.attrs.remove(attr_ref);
3205        };
3206    }
3207
3208    pub(crate) fn remove_avas<A: AsRef<Attribute>>(
3209        &mut self,
3210        attr: A,
3211        values: &BTreeSet<PartialValue>,
3212    ) {
3213        let attr_ref = attr.as_ref();
3214        self.valid.ecstate.change_ava(&self.valid.cid, attr_ref);
3215
3216        let rm = if let Some(vs) = self.attrs.get_mut(attr_ref) {
3217            values.iter().for_each(|k| {
3218                vs.remove(k, &self.valid.cid);
3219            });
3220            vs.is_empty()
3221        } else {
3222            false
3223        };
3224        if rm {
3225            self.attrs.remove(attr_ref);
3226        };
3227    }
3228
3229    pub(crate) fn purge_ava<A: AsRef<Attribute>>(&mut self, attr: A) {
3232        let attr_ref = attr.as_ref();
3233        self.valid.ecstate.change_ava(&self.valid.cid, attr_ref);
3234        let can_remove = self
3237            .attrs
3238            .get_mut(attr_ref)
3239            .map(|vs| vs.purge(&self.valid.cid))
3240            .unwrap_or_default();
3242        if can_remove {
3243            self.attrs.remove(attr_ref);
3244        }
3245    }
3246
3247    pub fn pop_ava<A: AsRef<Attribute>>(&mut self, attr: A) -> Option<ValueSet> {
3249        let attr_ref = attr.as_ref();
3250        self.valid.ecstate.change_ava(&self.valid.cid, attr_ref);
3251
3252        let mut vs = self.attrs.remove(attr_ref)?;
3253        if vs.purge(&self.valid.cid) {
3254            Some(vs)
3256        } else {
3257            let r_vs = vs.clone();
3259            self.attrs.insert(attr_ref.clone(), vs);
3260            Some(r_vs)
3261        }
3262    }
3263
3264    #[cfg(test)]
3269    pub(crate) fn force_trim_ava<A: AsRef<Attribute>>(&mut self, attr: A) -> Option<ValueSet> {
3270        self.valid
3271            .ecstate
3272            .change_ava(&self.valid.cid, attr.as_ref());
3273        self.attrs.remove(attr.as_ref())
3274    }
3275
3276    pub fn set_ava<T>(&mut self, attr: &Attribute, iter: T)
3279    where
3280        T: Clone + IntoIterator<Item = Value>,
3281    {
3282        self.purge_ava(attr);
3283        self.set_ava_iter_int(attr.clone(), iter)
3284    }
3285
3286    pub fn set_ava_set(&mut self, attr: &Attribute, vs: ValueSet) {
3289        self.purge_ava(attr);
3290        if let Some(existing_vs) = self.attrs.get_mut(attr) {
3291            let _ = existing_vs.merge(&vs);
3292        } else {
3293            self.attrs.insert(attr.clone(), vs);
3294        }
3295    }
3296
3297    pub fn merge_ava_set(&mut self, attr: &Attribute, vs: ValueSet) -> Result<(), OperationError> {
3300        self.valid.ecstate.change_ava(&self.valid.cid, attr);
3301        if let Some(existing_vs) = self.attrs.get_mut(attr) {
3302            existing_vs.merge(&vs)
3303        } else {
3304            self.attrs.insert(attr.clone(), vs);
3305            Ok(())
3306        }
3307    }
3308
3309    pub fn apply_modlist(
3311        &mut self,
3312        modlist: &ModifyList<ModifyValid>,
3313    ) -> Result<(), OperationError> {
3314        for modify in modlist {
3315            match modify {
3316                Modify::Present(attr, value) => {
3317                    self.add_ava(attr.clone(), value.clone());
3318                }
3319                Modify::Removed(attr, value) => {
3320                    self.remove_ava(attr, value);
3321                }
3322                Modify::Purged(attr) => {
3323                    self.purge_ava(attr);
3324                }
3325                Modify::Assert(attr, value) => {
3326                    self.assert_ava(attr, value).inspect_err(|_e| {
3327                        error!("Modification assertion was not met. {} {:?}", attr, value);
3328                    })?;
3329                }
3330                Modify::Set(attr, valueset) => self.set_ava_set(attr, valueset.clone()),
3331            }
3332        }
3333        Ok(())
3334    }
3335}
3336
3337impl<VALID, STATE> PartialEq for Entry<VALID, STATE> {
3338    fn eq(&self, rhs: &Entry<VALID, STATE>) -> bool {
3339        compare_attrs(&self.attrs, &rhs.attrs)
3350    }
3351}
3352
3353#[cfg(test)]
3354mod tests {
3355    use crate::prelude::*;
3356    use std::collections::BTreeSet as Set;
3357
3358    use hashbrown::HashMap;
3359
3360    use crate::be::{IdxKey, IdxSlope};
3361    use crate::entry::{Entry, EntryInit, EntryInvalid, EntryNew};
3362    use crate::modify::{Modify, ModifyList};
3363    use crate::value::{IndexType, PartialValue, Value};
3364
3365    #[test]
3366    fn test_entry_basic() {
3367        let mut e: Entry<EntryInit, EntryNew> = Entry::new();
3368
3369        e.add_ava(Attribute::UserId, Value::from("william"));
3370    }
3371
3372    #[test]
3373    fn test_entry_dup_value() {
3374        let mut e: Entry<EntryInit, EntryNew> = Entry::new();
3381        e.add_ava(Attribute::UserId, Value::from("william"));
3382        e.add_ava(Attribute::UserId, Value::from("william"));
3383
3384        let values = e.get_ava_set(Attribute::UserId).expect("Failed to get ava");
3385        assert_eq!(values.len(), 1)
3387    }
3388
3389    #[test]
3390    fn test_entry_pres() {
3391        let mut e: Entry<EntryInit, EntryNew> = Entry::new();
3392        e.add_ava(Attribute::UserId, Value::from("william"));
3393
3394        assert!(e.attribute_pres(Attribute::UserId));
3395        assert!(!e.attribute_pres(Attribute::Name));
3396    }
3397
3398    #[test]
3399    fn test_entry_equality() {
3400        let mut e: Entry<EntryInit, EntryNew> = Entry::new();
3401
3402        e.add_ava(Attribute::UserId, Value::from("william"));
3403
3404        assert!(e.attribute_equality(Attribute::UserId, &PartialValue::new_utf8s("william")));
3405        assert!(!e.attribute_equality(Attribute::UserId, &PartialValue::new_utf8s("test")));
3406        assert!(!e.attribute_equality(Attribute::NonExist, &PartialValue::new_utf8s("william")));
3407        assert!(!e.attribute_equality(Attribute::UserId, &PartialValue::new_iutf8("william")));
3409    }
3410
3411    #[test]
3412    fn test_entry_substring() {
3413        let mut e: Entry<EntryInit, EntryNew> = Entry::new();
3414
3415        e.add_ava(Attribute::UserId, Value::from("william"));
3416
3417        assert!(e.attribute_substring(Attribute::UserId, &PartialValue::new_utf8s("william")));
3418        assert!(e.attribute_substring(Attribute::UserId, &PartialValue::new_utf8s("will")));
3419        assert!(e.attribute_substring(Attribute::UserId, &PartialValue::new_utf8s("liam")));
3420        assert!(e.attribute_substring(Attribute::UserId, &PartialValue::new_utf8s("lli")));
3421        assert!(!e.attribute_substring(Attribute::UserId, &PartialValue::new_utf8s("llim")));
3422        assert!(!e.attribute_substring(Attribute::UserId, &PartialValue::new_utf8s("bob")));
3423        assert!(!e.attribute_substring(Attribute::UserId, &PartialValue::new_utf8s("wl")));
3424
3425        assert!(e.attribute_startswith(Attribute::UserId, &PartialValue::new_utf8s("will")));
3426        assert!(!e.attribute_startswith(Attribute::UserId, &PartialValue::new_utf8s("liam")));
3427        assert!(!e.attribute_startswith(Attribute::UserId, &PartialValue::new_utf8s("lli")));
3428        assert!(!e.attribute_startswith(Attribute::UserId, &PartialValue::new_utf8s("llim")));
3429        assert!(!e.attribute_startswith(Attribute::UserId, &PartialValue::new_utf8s("bob")));
3430        assert!(!e.attribute_startswith(Attribute::UserId, &PartialValue::new_utf8s("wl")));
3431
3432        assert!(e.attribute_endswith(Attribute::UserId, &PartialValue::new_utf8s("liam")));
3433        assert!(!e.attribute_endswith(Attribute::UserId, &PartialValue::new_utf8s("will")));
3434        assert!(!e.attribute_endswith(Attribute::UserId, &PartialValue::new_utf8s("lli")));
3435        assert!(!e.attribute_endswith(Attribute::UserId, &PartialValue::new_utf8s("llim")));
3436        assert!(!e.attribute_endswith(Attribute::UserId, &PartialValue::new_utf8s("bob")));
3437        assert!(!e.attribute_endswith(Attribute::UserId, &PartialValue::new_utf8s("wl")));
3438    }
3439
3440    #[test]
3441    fn test_entry_lessthan() {
3442        let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
3443
3444        let pv2 = PartialValue::new_uint32(2);
3445        let pv8 = PartialValue::new_uint32(8);
3446        let pv10 = PartialValue::new_uint32(10);
3447        let pv15 = PartialValue::new_uint32(15);
3448
3449        e1.add_ava(Attribute::TestAttr, Value::new_uint32(10));
3450
3451        assert!(!e1.attribute_lessthan(Attribute::TestAttr, &pv2));
3452        assert!(!e1.attribute_lessthan(Attribute::TestAttr, &pv8));
3453        assert!(!e1.attribute_lessthan(Attribute::TestAttr, &pv10));
3454        assert!(e1.attribute_lessthan(Attribute::TestAttr, &pv15));
3455
3456        e1.add_ava(Attribute::TestAttr, Value::new_uint32(8));
3457
3458        assert!(!e1.attribute_lessthan(Attribute::TestAttr, &pv2));
3459        assert!(!e1.attribute_lessthan(Attribute::TestAttr, &pv8));
3460        assert!(e1.attribute_lessthan(Attribute::TestAttr, &pv10));
3461        assert!(e1.attribute_lessthan(Attribute::TestAttr, &pv15));
3462    }
3463
3464    #[test]
3465    fn test_entry_apply_modlist() {
3466        let mut e: Entry<EntryInvalid, EntryNew> = Entry::new().into_invalid_new();
3468
3469        e.add_ava(Attribute::UserId, Value::from("william"));
3470
3471        let present_single_mods = ModifyList::new_valid_list(vec![Modify::Present(
3472            Attribute::Attr,
3473            Value::new_iutf8("value"),
3474        )]);
3475
3476        assert!(e.apply_modlist(&present_single_mods).is_ok());
3477
3478        assert!(e.attribute_equality(Attribute::UserId, &PartialValue::new_utf8s("william")));
3480        assert!(e.attribute_equality(Attribute::Attr, &PartialValue::new_iutf8("value")));
3481
3482        let present_multivalue_mods = ModifyList::new_valid_list(vec![
3484            Modify::Present(Attribute::Class, Value::new_iutf8("test")),
3485            Modify::Present(Attribute::Class, Value::new_iutf8("multi_test")),
3486        ]);
3487
3488        assert!(e.apply_modlist(&present_multivalue_mods).is_ok());
3489
3490        assert!(e.attribute_equality(Attribute::Class, &PartialValue::new_iutf8("test")));
3491        assert!(e.attribute_equality(Attribute::Class, &PartialValue::new_iutf8("multi_test")));
3492
3493        let purge_single_mods = ModifyList::new_valid_list(vec![Modify::Purged(Attribute::Attr)]);
3495
3496        assert!(e.apply_modlist(&purge_single_mods).is_ok());
3497
3498        assert!(!e.attribute_pres(Attribute::Attr));
3499
3500        let purge_multi_mods = ModifyList::new_valid_list(vec![Modify::Purged(Attribute::Class)]);
3501
3502        assert!(e.apply_modlist(&purge_multi_mods).is_ok());
3503
3504        assert!(!e.attribute_pres(Attribute::Class));
3505
3506        let purge_empty_mods = purge_single_mods;
3507
3508        assert!(e.apply_modlist(&purge_empty_mods).is_ok());
3509
3510        let remove_mods = ModifyList::new_valid_list(vec![Modify::Removed(
3512            Attribute::Attr,
3513            PartialValue::new_iutf8("value"),
3514        )]);
3515
3516        assert!(e.apply_modlist(&present_single_mods).is_ok());
3517        assert!(e.attribute_equality(Attribute::Attr, &PartialValue::new_iutf8("value")));
3518        assert!(e.apply_modlist(&remove_mods).is_ok());
3519        assert!(!e.attrs.contains_key(&Attribute::Attr));
3520
3521        let remove_empty_mods = remove_mods;
3522
3523        assert!(e.apply_modlist(&remove_empty_mods).is_ok());
3524
3525        assert!(!e.attrs.contains_key(&Attribute::Attr));
3526    }
3527
3528    #[test]
3529    fn test_entry_idx_diff() {
3530        let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
3531        e1.add_ava(Attribute::UserId, Value::from("william"));
3532        let mut e1_mod = e1.clone();
3533        e1_mod.add_ava(Attribute::Extra, Value::from("test"));
3534
3535        let e1 = e1.into_sealed_committed();
3536        let e1_mod = e1_mod.into_sealed_committed();
3537
3538        let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
3539        e2.add_ava(Attribute::UserId, Value::from("claire"));
3540        let e2 = e2.into_sealed_committed();
3541
3542        let mut idxmeta = HashMap::with_capacity(8);
3543        idxmeta.insert(
3544            IdxKey {
3545                attr: Attribute::UserId,
3546                itype: IndexType::Equality,
3547            },
3548            IdxSlope::MAX,
3549        );
3550        idxmeta.insert(
3551            IdxKey {
3552                attr: Attribute::UserId,
3553                itype: IndexType::Presence,
3554            },
3555            IdxSlope::MAX,
3556        );
3557        idxmeta.insert(
3558            IdxKey {
3559                attr: Attribute::Extra,
3560                itype: IndexType::Equality,
3561            },
3562            IdxSlope::MAX,
3563        );
3564
3565        let r1 = Entry::idx_diff(&idxmeta, None, None);
3567        eprintln!("{r1:?}");
3568        assert_eq!(r1, Vec::with_capacity(0));
3569
3570        let mut del_r = Entry::idx_diff(&idxmeta, Some(&e1), None);
3572        del_r.sort_unstable();
3573        eprintln!("del_r {del_r:?}");
3574        assert!(
3575            del_r[0]
3576                == Err((
3577                    &Attribute::UserId,
3578                    IndexType::Equality,
3579                    "william".to_string()
3580                ))
3581        );
3582        assert!(del_r[1] == Err((&Attribute::UserId, IndexType::Presence, "_".to_string())));
3583
3584        let mut add_r = Entry::idx_diff(&idxmeta, None, Some(&e1));
3586        add_r.sort_unstable();
3587        eprintln!("{add_r:?}");
3588        assert!(
3589            add_r[0]
3590                == Ok((
3591                    &Attribute::UserId,
3592                    IndexType::Equality,
3593                    "william".to_string()
3594                ))
3595        );
3596        assert!(add_r[1] == Ok((&Attribute::UserId, IndexType::Presence, "_".to_string())));
3597
3598        let no_r = Entry::idx_diff(&idxmeta, Some(&e1), Some(&e1));
3602        assert!(no_r.is_empty());
3603
3604        let add_a_r = Entry::idx_diff(&idxmeta, Some(&e1), Some(&e1_mod));
3606        assert!(add_a_r[0] == Ok((&Attribute::Extra, IndexType::Equality, "test".to_string())));
3607
3608        let del_a_r = Entry::idx_diff(&idxmeta, Some(&e1_mod), Some(&e1));
3610        assert!(del_a_r[0] == Err((&Attribute::Extra, IndexType::Equality, "test".to_string())));
3611
3612        let mut chg_r = Entry::idx_diff(&idxmeta, Some(&e1), Some(&e2));
3614        chg_r.sort_unstable();
3615        eprintln!("{chg_r:?}");
3616        assert!(
3617            chg_r[1]
3618                == Err((
3619                    &Attribute::UserId,
3620                    IndexType::Equality,
3621                    "william".to_string()
3622                ))
3623        );
3624
3625        assert!(
3626            chg_r[0]
3627                == Ok((
3628                    &Attribute::UserId,
3629                    IndexType::Equality,
3630                    "claire".to_string()
3631                ))
3632        );
3633    }
3634
3635    #[test]
3636    fn test_entry_mask_recycled_ts() {
3637        let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
3638        e1.add_ava(Attribute::Class, EntryClass::Person.to_value());
3639        let e1 = e1.into_sealed_committed();
3640        assert!(e1.mask_recycled_ts().is_some());
3641
3642        let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
3643        e2.add_ava(Attribute::Class, EntryClass::Person.to_value());
3644        e2.add_ava(Attribute::Class, EntryClass::Recycled.into());
3645        let e2 = e2.into_sealed_committed();
3646        assert!(e2.mask_recycled_ts().is_none());
3647
3648        let mut e3: Entry<EntryInit, EntryNew> = Entry::new();
3649        e3.add_ava(Attribute::Class, EntryClass::Tombstone.into());
3650        let e3 = e3.into_sealed_committed();
3651        assert!(e3.mask_recycled_ts().is_none());
3652    }
3653
3654    #[test]
3655    fn test_entry_idx_name2uuid_diff() {
3656        let r = Entry::idx_name2uuid_diff(None, None);
3658        assert_eq!(r, (None, None));
3659
3660        {
3662            let mut e: Entry<EntryInit, EntryNew> = Entry::new();
3663            e.add_ava(Attribute::Class, EntryClass::Person.to_value());
3664            let e = e.into_sealed_committed();
3665
3666            assert!(Entry::idx_name2uuid_diff(None, Some(&e)) == (Some(Set::new()), None));
3667        }
3668
3669        {
3670            let mut e: Entry<EntryInit, EntryNew> = Entry::new();
3671            e.add_ava(Attribute::Class, EntryClass::Person.to_value());
3672            e.add_ava(Attribute::GidNumber, Value::new_uint32(1300));
3673            e.add_ava(Attribute::Name, Value::new_iname("testperson"));
3674            e.add_ava(
3675                Attribute::Spn,
3676                Value::new_spn_str("testperson", "example.com"),
3677            );
3678            e.add_ava(
3679                Attribute::Uuid,
3680                Value::Uuid(uuid!("9fec0398-c46c-4df4-9df5-b0016f7d563f")),
3681            );
3682            let e = e.into_sealed_committed();
3683
3684            assert!(
3686                Entry::idx_name2uuid_diff(None, Some(&e))
3687                    == (
3688                        Some(btreeset![
3689                            "1300".to_string(),
3690                            "testperson".to_string(),
3691                            "testperson@example.com".to_string()
3692                        ]),
3693                        None
3694                    )
3695            );
3696            assert!(
3699                Entry::idx_name2uuid_diff(Some(&e), None)
3700                    == (
3701                        None,
3702                        Some(btreeset![
3703                            "1300".to_string(),
3704                            "testperson".to_string(),
3705                            "testperson@example.com".to_string()
3706                        ])
3707                    )
3708            );
3709
3710            assert!(
3712                Entry::idx_name2uuid_diff(Some(&e), Some(&e))
3713                    == (Some(Set::new()), Some(Set::new()))
3714            );
3715        }
3716        {
3719            let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
3720            e1.add_ava(Attribute::Class, EntryClass::Person.to_value());
3721            e1.add_ava(
3722                Attribute::Spn,
3723                Value::new_spn_str("testperson", "example.com"),
3724            );
3725            let e1 = e1.into_sealed_committed();
3726
3727            let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
3728            e2.add_ava(Attribute::Class, EntryClass::Person.to_value());
3729            e2.add_ava(Attribute::Name, Value::new_iname("testperson"));
3730            e2.add_ava(
3731                Attribute::Spn,
3732                Value::new_spn_str("testperson", "example.com"),
3733            );
3734            let e2 = e2.into_sealed_committed();
3735
3736            assert!(
3738                Entry::idx_name2uuid_diff(Some(&e1), Some(&e2))
3739                    == (Some(btreeset!["testperson".to_string()]), Some(Set::new()))
3740            );
3741
3742            assert!(
3744                Entry::idx_name2uuid_diff(Some(&e2), Some(&e1))
3745                    == (Some(Set::new()), Some(btreeset!["testperson".to_string()]))
3746            );
3747        }
3748
3749        {
3751            let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
3752            e1.add_ava(Attribute::Class, EntryClass::Person.to_value());
3753            e1.add_ava(
3754                Attribute::Spn,
3755                Value::new_spn_str("testperson", "example.com"),
3756            );
3757            let e1 = e1.into_sealed_committed();
3758
3759            let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
3760            e2.add_ava(Attribute::Class, EntryClass::Person.to_value());
3761            e2.add_ava(
3762                Attribute::Spn,
3763                Value::new_spn_str("renameperson", "example.com"),
3764            );
3765            let e2 = e2.into_sealed_committed();
3766
3767            assert!(
3768                Entry::idx_name2uuid_diff(Some(&e1), Some(&e2))
3769                    == (
3770                        Some(btreeset!["renameperson@example.com".to_string()]),
3771                        Some(btreeset!["testperson@example.com".to_string()])
3772                    )
3773            );
3774        }
3775    }
3776
3777    #[test]
3778    fn test_entry_idx_uuid2spn_diff() {
3779        assert!(Entry::idx_uuid2spn_diff(None, None).is_none());
3780
3781        let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
3782        e1.add_ava(
3783            Attribute::Spn,
3784            Value::new_spn_str("testperson", "example.com"),
3785        );
3786        let e1 = e1.into_sealed_committed();
3787
3788        let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
3789        e2.add_ava(
3790            Attribute::Spn,
3791            Value::new_spn_str("renameperson", "example.com"),
3792        );
3793        let e2 = e2.into_sealed_committed();
3794
3795        assert!(
3796            Entry::idx_uuid2spn_diff(None, Some(&e1))
3797                == Some(Ok(Value::new_spn_str("testperson", "example.com")))
3798        );
3799        assert!(Entry::idx_uuid2spn_diff(Some(&e1), None) == Some(Err(())));
3800        assert!(Entry::idx_uuid2spn_diff(Some(&e1), Some(&e1)).is_none());
3801        assert!(
3802            Entry::idx_uuid2spn_diff(Some(&e1), Some(&e2))
3803                == Some(Ok(Value::new_spn_str("renameperson", "example.com")))
3804        );
3805    }
3806
3807    #[test]
3808    fn test_entry_idx_uuid2rdn_diff() {
3809        assert!(Entry::idx_uuid2rdn_diff(None, None).is_none());
3810
3811        let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
3812        e1.add_ava(
3813            Attribute::Spn,
3814            Value::new_spn_str("testperson", "example.com"),
3815        );
3816        let e1 = e1.into_sealed_committed();
3817
3818        let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
3819        e2.add_ava(
3820            Attribute::Spn,
3821            Value::new_spn_str("renameperson", "example.com"),
3822        );
3823        let e2 = e2.into_sealed_committed();
3824
3825        assert!(
3826            Entry::idx_uuid2rdn_diff(None, Some(&e1))
3827                == Some(Ok("spn=testperson@example.com".to_string()))
3828        );
3829        assert!(Entry::idx_uuid2rdn_diff(Some(&e1), None) == Some(Err(())));
3830        assert!(Entry::idx_uuid2rdn_diff(Some(&e1), Some(&e1)).is_none());
3831        assert!(
3832            Entry::idx_uuid2rdn_diff(Some(&e1), Some(&e2))
3833                == Some(Ok("spn=renameperson@example.com".to_string()))
3834        );
3835    }
3836}