1use crate::model::{ActiveRow, SqlxModel};
4use crate::pool::Engine;
5use crate::value::SqlValue;
6use alibi_core::entity::{AuthAccount, AuthSession, AuthUser, AuthVerification};
7use alibi_core::error::AuthResult;
8pub use alibi_core::schema::AuthSchema;
9use alibi_core::types::{
10 CreateAccount, CreateSession, CreateUser, CreateVerification, UpdateAccount, UpdateUser,
11};
12use chrono::{DateTime, Utc};
13
14pub trait SqlxUserModel: AuthUser + SqlxModel {
15 fn additional_field_bindings(
21 fields: &alibi_core::field_policy::FieldValues,
22 _backend: Engine,
23 ) -> AuthResult<Vec<(&'static str, SqlValue)>> {
24 if fields.is_empty() {
25 return Ok(Vec::new());
26 }
27 Err(alibi_core::AuthError::internal(
28 "the user schema has no additional field bindings",
29 ))
30 }
31
32 fn set_additional_field(
37 _active: &mut ActiveRow,
38 _column: &'static str,
39 _value: SqlValue,
40 _backend: Engine,
41 ) -> AuthResult<()> {
42 Err(alibi_core::AuthError::internal(
43 "the user schema cannot stage additional fields",
44 ))
45 }
46
47 fn id_column() -> &'static str;
48
49 fn email_column() -> &'static str;
50
51 #[must_use]
53 fn username_column() -> Option<&'static str> {
54 None
55 }
56
57 #[must_use]
58 fn phone_number_column() -> Option<&'static str> {
59 None
60 }
61
62 fn name_column() -> &'static str;
63
64 fn created_at_column() -> &'static str;
65
66 #[must_use]
70 fn list_users_column(field: &str) -> Option<&'static str> {
71 match field {
72 "id" => Some(Self::id_column()),
73 "email" => Some(Self::email_column()),
74 "name" => Some(Self::name_column()),
75 "username" => Self::username_column(),
76 "createdAt" => Some(Self::created_at_column()),
77 _ => None,
78 }
79 }
80
81 fn parse_id(id: &str) -> AuthResult<SqlValue>;
86
87 fn new_active(id: Option<SqlValue>, create_user: CreateUser, now: DateTime<Utc>) -> ActiveRow;
88
89 fn apply_update(active: &mut ActiveRow, update: UpdateUser, now: DateTime<Utc>);
90
91 fn prepare_json_metadata(_active: &mut ActiveRow, _backend: Engine) -> AuthResult<()> {
98 Ok(())
99 }
100}
101
102pub trait SqlxSessionModel: AuthSession + SqlxModel {
103 fn materialize_secondary(_active: ActiveRow) -> AuthResult<Self> {
110 Err(alibi_core::AuthError::NotImplemented(
111 "Secondary session materialization is unsupported".into(),
112 ))
113 }
114
115 fn additional_field_bindings(
121 fields: &alibi_core::field_policy::FieldValues,
122 _backend: Engine,
123 ) -> AuthResult<Vec<(&'static str, SqlValue)>> {
124 if fields.is_empty() {
125 return Ok(Vec::new());
126 }
127 Err(alibi_core::AuthError::internal(
128 "the session schema has no additional field bindings",
129 ))
130 }
131
132 fn set_additional_field(
137 _active: &mut ActiveRow,
138 _column: &'static str,
139 _value: SqlValue,
140 _backend: Engine,
141 ) -> AuthResult<()> {
142 Err(alibi_core::AuthError::internal(
143 "the session schema cannot stage additional fields",
144 ))
145 }
146
147 fn id_column() -> &'static str;
148
149 fn token_column() -> &'static str;
150
151 fn user_id_column() -> &'static str;
152
153 fn active_column() -> &'static str;
154
155 fn expires_at_column() -> &'static str;
156
157 fn created_at_column() -> &'static str;
158
159 fn parse_id(id: &str) -> AuthResult<SqlValue>;
164
165 fn parse_user_id(user_id: &str) -> AuthResult<SqlValue>;
170
171 fn new_active(
172 id: Option<SqlValue>,
173 token: String,
174 create_session: CreateSession,
175 now: DateTime<Utc>,
176 ) -> ActiveRow;
177
178 fn set_expires_at(active: &mut ActiveRow, expires_at: DateTime<Utc>);
179
180 fn set_updated_at(active: &mut ActiveRow, updated_at: DateTime<Utc>);
181
182 fn set_active_organization_id(active: &mut ActiveRow, organization_id: Option<String>);
183
184 fn set_active_team_id(active: &mut ActiveRow, team_id: Option<String>) -> AuthResult<()> {
189 drop((active, team_id));
190 Err(alibi_core::AuthError::internal(
191 "the session schema has no active-team field",
192 ))
193 }
194}
195
196pub trait SqlxAccountModel: AuthAccount + SqlxModel {
197 fn additional_field_bindings(
203 fields: &alibi_core::field_policy::FieldValues,
204 _backend: Engine,
205 ) -> AuthResult<Vec<(&'static str, SqlValue)>> {
206 if fields.is_empty() {
207 return Ok(Vec::new());
208 }
209 Err(alibi_core::AuthError::internal(
210 "the account schema has no additional field bindings",
211 ))
212 }
213
214 fn set_additional_field(
219 _active: &mut ActiveRow,
220 _column: &'static str,
221 _value: SqlValue,
222 _backend: Engine,
223 ) -> AuthResult<()> {
224 Err(alibi_core::AuthError::internal(
225 "the account schema cannot stage additional fields",
226 ))
227 }
228
229 fn oauth_token_columns() -> Option<[&'static str; 3]> {
232 None
233 }
234
235 fn id_column() -> &'static str;
236 fn provider_id_column() -> &'static str;
237 fn account_id_column() -> &'static str;
238 fn user_id_column() -> &'static str;
239 fn created_at_column() -> &'static str;
240 fn parse_id(id: &str) -> AuthResult<SqlValue>;
245
246 fn parse_user_id(user_id: &str) -> AuthResult<SqlValue>;
251
252 fn new_active(
253 id: Option<SqlValue>,
254 create_account: CreateAccount,
255 now: DateTime<Utc>,
256 ) -> ActiveRow;
257 fn apply_update(active: &mut ActiveRow, update: UpdateAccount, now: DateTime<Utc>);
258}
259
260pub trait SqlxVerificationModel: AuthVerification + SqlxModel {
261 fn id_column() -> &'static str;
262 fn identifier_column() -> &'static str;
263 fn value_column() -> &'static str;
264 fn expires_at_column() -> &'static str;
265 fn created_at_column() -> &'static str;
266 #[must_use]
267 fn updated_at_column() -> Option<&'static str> {
268 None
269 }
270 fn parse_id(id: &str) -> AuthResult<SqlValue>;
275
276 fn parse_reservation_id(encoded: &str, digest: [u8; 32]) -> AuthResult<SqlValue> {
285 if let Ok(id) = Self::parse_id(encoded) {
286 return Ok(id);
287 }
288 let mut bytes = [0; 16];
289 for (byte, source) in bytes.iter_mut().zip(digest) {
290 *byte = source;
291 }
292 Self::parse_id(&uuid::Uuid::from_bytes(bytes).to_string()).map_err(|_error| {
293 alibi_core::AuthError::internal(
294 "the verification schema cannot represent deterministic reservation IDs",
295 )
296 })
297 }
298
299 fn new_active(
300 id: Option<SqlValue>,
301 verification: CreateVerification,
302 now: DateTime<Utc>,
303 ) -> ActiveRow;
304}