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