1use crate::model::{ActiveRow, SqlxModel};
4use crate::pool::Engine;
5use crate::value::SqlValue;
6use alibi_core::AuthError;
7use alibi_core::entity::{AuthAccount, AuthSession, AuthUser, AuthVerification};
8use alibi_core::error::AuthResult;
9use alibi_core::field_policy::FieldValues;
10pub use alibi_core::schema::AuthSchema;
11use alibi_core::types::{
12 CreateAccount, CreateSession, CreateUser, CreateVerification, UpdateAccount, UpdateUser,
13};
14use chrono::{DateTime, Utc};
15
16pub trait SqlxUserModel: AuthUser + SqlxModel {
17 fn additional_field_bindings(
23 fields: &FieldValues,
24 _backend: Engine,
25 ) -> AuthResult<Vec<(&'static str, SqlValue)>> {
26 if fields.is_empty() {
27 return Ok(Vec::new());
28 }
29 Err(alibi_core::AuthError::internal(
30 "the user schema has no additional field bindings",
31 ))
32 }
33
34 fn set_additional_field(
38 _active: &mut ActiveRow,
39 _column: &'static str,
40 _value: SqlValue,
41 _backend: Engine,
42 ) -> AuthResult<()> {
43 Err(alibi_core::AuthError::internal(
44 "the user schema cannot stage additional fields",
45 ))
46 }
47
48 fn id_column() -> &'static str;
49
50 fn email_column() -> &'static str;
51
52 #[must_use]
54 fn username_column() -> Option<&'static str> {
55 None
56 }
57
58 #[must_use]
59 fn phone_number_column() -> Option<&'static str> {
60 None
61 }
62
63 fn name_column() -> &'static str;
64
65 fn created_at_column() -> &'static str;
66
67 #[must_use]
71 fn list_users_column(field: &str) -> Option<&'static str> {
72 match field {
73 "id" => Some(Self::id_column()),
74 "email" => Some(Self::email_column()),
75 "name" => Some(Self::name_column()),
76 "username" => Self::username_column(),
77 "createdAt" => Some(Self::created_at_column()),
78 _ => None,
79 }
80 }
81
82 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(AuthError::NotImplemented(
111 "Secondary session materialization is unsupported".into(),
112 ))
113 }
114
115 fn additional_field_bindings(
121 fields: &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(
136 _active: &mut ActiveRow,
137 _column: &'static str,
138 _value: SqlValue,
139 _backend: Engine,
140 ) -> AuthResult<()> {
141 Err(alibi_core::AuthError::internal(
142 "the session schema cannot stage additional fields",
143 ))
144 }
145
146 fn id_column() -> &'static str;
147
148 fn token_column() -> &'static str;
149
150 fn user_id_column() -> &'static str;
151
152 fn active_column() -> &'static str;
153
154 fn expires_at_column() -> &'static str;
155
156 fn created_at_column() -> &'static str;
157
158 fn parse_id(id: &str) -> AuthResult<SqlValue>;
162
163 fn parse_user_id(user_id: &str) -> AuthResult<SqlValue>;
167
168 fn new_active(
169 id: Option<SqlValue>,
170 token: String,
171 create_session: CreateSession,
172 now: DateTime<Utc>,
173 ) -> ActiveRow;
174
175 fn set_expires_at(active: &mut ActiveRow, expires_at: DateTime<Utc>);
176
177 fn set_updated_at(active: &mut ActiveRow, updated_at: DateTime<Utc>);
178
179 fn set_active_organization_id(active: &mut ActiveRow, organization_id: Option<String>);
180
181 fn set_active_team_id(_active: &mut ActiveRow, _team_id: Option<String>) -> AuthResult<()> {
185 Err(alibi_core::AuthError::internal(
186 "the session schema has no active-team field",
187 ))
188 }
189}
190
191pub trait SqlxAccountModel: AuthAccount + SqlxModel {
192 fn additional_field_bindings(
198 fields: &FieldValues,
199 _backend: Engine,
200 ) -> AuthResult<Vec<(&'static str, SqlValue)>> {
201 if fields.is_empty() {
202 return Ok(Vec::new());
203 }
204 Err(alibi_core::AuthError::internal(
205 "the account schema has no additional field bindings",
206 ))
207 }
208
209 fn set_additional_field(
213 _active: &mut ActiveRow,
214 _column: &'static str,
215 _value: SqlValue,
216 _backend: Engine,
217 ) -> AuthResult<()> {
218 Err(alibi_core::AuthError::internal(
219 "the account schema cannot stage additional fields",
220 ))
221 }
222
223 fn oauth_token_columns() -> Option<[&'static str; 3]> {
226 None
227 }
228
229 fn id_column() -> &'static str;
230 fn provider_id_column() -> &'static str;
231 fn account_id_column() -> &'static str;
232 fn user_id_column() -> &'static str;
233 fn created_at_column() -> &'static str;
234 fn parse_id(id: &str) -> AuthResult<SqlValue>;
238
239 fn parse_user_id(user_id: &str) -> AuthResult<SqlValue>;
243
244 fn new_active(
245 id: Option<SqlValue>,
246 create_account: CreateAccount,
247 now: DateTime<Utc>,
248 ) -> ActiveRow;
249 fn apply_update(active: &mut ActiveRow, update: UpdateAccount, now: DateTime<Utc>);
250}
251
252pub trait SqlxVerificationModel: AuthVerification + SqlxModel {
253 fn id_column() -> &'static str;
254 fn identifier_column() -> &'static str;
255 fn value_column() -> &'static str;
256 fn expires_at_column() -> &'static str;
257 fn created_at_column() -> &'static str;
258 #[must_use]
259 fn updated_at_column() -> Option<&'static str> {
260 None
261 }
262 fn parse_id(id: &str) -> AuthResult<SqlValue>;
266
267 fn parse_reservation_id(encoded: &str, digest: [u8; 32]) -> AuthResult<SqlValue> {
276 if let Ok(id) = Self::parse_id(encoded) {
277 return Ok(id);
278 }
279 let mut bytes = [0; 16];
280 for (byte, source) in bytes.iter_mut().zip(digest) {
281 *byte = source;
282 }
283 Self::parse_id(&uuid::Uuid::from_bytes(bytes).to_string()).map_err(|_error| {
284 alibi_core::AuthError::internal(
285 "the verification schema cannot represent deterministic reservation IDs",
286 )
287 })
288 }
289
290 fn new_active(
291 id: Option<SqlValue>,
292 verification: CreateVerification,
293 now: DateTime<Utc>,
294 ) -> ActiveRow;
295}