Skip to main content

alibi_core/store/contracts/
user.rs

1use crate::AdapterRecord;
2use crate::user_validation::{PreparedUserCreation, UserValidationSource};
3use crate::{AuthError, AuthResult, AuthSchema, CreateUser, ListUsersParams, UpdateUser};
4use async_trait::async_trait;
5/// Numeric binding used when a registered user text field accepts a JSON number.
6/// The HTTP caller first rounds it to a JavaScript number, preserving negative zero.
7#[derive(Clone, Copy, Debug)]
8pub enum NumericTextInput {
9    Integer(i64),
10    Real(f64),
11}
12
13#[async_trait]
14pub trait UserStore<S: AuthSchema>: Send + Sync {
15    /// Read the provider verification column using the adapter's physical scalar
16    /// rules. This is retained output, not authorization input; typed models
17    /// continue to supply the canonical boolean accessor.
18    async fn provider_verification_output(
19        &self,
20        _id: &str,
21    ) -> AuthResult<Option<serde_json::Value>> {
22        Ok(None)
23    }
24
25    /// Return a retained adapter record. The default is the physical model's
26    /// serialized snapshot; initialized stores apply their declared output policy.
27    async fn create_user_record(
28        &self,
29        create_user: CreateUser,
30    ) -> AuthResult<AdapterRecord<S::User>> {
31        AdapterRecord::physical(self.create_user(create_user).await?)
32    }
33
34    /// Return a retained adapter record. The default is the physical model's
35    /// serialized snapshot; initialized stores apply their declared output policy.
36    async fn create_user_with_source_record(
37        &self,
38        create_user: CreateUser,
39        source: UserValidationSource,
40    ) -> AuthResult<AdapterRecord<S::User>> {
41        AdapterRecord::physical(self.create_user_with_source(create_user, source).await?)
42    }
43
44    /// Return a retained adapter record. The default is the physical model's
45    /// serialized snapshot; initialized stores apply their declared output policy.
46    async fn create_user_prepared_record(
47        &self,
48        prepared: PreparedUserCreation,
49    ) -> AuthResult<AdapterRecord<S::User>> {
50        AdapterRecord::physical(self.create_user_prepared(prepared).await?)
51    }
52
53    /// Return a retained adapter record. The default is the physical model's
54    /// serialized snapshot; initialized stores apply their declared output policy.
55    async fn get_user_by_id_record(&self, id: &str) -> AuthResult<Option<AdapterRecord<S::User>>> {
56        self.get_user_by_id(id)
57            .await?
58            .map(AdapterRecord::physical)
59            .transpose()
60    }
61
62    /// Return a retained adapter record. The default is the physical model's
63    /// serialized snapshot; initialized stores apply their declared output policy.
64    async fn get_user_by_email_record(
65        &self,
66        email: &str,
67    ) -> AuthResult<Option<AdapterRecord<S::User>>> {
68        self.get_user_by_email(email)
69            .await?
70            .map(AdapterRecord::physical)
71            .transpose()
72    }
73
74    /// Return a retained adapter record. The default is the physical model's
75    /// serialized snapshot; initialized stores apply their declared output policy.
76    async fn get_user_by_username_record(
77        &self,
78        username: &str,
79    ) -> AuthResult<Option<AdapterRecord<S::User>>> {
80        self.get_user_by_username(username)
81            .await?
82            .map(AdapterRecord::physical)
83            .transpose()
84    }
85
86    /// Return a retained adapter record. The default is the physical model's
87    /// serialized snapshot; initialized stores apply their declared output policy.
88    async fn get_user_by_phone_number_record(
89        &self,
90        phone_number: &str,
91    ) -> AuthResult<Option<AdapterRecord<S::User>>> {
92        self.get_user_by_phone_number(phone_number)
93            .await?
94            .map(AdapterRecord::physical)
95            .transpose()
96    }
97
98    /// Return a retained adapter record. The default is the physical model's
99    /// serialized snapshot; initialized stores apply their declared output policy.
100    async fn list_users_by_ids_record(
101        &self,
102        ids: &[String],
103    ) -> AuthResult<Vec<AdapterRecord<S::User>>> {
104        self.list_users_by_ids(ids)
105            .await?
106            .into_iter()
107            .map(AdapterRecord::physical)
108            .collect()
109    }
110
111    /// Return a retained adapter record. The default is the physical model's
112    /// serialized snapshot; initialized stores apply their declared output policy.
113    async fn list_users_by_ids_page_record(
114        &self,
115        ids: &[String],
116        limit: f64,
117    ) -> AuthResult<Vec<AdapterRecord<S::User>>> {
118        self.list_users_by_ids_page(ids, limit)
119            .await?
120            .into_iter()
121            .map(AdapterRecord::physical)
122            .collect()
123    }
124
125    /// Return a retained adapter record. The default is the physical model's
126    /// serialized snapshot; initialized stores apply their declared output policy.
127    async fn update_user_record(
128        &self,
129        id: &str,
130        update: UpdateUser,
131    ) -> AuthResult<AdapterRecord<S::User>> {
132        AdapterRecord::physical(self.update_user(id, update).await?)
133    }
134
135    /// Return a retained adapter record. The default is the physical model's
136    /// serialized snapshot; initialized stores apply their declared output policy.
137    async fn list_users_record(
138        &self,
139        params: ListUsersParams,
140    ) -> AuthResult<(Vec<AdapterRecord<S::User>>, usize)> {
141        let (models, count) = self.list_users(params).await?;
142        Ok((
143            models
144                .into_iter()
145                .map(AdapterRecord::physical)
146                .collect::<AuthResult<Vec<_>>>()?,
147            count,
148        ))
149    }
150
151    async fn create_user(&self, create_user: CreateUser) -> AuthResult<S::User>;
152    /// Create with endpoint-owned identity provenance, retaining the finalized
153    /// instance's validation and database-hook ordering.
154    async fn create_user_with_source(
155        &self,
156        create_user: CreateUser,
157        _source: UserValidationSource,
158    ) -> AuthResult<S::User> {
159        self.create_user(create_user).await
160    }
161    /// Persist a normalized, admitted candidate without normalizing trusted
162    /// callback mutations again. Unsupported custom adapters fail closed.
163    async fn create_user_prepared(&self, _prepared: PreparedUserCreation) -> AuthResult<S::User> {
164        Err(AuthError::NotImplemented(
165            "Prepared user creation is not supported by this store".into(),
166        ))
167    }
168    /// Coerce a numeric binding with the configured adapter's text semantics.
169    /// Custom adapters must implement this explicitly when accepting such input.
170    async fn coerce_user_text_number(&self, _input: NumericTextInput) -> AuthResult<String> {
171        Err(AuthError::NotImplemented(
172            "Numeric user-field text coercion is not supported by this store".into(),
173        ))
174    }
175    async fn get_user_by_id(&self, id: &str) -> AuthResult<Option<S::User>>;
176    /// Fetch multiple users by id.
177    ///
178    /// Implementations may return rows in any order. Callers must remap by id
179    /// when response order matters.
180    async fn list_users_by_ids(&self, ids: &[String]) -> AuthResult<Vec<S::User>>;
181    /// Apply the adapter's raw numeric page to actual matching users. Unsupported
182    /// stores fail closed rather than rounding, capping, or delegating to an unpaged read.
183    async fn list_users_by_ids_page(
184        &self,
185        _ids: &[String],
186        _limit: f64,
187    ) -> AuthResult<Vec<S::User>> {
188        Err(AuthError::NotImplemented(
189            "Raw numeric user pages are not supported by this store".into(),
190        ))
191    }
192    async fn get_user_by_email(&self, email: &str) -> AuthResult<Option<S::User>>;
193    async fn get_user_by_username(&self, username: &str) -> AuthResult<Option<S::User>>;
194    async fn get_user_by_phone_number(&self, _phone_number: &str) -> AuthResult<Option<S::User>> {
195        Err(AuthError::internal(
196            "phone-number lookup is not supported by this store",
197        ))
198    }
199    async fn update_user(&self, id: &str, update: UpdateUser) -> AuthResult<S::User>;
200    async fn delete_user(&self, id: &str) -> AuthResult<()>;
201    async fn list_users(&self, params: ListUsersParams) -> AuthResult<(Vec<S::User>, usize)>;
202}