alibi_core/store/stateless/
transaction.rs1use super::*;
2
3fn merge<T: Clone + PartialEq>(
7 live: &mut indexmap::IndexMap<String, T>,
8 base: &indexmap::IndexMap<String, T>,
9 changed: indexmap::IndexMap<String, T>,
10) {
11 live.retain(|id, _| !base.contains_key(id) || changed.contains_key(id));
12 for (id, row) in changed {
13 if base.get(&id) == Some(&row) {
14 continue;
15 }
16 if live.contains_key(&id) || !base.contains_key(&id) {
19 drop(live.insert(id, row));
20 }
21 }
22}
23
24struct OrganizationTransaction<'a> {
25 live: &'a StatelessStore,
26 snapshot: StatelessStore,
27}
28
29#[async_trait]
30impl TransactionStore<StatelessSchema> for StatelessStore {
31 async fn transaction_boxed(
32 &self,
33 work: Box<TransactionWork<StatelessSchema>>,
34 ) -> AuthResult<BoxedTransactionValue> {
35 let base = self.organization_state()?.clone();
36 let tx = OrganizationTransaction {
37 live: self,
38 snapshot: StatelessStore {
39 organizations: std::sync::Mutex::new(base.clone()),
40 ..Self::with_find_many_limit(self.find_many_limit)
41 },
42 };
43 let result = work(&tx).await?;
44 let changed = tx
45 .snapshot
46 .organizations
47 .into_inner()
48 .map_err(|_| AuthError::internal("No-database organization state poisoned"))?;
49 let mut live = self.organization_state()?;
50 merge(
51 &mut live.organizations,
52 &base.organizations,
53 changed.organizations,
54 );
55 merge(&mut live.members, &base.members, changed.members);
56 merge(
57 &mut live.invitations,
58 &base.invitations,
59 changed.invitations,
60 );
61 merge(&mut live.teams, &base.teams, changed.teams);
62 merge(
63 &mut live.team_members,
64 &base.team_members,
65 changed.team_members,
66 );
67 merge(&mut live.roles, &base.roles, changed.roles);
68 Ok(result)
69 }
70}
71
72#[async_trait]
73impl AuthTransaction<StatelessSchema> for OrganizationTransaction<'_> {
74 async fn get_team(&self, org: &str, id: &str) -> AuthResult<Option<Team>> {
75 TeamStore::get_team(&self.snapshot, Some(org), id).await
76 }
77 async fn add_team_member(
78 &self,
79 team: &str,
80 user: &str,
81 maximum: Option<f64>,
82 ) -> AuthResult<AddTeamMemberResult> {
83 TeamStore::add_team_member(&self.snapshot, team, user, maximum).await
84 }
85 async fn create_member(&self, data: CreateMember) -> AuthResult<Member> {
86 MemberStore::create_member(&self.snapshot, data).await
87 }
88 async fn prepare_secondary_session_creation(
89 &self,
90 input: CreateSession,
91 persist: bool,
92 ) -> AuthResult<SessionView> {
93 SessionStore::<StatelessSchema>::prepare_secondary_session_creation(
94 self.live, input, persist,
95 )
96 .await
97 }
98 async fn prepare_secondary_session_update(
99 &self,
100 session: SessionView,
101 expires_at: Option<DateTime<Utc>>,
102 fields: crate::field_policy::FieldValues,
103 ) -> AuthResult<Option<(SessionView, crate::field_policy::FieldValues)>> {
104 SessionStore::<StatelessSchema>::prepare_secondary_session_update(
105 self.live, session, expires_at, fields,
106 )
107 .await
108 }
109 async fn complete_secondary_session_update(
110 &self,
111 session: SessionView,
112 expires_at: Option<DateTime<Utc>>,
113 fields: crate::field_policy::FieldValues,
114 persist: bool,
115 ) -> AuthResult<Option<SessionView>> {
116 SessionStore::<StatelessSchema>::complete_secondary_session_update(
117 self.live, session, expires_at, fields, persist,
118 )
119 .await
120 }
121 async fn create_user(&self, data: CreateUser) -> AuthResult<UserView> {
124 UserStore::<StatelessSchema>::create_user(self.live, data).await
125 }
126 async fn create_user_prepared(&self, data: PreparedUserCreation) -> AuthResult<UserView> {
127 UserStore::<StatelessSchema>::create_user_prepared(self.live, data).await
128 }
129 async fn create_account(&self, data: CreateAccount) -> AuthResult<AccountView> {
130 AccountStore::<StatelessSchema>::create_account(self.live, data).await
131 }
132 async fn create_session(&self, data: CreateSession) -> AuthResult<SessionView> {
133 SessionStore::<StatelessSchema>::create_session(self.live, data).await
134 }
135}