1use crate::{AuthAccount, AuthResult, AuthSession, AuthUser, field_policy::FieldOutput};
4use chrono::{DateTime, Utc};
5use serde::{Serialize, Serializer};
6use std::borrow::Cow;
7
8#[derive(Clone, Debug, Default, Serialize)]
11#[serde(transparent)]
12pub struct AdapterOutput {
13 values: FieldOutput,
14 #[serde(skip)]
15 undefined_fields: std::collections::BTreeSet<String>,
16}
17
18impl AdapterOutput {
19 pub(crate) fn from_values(values: FieldOutput) -> Self {
20 Self {
21 values,
22 undefined_fields: std::collections::BTreeSet::new(),
23 }
24 }
25
26 pub(crate) fn insert(&mut self, name: String, value: Option<serde_json::Value>) {
27 match value {
28 Some(value) => {
29 let _ignored_previous = self.undefined_fields.remove(&name);
30 drop(self.values.insert(name, value));
31 }
32 None => {
33 drop(self.values.remove(&name));
34 let _ignored_clone = self.undefined_fields.insert(name);
35 }
36 }
37 }
38
39 pub(crate) fn extend(&mut self, output: Self) {
40 for (name, value) in output.values {
41 self.insert(name, Some(value));
42 }
43 for name in output.undefined_fields {
44 self.insert(name, None);
45 }
46 }
47
48 #[must_use]
50 pub fn contains_field(&self, name: &str) -> bool {
51 self.values.contains_key(name) || self.undefined_fields.contains(name)
52 }
53
54 #[must_use]
55 pub fn field_is_undefined(&self, name: &str) -> bool {
56 self.undefined_fields.contains(name)
57 }
58
59 #[must_use]
62 pub const fn values(&self) -> &FieldOutput {
63 &self.values
64 }
65
66 pub(crate) fn filter_returned(&self, fields: &crate::field_policy::FieldConfigs) -> Self {
67 let mut output = self.clone();
68 for (name, field) in fields {
69 if !field.returned {
70 drop(output.values.remove(name));
71 let _removed = output.undefined_fields.remove(name);
72 }
73 }
74 output
75 }
76}
77
78#[derive(Clone, Debug)]
82pub struct AdapterRecord<M> {
83 stored: M,
84 output: AdapterOutput,
85}
86
87impl<M: Serialize> AdapterRecord<M> {
88 pub fn physical(stored: M) -> AuthResult<Self> {
94 let serde_json::Value::Object(output) = serde_json::to_value(&stored)? else {
95 return Err(crate::AuthError::internal(
96 "An adapter model must serialize to an object",
97 ));
98 };
99 Ok(Self {
100 stored,
101 output: AdapterOutput::from_values(output),
102 })
103 }
104}
105
106impl<M> AdapterRecord<M> {
107 pub(crate) fn with_output(stored: M, output: AdapterOutput) -> Self {
108 Self { stored, output }
109 }
110
111 pub(crate) fn retain_provider_verification(&mut self, value: serde_json::Value) {
112 self.output.insert("emailVerified".into(), Some(value));
113 }
114
115 #[must_use]
116 pub const fn stored(&self) -> &M {
117 &self.stored
118 }
119
120 #[must_use]
121 pub fn into_stored(self) -> M {
122 self.stored
123 }
124
125 #[must_use]
128 pub const fn raw_snapshot(&self) -> &AdapterOutput {
129 &self.output
130 }
131}
132
133impl<M> Serialize for AdapterRecord<M> {
134 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
135 self.output.serialize(serializer)
136 }
137}
138
139macro_rules! delegate {
140 ($name:ident, $output:ty) => {
141 fn $name(&self) -> $output {
142 self.stored.$name()
143 }
144 };
145}
146
147impl<M: AuthUser> AuthUser for AdapterRecord<M> {
148 fn adapter_snapshot(&self) -> Option<&AdapterOutput> {
149 Some(&self.output)
150 }
151 delegate!(additional_fields, FieldOutput);
152 delegate!(id, Cow<'_, str>);
153 delegate!(email, Option<&str>);
154 delegate!(name, Option<&str>);
155 delegate!(email_verified, bool);
156 delegate!(image, Option<&str>);
157 delegate!(created_at, DateTime<Utc>);
158 delegate!(updated_at, DateTime<Utc>);
159 delegate!(username, Option<&str>);
160 delegate!(display_username, Option<&str>);
161 delegate!(two_factor_enabled, bool);
162 delegate!(two_factor_enabled_value, Option<bool>);
163 delegate!(role, Option<&str>);
164 delegate!(banned, bool);
165 delegate!(banned_value, Option<bool>);
166 delegate!(ban_reason, Option<&str>);
167 delegate!(ban_expires, Option<DateTime<Utc>>);
168 delegate!(metadata, &serde_json::Value);
169 delegate!(is_anonymous, Option<bool>);
170 delegate!(phone_number, Option<&str>);
171 delegate!(phone_number_verified, Option<bool>);
172 delegate!(last_login_method, Option<&str>);
173}
174
175impl<M: AuthSession> AuthSession for AdapterRecord<M> {
176 fn adapter_snapshot(&self) -> Option<&AdapterOutput> {
177 Some(&self.output)
178 }
179 delegate!(additional_fields, FieldOutput);
180 delegate!(id, Cow<'_, str>);
181 delegate!(expires_at, DateTime<Utc>);
182 delegate!(token, &str);
183 delegate!(created_at, DateTime<Utc>);
184 delegate!(updated_at, DateTime<Utc>);
185 delegate!(ip_address, Option<&str>);
186 delegate!(user_agent, Option<&str>);
187 delegate!(user_id, Cow<'_, str>);
188 delegate!(impersonated_by, Option<&str>);
189 delegate!(active_organization_id, Option<&str>);
190 delegate!(active_team_id, Option<&str>);
191 delegate!(active, bool);
192}
193
194impl<M: AuthAccount> AuthAccount for AdapterRecord<M> {
195 fn adapter_snapshot(&self) -> Option<&AdapterOutput> {
196 Some(&self.output)
197 }
198 delegate!(additional_fields, FieldOutput);
199 delegate!(id, Cow<'_, str>);
200 delegate!(account_id, &str);
201 delegate!(provider_id, &str);
202 delegate!(user_id, Cow<'_, str>);
203 delegate!(access_token, Option<&str>);
204 delegate!(refresh_token, Option<&str>);
205 delegate!(id_token, Option<&str>);
206 delegate!(access_token_expires_at, Option<DateTime<Utc>>);
207 delegate!(refresh_token_expires_at, Option<DateTime<Utc>>);
208 delegate!(scope, Option<&str>);
209 delegate!(password, Option<&str>);
210 delegate!(created_at, DateTime<Utc>);
211 delegate!(updated_at, DateTime<Utc>);
212}